def test_loading_sources_t1(discovery_request, sources):
    expected = {
        'scopes': {
            'listeners': [{
                'name': 'ssh',
                'port': 22,
                'tcp': True,
                'target': 'httpbin-proxy',
                'service_clusters': ['T1']
            }],
            'default': [
                {
                    'name': 'httpbin-proxy',
                    'service_clusters': ['T1'],
                    'domains': ['example.local'],
                    'endpoints': [{
                        'address': 'httpbin.org',
                        'port': 443
                    }],
                },
            ]
        }
    }
    instances = match_node(node_value=extract_node_key(discovery_request.node))
    assert instances.dict() == expected
async def deep_check():
    template = random.choice(
        list(XDS_TEMPLATES['default'].keys())
    )
    await discovery.response(
        mock_discovery_request(),
        xds_type=template
    )
    node = mock_discovery_request().node
    match_node(node_value=extract_node_key(node))
    return PlainTextResponse(f'Rendered {template} OK')
Example #3
0
def instances(
        service_cluster: str = Query(
            '*',
            title='The clients service cluster to emulate in this XDS request'
        ),
        modified:
    str = Query(
        'yes',
        title=
        'Whether the sources should run Modifiers/Global Modifiers prior to being returned'
    )):
    node = mock_discovery_request(service_cluster=service_cluster).node
    args = {
        'modify': yaml.safe_load(modified),
        'node_value': extract_node_key(node)
    }
    ret = match_node(**args)
    safe_response = jsonable_encoder(ret)
    return json_response_class(content=safe_response)
def test_loading_sources_wildcard(discovery_request, sources):
    expected = {
        'scopes': {
            'listeners': [{
                'name': 'ssh',
                'port': 22,
                'tcp': True,
                'target': 'httpbin-proxy',
                'service_clusters': ['T1']
            }],
            'default': [{
                'name':
                'google-proxy',
                'service_clusters': ['X1'],
                'domains': ['google.local'],
                'endpoints': [{
                    'address': 'google.com.au',
                    'port': 443,
                    'region': 'ap-southeast-2'
                }, {
                    'address': 'google.com',
                    'port': 443,
                    'region': 'us-west-1'
                }],
            }, {
                'name': 'httpbin-proxy',
                'service_clusters': ['T1'],
                'domains': ['example.local'],
                'endpoints': [{
                    'address': 'httpbin.org',
                    'port': 443
                }],
            }]
        }
    }
    discovery_request.node.cluster = '*'
    instances = match_node(node_value=extract_node_key(discovery_request.node))
    assert instances.dict() == expected
def test_loading_sources_x1(discovery_request, sources):
    expected = {
        'scopes': {
            'default': [{
                'name':
                'google-proxy',
                'service_clusters': ['X1'],
                'domains': ['google.local'],
                'endpoints': [{
                    'address': 'google.com.au',
                    'port': 443,
                    'region': 'ap-southeast-2'
                }, {
                    'address': 'google.com',
                    'port': 443,
                    'region': 'us-west-1'
                }],
            }]
        }
    }
    discovery_request.node.cluster = 'X1'
    instances = match_node(node_value=extract_node_key(discovery_request.node))
    assert instances.dict() == expected
async def response(request: DiscoveryRequest, xds_type: DiscoveryTypes, host: str = 'none'):
    """
    A Discovery **Request** typically looks something like:

    .. code-block:: json

        {
            "version_info": "0",
            "node": {
                "cluster": "T1",
                "build_version": "<revision hash>/<version>/Clean/RELEASE",
                "metadata": {
                    "auth": "..."
                }
            }
        }

    When we receive this, we give the client the latest configuration via a
    Discovery **Response** that looks something like this:

    .. code-block:: json

        {
            "version_info": "abcdef1234567890",
            "resources": []
        }

    The version_info is derived from :func:`sovereign.discovery.version_hash`

    :param request: An envoy Discovery Request
    :param xds_type: what type of XDS template to use when rendering
    :param host: the host header that was received from the envoy client
    :return: An envoy Discovery Response
    """
    template: XdsTemplate = XDS_TEMPLATES.get(request.envoy_version, default_templates)[xds_type]

    context = make_context(
        node_value=extract_node_key(request.node),
        template=template,
    )

    # If the discovery request came from a mock, it will
    # typically contain this metadata key.
    # This means we should prevent any decryptable data
    # from ending up in the response.
    if request.node.metadata.get('hide_private_keys'):
        context['crypto'] = disabled_suite

    config_version = '0'
    if config.cache_strategy == 'context':
        config_version = version_hash(context, template.checksum, request.node.common, request.resources)
        if config_version == request.version_info:
            return {'version_info': config_version}

    kwargs = dict(
        discovery_request=request,
        host_header=host,
        resource_names=request.resources,
        **context
    )

    if template.is_python_source:
        content = {'resources': list(template.code.call(**kwargs))}
    else:
        content = await template.content.render_async(**kwargs)

    if config.cache_strategy == 'content':
        config_version = version_hash(content)
        if config_version == request.version_info:
            return {'version_info': config_version}

    # This is the most expensive operation, I think, so it's performed as late as possible.
    if not template.is_python_source:
        content = deserialize_config(content)

    content['version_info'] = config_version
    return remove_unwanted_resources(content, request.resources)