diff --git a/CODEOWNERS b/CODEOWNERS index bfba7f9e..e6885e9e 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -31,10 +31,11 @@ /tools/apigee-x-trial-provision @yuriylesyuk @danistrebel /tools/decrypt-hybrid-assets @yuriylesyuk /tools/endpoints-oas-importer @danistrebel +/tools/grpc-http-gateway-generator @danistrebel @omidtahouri /tools/hybrid-quickstart @danistrebel /tools/oas-apigee-mock @markjkelly /tools/pipeline-linter @seymen @danistrebel /tools/pipeline-runner @seymen @danistrebel -/tools/sf-dependency-list @yuriylesyuk /tools/proxy-endpoint-unifier @anaik91 -/tools/target-server-validator @anaik91 +/tools/sf-dependency-list @yuriylesyuk +/tools/target-server-validator @anaik91 \ No newline at end of file diff --git a/README.md b/README.md index 92920071..51f17bb4 100644 --- a/README.md +++ b/README.md @@ -92,7 +92,8 @@ Apigee products. A tool to unify/split proxy endpoints based on API basepath. - [Apigee Target Server Validator](tools/target-server-validator) - A tool to validate all targets in Target Servers & Apigee API Proxy Bundles. - +- [gRPC to HTTP Gateway Generator](tools/grpc-http-gateway-generator) - + Generate gateways to expose gRPC services with HTTP API management. ## Labs This folder contains raw assets used to generate content to teach a particular diff --git a/tools/grpc-http-gateway-generator/README.md b/tools/grpc-http-gateway-generator/README.md new file mode 100644 index 00000000..6493d81e --- /dev/null +++ b/tools/grpc-http-gateway-generator/README.md @@ -0,0 +1,76 @@ +# gRPC to HTTP Gateway Generator + +The purpose of this tool is to generate a gRPC to HTTP gateway based on a protocol buffer. +It leverages the [gRPC Gateway](https://github.com/grpc-ecosystem/grpc-gateway) project to generate the gateway code. + +The generated gRPC gateway can then be used to create HTTP adapters for gRPC services and use them in a classical HTTP REST-based API management environment. + +![Architecture Overview](./img/architecture.png) + +## Prerequisites + +The generator assumed you have the protobuf compiler `protoc` installed. + +Note that `protoc` is pre-installed on Cloud Shell. + +To install `protoc` with `apt`, run the following command: + +```sh +apt install -y protobuf-compiler +``` + +## Generate the Gateway Code + +The gateway is generated based on a protocol buffer file that you supply with the `--proto-path` flag: + +```sh +./generate-gateway.sh --proto-path ./examples/currency.proto +``` + +Optionally you can also specify the desired output directory with the `--output` flag. If no output directory is specified the output will be generated in the `./generated/gateway` folder. + +## Run the Gateway + +You can run the gateway locally with the following commands and point to a gRPC server endpoint that runs on localhost port 9090: + +```sh +(cd generated/gateway && go run main.go --grpc-server-endpoint localhost:9090) +``` + +If you preffer to run the gateway as a container use the following commands to build and run the gateway container: + +```sh +(cd generated/gateway && docker build . -t gateway:latest) +docker run -p 8080:8080 -e GRPC_SERVER_ENDPOINT=localhost:9090 gateway:latest +``` + +## Try it out locally + +With the gateway running you can call the automatically generated API endpoints of the gateway to consume your gRPC service. + +With the gRPC Gateway pointing to an exposed currency service of the [microservice demo](https://github.com/GoogleCloudPlatform/microservices-demo) the currency conversion request would look like this: + +```sh +curl -X POST localhost:8080/hipstershop.CurrencyService/Convert -d '{"from": {"units": 3, "currency_code": "USD", "nanos": 0}, "to_code": "CHF"}' +``` + +Whist the code to request supported currencies looks like this: + +```sh +curl -X POST localhost:8080/hipstershop.CurrencyService/GetSupportedCurrencies +``` + +Note that the automatically generated API doesn't yet come in a RESTful format. This is one of the aspects that can be changed in an API management layer to improve the overall usability and security of the API. + +### Deploy to Cloud Run + +Once we've tested the gateway locally we can deploy it to Cloud Run for production use. + +```sh +(cd generated/gateway && gcloud run deploy currency-grpc-gw --source . --allow-unauthenticated --region europe-west1 --project $PROJECT_ID) +``` + +## Expose the Cloud Run Service via Apigee + +With the Gateway running in Cloud Run we can now expose it via Apigee. +For detailed instructions on how to expose a cloud run service in Apigee please see [this reference implementation](https://github.com/apigee/devrel/tree/main/references/cloud-run). \ No newline at end of file diff --git a/tools/grpc-http-gateway-generator/buf.gen.yaml b/tools/grpc-http-gateway-generator/buf.gen.yaml new file mode 100644 index 00000000..a3133c24 --- /dev/null +++ b/tools/grpc-http-gateway-generator/buf.gen.yaml @@ -0,0 +1,24 @@ +# Copyright 2024 Google LLC +# +# 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. + +version: v1 +plugins: + - plugin: go + out: gen/go + opt: + - paths=source_relative + - plugin: go-grpc + out: gen/go + opt: + - paths=source_relative \ No newline at end of file diff --git a/tools/grpc-http-gateway-generator/examples/currency-v1/apiproxy/currency-v1.xml b/tools/grpc-http-gateway-generator/examples/currency-v1/apiproxy/currency-v1.xml new file mode 100644 index 00000000..f0acd847 --- /dev/null +++ b/tools/grpc-http-gateway-generator/examples/currency-v1/apiproxy/currency-v1.xml @@ -0,0 +1,18 @@ + + + + \ No newline at end of file diff --git a/tools/grpc-http-gateway-generator/examples/currency-v1/apiproxy/policies/AM.SetConversionPath.xml b/tools/grpc-http-gateway-generator/examples/currency-v1/apiproxy/policies/AM.SetConversionPath.xml new file mode 100644 index 00000000..5d745abd --- /dev/null +++ b/tools/grpc-http-gateway-generator/examples/currency-v1/apiproxy/policies/AM.SetConversionPath.xml @@ -0,0 +1,21 @@ + + + + flow.target.pathsuffix + /hipstershop.CurrencyService/Convert + + \ No newline at end of file diff --git a/tools/grpc-http-gateway-generator/examples/currency-v1/apiproxy/policies/AM.SetCurrenciesPath.xml b/tools/grpc-http-gateway-generator/examples/currency-v1/apiproxy/policies/AM.SetCurrenciesPath.xml new file mode 100644 index 00000000..43cf6ef4 --- /dev/null +++ b/tools/grpc-http-gateway-generator/examples/currency-v1/apiproxy/policies/AM.SetCurrenciesPath.xml @@ -0,0 +1,21 @@ + + + + flow.target.pathsuffix + /hipstershop.CurrencyService/GetSupportedCurrencies + + \ No newline at end of file diff --git a/tools/grpc-http-gateway-generator/examples/currency-v1/apiproxy/policies/HM.SetTargetMethod.xml b/tools/grpc-http-gateway-generator/examples/currency-v1/apiproxy/policies/HM.SetTargetMethod.xml new file mode 100644 index 00000000..ff59942a --- /dev/null +++ b/tools/grpc-http-gateway-generator/examples/currency-v1/apiproxy/policies/HM.SetTargetMethod.xml @@ -0,0 +1,20 @@ + + + + POST + + \ No newline at end of file diff --git a/tools/grpc-http-gateway-generator/examples/currency-v1/apiproxy/policies/JS.SetTargetPath.xml b/tools/grpc-http-gateway-generator/examples/currency-v1/apiproxy/policies/JS.SetTargetPath.xml new file mode 100644 index 00000000..b7fd841d --- /dev/null +++ b/tools/grpc-http-gateway-generator/examples/currency-v1/apiproxy/policies/JS.SetTargetPath.xml @@ -0,0 +1,18 @@ + + + jsc://set-target-path.js + \ No newline at end of file diff --git a/tools/grpc-http-gateway-generator/examples/currency-v1/apiproxy/proxies/default.xml b/tools/grpc-http-gateway-generator/examples/currency-v1/apiproxy/proxies/default.xml new file mode 100644 index 00000000..5195c438 --- /dev/null +++ b/tools/grpc-http-gateway-generator/examples/currency-v1/apiproxy/proxies/default.xml @@ -0,0 +1,48 @@ + + + + + request.verb = "GET" and proxy.pathsuffix = "/currencies" + + + AM.SetCurrenciesPath + + + + + request.verb = "POST" and proxy.pathsuffix = "/convert" + + + AM.SetConversionPath + + + + + + + + HM.SetTargetMethod + + + + + /currency/v1 + + + default + + \ No newline at end of file diff --git a/tools/grpc-http-gateway-generator/examples/currency-v1/apiproxy/resources/jsc/set-target-path.js b/tools/grpc-http-gateway-generator/examples/currency-v1/apiproxy/resources/jsc/set-target-path.js new file mode 100644 index 00000000..1e426c44 --- /dev/null +++ b/tools/grpc-http-gateway-generator/examples/currency-v1/apiproxy/resources/jsc/set-target-path.js @@ -0,0 +1,29 @@ +/* + Copyright 2024 Google LLC + + 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. +*/ + +context.setVariable("target.copy.pathsuffix", false) + +var existingTargetUrl = context.getVariable("target.url"); +var targetPath = context.getVariable("flow.target.pathsuffix") || ""; // retrieve custom path, set by AM policies +var queryString = context.getVariable("request.querystring") || ""; + +var updatedTargetUrl = existingTargetUrl + targetPath + (queryString ? "?"+queryString : ""); + +context.setVariable("target.url", + existingTargetUrl + // use target base URL + targetPath + // append custom path + (queryString ? "?"+queryString : "") // conditionally append query params +); diff --git a/tools/grpc-http-gateway-generator/examples/currency-v1/apiproxy/targets/default.xml b/tools/grpc-http-gateway-generator/examples/currency-v1/apiproxy/targets/default.xml new file mode 100644 index 00000000..064848df --- /dev/null +++ b/tools/grpc-http-gateway-generator/examples/currency-v1/apiproxy/targets/default.xml @@ -0,0 +1,32 @@ + + + + + + JS.SetTargetPath + + + + + + + CLOUD_RUN_URL + + + CLOUD_RUN_URL + + \ No newline at end of file diff --git a/tools/grpc-http-gateway-generator/examples/currency-v1/cloud-run-service.yaml b/tools/grpc-http-gateway-generator/examples/currency-v1/cloud-run-service.yaml new file mode 100644 index 00000000..6d9ff4f9 --- /dev/null +++ b/tools/grpc-http-gateway-generator/examples/currency-v1/cloud-run-service.yaml @@ -0,0 +1,53 @@ +# Copyright 2024 Google LLC + +# 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. + +apiVersion: serving.knative.dev/v1 +kind: Service +metadata: + name: currency-service +spec: + template: + spec: + containers: + - name: grpc-gateway + image: GRPC_GATEWAY_IMAGE + ports: + - name: http1 + containerPort: 8080 + resources: + limits: + cpu: 1000m + memory: 512Mi + startupProbe: + timeoutSeconds: 240 + periodSeconds: 240 + failureThreshold: 1 + tcpSocket: + port: 8080 + - name: currencyservice-1 + image: gcr.io/google-samples/microservices-demo/currencyservice@sha256:e08a1f5d4e4b74fc3d6222d535a11615e8201e7075a090c1ba4436ef1f1cbe7b + env: + - name: PORT + value: "9090" + resources: + limits: + cpu: 1000m + memory: 512Mi + startupProbe: + timeoutSeconds: 1 + periodSeconds: 10 + failureThreshold: 3 + grpc: + port: 9090 + service: currencyservice-v1 diff --git a/tools/grpc-http-gateway-generator/examples/currency.proto b/tools/grpc-http-gateway-generator/examples/currency.proto new file mode 100644 index 00000000..d6b2f3ee --- /dev/null +++ b/tools/grpc-http-gateway-generator/examples/currency.proto @@ -0,0 +1,57 @@ +// Copyright 2020 Google LLC +// +// 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. + +syntax = "proto3"; + +package hipstershop; + +// -----------------Currency service----------------- + +service CurrencyService { + rpc GetSupportedCurrencies(Empty) returns (GetSupportedCurrenciesResponse) {} + rpc Convert(CurrencyConversionRequest) returns (Money) {} +} + +message Empty { +} + +// Represents an amount of money with its currency type. +message Money { + // The 3-letter currency code defined in ISO 4217. + string currency_code = 1; + + // The whole units of the amount. + // For example if `currencyCode` is `"USD"`, then 1 unit is one US dollar. + int64 units = 2; + + // Number of nano (10^-9) units of the amount. + // The value must be between -999,999,999 and +999,999,999 inclusive. + // If `units` is positive, `nanos` must be positive or zero. + // If `units` is zero, `nanos` can be positive, zero, or negative. + // If `units` is negative, `nanos` must be negative or zero. + // For example $-1.75 is represented as `units`=-1 and `nanos`=-750,000,000. + int32 nanos = 3; +} + +message GetSupportedCurrenciesResponse { + // The 3-letter currency code defined in ISO 4217. + repeated string currency_codes = 1; +} + +message CurrencyConversionRequest { + Money from = 1; + + // The 3-letter currency code defined in ISO 4217. + string to_code = 2; +} \ No newline at end of file diff --git a/tools/grpc-http-gateway-generator/generate-gateway.sh b/tools/grpc-http-gateway-generator/generate-gateway.sh new file mode 100755 index 00000000..b3feb84c --- /dev/null +++ b/tools/grpc-http-gateway-generator/generate-gateway.sh @@ -0,0 +1,106 @@ +#!/bin/bash +# Copyright 2024 Google LLC +# +# 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 -e + +# check if protoc is installed +if ! command -v protoc &> /dev/null; then + echo "[ERROR] protoc is not installed. Please install protoc before running this script." + exit 1 +fi + +proto_path="" +out="" + +while [[ $# -gt 0 ]]; do + case $1 in + --proto-path) + proto_path="$2" + shift 2 + ;; + --out) + out="$2" + shift 2 + ;; + --*|-*) + echo "Unknown option $1" + exit 1 + ;; + esac +done + +# check if proto path is provided +if [ -z "$proto_path" ]; then + echo "[ERROR] Proto path is required supply via variable --proto-path" + exit 1 +fi + +# check if proto path is a file +if [ ! -f "$proto_path" ]; then + echo "[ERROR] Proto path is not a file" + exit 1 +fi + +# check if output directory is provided +if [ -z "$out" ]; then + echo "[WARN] Output directory is not provided via variable --out. Using the default value ./generated/gateway" + out="$(pwd)/generated/gateway" +else + mkdir -p "$out" + out="$(cd "$out"; pwd -P)" +fi + +script_dir="$( cd -- "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" + +temp_dir=$(mktemp -d) +proto_file_name=$(basename "$proto_path") +cp "$proto_path" "$temp_dir/$proto_file_name" + + +# install tooling dependencies +pushd "$script_dir/tools" &> /dev/null +go mod tidy +go install \ + github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-grpc-gateway \ + github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2 \ + google.golang.org/protobuf/cmd/protoc-gen-go \ + google.golang.org/grpc/cmd/protoc-gen-go-grpc +PATH="$PATH:$(go env GOPATH)/bin" +export PATH +popd &> /dev/null + +# Generate the gRPC adapter +mkdir -p "$out/adapter" + +pushd "$temp_dir" &> /dev/null +protoc -I . \ + --go_out "$out/adapter" \ + --go_opt "M$proto_file_name=.;adapter" \ + --go-grpc_out "$out/adapter" \ + --go-grpc_opt "M$proto_file_name=.;adapter" \ + "./$proto_file_name" + +protoc -I . --grpc-gateway_out "$out/adapter" \ + --grpc-gateway_opt "M$proto_file_name=.;adapter" \ + --grpc-gateway_opt generate_unbound_methods=true \ + "./$proto_file_name" +popd &> /dev/null + +cp "$script_dir/templates/main.go" "$out/main.go" +cp "$script_dir/templates/Dockerfile" "$out/Dockerfile" + +(cd "$out/adapter" && go mod init adapter &> /dev/null && go mod tidy &> /dev/null) +(cd "$out" && go mod init gateway &> /dev/null && go mod edit -replace adapter=./adapter && go mod tidy &> /dev/null) diff --git a/tools/grpc-http-gateway-generator/img/architecture.png b/tools/grpc-http-gateway-generator/img/architecture.png new file mode 100644 index 00000000..26c63b92 Binary files /dev/null and b/tools/grpc-http-gateway-generator/img/architecture.png differ diff --git a/tools/grpc-http-gateway-generator/pipeline.sh b/tools/grpc-http-gateway-generator/pipeline.sh new file mode 100755 index 00000000..3e4c7a44 --- /dev/null +++ b/tools/grpc-http-gateway-generator/pipeline.sh @@ -0,0 +1,90 @@ +#!/bin/bash + +# Copyright 2024 Google LLC +# +# 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 -e # exit on first error + +SCRIPTPATH="$( cd "$(dirname "$0")" || exit >/dev/null 2>&1 ; pwd -P )" +export PATH="$PATH:$SCRIPTPATH/../../tools/apigee-sackmesser/bin" + +PROJECT_ID=$(gcloud config get-value project) +GCP_REGION=europe-west2 + +# Generate the gRCP Gateway based on the proto file +rm -rdf generated || true +./generate-gateway.sh --proto-path ./examples/currency.proto + +# Build the gRPC Gateway +(cd generated/gateway && CGO_ENABLED=0 go build -o grpcgateway .) + +# Build the grpc-gateway container and push it to Artifact Registry +(cd generated/gateway && docker build -t grpc-gateway:latest .) + +DOCKER_REPO="devrel" +REPO_LOCATION="europe" + +if [ -z "$(gcloud artifacts repositories describe $DOCKER_REPO \ + --location=$REPO_LOCATION \ + --project "$PROJECT_ID" \ + --format='get(name)')" ]; then \ + + gcloud artifacts repositories create $DOCKER_REPO \ + --repository-format=docker \ + --location=$REPO_LOCATION \ + --project="$PROJECT_ID" +fi + +IMAGE_PATH="$REPO_LOCATION-docker.pkg.dev/$PROJECT_ID/$DOCKER_REPO/grpc-gateway" +docker tag grpc-gateway:latest "$IMAGE_PATH:latest" +docker push "$IMAGE_PATH" + +# Deploy grpc-gateway container to Cloud Run +sed -i.bak "s|GRPC_GATEWAY_IMAGE|$IMAGE_PATH|g" "examples/currency-v1/cloud-run-service.yaml" + +gcloud run services replace examples/currency-v1/cloud-run-service.yaml \ + --project "$PROJECT_ID" --region $GCP_REGION \ + --platform managed + +# Generate and deploy an Apigee API proxy for the currency-service +SA_EMAIL="apigee-test-cloudrun@$APIGEE_X_ORG.iam.gserviceaccount.com" + +if [ -z "$(gcloud iam service-accounts list --filter "$SA_EMAIL" --format="value(email)" --project "$APIGEE_X_ORG")" ]; then + gcloud iam service-accounts create apigee-test-cloudrun \ + --description="Apigee Test Cloud Run" --project "$APIGEE_X_ORG" +fi + +gcloud run services add-iam-policy-binding currency-service \ + --member="serviceAccount:$SA_EMAIL" \ + --role='roles/run.invoker' \ + --region=$GCP_REGION \ + --platform=managed --project "$PROJECT_ID" + +CLOUD_RUN_URL=$(gcloud run services list --filter currency-service --format="value(status.url)" --limit 1) +sed -i "s|CLOUD_RUN_URL|$CLOUD_RUN_URL|g" "examples/currency-v1/apiproxy/targets/default.xml" + +TOKEN="$(gcloud config config-helper --force-auth-refresh --format json | jq -r '.credential.access_token')" +sackmesser deploy -d "$SCRIPTPATH/examples/currency-v1" -o "$APIGEE_X_ORG" -e "$APIGEE_X_ENV" -t "$TOKEN" --deployment-sa "$SA_EMAIL" + +# Test the Apigee API +curl -X GET "https://$APIGEE_X_HOSTNAME/currency/v1/currencies" + +curl -X POST "https://$APIGEE_X_HOSTNAME/currency/v1/convert" \ + -d '{"from": {"units": 3, "currency_code": "USD", "nanos": 0}, "to_code": "CHF"}' + +# Clean up + # undeploy and delete proxy + # delete CR service + # delete SA + # delete AR registry diff --git a/tools/grpc-http-gateway-generator/templates/Dockerfile b/tools/grpc-http-gateway-generator/templates/Dockerfile new file mode 100644 index 00000000..959ba5af --- /dev/null +++ b/tools/grpc-http-gateway-generator/templates/Dockerfile @@ -0,0 +1,25 @@ +# Copyright 2024 Google LLC +# +# 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 golang:alpine as app-builder + +WORKDIR /go/src/app +COPY . . + +RUN CGO_ENABLED=0 go build -o grpcgateway . + +FROM scratch +COPY --from=app-builder /go/src/app/grpcgateway /gateway + +ENTRYPOINT ["/gateway"] \ No newline at end of file diff --git a/tools/grpc-http-gateway-generator/templates/main.go b/tools/grpc-http-gateway-generator/templates/main.go new file mode 100644 index 00000000..937d90ed --- /dev/null +++ b/tools/grpc-http-gateway-generator/templates/main.go @@ -0,0 +1,76 @@ +// Copyright 2024 Google LLC +// +// 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. + +package main + +import ( + "context" + "flag" + "net/http" + "os" + + "github.com/grpc-ecosystem/grpc-gateway/v2/runtime" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials/insecure" + "google.golang.org/grpc/grpclog" + + gw "adapter" // needs to be replaced +) + +var ( + // command-line options: + // gRPC server endpoint + grpcServerEndpointFlag = flag.String("grpc-server-endpoint", "", "gRPC server endpoint") +) + +func run() error { + ctx := context.Background() + ctx, cancel := context.WithCancel(ctx) + defer cancel() + + // Register gRPC server endpoint + mux := runtime.NewServeMux() + opts := []grpc.DialOption{grpc.WithTransportCredentials(insecure.NewCredentials())} + + grpcServerEndpoint := *grpcServerEndpointFlag + if grpcServerEndpoint == "" { + grpcServerEndpoint = os.Getenv("GRPC_SERVER_ENDPOINT") + } + if grpcServerEndpoint == "" { + grpcServerEndpoint = "localhost:9090" + } + + grpclog.Infof("Upstream gRPC server endpoint = %s", grpcServerEndpoint) + + err := gw.RegisterCurrencyServiceHandlerFromEndpoint(ctx, mux, grpcServerEndpoint, opts) + if err != nil { + return err + } + + // Start HTTP server (and proxy calls to gRPC server endpoint) + port := os.Getenv("PORT") + if port == "" { + port = "8080" + } + grpclog.Infof("Serving gRPC-Gateway on http://0.0.0.0:%s", port) + return http.ListenAndServe( ":" + port, mux) +} + +func main() { + flag.Parse() + + if err := run(); err != nil { + grpclog.Fatal(err) + } +} \ No newline at end of file diff --git a/tools/grpc-http-gateway-generator/tools/go.mod b/tools/grpc-http-gateway-generator/tools/go.mod new file mode 100644 index 00000000..f296bf1d --- /dev/null +++ b/tools/grpc-http-gateway-generator/tools/go.mod @@ -0,0 +1,19 @@ +module tools + +go 1.22.4 + +require ( + github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 + google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.4.0 + google.golang.org/protobuf v1.34.2 +) + +require ( + github.com/kr/text v0.2.0 // indirect + github.com/rogpeppe/go-internal v1.12.0 // indirect + golang.org/x/text v0.15.0 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20240513163218-0867130af1f8 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240513163218-0867130af1f8 // indirect + google.golang.org/grpc v1.64.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/tools/grpc-http-gateway-generator/tools/go.sum b/tools/grpc-http-gateway-generator/tools/go.sum new file mode 100644 index 00000000..07939fa2 --- /dev/null +++ b/tools/grpc-http-gateway-generator/tools/go.sum @@ -0,0 +1,32 @@ +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 h1:bkypFPDjIYGfCYD5mRBvpqxfYX1YCS1PXdKYWi8FsN0= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0/go.mod h1:P+Lt/0by1T8bfcF3z737NnSbmxQAppXMRziHUxPOC8k= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= +github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= +golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs= +golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= +golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= +golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk= +golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +google.golang.org/genproto/googleapis/api v0.0.0-20240513163218-0867130af1f8 h1:W5Xj/70xIA4x60O/IFyXivR5MGqblAb8R3w26pnD6No= +google.golang.org/genproto/googleapis/api v0.0.0-20240513163218-0867130af1f8/go.mod h1:vPrPUTsDCYxXWjP7clS81mZ6/803D8K4iM9Ma27VKas= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240513163218-0867130af1f8 h1:mxSlqyb8ZAHsYDCfiXN1EDdNTdvjUJSLY+OnAUtYNYA= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240513163218-0867130af1f8/go.mod h1:I7Y+G38R2bu5j1aLzfFmQfTcU/WnFuqDwLZAbvKTKpM= +google.golang.org/grpc v1.64.0 h1:KH3VH9y/MgNQg1dE7b3XfVK0GsPSIzJwdF617gUSbvY= +google.golang.org/grpc v1.64.0/go.mod h1:oxjF8E3FBnjp+/gVFYdWacaLDx9na1aqy9oovLpxQYg= +google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.4.0 h1:9SxA29VM43MF5Z9dQu694wmY5t8E/Gxr7s+RSxiIDmc= +google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.4.0/go.mod h1:yZOK5zhQMiALmuweVdIVoQPa6eIJyXn2B9g5dJDhqX4= +google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= +google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/tools/grpc-http-gateway-generator/tools/tools.go b/tools/grpc-http-gateway-generator/tools/tools.go new file mode 100644 index 00000000..f5f270a6 --- /dev/null +++ b/tools/grpc-http-gateway-generator/tools/tools.go @@ -0,0 +1,24 @@ +// Copyright 2024 Google LLC +// +// 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. + +// +build tools + +package tools + +import ( + _ "github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-grpc-gateway" + _ "github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2" + _ "google.golang.org/grpc/cmd/protoc-gen-go-grpc" + _ "google.golang.org/protobuf/cmd/protoc-gen-go" +) \ No newline at end of file diff --git a/tools/pipeline-runner/Dockerfile b/tools/pipeline-runner/Dockerfile index d4044cf0..27c1ed8d 100644 --- a/tools/pipeline-runner/Dockerfile +++ b/tools/pipeline-runner/Dockerfile @@ -35,7 +35,10 @@ RUN apk add --no-cache \ ca-certificates \ ttf-freefont \ py-pip \ - zip + zip \ + make \ + go \ + protobuf-dev # Reduce nighly log (note: -ntp requires maven 3.6.1+) RUN mv /usr/bin/mvn /usr/bin/_mvn &&\