From e847766514957f6ceb81de0b678399918ed532a2 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 1 Feb 2023 16:59:51 +1300 Subject: [PATCH] Dump full parsed config to json-config api call (#4373) --- esphome/__main__.py | 5 ++++- esphome/dashboard/dashboard.py | 34 ++++++++++++++++++++++------------ esphome/yaml_util.py | 5 ++++- 3 files changed, 30 insertions(+), 14 deletions(-) diff --git a/esphome/__main__.py b/esphome/__main__.py index 9b6043ef50..24c2ce1d13 100644 --- a/esphome/__main__.py +++ b/esphome/__main__.py @@ -339,7 +339,7 @@ def command_config(args, config): _LOGGER.info("Configuration is valid!") if not CORE.verbose: config = strip_default_ids(config) - safe_print(yaml_util.dump(config)) + safe_print(yaml_util.dump(config, args.show_secrets)) return 0 @@ -665,6 +665,9 @@ def parse_args(argv): parser_config.add_argument( "configuration", help="Your YAML configuration file(s).", nargs="+" ) + parser_config.add_argument( + "--show-secrets", help="Show secrets in output.", action="store_true" + ) parser_compile = subparsers.add_parser( "compile", help="Read the configuration and compile a program." diff --git a/esphome/dashboard/dashboard.py b/esphome/dashboard/dashboard.py index 8b8414c62c..66e627dffe 100644 --- a/esphome/dashboard/dashboard.py +++ b/esphome/dashboard/dashboard.py @@ -25,10 +25,10 @@ import tornado.netutil import tornado.process import tornado.web import tornado.websocket +import yaml from tornado.log import access_log from esphome import const, platformio_api, util, yaml_util -from esphome.core import EsphomeError from esphome.helpers import get_bool_env, mkdir_p, run_system_command from esphome.storage_json import ( EsphomeStorageJSON, @@ -40,7 +40,7 @@ from esphome.storage_json import ( from esphome.util import get_serial_ports, shlex_quote from esphome.zeroconf import DashboardImportDiscovery, DashboardStatus, EsphomeZeroconf -from .util import password_hash, friendly_name_slugify +from .util import friendly_name_slugify, password_hash _LOGGER = logging.getLogger(__name__) @@ -1021,6 +1021,14 @@ class SecretKeysRequestHandler(BaseHandler): self.write(json.dumps(secret_keys)) +class SafeLoaderIgnoreUnknown(yaml.SafeLoader): + def ignore_unknown(self, node): + return f"{node.tag} {node.value}" + + +SafeLoaderIgnoreUnknown.add_constructor(None, SafeLoaderIgnoreUnknown.ignore_unknown) + + class JsonConfigRequestHandler(BaseHandler): @authenticated @bind_config @@ -1030,16 +1038,18 @@ class JsonConfigRequestHandler(BaseHandler): self.send_error(404) return - try: - content = yaml_util.load_yaml(filename, clear_secrets=False) - json_content = json.dumps( - content, default=lambda o: {"__type": str(type(o)), "repr": repr(o)} - ) - self.set_header("content-type", "application/json") - self.write(json_content) - except EsphomeError as err: - _LOGGER.warning("Error translating file %s to JSON: %s", filename, err) - self.send_error(500) + args = ["esphome", "config", settings.rel_path(configuration), "--show-secrets"] + + rc, stdout, _ = run_system_command(*args) + + if rc != 0: + self.send_error(422) + return + + data = yaml.load(stdout, Loader=SafeLoaderIgnoreUnknown) + self.set_header("content-type", "application/json") + self.write(json.dumps(data)) + self.finish() def get_base_frontend_path(): diff --git a/esphome/yaml_util.py b/esphome/yaml_util.py index 2689ce9245..b8aa8dd53f 100644 --- a/esphome/yaml_util.py +++ b/esphome/yaml_util.py @@ -390,8 +390,11 @@ def _load_yaml_internal(fname): loader.dispose() -def dump(dict_): +def dump(dict_, show_secrets=False): """Dump YAML to a string and remove null.""" + if show_secrets: + _SECRET_VALUES.clear() + _SECRET_CACHE.clear() return yaml.dump( dict_, default_flow_style=False, allow_unicode=True, Dumper=ESPHomeDumper )