diff --git a/.gitignore b/.gitignore index 8b692da27e8b..ac77ba2eae8d 100644 --- a/.gitignore +++ b/.gitignore @@ -7,5 +7,4 @@ docker/envoy /artifacts clang.bazelrc user.bazelrc -**/plugin.wasm compile_commands.json diff --git a/Makefile.core.mk b/Makefile.core.mk index b8f6c9dbb0e4..b31938ab3037 100644 --- a/Makefile.core.mk +++ b/Makefile.core.mk @@ -71,6 +71,9 @@ build_envoy_asan: build_wasm: $(foreach file, $(shell find extensions -name build_wasm.sh), cd $(TOP)/$(shell dirname $(file)) && bash ./build_wasm.sh &&) true +generate_wasm: + ./scripts/generate-wasm.sh -b -c + clean: @bazel clean @@ -108,7 +111,7 @@ test_release: export PATH=$(PATH) CC=$(CC) CXX=$(CXX) BAZEL_BUILD_ARGS="$(BAZEL_BUILD_ARGS)" && ./scripts/release-binary.sh -i push_release: - export PATH=$(PATH) CC=$(CC) CXX=$(CXX) BAZEL_BUILD_ARGS="$(BAZEL_BUILD_ARGS)" && ./scripts/release-binary.sh -d "$(RELEASE_GCS_PATH)" -p + export PATH=$(PATH) CC=$(CC) CXX=$(CXX) BAZEL_BUILD_ARGS="$(BAZEL_BUILD_ARGS)" && ./scripts/release-binary.sh -d "$(RELEASE_GCS_PATH)" -p && ./scripts/generate-wasm.sh -b -p .PHONY: build clean test check artifacts diff --git a/extensions/access_log_policy/Makefile b/extensions/access_log_policy/Makefile deleted file mode 100644 index d349791e4a75..000000000000 --- a/extensions/access_log_policy/Makefile +++ /dev/null @@ -1,17 +0,0 @@ -DOCKER_SDK=/sdk -CPP_API:=${DOCKER_SDK} -CPP_CONTEXT_LIB = ${CPP_API}/proxy_wasm_intrinsics.cc -ABSL = /root/abseil-cpp -ABSL_CPP = ${ABSL}/absl/strings/str_cat.cc ${ABSL}/absl/strings/str_split.cc ${ABSL}/absl/strings/numbers.cc ${ABSL}/absl/strings/ascii.cc - -PROTO_SRCS = extensions/common/node_info.pb.cc -COMMON_SRCS = extensions/common/context.cc - -all: plugin.wasm - -%.wasm %.wat: %.cc ${CPP_API}/proxy_wasm_intrinsics.h ${CPP_API}/proxy_wasm_enums.h ${CPP_API}/proxy_wasm_externs.h ${CPP_API}/proxy_wasm_api.h ${CPP_API}/proxy_wasm_intrinsics.js ${CPP_CONTEXT_LIB} - protoc extensions/common/node_info.proto --cpp_out=. - em++ -s STANDALONE_WASM=1 -s EMIT_EMSCRIPTEN_METADATA=1 --std=c++17 -O3 -I${CPP_API} -I${CPP_API}/google/protobuf -I../../extensions/common -I. -I/usr/local/include -I${ABSL} --js-library ${CPP_API}/proxy_wasm_intrinsics.js ${ABSL_CPP} $*.cc ${CPP_API}/proxy_wasm_intrinsics.pb.cc ${PROTO_SRCS} ${COMMON_SRCS} ${CPP_CONTEXT_LIB} ${CPP_API}/libprotobuf.a -o $*.wasm - rm -f $*.wast - rm -f extensions/common/node_info.pb.* - chown ${uid}.${gid} $^ diff --git a/extensions/metadata_exchange/Makefile b/extensions/metadata_exchange/Makefile index d349791e4a75..7056b1b522b8 100644 --- a/extensions/metadata_exchange/Makefile +++ b/extensions/metadata_exchange/Makefile @@ -11,7 +11,7 @@ all: plugin.wasm %.wasm %.wat: %.cc ${CPP_API}/proxy_wasm_intrinsics.h ${CPP_API}/proxy_wasm_enums.h ${CPP_API}/proxy_wasm_externs.h ${CPP_API}/proxy_wasm_api.h ${CPP_API}/proxy_wasm_intrinsics.js ${CPP_CONTEXT_LIB} protoc extensions/common/node_info.proto --cpp_out=. - em++ -s STANDALONE_WASM=1 -s EMIT_EMSCRIPTEN_METADATA=1 --std=c++17 -O3 -I${CPP_API} -I${CPP_API}/google/protobuf -I../../extensions/common -I. -I/usr/local/include -I${ABSL} --js-library ${CPP_API}/proxy_wasm_intrinsics.js ${ABSL_CPP} $*.cc ${CPP_API}/proxy_wasm_intrinsics.pb.cc ${PROTO_SRCS} ${COMMON_SRCS} ${CPP_CONTEXT_LIB} ${CPP_API}/libprotobuf.a -o $*.wasm + em++ -s STANDALONE_WASM=1 -s EMIT_EMSCRIPTEN_METADATA=1 -s EXPORTED_FUNCTIONS=['_malloc','_free'] --std=c++17 -O3 -I${CPP_API} -I${CPP_API}/google/protobuf -I../../extensions/common -I. -I/usr/local/include -I${ABSL} --js-library ${CPP_API}/proxy_wasm_intrinsics.js ${ABSL_CPP} $*.cc ${CPP_API}/proxy_wasm_intrinsics.pb.cc ${PROTO_SRCS} ${COMMON_SRCS} ${CPP_CONTEXT_LIB} ${CPP_API}/libprotobuf.a -o $*.wasm rm -f $*.wast rm -f extensions/common/node_info.pb.* chown ${uid}.${gid} $^ diff --git a/extensions/metadata_exchange/plugin.wasm b/extensions/metadata_exchange/plugin.wasm new file mode 100644 index 000000000000..f608813faa58 Binary files /dev/null and b/extensions/metadata_exchange/plugin.wasm differ diff --git a/extensions/stats/Makefile b/extensions/stats/Makefile index 7834865cbc2e..349be33751a7 100644 --- a/extensions/stats/Makefile +++ b/extensions/stats/Makefile @@ -12,7 +12,7 @@ all: plugin.wasm %.wasm %.wat: %.cc ${CPP_API}/proxy_wasm_intrinsics.h ${CPP_API}/proxy_wasm_enums.h ${CPP_API}/proxy_wasm_externs.h ${CPP_API}/proxy_wasm_api.h ${CPP_API}/proxy_wasm_intrinsics.js ${CPP_CONTEXT_LIB} protoc extensions/common/node_info.proto --cpp_out=. protoc config.proto --cpp_out=. - em++ -s STANDALONE_WASM=1 -s EMIT_EMSCRIPTEN_METADATA=1 --std=c++17 -O3 -I${CPP_API} -I${CPP_API}/google/protobuf -Iextensions/common -I. -I/usr/local/include -I${ABSL} -I. --js-library ${CPP_API}/proxy_wasm_intrinsics.js $*.cc ${CPP_API}/proxy_wasm_intrinsics.pb.cc ${PROTO_SRCS} ${COMMON_SRCS} ${CPP_CONTEXT_LIB} ${ABSL_CPP} ${CPP_API}/libprotobuf.a -o $*.wasm + em++ -s STANDALONE_WASM=1 -s EMIT_EMSCRIPTEN_METADATA=1 -s EXPORTED_FUNCTIONS=['_malloc','_free'] --std=c++17 -O3 -I${CPP_API} -I${CPP_API}/google/protobuf -Iextensions/common -I. -I/usr/local/include -I${ABSL} -I. --js-library ${CPP_API}/proxy_wasm_intrinsics.js $*.cc ${CPP_API}/proxy_wasm_intrinsics.pb.cc ${PROTO_SRCS} ${COMMON_SRCS} ${CPP_CONTEXT_LIB} ${ABSL_CPP} ${CPP_API}/libprotobuf.a -o $*.wasm rm -f $*.wast rm -f extensions/common/node_info.pb.* extensions/stats/config.pb.* chown ${uid}.${gid} $^ diff --git a/extensions/stats/plugin.wasm b/extensions/stats/plugin.wasm new file mode 100644 index 000000000000..d46ecb1e071b Binary files /dev/null and b/extensions/stats/plugin.wasm differ diff --git a/extensions/access_log_policy/build_wasm.sh b/prow/proxy-presubmit-wasm.sh similarity index 63% rename from extensions/access_log_policy/build_wasm.sh rename to prow/proxy-presubmit-wasm.sh index d4f0d2c00b9e..be83f854da4e 100755 --- a/extensions/access_log_policy/build_wasm.sh +++ b/prow/proxy-presubmit-wasm.sh @@ -1,6 +1,6 @@ #!/bin/bash - -# Copyright Istio Authors +# +# Copyright 2020 Istio Authors. 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. @@ -14,7 +14,15 @@ # See the License for the specific language governing permissions and # limitations under the License. -set -e +WD=$(dirname $0) +WD=$(cd $WD; pwd) +ROOT=$(dirname $WD) + +####################################### +# Presubmit script triggered by Prow. # +####################################### + +source "${WD}/proxy-common.inc" -docker run -e uid="$(id -u)" -e gid="$(id -g)" -v $PWD:/work -w /work -v $(realpath $PWD/../../extensions):/work/extensions gcr.io/istio-testing/wasmsdk:v2 bash /build_wasm.sh -rmdir extensions +echo 'Generate and check Wasm plugin files' +make generate_wasm diff --git a/scripts/generate-wasm.sh b/scripts/generate-wasm.sh new file mode 100755 index 000000000000..b889505204d2 --- /dev/null +++ b/scripts/generate-wasm.sh @@ -0,0 +1,92 @@ +#!/bin/bash +# +# Copyright 2020 Istio Authors. 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. +# +################################################################################ +# + +set -ex + +function usage() { + echo "$0 + -b build the wasm sdk image base on ENVOY SHA if it does not exist in `gcr.io/istio-testing` HUB. + If the image already exist in the HUB, this will be noop. + The container will be used to compile wasm files. + -p push the wasm sdk container built from the envoy SHA. Must use with `-b` + -c controls whether to check diff of generated wasm files." + exit 1 +} + +BUILD_CONTAINER=0 +PUSH_CONTAINER=0 +CHECK_DIFF=0 + +while getopts bpc arg ; do + case "${arg}" in + b) BUILD_CONTAINER=1;; + p) PUSH_DOCKER_IMAGE=1;; + c) CHECK_DIFF=1;; + *) usage;; + esac +done + +# Get SHA of envoy-wasm repo +ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd -P)" +WORKSPACE=${ROOT}/WORKSPACE +ENVOY_SHA="$(grep -Pom1 "^ENVOY_SHA = \"\K[a-zA-Z0-9]{40}" "${WORKSPACE}")" +IMAGE=gcr.io/istio-testing/wasmsdk +TAG=${ENVOY_SHA} + +# Try pull wasm builder image. +docker pull ${IMAGE}:${TAG} || echo "${IMAGE}:${TAG} does not exist" + +# If image does not exist, try build it +if [[ "$(docker images -q ${IMAGE}:${TAG} 2> /dev/null)" == "" ]]; then + if [[ ${BUILD_CONTAINER} == 0 ]]; then + echo "no builder image to compile wasm. Add `-b` option to create the builder image" + exit 1 + fi + # Clone envoy-wasm repo and checkout to that SHA + TMP_DIR=$(mktemp -d -t envoy-wasm-XXXXXXXXXX) + trap "rm -rf ${TMP_DIR}" EXIT + + # Check out to envoy SHA + cd ${TMP_DIR} + git clone https://github.com/envoyproxy/envoy-wasm + cd envoy-wasm + git checkout ${ENVOY_SHA} + + # Rebuild and push + cd api/wasm/cpp && docker build -t ${IMAGE}:${TAG} -f Dockerfile-sdk . + if [[ ${PUSH_DOCKER_IMAGE} == 1 ]]; then + docker push ${IMAGE}:${TAG} || "fail to push to gcr.io/istio-testing hub" + fi +fi + +# Regenerate all wasm plugins and compare diffs +# Tag image to v2, which is what used by all build wasm script. +docker tag ${IMAGE}:${TAG} ${IMAGE}:v2 +cd ${ROOT} +find . -name "*.wasm" -type f -delete +make build_wasm + +if [[ ${CHECK_DIFF} == 1 ]]; then + if [[ -n "$(git status --porcelain 2>/dev/null)" ]]; then + echo "wasm files are out of dated and need to be regenerated, run './scripts/generate-wasm.sh -b' to regenerate them" + exit 1 + else + echo "wasm files are up to dated" + fi +fi diff --git a/test/envoye2e/env/ports.go b/test/envoye2e/env/ports.go index d3651927a1c9..86e24c0edadd 100644 --- a/test/envoye2e/env/ports.go +++ b/test/envoye2e/env/ports.go @@ -44,6 +44,7 @@ const ( BasicHTTPGateway StatsPayload StatsParallel + StatsWasm StatsPluginTest diff --git a/test/envoye2e/stats/stats_xds_test.go b/test/envoye2e/stats/stats_xds_test.go index 282d0af8b2ba..8435153a21f3 100644 --- a/test/envoye2e/stats/stats_xds_test.go +++ b/test/envoye2e/stats/stats_xds_test.go @@ -44,9 +44,9 @@ filter_chains: config: config: vm_config: - runtime: "envoy.wasm.runtime.null" + runtime: {{ .Vars.WasmRuntime }} code: - local: { inline_string: "envoy.wasm.metadata_exchange" } + local: { {{ .Vars.MetadataExchangeFilterCode }} } configuration: "test" - name: envoy.filters.http.wasm config: @@ -54,9 +54,9 @@ filter_chains: root_id: "stats_outbound" vm_config: vm_id: stats_outbound{{ .N }} - runtime: envoy.wasm.runtime.null + runtime: {{ .Vars.WasmRuntime }} code: - local: { inline_string: "envoy.wasm.stats" } + local: { {{ .Vars.StatsFilterCode }} } configuration: | { "debug": "false", max_peer_cache_size: 20, field_separator: ";.;" } - name: envoy.router @@ -90,9 +90,9 @@ filter_chains: config: config: vm_config: - runtime: "envoy.wasm.runtime.null" + runtime: {{ .Vars.WasmRuntime }} code: - local: { inline_string: "envoy.wasm.metadata_exchange" } + local: { {{ .Vars.MetadataExchangeFilterCode }} } configuration: "test" - name: envoy.filters.http.wasm config: @@ -100,9 +100,9 @@ filter_chains: root_id: "stats_inbound" vm_config: vm_id: stats_inbound{{ .N }} - runtime: envoy.wasm.runtime.null + runtime: {{ .Vars.WasmRuntime }} code: - local: { inline_string: "envoy.wasm.stats" } + local: { {{ .Vars.StatsFilterCode }} } configuration: | { "debug": "false", max_peer_cache_size: 20, field_separator: ";.;" } - name: envoy.router @@ -135,12 +135,15 @@ func TestStatsPayload(t *testing.T) { ports := env.NewPorts(env.StatsPayload) params := &driver.Params{ Vars: map[string]string{ - "ClientPort": fmt.Sprintf("%d", ports.AppToClientProxyPort), - "BackendPort": fmt.Sprintf("%d", ports.BackendPort), - "ClientAdmin": fmt.Sprintf("%d", ports.ClientAdminPort), - "ServerAdmin": fmt.Sprintf("%d", ports.ServerAdminPort), - "ServerPort": fmt.Sprintf("%d", ports.ClientToServerProxyPort), - "RequestCount": "10", + "ClientPort": fmt.Sprintf("%d", ports.AppToClientProxyPort), + "BackendPort": fmt.Sprintf("%d", ports.BackendPort), + "ClientAdmin": fmt.Sprintf("%d", ports.ClientAdminPort), + "ServerAdmin": fmt.Sprintf("%d", ports.ServerAdminPort), + "ServerPort": fmt.Sprintf("%d", ports.ClientToServerProxyPort), + "RequestCount": "10", + "MetadataExchangeFilterCode": "inline_string: \"envoy.wasm.metadata_exchange\"", + "StatsFilterCode": "inline_string: \"envoy.wasm.stats\"", + "WasmRuntime": "envoy.wasm.runtime.null", }, XDS: int(ports.XDSPort), } @@ -173,12 +176,15 @@ func TestStatsParallel(t *testing.T) { ports := env.NewPorts(env.StatsParallel) params := &driver.Params{ Vars: map[string]string{ - "ClientPort": fmt.Sprintf("%d", ports.AppToClientProxyPort), - "BackendPort": fmt.Sprintf("%d", ports.BackendPort), - "ClientAdmin": fmt.Sprintf("%d", ports.ClientAdminPort), - "ServerAdmin": fmt.Sprintf("%d", ports.ServerAdminPort), - "ServerPort": fmt.Sprintf("%d", ports.ClientToServerProxyPort), - "RequestCount": "1", + "ClientPort": fmt.Sprintf("%d", ports.AppToClientProxyPort), + "BackendPort": fmt.Sprintf("%d", ports.BackendPort), + "ClientAdmin": fmt.Sprintf("%d", ports.ClientAdminPort), + "ServerAdmin": fmt.Sprintf("%d", ports.ServerAdminPort), + "ServerPort": fmt.Sprintf("%d", ports.ClientToServerProxyPort), + "RequestCount": "1", + "MetadataExchangeFilterCode": "inline_string: \"envoy.wasm.metadata_exchange\"", + "StatsFilterCode": "inline_string: \"envoy.wasm.stats\"", + "WasmRuntime": "envoy.wasm.runtime.null", }, XDS: int(ports.XDSPort), } @@ -233,3 +239,44 @@ func TestStatsParallel(t *testing.T) { t.Fatal(err) } } + +func TestStatsWasm(t *testing.T) { + ports := env.NewPorts(env.StatsWasm) + params := &driver.Params{ + Vars: map[string]string{ + "ClientPort": fmt.Sprintf("%d", ports.AppToClientProxyPort), + "BackendPort": fmt.Sprintf("%d", ports.BackendPort), + "ClientAdmin": fmt.Sprintf("%d", ports.ClientAdminPort), + "ServerAdmin": fmt.Sprintf("%d", ports.ServerAdminPort), + "ServerPort": fmt.Sprintf("%d", ports.ClientToServerProxyPort), + "RequestCount": "10", + "MetadataExchangeFilterCode": "filename: extensions/metadata_exchange/plugin.wasm", + "StatsFilterCode": "filename: extensions/stats/plugin.wasm", + "WasmRuntime": "envoy.wasm.runtime.v8", + }, + XDS: int(ports.XDSPort), + } + params.Vars["ClientMetadata"] = params.LoadTestData("testdata/client_node_metadata.json.tmpl") + params.Vars["ServerMetadata"] = params.LoadTestData("testdata/server_node_metadata.json.tmpl") + params.Vars["StatsConfig"] = params.LoadTestData("testdata/bootstrap/stats.yaml.tmpl") + + if err := (&driver.Scenario{ + []driver.Step{ + &driver.XDS{}, + &driver.Update{Node: "client", Version: "0", Listeners: []string{StatsClientHTTPListener}}, + &driver.Update{Node: "server", Version: "0", Listeners: []string{StatsServerHTTPListener}}, + &driver.Envoy{Bootstrap: params.LoadTestData("testdata/bootstrap/server.yaml.tmpl")}, + &driver.Envoy{Bootstrap: params.LoadTestData("testdata/bootstrap/client.yaml.tmpl")}, + &driver.Sleep{1 * time.Second}, + &driver.Repeat{N: 10, Step: &driver.Get{ports.AppToClientProxyPort, "hello, world!"}}, + &driver.Stats{ports.ClientAdminPort, map[string]driver.StatMatcher{ + "istio_requests_total": &driver.ExactStat{"testdata/metric/client_request_total.yaml.tmpl"}, + }}, + &driver.Stats{ports.ServerAdminPort, map[string]driver.StatMatcher{ + "istio_requests_total": &driver.ExactStat{"testdata/metric/server_request_total.yaml.tmpl"}, + }}, + }, + }).Run(params); err != nil { + t.Fatal(err) + } +}