Add Consul Lambda integration tests (#13770)

This commit is contained in:
Chris Thain 2022-07-21 09:54:56 -07:00 committed by GitHub
parent 2875cbe856
commit 00f9dc2a70
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 237 additions and 0 deletions

View File

@ -876,8 +876,13 @@ jobs:
environment: environment:
ENVOY_VERSION: << parameters.envoy-version >> ENVOY_VERSION: << parameters.envoy-version >>
XDS_TARGET: << parameters.xds-target >> XDS_TARGET: << parameters.xds-target >>
AWS_LAMBDA_REGION: us-west-2
steps: &ENVOY_INTEGRATION_TEST_STEPS steps: &ENVOY_INTEGRATION_TEST_STEPS
- checkout - checkout
- assume-role:
access-key: AWS_ACCESS_KEY_ID_LAMBDA
secret-key: AWS_SECRET_ACCESS_KEY_LAMBDA
role-arn: ROLE_ARN_LAMBDA
# Get go binary from workspace # Get go binary from workspace
- attach_workspace: - attach_workspace:
at: . at: .

View File

@ -0,0 +1,4 @@
#!/bin/bash
snapshot_envoy_admin localhost:19000 s1 primary || true
snapshot_envoy_admin localhost:20000 terminating-gateway primary || true

View File

@ -0,0 +1,12 @@
config_entries {
bootstrap {
kind = "terminating-gateway"
name = "terminating-gateway"
services = [
{
name = "l2"
}
]
}
}

View File

@ -0,0 +1,12 @@
{
"Node": "lambdas",
"SkipNodeUpdate": true,
"NodeMeta": {
"external-node": "true",
"external-probe": "true"
},
"Service": {
"ID": "l1",
"Service": "l1"
}
}

View File

@ -0,0 +1,12 @@
{
"Node": "lambdas",
"SkipNodeUpdate": true,
"NodeMeta": {
"external-node": "true",
"external-probe": "true"
},
"Service": {
"ID": "l2",
"Service": "l2"
}
}

View File

@ -0,0 +1,3 @@
connect {
enable_serverless_plugin = true
}

View File

@ -0,0 +1,11 @@
{
"Kind": "service-defaults",
"Name": "l1",
"Protocol": "http",
"Meta": {
"serverless.consul.hashicorp.com/v1alpha1/lambda/enabled": "true",
"serverless.consul.hashicorp.com/v1alpha1/lambda/region": "${AWS_LAMBDA_REGION}",
"serverless.consul.hashicorp.com/v1alpha1/lambda/arn": "${AWS_LAMBDA_ARN}",
"serverless.consul.hashicorp.com/v1alpha1/lambda/payload-passthrough": "true"
}
}

View File

@ -0,0 +1,11 @@
{
"Kind": "service-defaults",
"Name": "l2",
"Protocol": "http",
"Meta": {
"serverless.consul.hashicorp.com/v1alpha1/lambda/enabled": "true",
"serverless.consul.hashicorp.com/v1alpha1/lambda/region": "${AWS_LAMBDA_REGION}",
"serverless.consul.hashicorp.com/v1alpha1/lambda/arn": "${AWS_LAMBDA_ARN}",
"serverless.consul.hashicorp.com/v1alpha1/lambda/payload-passthrough": "false"
}
}

View File

@ -0,0 +1,5 @@
services {
name = "terminating-gateway"
kind = "terminating-gateway"
port = 8443
}

View File

@ -0,0 +1,20 @@
services {
name = "s1"
port = 8080
connect {
sidecar_service {
proxy {
upstreams = [
{
destination_name = "l1"
local_bind_port = 1234
},
{
destination_name = "l2"
local_bind_port = 5678
}
]
}
}
}
}

View File

@ -0,0 +1,19 @@
#!/bin/bash
set -eEuo pipefail
# Copy lambda config files into the register dir
find ${CASE_DIR} -maxdepth 1 -name '*_l*.json' -type f -exec cp -f {} workdir/${CLUSTER}/register \;
# wait for tgw config entry
wait_for_config_entry terminating-gateway terminating-gateway
register_services primary
register_lambdas primary
# wait for Lambda config entries
wait_for_config_entry service-defaults l1
wait_for_config_entry service-defaults l2
gen_envoy_bootstrap s1 19000 primary
gen_envoy_bootstrap terminating-gateway 20000 primary true

View File

@ -0,0 +1,15 @@
#!/bin/bash
# Ensure that the environment variables required to configure and invoke the Lambda function are present, otherwise skip.
# Note that `set | grep ...` is used here because we cannot check the vars directly. If they are unbound the test will
# fail instead of being skipped.
export SKIP_CASE=""
[ -n "$(set | grep '^AWS_LAMBDA_REGION=')" ] || export SKIP_CASE="AWS_LAMBDA_REGION is not present in the environment"
[ -n "$(set | grep '^AWS_LAMBDA_ARN=')" ] || export SKIP_CASE="AWS_LAMBDA_ARN is not present in the environment"
[ -n "$(set | grep '^AWS_SESSION_TOKEN=')" ] || export SKIP_CASE="AWS_SESSION_TOKEN is not present in the environment"
[ -n "$(set | grep '^AWS_SECRET_ACCESS_KEY=')" ] || export SKIP_CASE="AWS_SECRET_ACCESS_KEY is not present in the environment"
[ -n "$(set | grep '^AWS_ACCESS_KEY_ID=')" ] || export SKIP_CASE="AWS_ACCESS_KEY_ID is not present in the environment"
[ -n "$SKIP_CASE" ] && return 0
export REQUIRED_SERVICES="s1 s1-sidecar-proxy terminating-gateway-primary"

View File

@ -0,0 +1,39 @@
#!/usr/bin/env bats
load helpers
@test "s1 has lambda cluster for l1" {
assert_lambda_envoy_dynamic_cluster_exists localhost:19000 l1
}
@test "s1 has lambda http filter for l1" {
assert_lambda_envoy_dynamic_http_filter_exists localhost:19000 l1 $AWS_LAMBDA_ARN
}
@test "terminating gateway has lambda cluster for l2" {
assert_lambda_envoy_dynamic_cluster_exists localhost:20000 l2
}
@test "terminating gateway has lambda http filter for l2" {
assert_lambda_envoy_dynamic_http_filter_exists localhost:20000 l2 $AWS_LAMBDA_ARN
}
@test "s1 can call l1 through its sidecar-proxy" {
run retry_default curl -s -f -H "Content-type: application/json" -d '"hello"' 'localhost:1234'
[ "$status" -eq 0 ]
# l1 is configured with payload_passthrough = true so the response needs to be unwrapped
[ $(echo "$output" | jq -r '.statusCode') -eq 200 ]
[ $(echo "$output" | jq -r '.body') == "hello" ]
}
@test "s1 can call l2 through the terminating gateway" {
run retry_default curl -s -f -H "Content-type: application/json" -d '"hello"' 'localhost:5678'
[ "$status" -eq 0 ]
[ "$output" == '"hello"' ]
# Omitting the Content-type in the request will cause envoy to base64 encode the request.
run curl -s -f -d '{"message":"hello"}' 'localhost:5678'
[ "$status" -eq 0 ]
[ "$output" == '{"message":"hello"}' ]
}

View File

@ -966,3 +966,55 @@ function create_peering {
# echo "$output" >&3 # echo "$output" >&3
[ "$status" == 0 ] [ "$status" == 0 ]
} }
function get_lambda_envoy_http_filter {
local HOSTPORT=$1
local NAME_PREFIX=$2
run retry_default curl -s -f $HOSTPORT/config_dump
[ "$status" -eq 0 ]
# get the full http filter object so the individual fields can be validated.
echo "$output" | jq --raw-output ".configs[2].dynamic_listeners[] | .active_state.listener.filter_chains[].filters[] | select(.name == \"envoy.filters.network.http_connection_manager\") | .typed_config.http_filters[] | select(.name == \"envoy.filters.http.aws_lambda\") | .typed_config"
}
function register_lambdas {
local DC=${1:-primary}
# register lambdas to the catalog
for f in $(find workdir/${DC}/register -type f -name 'lambda_*.json'); do
retry_default curl -sL -XPUT -d @${f} "http://localhost:8500/v1/catalog/register" >/dev/null && \
echo "Registered Lambda: $(jq -r .Service.Service $f)"
done
# write service-defaults config entries for lambdas
for f in $(find workdir/${DC}/register -type f -name 'service_defaults_*.json'); do
varsub ${f} AWS_LAMBDA_REGION AWS_LAMBDA_ARN
retry_default curl -sL -XPUT -d @${f} "http://localhost:8500/v1/config" >/dev/null && \
echo "Wrote config: $(jq -r '.Kind + " / " + .Name' $f)"
done
}
function assert_lambda_envoy_dynamic_cluster_exists {
local HOSTPORT=$1
local NAME_PREFIX=$2
local BODY=$(get_envoy_dynamic_cluster_once $HOSTPORT $NAME_PREFIX)
[ -n "$BODY" ]
[ "$(echo $BODY | jq -r '.cluster.transport_socket.typed_config.sni')" == '*.amazonaws.com' ]
}
function assert_lambda_envoy_dynamic_http_filter_exists {
local HOSTPORT=$1
local NAME_PREFIX=$2
local ARN=$3
local FILTER=$(get_lambda_envoy_http_filter $HOSTPORT $NAME_PREFIX)
[ -n "$FILTER" ]
[ "$(echo $FILTER | jq -r '.arn')" == "$ARN" ]
}
function varsub {
local file=$1 ; shift
for v in "$@"; do
sed -i "s/\${$v}/${!v}/g" $file
done
}

