Ejemplo n.º 1
0
    def __init__(self, ad, loop, logger, access, **config):

        self.AD = ad
        self.logger = logger
        self.acc = access

        self.dashboard_dir = None
        self._process_arg("dashboard_dir", config)

        self.dash_password = None
        self._process_arg("dash_password", config)

        self.dash_url = None
        self._process_arg("dash_url", config)

        self.config_dir = None
        self._process_arg("config_dir", config)

        self.dash_compile_on_start = False
        self._process_arg("dash_compile_on_start", config)

        self.dash_force_compile = False
        self._process_arg("dash_force_compile", config)

        self.work_factor = 8
        self._process_arg("work_factor", config)

        self.profile_dashboard = False
        self._process_arg("profile_dashboard", config)

        self.dash_ssl_certificate = None
        self._process_arg("dash_ssl_certificate", config)

        self.dash_ssl_key = None
        self._process_arg("dash_ssl_key", config)

        self.rss_feeds = None
        self._process_arg("rss_feeds", config)

        self.fa4compatibility = False
        self._process_arg("fa4compatibility", config)

        if "rss_feeds" in config:
            self.rss_feeds = []
            for feed in config["rss_feeds"]:
                if feed["target"].count('.') != 1:
                    self.log("WARNING", "Invalid RSS feed target: {}".format(feed["target"]))
                else:
                    self.rss_feeds.append(feed)

        self.rss_update = None
        self._process_arg("rss_update", config)

        self.rss_last_update = None

        self.stopping = False

        url = urlparse(self.dash_url)

        dash_net = url.netloc.split(":")
        self.dash_host = dash_net[0]
        try:
            self.dash_port = dash_net[1]
        except IndexError:
            self.dash_port = 80

        if self.dash_host == "":
            raise ValueError("Invalid host for 'dash_url'")

        # find dashboard dir

        if self.dashboard_dir is None:
            if self.config_dir is None:
                self.dashboard_dir = utils.find_path("dashboards")
            else:
                self.dashboard_dir = os.path.join(self.config_dir, "dashboards")


            #
            # Setup compile directories
            #
            if self.config_dir is None:
                self.compile_dir = utils.find_path("compiled")
            else:
                self.compile_dir = os.path.join(self.config_dir, "compiled")


        # Setup WS handler

        self.app = web.Application()
        self.app['websockets'] = {}

        self.loop = loop
        self.executor = concurrent.futures.ThreadPoolExecutor(max_workers=5)

        try:
            self.dashboard_obj = dashboard.Dashboard(self.config_dir, access,
                                                 dash_compile_on_start=self.dash_compile_on_start,
                                                 dash_force_compile=self.dash_force_compile,
                                                 profile_dashboard=self.profile_dashboard,
                                                 dashboard_dir = self.dashboard_dir,
                                                 fa4compatibility=self.fa4compatibility
                                                     )
            self.setup_routes()

            if self.dash_ssl_certificate is not None and self.dash_ssl_key is not None:
                context = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
                context.load_cert_chain(self.dash_ssl_certificate, self.dash_ssl_key)
            else:
                context = None

            handler = self.app.make_handler()

            f = loop.create_server(handler, "0.0.0.0", int(self.dash_port), ssl=context)

            #print((([ip for ip in socket.gethostbyname_ex(socket.gethostname())[2] if not ip.startswith("127.")] or [
             #   [(s.connect(("8.8.8.8", 53)), s.getsockname()[0], s.close()) for s in
             #    [socket.socket(socket.AF_INET, socket.SOCK_DGRAM)]][0][1]]) + ["no IP found"])[0])

            loop.create_task(f)
            loop.create_task(self.update_rss())
        except:
            self.log("WARNING", '-' * 60)
            self.log("WARNING", "Unexpected error in dashboard thread")
            self.log("WARNING", '-' * 60)
            self.log("WARNING", traceback.format_exc())
            self.log("WARNING", '-' * 60)
