# Copyright 2018 Datawire. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License from abc import abstractmethod from typing import TYPE_CHECKING, Any, Dict, Optional, Tuple from ..cache import Cache from ..utils import dump_json if TYPE_CHECKING: from ..ir import IR, IRResource # pragma: no cover from ..ir.irhttpmappinggroup import IRHTTPMappingGroup # pragma: no cover from ..ir.irserviceresolver import ClustermapEntry # pragma: no cover def sanitize_pre_json(input): # Removes all potential null values if isinstance(input, dict): for key, value in list(input.items()): if value is None: del input[key] else: sanitize_pre_json(value) elif isinstance(input, list): for item in input: sanitize_pre_json(item) return input class EnvoyConfig: """ Base class for Envoy configuration that permits fetching configuration for various elements to show in diagnostics. """ ir: "IR" elements: Dict[str, Dict[str, Any]] def __init__(self, ir: "IR") -> None: self.ir = ir self.elements = {} def add_element(self, kind: str, key: str, obj: Any) -> None: eldict = self.elements.setdefault(kind, {}) eldict[key] = obj def get_element(self, kind: str, key: str, default: Any) -> Optional[Any]: eldict = self.elements.get(kind, {}) return eldict.get(key, default) def pop_element(self, kind: str, key: str, default: Any) -> Optional[Any]: eldict = self.elements.get(kind, {}) return eldict.pop(key, default) def save_element(self, kind: str, resource: "IRResource", obj: Any): self.add_element(kind, resource.rkey, obj) self.add_element(kind, resource.location, obj) return obj @abstractmethod def has_listeners(self) -> bool: pass @abstractmethod def split_config(self) -> Tuple[Dict[str, Any], Dict[str, Any], Dict[str, "ClustermapEntry"]]: pass @abstractmethod def as_dict(self) -> Dict[str, Any]: pass def as_json(self): return dump_json(sanitize_pre_json(self.as_dict()), pretty=True) @classmethod def generate(cls, ir: "IR", cache: Optional[Cache] = None) -> "EnvoyConfig": from . import V3Config return V3Config(ir, cache=cache) class EnvoyRoute: def __init__(self, group: "IRHTTPMappingGroup"): self.prefix = "prefix" self.path = "path" self.regex = "regex" self.envoy_route = self._get_envoy_route(group) def _get_envoy_route(self, group: "IRHTTPMappingGroup") -> str: if group.get("prefix_regex", False): return self.regex if group.get("prefix_exact", False): return self.path else: return self.prefix