def __init__(self, ir: 'IR', aconf: Config, rkey: str, # REQUIRED name: str, # REQUIRED location: str, # REQUIRED kind: str="IRMapping", apiVersion: str="ambassador/v1", # Not a typo! See below. precedence: int=0, rewrite: str="/", **kwargs) -> None: # OK, this is a bit of a pain. We want to preserve the name and rkey and # such here, unlike most kinds of IRResource. So. Shallow copy the keys # we're going to allow from the incoming kwargs... new_args = {x: kwargs[x] for x in kwargs.keys() if x in IRHTTPMapping.AllowedKeys} # ...then set up the headers (since we need them to compute our group ID). hdrs = [] add_request_hdrs = kwargs.get('add_request_headers', {}) if 'headers' in kwargs: for name, value in kwargs.get('headers', {}).items(): if value is True: hdrs.append(Header(name)) else: hdrs.append(Header(name, value)) if 'regex_headers' in kwargs: for name, value in kwargs.get('regex_headers', {}).items(): hdrs.append(Header(name, value, regex=True)) if 'host' in kwargs: hdrs.append(Header(":authority", kwargs['host'], kwargs.get('host_regex', False))) self.tls_context = self.match_tls_context(kwargs['host'], ir) if 'service' in kwargs: svc = Service(ir.logger, kwargs['service']) if 'add_linkerd_headers' in kwargs: if kwargs['add_linkerd_headers'] is True: add_request_hdrs['l5d-dst-override'] = svc.hostname_port else: if 'add_linkerd_headers' in ir.ambassador_module and ir.ambassador_module.add_linkerd_headers is True: add_request_hdrs['l5d-dst-override'] = svc.hostname_port if 'method' in kwargs: hdrs.append(Header(":method", kwargs['method'], kwargs.get('method_regex', False))) # ...and then init the superclass. super().__init__( ir=ir, aconf=aconf, rkey=rkey, location=location, kind=kind, name=name, apiVersion=apiVersion, headers=hdrs, add_request_headers=add_request_hdrs, precedence=precedence, rewrite=rewrite, **new_args ) if 'outlier_detection' in kwargs: self.post_error(RichStatus.fromError("outlier_detection is not supported"))
def __init__( self, ir: 'IR', aconf: Config, rkey: str, # REQUIRED name: str, # REQUIRED location: str, # REQUIRED namespace: Optional[str] = None, metadata_labels: Optional[Dict[str, str]] = None, kind: str = "IRHTTPMapping", apiVersion: str = "getambassador.io/v2", # Not a typo! See below. precedence: int = 0, rewrite: str = "/", cluster_tag: Optional[str] = None, **kwargs) -> None: # OK, this is a bit of a pain. We want to preserve the name and rkey and # such here, unlike most kinds of IRResource, so we shallow copy the keys # we're going to allow from the incoming kwargs. # # NOTE WELL: things that we explicitly process below should _not_ be listed in # AllowedKeys. The point of AllowedKeys is this loop below. new_args = {} # When we look up defaults, use lookup class "httpmapping"... and yeah, we need the # IR, too. self.default_class = "httpmapping" self.ir = ir for key, check_defaults in IRHTTPMapping.AllowedKeys.items(): # Do we have a keyword arg for this key? if key in kwargs: # Yes, it wins. value = kwargs[key] self.ir.logger.info( f"IRHTTPMapping: accept {key}={value} from kwargs") new_args[key] = value elif check_defaults: # No value in kwargs, but we're allowed to check defaults for it. value = self.lookup_default(key) if value is not None: self.ir.logger.info( f"IRHTTPMapping: accept {key}={value} from defaults") new_args[key] = value # add_linkerd_headers is special, because we support setting it as a default # in the bare Ambassador module. We should really toss this and use the defaults # mechanism, but not for 1.4.3. if "add_linkerd_headers" not in new_args: # They didn't set it explicitly, so check for the older way. add_linkerd_headers = self.ir.ambassador_module.get( 'add_linkerd_headers', None) if add_linkerd_headers != None: new_args["add_linkerd_headers"] = add_linkerd_headers # OK. On to set up the headers (since we need them to compute our group ID). hdrs = [] query_parameters = [] regex_rewrite = kwargs.get('regex_rewrite', {}) if 'headers' in kwargs: for name, value in kwargs.get('headers', {}).items(): if value is True: hdrs.append(KeyValueDecorator(name)) else: hdrs.append(KeyValueDecorator(name, value)) if 'regex_headers' in kwargs: for name, value in kwargs.get('regex_headers', {}).items(): hdrs.append(KeyValueDecorator(name, value, regex=True)) if 'host' in kwargs: hdrs.append( KeyValueDecorator(":authority", kwargs['host'], kwargs.get('host_regex', False))) self.tls_context = self.match_tls_context(kwargs['host'], ir) if 'method' in kwargs: hdrs.append( KeyValueDecorator(":method", kwargs['method'], kwargs.get('method_regex', False))) # Next up: figure out what headers we need to add to each request. Again, if the key # is present in kwargs, the kwargs value wins -- this is important to allow explicitly # setting a value of `{}` to override a default! add_request_hdrs: dict if 'add_request_headers' in kwargs: add_request_hdrs = kwargs['add_request_headers'] else: add_request_hdrs = self.lookup_default('add_request_headers', {}) # Remember that we may need to add the Linkerd headers, too. add_linkerd_headers = new_args.get('add_linkerd_headers', False) if add_linkerd_headers: # Yup. We need the service info for this... if 'service' in kwargs: svc = Service(ir.logger, kwargs['service']) add_request_hdrs['l5d-dst-override'] = svc.hostname_port else: # Uh. This is pretty much impossible. self.post_error("Service is required for HTTP Mappings") # XXX BRUTAL HACK HERE: # If we _don't_ have an origination context, but our IR has an agent_origination_ctx, # force TLS origination because it's the agent. I know, I know. It's a hack. if ('tls' not in new_args) and ir.agent_origination_ctx: ir.logger.info( f"Mapping {name}: Agent forcing origination TLS context to {ir.agent_origination_ctx.name}" ) new_args['tls'] = ir.agent_origination_ctx.name if 'query_parameters' in kwargs: for name, value in kwargs.get('query_parameters', {}).items(): if value is True: query_parameters.append(KeyValueDecorator(name)) else: query_parameters.append(KeyValueDecorator(name, value)) if 'regex_query_parameters' in kwargs: for name, value in kwargs.get('regex_query_parameters', {}).items(): query_parameters.append( KeyValueDecorator(name, value, regex=True)) if 'regex_rewrite' in kwargs: if rewrite: self.ir.aconf.post_notice( "Cannot specify both rewrite and regex_rewrite: using regex_rewrite and ignoring rewrite" ) rewrite = "" rewrite_items = kwargs.get('regex_rewrite', {}) regex_rewrite = { 'pattern': rewrite_items.get('pattern', ''), 'substitution': rewrite_items.get('substitution', '') } # ...and then init the superclass. super().__init__(ir=ir, aconf=aconf, rkey=rkey, location=location, kind=kind, name=name, namespace=namespace, metadata_labels=metadata_labels, apiVersion=apiVersion, headers=hdrs, add_request_headers=add_request_hdrs, precedence=precedence, rewrite=rewrite, cluster_tag=cluster_tag, query_parameters=query_parameters, regex_rewrite=regex_rewrite, **new_args) if 'outlier_detection' in kwargs: self.post_error( RichStatus.fromError("outlier_detection is not supported"))
def __init__( self, ir: 'IR', aconf: Config, rkey: str, # REQUIRED name: str, # REQUIRED location: str, # REQUIRED service: str, # REQUIRED namespace: Optional[str] = None, metadata_labels: Optional[Dict[str, str]] = None, kind: str = "IRHTTPMapping", apiVersion: str = "x.getambassador.io/v3alpha1", # Not a typo! See below. precedence: int = 0, rewrite: str = "/", cluster_tag: Optional[str] = None, **kwargs) -> None: # OK, this is a bit of a pain. We want to preserve the name and rkey and # such here, unlike most kinds of IRResource, so we shallow copy the keys # we're going to allow from the incoming kwargs. # # NOTE WELL: things that we explicitly process below should _not_ be listed in # AllowedKeys. The point of AllowedKeys is this loop below. new_args = {} # When we look up defaults, use lookup class "httpmapping"... and yeah, we need the # IR, too. self.default_class = "httpmapping" self.ir = ir for key, check_defaults in IRHTTPMapping.AllowedKeys.items(): # Do we have a keyword arg for this key? if key in kwargs: # Yes, it wins. value = kwargs[key] new_args[key] = value elif check_defaults: # No value in kwargs, but we're allowed to check defaults for it. value = self.lookup_default(key) if value is not None: new_args[key] = value # add_linkerd_headers is special, because we support setting it as a default # in the bare Ambassador module. We should really toss this and use the defaults # mechanism, but not for 1.4.3. if "add_linkerd_headers" not in new_args: # They didn't set it explicitly, so check for the older way. add_linkerd_headers = self.ir.ambassador_module.get( 'add_linkerd_headers', None) if add_linkerd_headers != None: new_args["add_linkerd_headers"] = add_linkerd_headers # OK. On to set up the headers (since we need them to compute our group ID). hdrs = [] query_parameters = [] regex_rewrite = kwargs.get('regex_rewrite', {}) # Start by assuming that nothing in our arguments mentions hosts (so no host and no host_regex). host = None host_regex = False # Also start self.host as unspecified. self.host = None # OK. Start by looking for a :authority header match. if 'headers' in kwargs: for name, value in kwargs.get('headers', {}).items(): if value is True: hdrs.append(KeyValueDecorator(name)) else: # An exact match on the :authority header is special -- treat it like # they set the "host" element (but note that we'll allow the actual # "host" element to override it later). if name.lower() == ':authority': # This is an _exact_ match, so it mustn't contain a "*" -- that's illegal in the DNS. if "*" in value: # We can't call self.post_error() yet, because we're not initialized yet. So we cheat a bit # and defer the error for later. new_args[ "_deferred_error"] = f":authority exact-match '{value}' contains *, which cannot match anything." ir.logger.debug( "IRHTTPMapping %s: self.host contains * (%s, :authority)", name, value) else: # No globs, just save it. (We'll end up using it as a glob later, in the Envoy # config part of the world, but that's OK -- a glob with no "*" in it will always # match only itself.) host = value ir.logger.debug( "IRHTTPMapping %s: self.host == %s (:authority)", name, self.host) # DO NOT save the ':authority' match here -- we'll pick it up after we've checked # for hostname, too. else: # It's not an :authority match, so we're good. hdrs.append(KeyValueDecorator(name, value)) if 'regex_headers' in kwargs: # DON'T do anything special with a regex :authority match: we can't # do host-based filtering within the IR for it anyway. for name, value in kwargs.get('regex_headers', {}).items(): hdrs.append(KeyValueDecorator(name, value, regex=True)) if 'host' in kwargs: # It's deliberate that we'll allow kwargs['host'] to silently override an exact :authority # header match. host = kwargs['host'] host_regex = kwargs.get('host_regex', False) # If it's not a regex, it's an exact match -- make sure it doesn't contain a '*'. if not host_regex: if "*" in host: # We can't call self.post_error() yet, because we're not initialized yet. So we cheat a bit # and defer the error for later. new_args[ "_deferred_error"] = f"host exact-match {host} contains *, which cannot match anything." ir.logger.debug( "IRHTTPMapping %s: self.host contains * (%s, host)", name, host) else: ir.logger.debug("IRHTTPMapping %s: self.host == %s (host)", name, self.host) # Finally, check for 'hostname'. if 'hostname' in kwargs: # It's deliberate that we allow kwargs['hostname'] to override anything else -- even a regex host. # Yell about it, though. if host: ir.logger.warning( "Mapping %s in namespace %s: both host and hostname are set, using hostname and ignoring host", name, namespace) # No need to be so careful about "*" here, since hostname is defined to be a glob. host = kwargs['hostname'] host_regex = False ir.logger.debug("IRHTTPMapping %s: self.host gl~ %s (hostname)", name, self.host) # If we have a host, include a ":authority" match. We're treating this as if it were # an exact match, but that's because the ":authority" match is handling specially by # Envoy. if host: hdrs.append(KeyValueDecorator(":authority", host, host_regex)) # Finally, if our host isn't a regex, save it in self.host. if not host_regex: self.host = host if 'method' in kwargs: hdrs.append( KeyValueDecorator(":method", kwargs['method'], kwargs.get('method_regex', False))) if 'use_websocket' in new_args: allow_upgrade = new_args.setdefault('allow_upgrade', []) if 'websocket' not in allow_upgrade: allow_upgrade.append('websocket') del new_args['use_websocket'] # Next up: figure out what headers we need to add to each request. Again, if the key # is present in kwargs, the kwargs value wins -- this is important to allow explicitly # setting a value of `{}` to override a default! add_request_hdrs: dict add_response_hdrs: dict if 'add_request_headers' in kwargs: add_request_hdrs = kwargs['add_request_headers'] else: add_request_hdrs = self.lookup_default('add_request_headers', {}) if 'add_response_headers' in kwargs: add_response_hdrs = kwargs['add_response_headers'] else: add_response_hdrs = self.lookup_default('add_response_headers', {}) # Remember that we may need to add the Linkerd headers, too. add_linkerd_headers = new_args.get('add_linkerd_headers', False) # XXX The resolver lookup code is duplicated from IRBaseMapping.setup -- # needs to be fixed after 1.6.1. resolver_name = kwargs.get( 'resolver') or self.ir.ambassador_module.get( 'resolver', 'kubernetes-service') assert (resolver_name ) # for mypy -- resolver_name cannot be None at this point resolver = self.ir.get_resolver(resolver_name) if resolver: resolver_kind = resolver.kind else: # In IRBaseMapping.setup, we post an error if the resolver is unknown. # Here, we just don't bother; we're only using it for service # qualification. resolver_kind = 'KubernetesBogusResolver' service = normalize_service_name(ir, service, namespace, resolver_kind, rkey=rkey) self.ir.logger.debug( f"Mapping {name} service qualified to {repr(service)}") svc = Service(ir.logger, service) if add_linkerd_headers: add_request_hdrs['l5d-dst-override'] = svc.hostname_port # XXX BRUTAL HACK HERE: # If we _don't_ have an origination context, but our IR has an agent_origination_ctx, # force TLS origination because it's the agent. I know, I know. It's a hack. if ('tls' not in new_args) and ir.agent_origination_ctx: ir.logger.debug( f"Mapping {name}: Agent forcing origination TLS context to {ir.agent_origination_ctx.name}" ) new_args['tls'] = ir.agent_origination_ctx.name if 'query_parameters' in kwargs: for name, value in kwargs.get('query_parameters', {}).items(): if value is True: query_parameters.append(KeyValueDecorator(name)) else: query_parameters.append(KeyValueDecorator(name, value)) if 'regex_query_parameters' in kwargs: for name, value in kwargs.get('regex_query_parameters', {}).items(): query_parameters.append( KeyValueDecorator(name, value, regex=True)) if 'regex_rewrite' in kwargs: if rewrite and rewrite != "/": self.ir.aconf.post_notice( "Cannot specify both rewrite and regex_rewrite: using regex_rewrite and ignoring rewrite" ) rewrite = "" rewrite_items = kwargs.get('regex_rewrite', {}) regex_rewrite = { 'pattern': rewrite_items.get('pattern', ''), 'substitution': rewrite_items.get('substitution', '') } # ...and then init the superclass. super().__init__(ir=ir, aconf=aconf, rkey=rkey, location=location, service=service, kind=kind, name=name, namespace=namespace, metadata_labels=metadata_labels, apiVersion=apiVersion, headers=hdrs, add_request_headers=add_request_hdrs, add_response_headers=add_response_hdrs, precedence=precedence, rewrite=rewrite, cluster_tag=cluster_tag, query_parameters=query_parameters, regex_rewrite=regex_rewrite, **new_args) if 'outlier_detection' in kwargs: self.post_error( RichStatus.fromError("outlier_detection is not supported"))
def __init__(self, ir: 'IR', aconf: Config, rkey: str, # REQUIRED name: str, # REQUIRED location: str, # REQUIRED namespace: Optional[str] = None, metadata_labels: Optional[Dict[str, str]] = None, kind: str="IRHTTPMapping", apiVersion: str="getambassador.io/v2", # Not a typo! See below. precedence: int=0, rewrite: str="/", cluster_tag: Optional[str]=None, **kwargs) -> None: # OK, this is a bit of a pain. We want to preserve the name and rkey and # such here, unlike most kinds of IRResource. So. Shallow copy the keys # we're going to allow from the incoming kwargs... new_args = {x: kwargs[x] for x in kwargs.keys() if x in IRHTTPMapping.AllowedKeys} # ...then set up the headers (since we need them to compute our group ID). hdrs = [] add_request_hdrs = kwargs.get('add_request_headers', {}) if 'headers' in kwargs: for name, value in kwargs.get('headers', {}).items(): if value is True: hdrs.append(Header(name)) else: hdrs.append(Header(name, value)) if 'regex_headers' in kwargs: for name, value in kwargs.get('regex_headers', {}).items(): hdrs.append(Header(name, value, regex=True)) if 'host' in kwargs: hdrs.append(Header(":authority", kwargs['host'], kwargs.get('host_regex', False))) self.tls_context = self.match_tls_context(kwargs['host'], ir) if 'service' in kwargs: svc = Service(ir.logger, kwargs['service']) if 'add_linkerd_headers' in kwargs: if kwargs['add_linkerd_headers'] is True: add_request_hdrs['l5d-dst-override'] = svc.hostname_port else: if 'add_linkerd_headers' in ir.ambassador_module and ir.ambassador_module.add_linkerd_headers is True: add_request_hdrs['l5d-dst-override'] = svc.hostname_port if 'method' in kwargs: hdrs.append(Header(":method", kwargs['method'], kwargs.get('method_regex', False))) # XXX BRUTAL HACK HERE: # If we _don't_ have an origination context, but our IR has an agent_origination_ctx, # force TLS origination because it's the agent. I know, I know. It's a hack. if ('tls' not in new_args) and ir.agent_origination_ctx: ir.logger.info(f"Mapping {name}: Agent forcing origination TLS context to {ir.agent_origination_ctx.name}") new_args['tls'] = ir.agent_origination_ctx.name # ...and then init the superclass. super().__init__( ir=ir, aconf=aconf, rkey=rkey, location=location, kind=kind, name=name, namespace=namespace, metadata_labels=metadata_labels, apiVersion=apiVersion, headers=hdrs, add_request_headers=add_request_hdrs, precedence=precedence, rewrite=rewrite, cluster_tag=cluster_tag, **new_args ) if 'outlier_detection' in kwargs: self.post_error(RichStatus.fromError("outlier_detection is not supported"))
def v2filter_authv1(auth: IRAuth, v2config: 'V2Config'): del v2config # silence unused-variable warning assert auth.cluster cluster = typecast(IRCluster, auth.cluster) if auth.api_version != "ambassador/v1": auth.ir.logger.warning("IRAuth_v1 working on %s, mismatched at %s" % (auth.name, auth.api_version)) assert auth.proto raw_body_info: Optional[Dict[str, int]] = auth.get('include_body') if not raw_body_info and auth.get('allow_request_body', False): raw_body_info = {'max_bytes': 4096, 'allow_partial': True} body_info: Optional[Dict[str, int]] = None if raw_body_info: body_info = {} if 'max_bytes' in raw_body_info: body_info['max_request_bytes'] = raw_body_info['max_bytes'] if 'allow_partial' in raw_body_info: body_info['allow_partial_message'] = raw_body_info['allow_partial'] auth_info: Dict[str, Any] = {} if auth.proto == "http": allowed_authorization_headers = [] headers_to_add = [] for key in list( set(auth.allowed_authorization_headers).union( AllowedAuthorizationHeaders)): allowed_authorization_headers.append({"exact": key}) allowed_request_headers = [] for key in list( set(auth.allowed_request_headers).union( AllowedRequestHeaders)): allowed_request_headers.append({"exact": key}) if auth.get('add_linkerd_headers', False): svc = Service(auth.ir.logger, auth_cluster_uri(auth, cluster)) headers_to_add.append({ 'key': 'l5d-dst-override', 'value': svc.hostname_port }) auth_info = { 'name': 'envoy.ext_authz', 'config': { 'http_service': { 'server_uri': { 'uri': auth_cluster_uri(auth, cluster), 'cluster': cluster.name, 'timeout': "%0.3fs" % (float(auth.timeout_ms) / 1000.0) }, 'path_prefix': auth.path_prefix, 'authorization_request': { 'allowed_headers': { 'patterns': allowed_request_headers }, 'headers_to_add': headers_to_add }, 'authorization_response': { 'allowed_upstream_headers': { 'patterns': allowed_authorization_headers }, 'allowed_client_headers': { 'patterns': allowed_authorization_headers } } }, } } if auth.proto == "grpc": auth_info = { 'name': 'envoy.ext_authz', 'config': { 'grpc_service': { 'envoy_grpc': { 'cluster_name': cluster.name }, 'timeout': "%0.3fs" % (float(auth.timeout_ms) / 1000.0) }, 'use_alpha': True } } if auth_info: if body_info: auth_info['config']['with_request_body'] = body_info if 'failure_mode_allow' in auth: auth_info['config']["failure_mode_allow"] = auth.failure_mode_allow if 'status_on_error' in auth: status_on_error: Optional[Dict[str, int]] = auth.get('status_on_error') auth_info['config']["status_on_error"] = status_on_error return auth_info # If here, something's gone horribly wrong. auth.post_error("Protocol '%s' is not supported, auth not enabled" % auth.proto) return None
res_source = 'mapping' if not res_name: res_name = global_resolver res_source = 'defaults' ctx_name = mapping.get('tls', None) logger.debug(f'Mapping {mname}: resolver {res_name} from {res_source}, service {mapping.service}, tls {ctx_name}') if res_name: resolver = resolvers.get(res_name, None) logger.debug(f'-> resolver {resolver}') if resolver: svc = Service(logger, mapping.service, ctx_name) if resolver.kind == 'ConsulResolver': logger.debug(f'Mapping {mname} uses Consul resolver {res_name}') # At the moment, we stuff the resolver's datacenter into the association # ID for this watch. The ResourceFetcher relies on that. consul_watches.append( { "id": resolver.datacenter, "consul-address": resolver.address, "datacenter": resolver.datacenter, "service-name": svc.hostname } )
def load_yaml(self, yaml_stream): self.aconf = Config() fetcher = ResourceFetcher(self.logger, self.aconf, watch_only=True) fetcher.parse_watt(yaml_stream.read()) self.aconf.load_all(fetcher.sorted()) # We can lift mappings straight from the aconf... mappings = self.aconf.get_config('mappings') or {} # ...but we need the fake IR to deal with resolvers and TLS contexts. self.fake = FakeIR(self.aconf, logger=self.logger) self.logger.debug("IR: %s" % self.fake.as_json()) resolvers = self.fake.resolvers contexts = self.fake.tls_contexts self.logger.debug(f'mappings: {len(mappings)}') self.logger.debug(f'resolvers: {len(resolvers)}') self.logger.debug(f'contexts: {len(contexts)}') global_resolver = self.fake.ambassador_module.get('resolver', None) global_label_selector = os.environ.get('AMBASSADOR_LABEL_SELECTOR', '') self.logger.debug('label-selector: %s' % global_label_selector) # watch the AES Secret if the edge stack is running if self.fake.edge_stack_allowed: aes_secret_name = os.getenv(ENV_AES_SECRET_NAME, DEFAULT_AES_SECRET_NAME) aes_secret_namespace = os.getenv(ENV_AES_SECRET_NAMESPACE, Config.ambassador_namespace) self.logger.debug(f'edge stack detected: need secret {aes_secret_name}.{aes_secret_namespace}') self.add_kube_watch(f'Secret {aes_secret_name}', 'secret', namespace=aes_secret_namespace, field_selector=f"metadata.name={aes_secret_name}") # Walk hosts. for host in self.fake.get_hosts(): sel = host.get('selector') or {} match_labels = sel.get('matchLabels') or {} label_selectors: List[str] = [] if global_label_selector: label_selectors.append(global_label_selector) if match_labels: label_selectors += [ f"{l}={v}" for l, v in match_labels.items() ] label_selector = ','.join(label_selectors) if label_selectors else None for wanted_kind in ['service', 'secret']: self.add_kube_watch(f"Host {host.name}", wanted_kind, host.namespace, label_selector=label_selector) for mname, mapping in mappings.items(): res_name = mapping.get('resolver', None) res_source = 'mapping' if not res_name: res_name = global_resolver res_source = 'defaults' ctx_name = mapping.get('tls', None) self.logger.debug( f'Mapping {mname}: resolver {res_name} from {res_source}, service {mapping.service}, tls {ctx_name}') if res_name: resolver = resolvers.get(res_name, None) self.logger.debug(f'-> resolver {resolver}') if resolver: svc = Service(logger, mapping.service, ctx_name) if resolver.kind == 'ConsulResolver': self.logger.debug(f'Mapping {mname} uses Consul resolver {res_name}') # At the moment, we stuff the resolver's datacenter into the association # ID for this watch. The ResourceFetcher relies on that. self.consul_watches.append( { "id": resolver.datacenter, "consul-address": resolver.address, "datacenter": resolver.datacenter, "service-name": svc.hostname } ) elif resolver.kind == 'KubernetesEndpointResolver': host = svc.hostname namespace = Config.ambassador_namespace if not host: # This is really kind of impossible. self.logger.error(f"KubernetesEndpointResolver {res_name} has no 'hostname'") continue if "." in host: (host, namespace) = host.split(".", 2)[0:2] self.logger.debug(f'...kube endpoints: svc {svc.hostname} -> host {host} namespace {namespace}') self.add_kube_watch(f"endpoint", "endpoints", namespace, label_selector=global_label_selector, field_selector=f"metadata.name={host}") for secret_key, secret_info in self.fake.secret_recorder.needed.items(): self.logger.debug(f'need secret {secret_info.name}.{secret_info.namespace}') self.add_kube_watch(f"needed secret", "secret", secret_info.namespace, label_selector=global_label_selector, field_selector=f"metadata.name={secret_info.name}") if self.fake.edge_stack_allowed: # If the edge stack is allowed, make sure we watch for our fallback context. self.add_kube_watch("Fallback TLSContext", "TLSContext", namespace=Config.ambassador_namespace) ambassador_basedir = os.environ.get('AMBASSADOR_CONFIG_BASE_DIR', '/ambassador') if os.path.exists(os.path.join(ambassador_basedir, '.ambassadorinstallations_ok')): self.add_kube_watch("AmbassadorInstallations", "ambassadorinstallations.getambassador.io", Config.ambassador_namespace) ambassador_knative_requested = (os.environ.get("AMBASSADOR_KNATIVE_SUPPORT", "-unset-").lower() == 'true') if ambassador_knative_requested: self.logger.debug('Looking for Knative support...') if os.path.exists(os.path.join(ambassador_basedir, '.knative_clusteringress_ok')): # Watch for clusteringresses.networking.internal.knative.dev in any namespace and with any labels. self.logger.debug('watching for clusteringresses.networking.internal.knative.dev') self.add_kube_watch("Knative clusteringresses", "clusteringresses.networking.internal.knative.dev", None) if os.path.exists(os.path.join(ambassador_basedir, '.knative_ingress_ok')): # Watch for ingresses.networking.internal.knative.dev in any namespace and # with any labels. self.add_kube_watch("Knative ingresses", "ingresses.networking.internal.knative.dev", None) self.watchset = { "kubernetes-watches": self.kube_watches, "consul-watches": self.consul_watches } save_dir = os.environ.get('AMBASSADOR_WATCH_DIR', '/tmp') if save_dir: watchset = dump_json(self.watchset) with open(os.path.join(save_dir, 'watch.json'), "w") as output: output.write(watchset)