Ejemplo n.º 2
0
    def main(self):  # noqa: C901
        """Initial AppDaemon entry point.

        Parse command line arguments, load configuration, set up logging.

        """

        self.init_signals()

        # Get command line args

        parser = argparse.ArgumentParser()

        parser.add_argument(
            "-c", "--config", help="full path to config directory", type=str, default=None,
        )
        parser.add_argument("-p", "--pidfile", help="full path to PID File", default=None)
        parser.add_argument(
            "-t", "--timewarp", help="speed that the scheduler will work at for time travel", default=1, type=float,
        )
        parser.add_argument(
            "-s", "--starttime", help="start time for scheduler <YYYY-MM-DD HH:MM:SS|YYYY-MM-DD#HH:MM:SS>", type=str,
        )
        parser.add_argument(
            "-e",
            "--endtime",
            help="end time for scheduler <YYYY-MM-DD HH:MM:SS|YYYY-MM-DD#HH:MM:SS>",
            type=str,
            default=None,
        )
        parser.add_argument(
            "-D",
            "--debug",
            help="global debug level",
            default="INFO",
            choices=["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"],
        )
        parser.add_argument("-m", "--moduledebug", nargs=2, action="append")
        parser.add_argument("-v", "--version", action="version", version="%(prog)s " + utils.__version__)
        parser.add_argument("--profiledash", help=argparse.SUPPRESS, action="store_true")

        args = parser.parse_args()

        config_dir = args.config
        pidfile = args.pidfile

        if config_dir is None:
            config_file_yaml = utils.find_path("appdaemon.yaml")
        else:
            config_file_yaml = os.path.join(config_dir, "appdaemon.yaml")

        if config_file_yaml is None:
            print("FATAL: no configuration directory defined and defaults not present\n")
            parser.print_help()
            sys.exit(1)

        module_debug = {}
        if args.moduledebug is not None:
            for arg in args.moduledebug:
                module_debug[arg[0]] = arg[1]

        #
        # First locate secrets file
        #
        try:

            #
            # Read config file using include directory
            #

            yaml.add_constructor("!include", utils._include_yaml, Loader=yaml.SafeLoader)

            #
            # Read config file using environment variables
            #

            yaml.add_constructor("!env_var", utils._env_var_yaml, Loader=yaml.SafeLoader)

            #
            # Initially load file to see if secret directive is present
            #
            yaml.add_constructor("!secret", utils._dummy_secret, Loader=yaml.SafeLoader)
            with open(config_file_yaml, "r") as yamlfd:
                config_file_contents = yamlfd.read()

            config = yaml.load(config_file_contents, Loader=yaml.SafeLoader)

            if "secrets" in config:
                secrets_file = config["secrets"]
            else:
                secrets_file = os.path.join(os.path.dirname(config_file_yaml), "secrets.yaml")

            #
            # Read Secrets
            #
            if os.path.isfile(secrets_file):
                with open(secrets_file, "r") as yamlfd:
                    secrets_file_contents = yamlfd.read()

                utils.secrets = yaml.load(secrets_file_contents, Loader=yaml.SafeLoader)

            else:
                if "secrets" in config:
                    print(
                        "ERROR", "Error loading secrets file: {}".format(config["secrets"]),
                    )
                    sys.exit()

            #
            # Read config file again, this time with secrets
            #

            yaml.add_constructor("!secret", utils._secret_yaml, Loader=yaml.SafeLoader)

            with open(config_file_yaml, "r") as yamlfd:
                config_file_contents = yamlfd.read()

            config = yaml.load(config_file_contents, Loader=yaml.SafeLoader)

        except yaml.YAMLError as exc:
            print("ERROR", "Error loading configuration")
            if hasattr(exc, "problem_mark"):
                if exc.context is not None:
                    print("ERROR", "parser says")
                    print("ERROR", str(exc.problem_mark))
                    print("ERROR", str(exc.problem) + " " + str(exc.context))
                else:
                    print("ERROR", "parser says")
                    print("ERROR", str(exc.problem_mark))
                    print("ERROR", str(exc.problem))
            sys.exit()

        if "appdaemon" not in config:
            print("ERROR", "no 'appdaemon' section in {}".format(config_file_yaml))
            sys.exit()

        appdaemon = config["appdaemon"]
        if "disable_apps" not in appdaemon:
            appdaemon["disable_apps"] = False

        appdaemon["config_dir"] = config_dir
        appdaemon["config_file"] = config_file_yaml
        appdaemon["app_config_file"] = os.path.join(os.path.dirname(config_file_yaml), "apps.yaml")
        appdaemon["module_debug"] = module_debug

        if args.starttime is not None:
            appdaemon["starttime"] = args.starttime

        if args.endtime is not None:
            appdaemon["endtime"] = args.endtime

        if "timewarp" not in appdaemon:
            appdaemon["timewarp"] = args.timewarp

        appdaemon["loglevel"] = args.debug

        appdaemon["config_dir"] = os.path.dirname(config_file_yaml)

        appdaemon["stop_function"] = self.stop

        hadashboard = None
        if "hadashboard" in config:
            if config["hadashboard"] is None:
                hadashboard = {}
            else:
                hadashboard = config["hadashboard"]

            hadashboard["profile_dashboard"] = args.profiledash
            hadashboard["config_dir"] = config_dir
            hadashboard["config_file"] = config_file_yaml
            hadashboard["config_dir"] = os.path.dirname(config_file_yaml)
            if args.profiledash:
                hadashboard["profile_dashboard"] = True

            if "dashboard" not in hadashboard:
                hadashboard["dashboard"] = True

        old_admin = None
        if "old_admin" in config:
            if config["old_admin"] is None:
                old_admin = {}
            else:
                old_admin = config["old_admin"]
        admin = None
        if "admin" in config:
            if config["admin"] is None:
                admin = {}
            else:
                admin = config["admin"]
        api = None
        if "api" in config:
            if config["api"] is None:
                api = {}
            else:
                api = config["api"]

        http = None
        if "http" in config:
            http = config["http"]

        # Setup _logging

        if "log" in config:
            print(
                "ERROR", "'log' directive deprecated, please convert to new 'logs' syntax",
            )
            sys.exit(1)
        if "logs" in config:
            logs = config["logs"]
        else:
            logs = {}

        self.logging = logging.Logging(logs, args.debug)
        self.logger = self.logging.get_logger()

        if "time_zone" in config["appdaemon"]:
            self.logging.set_tz(pytz.timezone(config["appdaemon"]["time_zone"]))

        # Startup message

        self.logger.info("AppDaemon Version %s starting", utils.__version__)
        self.logger.info(
            "Python version is %s.%s.%s", sys.version_info[0], sys.version_info[1], sys.version_info[2],
        )
        self.logger.info("Configuration read from: %s", config_file_yaml)
        self.logging.dump_log_config()
        self.logger.debug("AppDaemon Section: %s", config.get("appdaemon"))
        self.logger.debug("HADashboard Section: %s", config.get("hadashboard"))

        exit = False

        if "time_zone" not in config["appdaemon"]:
            self.logger.error("time_zone not specified in appdaemon.yaml")
            exit = True

        if "latitude" not in config["appdaemon"]:
            self.logger.error("latitude not specified in appdaemon.yaml")
            exit = True

        if "longitude" not in config["appdaemon"]:
            self.logger.error("longitude not specified in appdaemon.yaml")
            exit = True

        if "elevation" not in config["appdaemon"]:
            self.logger.error("elevation not specified in appdaemon.yaml")
            exit = True

        if exit is True:
            sys.exit(1)

        utils.check_path("config_file", self.logger, config_file_yaml, pathtype="file")

        if pidfile is not None:
            self.logger.info("Using pidfile: %s", pidfile)
            dir = os.path.dirname(pidfile)
            name = os.path.basename(pidfile)
            try:
                with pid.PidFile(name, dir):
                    self.run(appdaemon, hadashboard, old_admin, admin, api, http)
            except pid.PidFileError:
                self.logger.error("Unable to acquire pidfile - terminating")
        else:
            self.run(appdaemon, hadashboard, old_admin, admin, api, http)