View File

@ -43,6 +43,20 @@ function network_snippet {
echo "--net container:envoy_consul-${DC}_1" echo "--net container:envoy_consul-${DC}_1"
} }
function aws_snippet {
local snippet=""
# The Lambda integration cases assume that a Lambda function exists in $AWS_REGION with an ARN of $AWS_LAMBDA_ARN.
# The AWS credentials must have permission to invoke the Lambda function.
[ -n "$(set | grep '^AWS_ACCESS_KEY_ID=')" ] && snippet="${snippet} -e AWS_ACCESS_KEY_ID=$AWS_ACCESS_KEY_ID"
[ -n "$(set | grep '^AWS_SECRET_ACCESS_KEY=')" ] && snippet="${snippet} -e AWS_SECRET_ACCESS_KEY=$AWS_SECRET_ACCESS_KEY"
[ -n "$(set | grep '^AWS_SESSION_TOKEN=')" ] && snippet="${snippet} -e AWS_SESSION_TOKEN=$AWS_SESSION_TOKEN"
[ -n "$(set | grep '^AWS_LAMBDA_REGION=')" ] && snippet="${snippet} -e AWS_LAMBDA_REGION=$AWS_LAMBDA_REGION"
[ -n "$(set | grep '^AWS_LAMBDA_ARN=')" ] && snippet="${snippet} -e AWS_LAMBDA_ARN=$AWS_LAMBDA_ARN"
echo "$snippet"
}
function init_workdir { function init_workdir {
local CLUSTER="$1" local CLUSTER="$1"
@ -333,6 +347,7 @@ function verify {
$WORKDIR_SNIPPET \ $WORKDIR_SNIPPET \
--pid=host \ --pid=host \
$(network_snippet $CLUSTER) \ $(network_snippet $CLUSTER) \
$(aws_snippet) \
bats-verify \ bats-verify \
--pretty /workdir/${CLUSTER}/bats ; then --pretty /workdir/${CLUSTER}/bats ; then
echogreen "✓ PASS" echogreen "✓ PASS"
@ -679,6 +694,7 @@ function common_run_container_sidecar_proxy {
docker run -d --name $(container_name_prev) \ docker run -d --name $(container_name_prev) \
$WORKDIR_SNIPPET \ $WORKDIR_SNIPPET \
$(network_snippet $CLUSTER) \ $(network_snippet $CLUSTER) \
$(aws_snippet) \
"${HASHICORP_DOCKER_PROXY}/envoyproxy/envoy:v${ENVOY_VERSION}" \ "${HASHICORP_DOCKER_PROXY}/envoyproxy/envoy:v${ENVOY_VERSION}" \
envoy \ envoy \
-c /workdir/${CLUSTER}/envoy/${service}-bootstrap.json \ -c /workdir/${CLUSTER}/envoy/${service}-bootstrap.json \
@ -765,6 +781,7 @@ function common_run_container_gateway {
docker run -d --name $(container_name_prev) \ docker run -d --name $(container_name_prev) \
$WORKDIR_SNIPPET \ $WORKDIR_SNIPPET \
$(network_snippet $DC) \ $(network_snippet $DC) \
$(aws_snippet) \
"${HASHICORP_DOCKER_PROXY}/envoyproxy/envoy:v${ENVOY_VERSION}" \ "${HASHICORP_DOCKER_PROXY}/envoyproxy/envoy:v${ENVOY_VERSION}" \
envoy \ envoy \
-c /workdir/${DC}/envoy/${name}-bootstrap.json \ -c /workdir/${DC}/envoy/${name}-bootstrap.json \