Ejemplo n.º 3
0
    def __init__(self, ad, loop, logger, access, **config):

        self.AD = ad
        self.logger = logger
        self.acc = access

        self.dashboard_dir = None
        self._process_arg("dashboard_dir", config)

        self.dash_password = None
        self._process_arg("dash_password", config)

        self.dash_url = None
        self._process_arg("dash_url", config)

        self.config_dir = None
        self._process_arg("config_dir", config)

        self.dash_compile_on_start = False
        self._process_arg("dash_compile_on_start", config)

        self.dash_force_compile = False
        self._process_arg("dash_force_compile", config)

        self.work_factor = 8
        self._process_arg("work_factor", config)

        self.profile_dashboard = False
        self._process_arg("profile_dashboard", config)

        self.dash_ssl_certificate = None
        self._process_arg("dash_ssl_certificate", config)

        self.dash_ssl_key = None
        self._process_arg("dash_ssl_key", config)

        self.rss_feeds = None
        self._process_arg("rss_feeds", config)

        self.fa4compatibility = False
        self._process_arg("fa4compatibility", config)

        if "rss_feeds" in config:
            self.rss_feeds = []
            for feed in config["rss_feeds"]:
                if feed["target"].count('.') != 1:
                    self.log(
                        "WARNING",
                        "Invalid RSS feed target: {}".format(feed["target"]))
                else:
                    self.rss_feeds.append(feed)

        self.rss_update = None
        self._process_arg("rss_update", config)

        self.rss_last_update = None

        self.stopping = False

        url = urlparse(self.dash_url)

        dash_net = url.netloc.split(":")
        self.dash_host = dash_net[0]
        try:
            self.dash_port = dash_net[1]
        except IndexError:
            self.dash_port = 80

        if self.dash_host == "":
            raise ValueError("Invalid host for 'dash_url'")

        # find dashboard dir

        if self.dashboard_dir is None:
            if self.config_dir is None:
                self.dashboard_dir = utils.find_path("dashboards")
            else:
                self.dashboard_dir = os.path.join(self.config_dir,
                                                  "dashboards")

            #
            # Setup compile directories
            #
            if self.config_dir is None:
                self.compile_dir = utils.find_path("compiled")
            else:
                self.compile_dir = os.path.join(self.config_dir, "compiled")

        # Setup WS handler

        self.app = web.Application()
        self.app['websockets'] = {}

        self.loop = loop
        self.executor = concurrent.futures.ThreadPoolExecutor(max_workers=5)

        try:
            self.dashboard_obj = dashboard.Dashboard(
                self.config_dir,
                access,
                dash_compile_on_start=self.dash_compile_on_start,
                dash_force_compile=self.dash_force_compile,
                profile_dashboard=self.profile_dashboard,
                dashboard_dir=self.dashboard_dir,
                fa4compatibility=self.fa4compatibility)
            self.setup_routes()

            if self.dash_ssl_certificate is not None and self.dash_ssl_key is not None:
                context = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
                context.load_cert_chain(self.dash_ssl_certificate,
                                        self.dash_ssl_key)
            else:
                context = None

            handler = self.app.make_handler()

            f = loop.create_server(handler,
                                   "0.0.0.0",
                                   int(self.dash_port),
                                   ssl=context)

            #print((([ip for ip in socket.gethostbyname_ex(socket.gethostname())[2] if not ip.startswith("127.")] or [
            #   [(s.connect(("8.8.8.8", 53)), s.getsockname()[0], s.close()) for s in
            #    [socket.socket(socket.AF_INET, socket.SOCK_DGRAM)]][0][1]]) + ["no IP found"])[0])

            loop.create_task(f)
            loop.create_task(self.update_rss())
        except:
            self.log("WARNING", '-' * 60)
            self.log("WARNING", "Unexpected error in dashboard thread")
            self.log("WARNING", '-' * 60)
            self.log("WARNING", traceback.format_exc())
            self.log("WARNING", '-' * 60)
Ejemplo n.º 4
0
    def __init__(self, logging, loop, **kwargs):

        #
        # Import various AppDaemon bits and pieces now to avoid circular import
        #

        import appdaemon.utils as utils
        import appdaemon.thread_async as appq
        import appdaemon.utility_loop as utility
        import appdaemon.plugin_management as plugins
        import appdaemon.threading
        import appdaemon.app_management as apps
        import appdaemon.callbacks as callbacks
        import appdaemon.futures as futures
        import appdaemon.state as state
        import appdaemon.events as events
        import appdaemon.services as services
        import appdaemon.sequences as sequences
        import appdaemon.scheduler as scheduler

        self.logging = logging
        self.logging.register_ad(self)
        self.logger = logging.get_logger()
        self.threading = None
        self.callbacks = None
        self.futures = None
        self.state = None

        self.config = kwargs
        self.booted = "booting"
        self.config["ad_version"] = utils.__version__
        self.check_app_updates_profile = ""

        self.was_dst = False

        self.last_state = None

        self.executor = None
        self.loop = None
        self.srv = None
        self.appd = None
        self.stopping = False
        self.http = None
        self.admin_loop = None

        self.global_vars = {}
        self.global_lock = threading.RLock()

        self.config_file_modified = 0

        self.sched = None
        self.thread_async = None
        self.utility = None
        self.module_debug = kwargs["module_debug"]

        # User Supplied/Defaults

        self.load_distribution = "roundrobbin"
        utils.process_arg(self, "load_distribution", kwargs)

        self.app_dir = None
        utils.process_arg(self, "app_dir", kwargs)

        self.starttime = None
        utils.process_arg(self, "starttime", kwargs)

        self.latitude = None
        utils.process_arg(self, "latitude", kwargs, float=True)

        self.longitude = None
        utils.process_arg(self, "longitude", kwargs, float=True)

        self.elevation = None
        utils.process_arg(self, "elevation", kwargs, int=True)

        self.time_zone = None
        utils.process_arg(self, "time_zone", kwargs)

        self.tz = None
        self.loop = loop

        self.logfile = None
        self.errfile = None

        self.config_file = None
        utils.process_arg(self, "config_file", kwargs)

        self.config_dir = None
        utils.process_arg(self, "config_dir", kwargs)

        self.timewarp = 1
        utils.process_arg(self, "timewarp", kwargs, float=True)

        self.max_clock_skew = 1
        utils.process_arg(self, "max_clock_skew", kwargs, int=True)

        self.thread_duration_warning_threshold = 10
        utils.process_arg(self,
                          "thread_duration_warning_threshold",
                          kwargs,
                          float=True)

        self.threadpool_workers = 10
        utils.process_arg(self, "threadpool_workers", kwargs, int=True)

        self.endtime = None
        utils.process_arg(self, "endtime", kwargs)

        self.loglevel = "INFO"
        utils.process_arg(self, "loglevel", kwargs)

        self.api_port = None
        utils.process_arg(self, "api_port", kwargs)

        self.utility_delay = 1
        utils.process_arg(self, "utility_delay", kwargs, int=True)

        self.admin_delay = 1
        utils.process_arg(self, "admin_delay", kwargs, int=True)

        self.max_utility_skew = self.utility_delay * 2
        utils.process_arg(self, "max_utility_skew", kwargs, float=True)

        self.check_app_updates_profile = False
        utils.process_arg(self, "check_app_updates_profile", kwargs)

        self.production_mode = False
        utils.process_arg(self, "production_mode", kwargs)

        self.invalid_yaml_warnings = True
        utils.process_arg(self, "invalid_yaml_warnings", kwargs)

        self.missing_app_warnings = True
        utils.process_arg(self, "missing_app_warnings", kwargs)

        self.log_thread_actions = False
        utils.process_arg(self, "log_thread_actions", kwargs)

        self.qsize_warning_threshold = 50
        utils.process_arg(self, "qsize_warning_threshold", kwargs, int=True)

        self.qsize_warning_step = 60
        utils.process_arg(self, "qsize_warning_step", kwargs, int=True)

        self.qsize_warning_iterations = 10
        utils.process_arg(self, "qsize_warning_iterations", kwargs, int=True)

        self.internal_function_timeout = 10
        utils.process_arg(self, "internal_function_timeout", kwargs, int=True)

        self.namespaces = {}
        utils.process_arg(self, "namespaces", kwargs)

        self.exclude_dirs = ["__pycache__"]
        if "exclude_dirs" in kwargs:
            self.exclude_dirs += kwargs["exclude_dirs"]

        self.stop_function = None
        utils.process_arg(self, "stop_function", kwargs)

        if not kwargs.get("cert_verify", True):
            self.certpath = False

        if kwargs.get("disable_apps") is True:
            self.apps = False
            self.logging.log("INFO", "Apps are disabled")
        else:
            self.apps = True

        #
        # Set up services
        #
        self.services = services.Services(self)

        #
        # Set up sequences
        #
        self.sequences = sequences.Sequences(self)

        #
        # Set up scheduler
        #
        self.sched = scheduler.Scheduler(self)

        #
        # Set up state
        #
        self.state = state.State(self)

        #
        # Set up events
        #
        self.events = events.Events(self)

        #
        # Set up callbacks
        #
        self.callbacks = callbacks.Callbacks(self)

        #
        # Set up futures
        #
        self.futures = futures.Futures(self)

        if self.apps is True:
            if self.app_dir is None:
                if self.config_dir is None:
                    self.app_dir = utils.find_path("apps")
                    self.config_dir = os.path.dirname(self.app_dir)
                else:
                    self.app_dir = os.path.join(self.config_dir, "apps")

            utils.check_path("config_dir",
                             self.logger,
                             self.config_dir,
                             permissions="rwx")
            utils.check_path("appdir", self.logger, self.app_dir)

            # Initialize Apps

            self.app_management = apps.AppManagement(
                self, kwargs.get("app_config_file", None))

            # threading setup

            self.threading = appdaemon.threading.Threading(self, kwargs)

        self.stopping = False

        #
        # Set up Executor ThreadPool
        #
        if "threadpool_workers" in kwargs:
            self.threadpool_workers = int(kwargs["threadpool_workers"])

        self.executor = concurrent.futures.ThreadPoolExecutor(
            max_workers=self.threadpool_workers)

        # Initialize Plugins

        if "plugins" in kwargs:
            args = kwargs["plugins"]
        else:
            args = None

        self.plugins = plugins.Plugins(self, args)

        # Create thread_async Loop

        self.logger.debug("Starting thread_async loop")

        if self.apps is True:
            self.thread_async = appq.ThreadAsync(self)
            loop.create_task(self.thread_async.loop())

        # Create utility loop

        self.logger.debug("Starting utility loop")

        self.utility = utility.Utility(self)
        loop.create_task(self.utility.loop())
Ejemplo n.º 5
0
    def __init__(self, ad: AppDaemon, loop, logging, appdaemon, dashboard,
                 admin, api, http):

        self.AD = ad
        self.logging = logging
        self.logger = ad.logging.get_child("_http")
        self.access = ad.logging.get_access()

        self.appdaemon = appdaemon
        self.dashboard = dashboard
        self.dashboard_dir = None
        self.admin = admin
        self.http = http
        self.api = api
        self.runner = None

        self.template_dir = os.path.join(os.path.dirname(__file__), "assets",
                                         "templates")

        self.password = None
        self._process_arg("password", http)

        self.valid_tokens = []
        self._process_arg("tokens", http)

        self.url = None
        self._process_arg("url", http)

        self.work_factor = 12
        self._process_arg("work_factor", http)

        self.ssl_certificate = None
        self._process_arg("ssl_certificate", http)

        self.ssl_key = None
        self._process_arg("ssl_key", http)

        self.transport = "ws"
        self._process_arg("transport", http)
        self.logger.info("Using '%s' for event stream", self.transport)

        self.config_dir = None
        self._process_arg("config_dir", dashboard)

        self.static_dirs = {}
        self._process_arg("static_dirs", http)

        self.stopping = False

        self.endpoints = {}
        self.app_routes = {}

        self.dashboard_obj = None
        self.admin_obj = None

        self.install_dir = os.path.dirname(__file__)

        self.javascript_dir = os.path.join(self.install_dir, "assets",
                                           "javascript")
        self.template_dir = os.path.join(self.install_dir, "assets",
                                         "templates")
        self.css_dir = os.path.join(self.install_dir, "assets", "css")
        self.fonts_dir = os.path.join(self.install_dir, "assets", "fonts")
        self.webfonts_dir = os.path.join(self.install_dir, "assets",
                                         "webfonts")
        self.images_dir = os.path.join(self.install_dir, "assets", "images")

        try:
            url = urlparse(self.url)

            net = url.netloc.split(":")
            self.host = net[0]
            try:
                self.port = net[1]
            except IndexError:
                self.port = 80

            if self.host == "":
                raise ValueError("Invalid host for 'url'")

            self.app = web.Application()

            if "headers" in self.http:
                self.app.on_response_prepare.append(self.add_response_headers)

            # Setup event stream

            self.stream = stream.ADStream(self.AD, self.app, self.transport)

            self.loop = loop
            self.executor = concurrent.futures.ThreadPoolExecutor(
                max_workers=5)

            if self.ssl_certificate is not None and self.ssl_key is not None:
                self.context = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
                self.context.load_cert_chain(self.ssl_certificate,
                                             self.ssl_key)
            else:
                self.context = None

            self.setup_http_routes()

            #
            # API
            #

            if api is not None:
                self.logger.info("Starting API")
                self.setup_api_routes()
            else:
                self.logger.info("API is disabled")

            #
            # Admin
            #

            if admin is not None:
                self.logger.info("Starting Admin Interface")

                self.stats_update = "realtime"
                self._process_arg("stats_update", admin)

                self.admin_obj = adadmin.Admin(
                    self.config_dir,
                    logging,
                    self.AD,
                    javascript_dir=self.javascript_dir,
                    template_dir=self.template_dir,
                    css_dir=self.css_dir,
                    fonts_dir=self.fonts_dir,
                    webfonts_dir=self.webfonts_dir,
                    images_dir=self.images_dir,
                    transport=self.transport,
                    **admin)

            else:
                self.logger.info("Admin Interface is disabled")
            #
            # Dashboards
            #

            if dashboard is not None:
                self.logger.info("Starting Dashboards")

                self._process_arg("dashboard_dir", dashboard)

                self.compile_on_start = True
                self._process_arg("compile_on_start", dashboard)

                self.force_compile = False
                self._process_arg("force_compile", dashboard)

                self.profile_dashboard = False
                self._process_arg("profile_dashboard", dashboard)

                self.rss_feeds = None
                self._process_arg("rss_feeds", dashboard)

                self.fa4compatibility = False
                self._process_arg("fa4compatibility", dashboard)

                if "rss_feeds" in dashboard:
                    self.rss_feeds = []
                    for feed in dashboard["rss_feeds"]:
                        if feed["target"].count(".") != 1:
                            self.logger.warning("Invalid RSS feed target: %s",
                                                feed["target"])
                        else:
                            self.rss_feeds.append(feed)

                self.rss_update = None
                self._process_arg("rss_update", dashboard)

                self.rss_last_update = None

                # find dashboard dir

                if self.dashboard_dir is None:
                    if self.config_dir is None:
                        self.dashboard_dir = utils.find_path("dashboards")
                    else:
                        self.dashboard_dir = os.path.join(
                            self.config_dir, "dashboards")

                self.javascript_dir = os.path.join(self.install_dir, "assets",
                                                   "javascript")
                self.template_dir = os.path.join(self.install_dir, "assets",
                                                 "templates")
                self.css_dir = os.path.join(self.install_dir, "assets", "css")
                self.fonts_dir = os.path.join(self.install_dir, "assets",
                                              "fonts")
                self.webfonts_dir = os.path.join(self.install_dir, "assets",
                                                 "webfonts")
                self.images_dir = os.path.join(self.install_dir, "assets",
                                               "images")

                #
                # Setup compile directories
                #
                if self.config_dir is None:
                    self.compile_dir = utils.find_path("compiled")
                else:
                    self.compile_dir = os.path.join(self.config_dir,
                                                    "compiled")

                self.dashboard_obj = addashboard.Dashboard(
                    self.config_dir,
                    self.logging,
                    dash_compile_on_start=self.compile_on_start,
                    dash_force_compile=self.force_compile,
                    profile_dashboard=self.profile_dashboard,
                    dashboard_dir=self.dashboard_dir,
                    fa4compatibility=self.fa4compatibility,
                    transport=self.transport,
                    javascript_dir=self.javascript_dir,
                    template_dir=self.template_dir,
                    css_dir=self.css_dir,
                    fonts_dir=self.fonts_dir,
                    webfonts_dir=self.webfonts_dir,
                    images_dir=self.images_dir,
                )
                self.setup_dashboard_routes()

            else:
                self.logger.info("Dashboards Disabled")

            #
            # Finish up and start the server
            #

            # handler = self.app.make_handler()

            # f = loop.create_server(handler, "0.0.0.0", int(self.port), ssl=context)
            # loop.create_task(f)

            if self.dashboard_obj is not None:
                loop.create_task(self.update_rss())

        except Exception:
            self.logger.warning("-" * 60)
            self.logger.warning("Unexpected error in HTTP module")
            self.logger.warning("-" * 60)
            self.logger.warning(traceback.format_exc())
            self.logger.warning("-" * 60)
Ejemplo n.º 6
0
    def __init__(self, ad, loop, logger, access, **config):

        self.AD = ad
        self.logger = logger
        self.acc = access

        self.dashboard_dir = None
        self._process_arg("dashboard_dir", config)

        self.dash_password = None
        self._process_arg("dash_password", config)

        self.dash_url = None
        self._process_arg("dash_url", config)

        self.config_dir = None
        self._process_arg("config_dir", config)

        self.dash_compile_on_start = False
        self._process_arg("dash_compile_on_start", config)

        self.dash_force_compile = False
        self._process_arg("dash_force_compile", config)

        self.work_factor = 8
        self._process_arg("work_factor", config)

        self.profile_dashboard = False
        self._process_arg("profile_dashboard", config)

        self.dash_ssl_certificate = None
        self._process_arg("dash_ssl_certificate", config)

        self.dash_ssl_key = None
        self._process_arg("dash_ssl_key", config)

        self.rss_feeds = None
        self._process_arg("rss_feeds", config)

        self.rss_update = None
        self._process_arg("rss_update", config)

        self.rss_last_update = None

        self.stopping = False

        url = urlparse(self.dash_url)

        dash_net = url.netloc.split(":")
        self.dash_host = dash_net[0]
        try:
            self.dash_port = dash_net[1]
        except IndexError:
            self.dash_port = 80

        if self.dash_host == "":
            raise ValueError("Invalid host for 'dash_url'")

        # find dashboard dir

        if self.dashboard_dir is None:
            if self.config_dir is None:
                self.dashboard_dir = utils.find_path("dashboards")
            else:
                self.dashboard_dir = os.path.join(self.config_dir, "dashboards")


            #
            # Setup compile directories
            #
            if self.config_dir is None:
                self.compile_dir = utils.find_path("compiled")
            else:
                self.compile_dir = os.path.join(self.config_dir, "compiled")


        # Setup WS handler

        self.app = web.Application()
        self.app['websockets'] = {}

        self.loop = loop
        self.executor = concurrent.futures.ThreadPoolExecutor(max_workers=5)

        try:
            self.dashboard_obj = dashboard.Dashboard(self.config_dir, access,
                                                 dash_compile_on_start=self.dash_compile_on_start,
                                                 dash_force_compile=self.dash_force_compile,
                                                 profile_dashboard=self.profile_dashboard,
                                                 dashboard_dir = self.dashboard_dir,
                                                     )
            self.setup_routes()

            if self.dash_ssl_certificate is not None and self.dash_ssl_key is not None:
                context = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
                context.load_cert_chain(self.dash_ssl_certificate, self.dash_ssl_key)
            else:
                context = None

            handler = self.app.make_handler()

            f = loop.create_server(handler, "0.0.0.0", int(self.dash_port), ssl=context)

            loop.create_task(f)
            loop.create_task(self.update_rss())
        except:
            self.log("WARNING", '-' * 60)
            self.log("WARNING", "Unexpected error in dashboard thread")
            self.log("WARNING", '-' * 60)
            self.log("WARNING", traceback.format_exc())
            self.log("WARNING", '-' * 60)
Ejemplo n.º 7
0
    def main(self):

        # import appdaemon.stacktracer
        # appdaemon.stacktracer.trace_start("/tmp/trace.html")

        self.init_signals()

        # Get command line args

        parser = argparse.ArgumentParser()

        parser.add_argument("-c",
                            "--config",
                            help="full path to config directory",
                            type=str,
                            default=None)
        parser.add_argument("-p",
                            "--pidfile",
                            help="full path to PID File",
                            default="/tmp/hapush.pid")
        parser.add_argument(
            "-t",
            "--tick",
            help="time that a tick in the schedular lasts (seconds)",
            default=1,
            type=float)
        parser.add_argument(
            "-s",
            "--starttime",
            help="start time for scheduler <YYYY-MM-DD HH:MM:SS>",
            type=str)
        parser.add_argument(
            "-e",
            "--endtime",
            help="end time for scheduler <YYYY-MM-DD HH:MM:SS>",
            type=str,
            default=None)
        parser.add_argument("-i",
                            "--interval",
                            help="multiplier for scheduler tick",
                            type=float,
                            default=1)
        parser.add_argument(
            "-D",
            "--debug",
            help="debug level",
            default="INFO",
            choices=["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"])
        parser.add_argument('-v',
                            '--version',
                            action='version',
                            version='%(prog)s ' + utils.__version__)
        parser.add_argument('--profiledash',
                            help=argparse.SUPPRESS,
                            action='store_true')

        # Windows does not have Daemonize package so disallow
        if platform.system() != "Windows":
            parser.add_argument("-d",
                                "--daemon",
                                help="run as a background process",
                                action="store_true")

        args = parser.parse_args()

        config_dir = args.config

        if platform.system() != "Windows":
            from daemonize import Daemonize

        if platform.system() != "Windows":
            isdaemon = args.daemon
        else:
            isdaemon = False

        if config_dir is None:
            config_file_yaml = utils.find_path("appdaemon.yaml")
        else:
            config_file_yaml = os.path.join(config_dir, "appdaemon.yaml")

        if config_file_yaml is None:
            print(
                "FATAL: no configuration directory defined and defaults not present\n"
            )
            parser.print_help()
            sys.exit(1)

        config = None

        #
        # First locate secrets file
        #
        try:

            #
            # Initially load file to see if secret directive is present
            #
            yaml.add_constructor('!secret', utils._dummy_secret)
            with open(config_file_yaml, 'r') as yamlfd:
                config_file_contents = yamlfd.read()

            config = yaml.load(config_file_contents)

            if "secrets" in config:
                secrets_file = config["secrets"]
            else:
                secrets_file = os.path.join(os.path.dirname(config_file_yaml),
                                            "secrets.yaml")

            #
            # Read Secrets
            #
            if os.path.isfile(secrets_file):
                with open(secrets_file, 'r') as yamlfd:
                    secrets_file_contents = yamlfd.read()

                utils.secrets = yaml.load(secrets_file_contents)

            else:
                if "secrets" in config:
                    print(
                        "ERROR", "Error loading secrets file: {}".format(
                            config["secrets"]))
                    sys.exit()

            #
            # Read config file again, this time with secrets
            #
            yaml.add_constructor('!secret', utils._secret_yaml)

            with open(config_file_yaml, 'r') as yamlfd:
                config_file_contents = yamlfd.read()

            config = yaml.load(config_file_contents)

        except yaml.YAMLError as exc:
            print("ERROR", "Error loading configuration")
            if hasattr(exc, 'problem_mark'):
                if exc.context is not None:
                    print("ERROR", "parser says")
                    print("ERROR", str(exc.problem_mark))
                    print("ERROR", str(exc.problem) + " " + str(exc.context))
                else:
                    print("ERROR", "parser says")
                    print("ERROR", str(exc.problem_mark))
                    print("ERROR", str(exc.problem))
            sys.exit()

        if "appdaemon" not in config:
            print("ERROR",
                  "no 'appdaemon' section in {}".format(config_file_yaml))
            sys.exit()

        appdaemon = config["appdaemon"]
        if "disable_apps" not in appdaemon:
            appdaemon["disable_apps"] = False

        appdaemon["config_dir"] = config_dir
        appdaemon["config_file"] = config_file_yaml
        appdaemon["app_config_file"] = os.path.join(
            os.path.dirname(config_file_yaml), "apps.yaml")

        if args.starttime is not None:
            appdaemon["starttime"] = args.starttime

        if args.endtime is not None:
            appdaemon["endtime"] = args.endtime

        appdaemon["tick"] = args.tick
        appdaemon["interval"] = args.interval
        appdaemon["loglevel"] = args.debug

        appdaemon["config_dir"] = os.path.dirname(config_file_yaml)

        appdaemon["stop_function"] = self.stop

        if "hadashboard" in config:
            hadashboard = config["hadashboard"]
            hadashboard["profile_dashboard"] = args.profiledash
            hadashboard["config_dir"] = config_dir
            hadashboard["config_file"] = config_file_yaml
            hadashboard["config_dir"] = os.path.dirname(config_file_yaml)
            if args.profiledash:
                hadashboard["profile_dashboard"] = True

            if "dashboard" not in hadashboard:
                hadashboard["dashboard"] = True

        else:
            hadashboard = {"dashboard": False}

        if "log" not in config:
            logfile = "STDOUT"
            errorfile = "STDERR"
            diagfile = "STDOUT"
            log_size = 1000000
            log_generations = 3
            accessfile = None
        else:
            logfile = config['log'].get("logfile", "STDOUT")
            errorfile = config['log'].get("errorfile", "STDERR")
            diagfile = config['log'].get("diagfile", "NONE")
            if diagfile == "NONE":
                diagfile = logfile
            log_size = config['log'].get("log_size", 1000000)
            log_generations = config['log'].get("log_generations", 3)
            accessfile = config['log'].get("accessfile")

        if isdaemon and (logfile == "STDOUT" or errorfile == "STDERR"
                         or logfile == "STDERR" or errorfile == "STDOUT"):
            print("ERROR", "STDOUT and STDERR not allowed with -d")
            sys.exit()

        # Setup Logging

        self.logger = logging.getLogger("log1")
        numeric_level = getattr(logging, args.debug, None)
        self.logger.setLevel(numeric_level)
        self.logger.propagate = False
        # formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s')

        # Send to file if we are daemonizing, else send to console

        fh = None
        if logfile != "STDOUT":
            fh = RotatingFileHandler(logfile,
                                     maxBytes=log_size,
                                     backupCount=log_generations)
            fh.setLevel(numeric_level)
            # fh.setFormatter(formatter)
            self.logger.addHandler(fh)
        else:
            # Default for StreamHandler() is sys.stderr
            ch = logging.StreamHandler(stream=sys.stdout)
            ch.setLevel(numeric_level)
            # ch.setFormatter(formatter)
            self.logger.addHandler(ch)

        # Setup compile output

        self.error = logging.getLogger("log2")
        numeric_level = getattr(logging, args.debug, None)
        self.error.setLevel(numeric_level)
        self.error.propagate = False
        # formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s')

        if errorfile != "STDERR":
            efh = RotatingFileHandler(errorfile,
                                      maxBytes=log_size,
                                      backupCount=log_generations)
        else:
            efh = logging.StreamHandler()

        efh.setLevel(numeric_level)
        # efh.setFormatter(formatter)
        self.error.addHandler(efh)

        # setup diag output

        self.diag = logging.getLogger("log3")
        numeric_level = getattr(logging, args.debug, None)
        self.diag.setLevel(numeric_level)
        self.diag.propagate = False
        # formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s')

        if diagfile != "STDOUT":
            dfh = RotatingFileHandler(diagfile,
                                      maxBytes=log_size,
                                      backupCount=log_generations)
        else:
            dfh = logging.StreamHandler()

        dfh.setLevel(numeric_level)
        # dfh.setFormatter(formatter)
        self.diag.addHandler(dfh)

        # Setup dash output
        if accessfile is not None:
            self.access = logging.getLogger("log4")
            numeric_level = getattr(logging, args.debug, None)
            self.access.setLevel(numeric_level)
            self.access.propagate = False
            # formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s')
            efh = RotatingFileHandler(config['log'].get("accessfile"),
                                      maxBytes=log_size,
                                      backupCount=log_generations)

            efh.setLevel(numeric_level)
            # efh.setFormatter(formatter)
            self.access.addHandler(efh)
        else:
            self.access = self.logger

        # Startup message

        self.log(self.logger, "INFO",
                 "AppDaemon Version {} starting".format(utils.__version__))
        self.log(self.logger, "INFO",
                 "Configuration read from: {}".format(config_file_yaml))
        self.log(self.logger, "DEBUG",
                 "AppDaemon Section: {}".format(config.get("AppDaemon")))
        self.log(self.logger, "DEBUG",
                 "HADashboard Section: {}".format(config.get("HADashboard")))

        utils.check_path("config_file",
                         self.logger,
                         config_file_yaml,
                         pathtype="file")

        if isdaemon:
            keep_fds = [fh.stream.fileno(), efh.stream.fileno()]
            pid = args.pidfile
            daemon = Daemonize(app="appdaemon",
                               pid=pid,
                               action=self.run,
                               keep_fds=keep_fds)
            daemon.start()
            while True:
                time.sleep(1)
        else:
            self.run(appdaemon, hadashboard)
Ejemplo n.º 8
0
    def main(self):

        # import appdaemon.stacktracer
        # appdaemon.stacktracer.trace_start("/tmp/trace.html")

        self.init_signals()

        # Get command line args

        parser = argparse.ArgumentParser()

        parser.add_argument("-c", "--config", help="full path to config directory", type=str, default=None)
        parser.add_argument("-p", "--pidfile", help="full path to PID File", default="/tmp/hapush.pid")
        parser.add_argument("-t", "--tick", help="time that a tick in the schedular lasts (seconds)", default=1, type=float)
        parser.add_argument("-s", "--starttime", help="start time for scheduler <YYYY-MM-DD HH:MM:SS>", type=str)
        parser.add_argument("-e", "--endtime", help="end time for scheduler <YYYY-MM-DD HH:MM:SS>", type=str, default=None)
        parser.add_argument("-i", "--interval", help="multiplier for scheduler tick", type=float, default=1)
        parser.add_argument("-D", "--debug", help="debug level", default="INFO", choices=
                            [
                                "DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"
                            ])
        parser.add_argument('-v', '--version', action='version', version='%(prog)s ' + utils.__version__)
        parser.add_argument('--profiledash', help=argparse.SUPPRESS, action='store_true')

        # Windows does not have Daemonize package so disallow
        if platform.system() != "Windows":
            parser.add_argument("-d", "--daemon", help="run as a background process", action="store_true")

        args = parser.parse_args()

        config_dir = args.config

        if platform.system() != "Windows":
            from daemonize import Daemonize

        if platform.system() != "Windows":
            isdaemon = args.daemon
        else:
            isdaemon = False

        if config_dir is None:
            config_file_yaml = utils.find_path("appdaemon.yaml")
        else:
            config_file_yaml = os.path.join(config_dir, "appdaemon.yaml")

        if config_file_yaml is None:
            print("FATAL: no configuration directory defined and defaults not present\n")
            parser.print_help()
            sys.exit(1)

        config = None

        #
        # First locate secrets file
        #
        try:

            #
            # Initially load file to see if secret directive is present
            #
            yaml.add_constructor('!secret', utils._dummy_secret, Loader=yaml.SafeLoader)
            with open(config_file_yaml, 'r') as yamlfd:
                config_file_contents = yamlfd.read()

            config = yaml.load(config_file_contents, Loader=yaml.SafeLoader)

            if "secrets" in config:
                secrets_file = config["secrets"]
            else:
                secrets_file = os.path.join(os.path.dirname(config_file_yaml), "secrets.yaml")

            #
            # Read Secrets
            #
            if os.path.isfile(secrets_file):
                with open(secrets_file, 'r') as yamlfd:
                    secrets_file_contents = yamlfd.read()

                utils.secrets = yaml.load(secrets_file_contents, Loader=yaml.SafeLoader)

            else:
                if "secrets" in config:
                    print("ERROR", "Error loading secrets file: {}".format(config["secrets"]))
                    sys.exit()

            #
            # Read config file again, this time with secrets
            #
            yaml.add_constructor('!secret', utils._secret_yaml, Loader=yaml.SafeLoader)

            with open(config_file_yaml, 'r') as yamlfd:
                config_file_contents = yamlfd.read()

            config = yaml.load(config_file_contents, Loader=yaml.SafeLoader)

        except yaml.YAMLError as exc:
            print("ERROR", "Error loading configuration")
            if hasattr(exc, 'problem_mark'):
                if exc.context is not None:
                    print("ERROR", "parser says")
                    print("ERROR", str(exc.problem_mark))
                    print("ERROR", str(exc.problem) + " " + str(exc.context))
                else:
                    print("ERROR", "parser says")
                    print("ERROR", str(exc.problem_mark))
                    print("ERROR", str(exc.problem))
            sys.exit()

        if "appdaemon" not in config:
            print("ERROR", "no 'appdaemon' section in {}".format(config_file_yaml))
            sys.exit()

        appdaemon = config["appdaemon"]
        if "disable_apps" not in appdaemon:
            appdaemon["disable_apps"] = False

        appdaemon["config_dir"] = config_dir
        appdaemon["config_file"] = config_file_yaml
        appdaemon["app_config_file"] = os.path.join(os.path.dirname(config_file_yaml), "apps.yaml")


        if args.starttime is not None:
            appdaemon["starttime"] = args.starttime

        if args.endtime is not None:
            appdaemon["endtime"] = args.endtime

        appdaemon["tick"] = args.tick
        appdaemon["interval"] = args.interval
        appdaemon["loglevel"] = args.debug

        appdaemon["config_dir"] = os.path.dirname(config_file_yaml)

        appdaemon["stop_function"] = self.stop

        if "hadashboard" in config:
            hadashboard = config["hadashboard"]
            hadashboard["profile_dashboard"] = args.profiledash
            hadashboard["config_dir"] = config_dir
            hadashboard["config_file"] = config_file_yaml
            hadashboard["config_dir"] = os.path.dirname(config_file_yaml)
            if args.profiledash:
                hadashboard["profile_dashboard"] = True

            if "dashboard" not in hadashboard:
                hadashboard["dashboard"] = True

        else:
            hadashboard = {"dashboard": False}

        if "log" not in config:
            logfile = "STDOUT"
            errorfile = "STDERR"
            diagfile = "STDOUT"
            log_size = 1000000
            log_generations = 3
            accessfile = None
        else:
            logfile = config['log'].get("logfile", "STDOUT")
            errorfile = config['log'].get("errorfile", "STDERR")
            diagfile = config['log'].get("diagfile", "NONE")
            if diagfile == "NONE":
                diagfile = logfile
            log_size = config['log'].get("log_size", 1000000)
            log_generations = config['log'].get("log_generations", 3)
            accessfile = config['log'].get("accessfile")

        if isdaemon and (
                            logfile == "STDOUT" or errorfile == "STDERR"
                            or logfile == "STDERR" or errorfile == "STDOUT"
                        ):
            print("ERROR", "STDOUT and STDERR not allowed with -d")
            sys.exit()

        # Setup Logging

        self.logger = logging.getLogger("log1")
        numeric_level = getattr(logging, args.debug, None)
        self.logger.setLevel(numeric_level)
        self.logger.propagate = False
        # formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s')

        # Send to file if we are daemonizing, else send to console

        fh = None
        if logfile != "STDOUT":
            fh = RotatingFileHandler(logfile, maxBytes=log_size, backupCount=log_generations)
            fh.setLevel(numeric_level)
            # fh.setFormatter(formatter)
            self.logger.addHandler(fh)
        else:
            # Default for StreamHandler() is sys.stderr
            ch = logging.StreamHandler(stream=sys.stdout)
            ch.setLevel(numeric_level)
            # ch.setFormatter(formatter)
            self.logger.addHandler(ch)

        # Setup compile output

        self.error = logging.getLogger("log2")
        numeric_level = getattr(logging, args.debug, None)
        self.error.setLevel(numeric_level)
        self.error.propagate = False
        # formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s')

        if errorfile != "STDERR":
            efh = RotatingFileHandler(
                errorfile, maxBytes=log_size, backupCount=log_generations
            )
        else:
            efh = logging.StreamHandler()

        efh.setLevel(numeric_level)
        # efh.setFormatter(formatter)
        self.error.addHandler(efh)

        # setup diag output

        self.diag = logging.getLogger("log3")
        numeric_level = getattr(logging, args.debug, None)
        self.diag.setLevel(numeric_level)
        self.diag.propagate = False
        # formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s')

        if diagfile != "STDOUT":
            dfh = RotatingFileHandler(
                diagfile, maxBytes=log_size, backupCount=log_generations
            )
        else:
            dfh = logging.StreamHandler()

        dfh.setLevel(numeric_level)
        # dfh.setFormatter(formatter)
        self.diag.addHandler(dfh)

        # Setup dash output
        if accessfile is not None:
            self.access = logging.getLogger("log4")
            numeric_level = getattr(logging, args.debug, None)
            self.access.setLevel(numeric_level)
            self.access.propagate = False
            # formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s')
            efh = RotatingFileHandler(
                config['log'].get("accessfile"), maxBytes=log_size, backupCount=log_generations
            )

            efh.setLevel(numeric_level)
            # efh.setFormatter(formatter)
            self.access.addHandler(efh)
        else:
            self.access = self.logger

        # Startup message

        self.log(self.logger, "INFO", "AppDaemon Version {} starting".format(utils.__version__))
        self.log(self.logger, "INFO", "Configuration read from: {}".format(config_file_yaml))
        self.log(self.logger, "DEBUG", "AppDaemon Section: {}".format(config.get("AppDaemon")))
        self.log(self.logger, "DEBUG", "HADashboard Section: {}".format(config.get("HADashboard")))

        utils.check_path("config_file", self.logger, config_file_yaml, pathtype="file")

        if isdaemon:
            keep_fds = [fh.stream.fileno(), efh.stream.fileno()]
            pid = args.pidfile
            daemon = Daemonize(app="appdaemon", pid=pid, action=self.run,
                               keep_fds=keep_fds)
            daemon.start()
            while True:
                time.sleep(1)
        else:
            self.run(appdaemon, hadashboard)
Ejemplo n.º 9
0
    def _process_dashboard(self, dashboard):
        self.logger.info("Starting Dashboards")

        self._process_arg("dashboard_dir", dashboard)

        self.compile_on_start = True
        self._process_arg("compile_on_start", dashboard)

        self.force_compile = False
        self._process_arg("force_compile", dashboard)

        self.profile_dashboard = False
        self._process_arg("profile_dashboard", dashboard)

        self.rss_feeds = None
        self._process_arg("rss_feeds", dashboard)

        self.fa4compatibility = False
        self._process_arg("fa4compatibility", dashboard)

        if "rss_feeds" in dashboard:
            self.rss_feeds = []
            for feed in dashboard["rss_feeds"]:
                if feed["target"].count(".") != 1:
                    self.logger.warning("Invalid RSS feed target: %s",
                                        feed["target"])
                else:
                    self.rss_feeds.append(feed)

        self.rss_update = None
        self._process_arg("rss_update", dashboard)

        self.rss_last_update = None

        # find dashboard dir

        if self.dashboard_dir is None:
            if self.config_dir is None:
                self.dashboard_dir = utils.find_path("dashboards")
            else:
                self.dashboard_dir = os.path.join(self.config_dir,
                                                  "dashboards")

        self.javascript_dir = os.path.join(self.install_dir, "assets",
                                           "javascript")
        self.template_dir = os.path.join(self.install_dir, "assets",
                                         "templates")
        self.css_dir = os.path.join(self.install_dir, "assets", "css")
        self.fonts_dir = os.path.join(self.install_dir, "assets", "fonts")
        self.webfonts_dir = os.path.join(self.install_dir, "assets",
                                         "webfonts")
        self.images_dir = os.path.join(self.install_dir, "assets", "images")

        #
        # Setup compile directories
        #
        if self.config_dir is None:
            self.compile_dir = utils.find_path("compiled")
        else:
            self.compile_dir = os.path.join(self.config_dir, "compiled")

        self.dashboard_obj = addashboard.Dashboard(
            self.config_dir,
            self.logging,
            dash_compile_on_start=self.compile_on_start,
            dash_force_compile=self.force_compile,
            profile_dashboard=self.profile_dashboard,
            dashboard_dir=self.dashboard_dir,
            fa4compatibility=self.fa4compatibility,
            transport=self.transport,
            javascript_dir=self.javascript_dir,
            template_dir=self.template_dir,
            css_dir=self.css_dir,
            fonts_dir=self.fonts_dir,
            webfonts_dir=self.webfonts_dir,
            images_dir=self.images_dir,
        )
        self.setup_dashboard_routes()