diff --git a/BUILD.bazel b/BUILD.bazel index 750dcaad..45300fde 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -6,6 +6,7 @@ load("@gazelle//:def.bzl", "gazelle") # gazelle:resolve go github.com/uber/submitqueue/gateway/protopb //gateway/protopb # gazelle:resolve go github.com/uber/submitqueue/orchestrator/protopb //orchestrator/protopb # gazelle:resolve go github.com/uber/submitqueue/stovepipe/gateway/protopb //stovepipe/gateway/protopb +# gazelle:resolve go github.com/uber/submitqueue/stovepipe/orchestrator/protopb //stovepipe/orchestrator/protopb # Export marker files for test data dependencies (used by FindRepoRoot in tests) exports_files( diff --git a/Makefile b/Makefile index 573fb595..6a43de36 100644 --- a/Makefile +++ b/Makefile @@ -14,6 +14,8 @@ SUBMITQUEUE_LOCAL_PROJECT = submitqueue # Stovepipe compose files STOVEPIPE_GATEWAY_COMPOSE_FILE = example/stovepipe/gateway/server/docker-compose.yml +STOVEPIPE_ORCHESTRATOR_COMPOSE_FILE = example/stovepipe/orchestrator/server/docker-compose.yml +STOVEPIPE_STACK_COMPOSE_FILE = example/stovepipe/docker-compose.yml # Fixed project name for local manual testing (tests use unique random names) STOVEPIPE_LOCAL_PROJECT = stovepipe @@ -38,7 +40,7 @@ define assert_clean fi endef -.PHONY: build build-all-linux build-gateway-linux build-orchestrator-linux build-stovepipe-gateway-linux check-gazelle check-mocks check-tidy clean clean-proto deps e2e-test fmt gazelle integration-test integration-test-consumer integration-test-extensions integration-test-gateway integration-test-orchestrator license-fix lint lint-fmt lint-license local-clean local-gateway-start local-gateway-stop local-init-schemas local-init-stovepipe-queue-schema local-logs local-orchestrator-start local-orchestrator-stop local-ps local-restart local-start local-stop local-stovepipe-gateway-start mocks proto query-deps query-targets run-client-gateway run-client-orchestrator run-client-stovepipe-gateway run-queue-admin test test-no-cache tidy tidy-bazel tidy-go help +.PHONY: build build-all-linux build-gateway-linux build-orchestrator-linux build-stovepipe-gateway-linux build-stovepipe-orchestrator-linux check-gazelle check-mocks check-tidy clean clean-proto deps e2e-test fmt gazelle integration-test integration-test-consumer integration-test-extensions integration-test-gateway integration-test-orchestrator license-fix lint lint-fmt lint-license local-clean local-gateway-start local-gateway-stop local-init-schemas local-init-stovepipe-queue-schema local-logs local-orchestrator-start local-orchestrator-stop local-ps local-restart local-start local-stop local-stovepipe-gateway-start local-stovepipe-orchestrator-start local-stovepipe-start mocks proto query-deps query-targets run-client-gateway run-client-orchestrator run-client-stovepipe-gateway run-client-stovepipe-orchestrator run-queue-admin test test-no-cache tidy tidy-bazel tidy-go help build: ## Build all services and examples @@ -47,7 +49,7 @@ build: ## Build all services and examples @echo "Build complete!" # Build Linux binaries required for Docker containers -build-all-linux: build-gateway-linux build-orchestrator-linux build-stovepipe-gateway-linux ## Build all Linux binaries for Docker +build-all-linux: build-gateway-linux build-orchestrator-linux build-stovepipe-gateway-linux build-stovepipe-orchestrator-linux ## Build all Linux binaries for Docker @echo "All Linux binaries ready for Docker" build-gateway-linux: ## Build Gateway Linux binary for Docker @@ -74,6 +76,14 @@ build-stovepipe-gateway-linux: ## Build Stovepipe gateway Linux binary for Docke cp -f bazel-bin/example/stovepipe/gateway/server/gateway .docker-bin/stovepipe-gateway @echo "Stovepipe gateway Linux binary ready at .docker-bin/stovepipe-gateway" +build-stovepipe-orchestrator-linux: ## Build Stovepipe orchestrator Linux binary for Docker + @echo "Building Stovepipe orchestrator Linux binary for Docker..." + @$(BAZEL) build --platforms=@rules_go//go/toolchain:linux_amd64 //example/stovepipe/orchestrator/server:orchestrator + @mkdir -p .docker-bin + @cp -f bazel-bin/example/stovepipe/orchestrator/server/orchestrator_/orchestrator .docker-bin/stovepipe-orchestrator 2>/dev/null || \ + cp -f bazel-bin/example/stovepipe/orchestrator/server/orchestrator .docker-bin/stovepipe-orchestrator + @echo "Stovepipe orchestrator Linux binary ready at .docker-bin/stovepipe-orchestrator" + check-gazelle: ## Check BUILD.bazel files are up to date @echo "Running Gazelle to check BUILD files..." @$(BAZEL) run //:gazelle @@ -99,6 +109,7 @@ clean-proto: ## Clean generated proto files @rm -rf gateway/protopb/*.pb.go @rm -rf orchestrator/protopb/*.pb.go @rm -rf stovepipe/gateway/protopb/*.pb.go + @rm -rf stovepipe/orchestrator/protopb/*.pb.go @echo "Proto clean complete!" deps: tidy-go ## Download and tidy Go dependencies @@ -266,9 +277,47 @@ local-start: build-all-linux ## Start full stack (Gateway + Orchestrator + MySQL local-stop: ## Stop all services (keep data) @echo "Stopping all services..." @$(COMPOSE) -f $(COMPOSE_FILE) -p $(SUBMITQUEUE_LOCAL_PROJECT) down - @$(COMPOSE) -f $(STOVEPIPE_GATEWAY_COMPOSE_FILE) -p $(STOVEPIPE_LOCAL_PROJECT) down + @$(COMPOSE) -f $(STOVEPIPE_STACK_COMPOSE_FILE) -p $(STOVEPIPE_LOCAL_PROJECT) down @echo "Services stopped. Data volumes preserved." +local-stovepipe-logs: ## View logs from all running Stovepipe services + @$(COMPOSE) -f $(STOVEPIPE_STACK_COMPOSE_FILE) -p $(STOVEPIPE_LOCAL_PROJECT) logs -f + +local-stovepipe-start: build-stovepipe-gateway-linux build-stovepipe-orchestrator-linux ## Start full Stovepipe stack (gateway + orchestrator + MySQL) + @echo "Starting full Stovepipe stack with compose..." + @$(COMPOSE) -f $(STOVEPIPE_STACK_COMPOSE_FILE) -p $(STOVEPIPE_LOCAL_PROJECT) up -d --build --wait + @echo "Applying queue schema to mysql-queue (no Stovepipe app schema yet)..." + @$(MAKE) -s local-init-stovepipe-queue-schema + @echo "" + @echo "✅ Full Stovepipe stack is running!" + @echo "" + @echo "Expected container NAMEs (project=$(STOVEPIPE_LOCAL_PROJECT), one replica each):" + @echo " $(STOVEPIPE_LOCAL_PROJECT)-mysql-app-1" + @echo " $(STOVEPIPE_LOCAL_PROJECT)-mysql-queue-1" + @echo " $(STOVEPIPE_LOCAL_PROJECT)-gateway-service-1" + @echo " $(STOVEPIPE_LOCAL_PROJECT)-orchestrator-service-1" + @echo "" + @$(COMPOSE) -f $(STOVEPIPE_STACK_COMPOSE_FILE) -p $(STOVEPIPE_LOCAL_PROJECT) ps + @echo "" + @echo "Stovepipe gateway gRPC port: $$(docker port $(STOVEPIPE_LOCAL_PROJECT)-gateway-service-1 8080 2>/dev/null | cut -d: -f2 || echo 'unknown')" + @echo "Stovepipe orchestrator gRPC port: $$(docker port $(STOVEPIPE_LOCAL_PROJECT)-orchestrator-service-1 8080 2>/dev/null | cut -d: -f2 || echo 'unknown')" + @echo "MySQL App port: $$(docker port $(STOVEPIPE_LOCAL_PROJECT)-mysql-app-1 3306 2>/dev/null | cut -d: -f2 || echo 'unknown')" + @echo "MySQL Queue port: $$(docker port $(STOVEPIPE_LOCAL_PROJECT)-mysql-queue-1 3306 2>/dev/null | cut -d: -f2 || echo 'unknown')" + +local-stovepipe-orchestrator-start: build-stovepipe-orchestrator-linux ## Start Stovepipe orchestrator locally (orchestrator + 2 MySQL databases) + @echo "Starting Stovepipe orchestrator with compose..." + @$(COMPOSE) -f $(STOVEPIPE_ORCHESTRATOR_COMPOSE_FILE) -p $(STOVEPIPE_LOCAL_PROJECT) up -d --build --wait + @echo "Applying queue schema to mysql-queue (no Stovepipe app schema yet)..." + @$(MAKE) -s local-init-stovepipe-queue-schema + @echo "" + @echo "✅ Stovepipe orchestrator is running!" + @echo "" + @$(COMPOSE) -f $(STOVEPIPE_ORCHESTRATOR_COMPOSE_FILE) -p $(STOVEPIPE_LOCAL_PROJECT) ps + @echo "" + @echo "Stovepipe orchestrator gRPC port: $$(docker port $(STOVEPIPE_LOCAL_PROJECT)-orchestrator-service-1 8080 2>/dev/null | cut -d: -f2 || echo 'unknown')" + @echo "MySQL App port: $$(docker port $(STOVEPIPE_LOCAL_PROJECT)-mysql-app-1 3306 2>/dev/null | cut -d: -f2 || echo 'unknown')" + @echo "MySQL Queue port: $$(docker port $(STOVEPIPE_LOCAL_PROJECT)-mysql-queue-1 3306 2>/dev/null | cut -d: -f2 || echo 'unknown')" + local-stovepipe-gateway-start: build-stovepipe-gateway-linux ## Start Stovepipe gateway locally (gateway + 2 MySQL databases) @echo "Starting Stovepipe gateway with compose..." @$(COMPOSE) -f $(STOVEPIPE_GATEWAY_COMPOSE_FILE) -p $(STOVEPIPE_LOCAL_PROJECT) up -d --build --wait @@ -279,7 +328,7 @@ local-stovepipe-gateway-start: build-stovepipe-gateway-linux ## Start Stovepipe @echo "" @$(COMPOSE) -f $(STOVEPIPE_GATEWAY_COMPOSE_FILE) -p $(STOVEPIPE_LOCAL_PROJECT) ps @echo "" - @echo "Stovepipe gateway gRPC port: $$(docker port $(STOVEPIPE_LOCAL_PROJECT)-stovepipe-service-1 8080 2>/dev/null | cut -d: -f2 || echo 'unknown')" + @echo "Stovepipe gateway gRPC port: $$(docker port $(STOVEPIPE_LOCAL_PROJECT)-gateway-service-1 8080 2>/dev/null | cut -d: -f2 || echo 'unknown')" @echo "MySQL App port: $$(docker port $(STOVEPIPE_LOCAL_PROJECT)-mysql-app-1 3306 2>/dev/null | cut -d: -f2 || echo 'unknown')" @echo "MySQL Queue port: $$(docker port $(STOVEPIPE_LOCAL_PROJECT)-mysql-queue-1 3306 2>/dev/null | cut -d: -f2 || echo 'unknown')" @@ -302,6 +351,10 @@ proto: ## Generate protobuf files from .proto definitions --go-grpc_out=stovepipe/gateway/protopb --go-grpc_opt=paths=source_relative \ --yarpc-go_out=stovepipe/gateway/protopb --yarpc-go_opt=paths=source_relative \ --proto_path=stovepipe/gateway/proto stovepipe/gateway/proto/gateway.proto + @protoc --go_out=stovepipe/orchestrator/protopb --go_opt=paths=source_relative \ + --go-grpc_out=stovepipe/orchestrator/protopb --go-grpc_opt=paths=source_relative \ + --yarpc-go_out=stovepipe/orchestrator/protopb --yarpc-go_opt=paths=source_relative \ + --proto_path=stovepipe/orchestrator/proto stovepipe/orchestrator/proto/orchestrator.proto @echo "Protobuf files generated successfully!" # Bazel query helpers @@ -323,6 +376,10 @@ run-client-orchestrator: run-client-stovepipe-gateway: @$(BAZEL) run //example/stovepipe/gateway/client:gateway -- -addr $(or $(SERVER_ADDR),localhost:8083) -message "$(or $(MESSAGE),ping)" +# Run stovepipe orchestrator client (connects to any running stovepipe orchestrator service) +run-client-stovepipe-orchestrator: + @$(BAZEL) run //example/stovepipe/orchestrator/client:orchestrator -- -addr $(or $(SERVER_ADDR),localhost:8084) -message "$(or $(MESSAGE),ping)" + run-queue-admin: ## Run queue-admin CLI (use ARGS to pass arguments, e.g. make run-queue-admin ARGS="list-topics") @$(BAZEL) run //extension/queue/mysql/ctl -- $(ARGS) diff --git a/example/README.md b/example/README.md index e553512e..b1507bc8 100644 --- a/example/README.md +++ b/example/README.md @@ -7,6 +7,7 @@ Example gRPC servers and clients for running the submitqueue services locally. - **SubmitQueue Gateway** (port 8081) — entry point for land requests. Exposes `Ping` and `Land` RPCs. - **SubmitQueue Orchestrator** (port 8082) — coordinates the pipeline. Exposes `Ping` RPC and consumes queue messages across 9 pipeline topics. - **Stovepipe Gateway** (port 8083) - entry point for commit deployment verification requests. Exposes `Ping` RPC. +- **Stovepipe Orchestrator** (port 8084) - coordinates the commit verification pipeline. Exposes `Ping` RPC. Services require MySQL (app database + queue database). Docker Compose handles this automatically. @@ -28,12 +29,19 @@ example/ │ ├── gateway/main.go # Gateway ping client │ └── orchestrator/main.go # Orchestrator ping client └── stovepipe/ - └── gateway/ + ├── docker-compose.yml # Full stack (Stovepipe Gateway + Orchestrator + 2x MySQL) + ├── gateway/ + │ ├── server/ + │ │ ├── main.go # Stovepipe gateway gRPC server (Docker: :8080; go run default :8083) + │ │ ├── Dockerfile + │ │ └── docker-compose.yml # Gateway-only stack + │ └── client/main.go # Stovepipe gateway ping client + └── orchestrator/ ├── server/ - │ ├── main.go # Stovepipe gateway gRPC server (Docker: :8080; go run default :8083) + │ ├── main.go # Stovepipe orchestrator gRPC server (Docker: :8080; go run default :8084) │ ├── Dockerfile - │ └── docker-compose.yml # Gateway-only stack - └── client/main.go # Stovepipe gateway ping client + │ └── docker-compose.yml # Orchestrator-only stack + └── client/main.go # Stovepipe orchestrator ping client ``` ## Running @@ -47,8 +55,10 @@ make local-start make local-gateway-start make local-orchestrator-start -# Start Stovepipe gateway (Gateway + 2x MySQL) +# Start full Stovepipe stack (Gateway + Orchestrator + MySQL) +make local-stovepipe-start make local-stovepipe-gateway-start +make local-stovepipe-orchestrator-start # View logs and status make local-logs @@ -58,7 +68,7 @@ make local-ps make local-stop ``` -For Docker, `make build-stovepipe-gateway-linux` copies a Linux binary to `.docker-bin/stovepipe-gateway` so it does not overwrite SubmitQueue’s `.docker-bin/gateway`. Stovepipe `make local-stovepipe-gateway-start` applies **only the queue schema** on `mysql-queue` (`make local-init-stovepipe-queue-schema`); SubmitQueue storage/counter schemas on `mysql-app` are skipped until Stovepipe has its own app schema. `make local-stop` stops the SubmitQueue stack and runs `docker compose down` on the Stovepipe gateway compose file for **`STOVEPIPE_LOCAL_PROJECT`** (default `stovepipe`). SubmitQueue examples use project **`submitqueue`** by default (`make SUBMITQUEUE_LOCAL_PROJECT=myname ...`). Stovepipe containers are named like `stovepipe-mysql-app-1`, not `submitqueue-*`. +For Docker, `make build-stovepipe-gateway-linux` copies a Linux binary to `.docker-bin/stovepipe-gateway` so it does not overwrite SubmitQueue’s `.docker-bin/gateway`. Stovepipe `make local-stovepipe-gateway-start` applies **only the queue schema** on `mysql-queue` (`make local-init-stovepipe-queue-schema`); SubmitQueue storage/counter schemas on `mysql-app` are skipped until Stovepipe has its own app schema. Compose service keys are **`gateway-service`** and **`orchestrator-service`** (same as `example/server`), so with default project **`stovepipe`** you should see **`stovepipe-gateway-service-1`** and **`stovepipe-orchestrator-service-1`** — not `stovepipe-stovepipe-*` (that pattern was from older service names; run **`make local-stop`** to run `docker compose down --remove-orphans` and drop orphans). `make local-stop` also stops the SubmitQueue stack. SubmitQueue examples use project **`submitqueue`** by default (`make SUBMITQUEUE_LOCAL_PROJECT=myname ...`). Stovepipe containers are named like `stovepipe-mysql-app-1`, not `submitqueue-*`. ### Bazel @@ -67,11 +77,13 @@ For Docker, `make build-stovepipe-gateway-linux` copies a Linux binary to `.dock bazel build //example/server/gateway:gateway bazel build //example/server/orchestrator:orchestrator bazel build //example/stovepipe/gateway/server:gateway +bazel build //example/stovepipe/orchestrator/server:orchestrator # Build clients bazel build //example/client/gateway:gateway bazel build //example/client/orchestrator:orchestrator bazel build //example/stovepipe/gateway/client:gateway +bazel build //example/stovepipe/orchestrator/client:orchestrator ``` ### Go @@ -80,6 +92,7 @@ bazel build //example/stovepipe/gateway/client:gateway go run example/server/gateway/main.go go run example/server/orchestrator/main.go go run example/stovepipe/gateway/server/main.go +go run example/stovepipe/orchestrator/server/main.go ``` ## Testing with Clients @@ -89,6 +102,7 @@ go run example/stovepipe/gateway/server/main.go go run example/client/gateway/main.go -addr localhost:8081 -message "hello" go run example/client/orchestrator/main.go -addr localhost:8082 -message "hello" go run example/stovepipe/gateway/client/main.go -addr localhost:8083 -message "hello" +go run example/stovepipe/orchestrator/client/main.go -addr localhost:8084 -message "hello" ``` Client flags: @@ -110,16 +124,19 @@ go install github.com/fullstorydev/grpcurl/cmd/grpcurl@latest grpcurl -plaintext -d '{"message": "hello"}' localhost:8081 uber.submitqueue.gateway.SubmitQueueGateway/Ping grpcurl -plaintext -d '{"message": "hello"}' localhost:8082 uber.submitqueue.orchestrator.SubmitQueueOrchestrator/Ping grpcurl -plaintext -d '{"message": "hello"}' localhost:8083 uber.submitqueue.stovepipe.StovepipeGateway/Ping +grpcurl -plaintext -d '{"message": "hello"}' localhost:8084 uber.submitqueue.stovepipe.orchestrator.StovepipeOrchestrator/Ping # List services grpcurl -plaintext localhost:8081 list grpcurl -plaintext localhost:8082 list grpcurl -plaintext localhost:8083 list +grpcurl -plaintext localhost:8084 list # Describe a service grpcurl -plaintext localhost:8081 describe uber.submitqueue.gateway.SubmitQueueGateway grpcurl -plaintext localhost:8082 describe uber.submitqueue.orchestrator.SubmitQueueOrchestrator grpcurl -plaintext localhost:8083 describe uber.submitqueue.stovepipe.StovepipeGateway +grpcurl -plaintext localhost:8084 describe uber.submitqueue.stovepipe.orchestrator.StovepipeOrchestrator ``` ## API Reference @@ -151,3 +168,12 @@ grpcurl -plaintext localhost:8083 describe uber.submitqueue.stovepipe.StovepipeG | Method | Description | |--------|-------------| | `Ping` | Health check | + +### Stovepipe Orchestrator + +**Service**: `uber.submitqueue.stovepipe.orchestrator.StovepipeOrchestrator` +**Proto**: `stovepipe/orchestrator/proto/orchestrator.proto` + +| Method | Description | +|--------|-------------| +| `Ping` | Health check | diff --git a/example/stovepipe/BUILD.bazel b/example/stovepipe/BUILD.bazel new file mode 100644 index 00000000..cb1f7a27 --- /dev/null +++ b/example/stovepipe/BUILD.bazel @@ -0,0 +1,4 @@ +exports_files( + ["docker-compose.yml"], + visibility = ["//visibility:public"], +) diff --git a/example/stovepipe/docker-compose.yml b/example/stovepipe/docker-compose.yml new file mode 100644 index 00000000..4952f914 --- /dev/null +++ b/example/stovepipe/docker-compose.yml @@ -0,0 +1,88 @@ +# Docker Compose for full Stovepipe stack (Gateway + Orchestrator + MySQL) +# +# Use with `make local-stovepipe-start`; use per-service compose files +# under example/stovepipe/gateway/server/ or example/stovepipe/orchestrator/server/ +# for single-service stacks. +# +# IMPORTANT: Before running compose, build the Linux binaries: +# make build-stovepipe-gateway-linux build-stovepipe-orchestrator-linux +# OR +# bazel build --platforms=@rules_go//go/toolchain:linux_amd64 \ +# //example/stovepipe/gateway/server:gateway \ +# //example/stovepipe/orchestrator/server:orchestrator +# +# Quick start: +# make local-stovepipe-start +# + +services: + # Application Database - Stores business data (requests, counters, etc.) + mysql-app: + image: mysql:8.0 + environment: + MYSQL_ROOT_PASSWORD: root + MYSQL_DATABASE: submitqueue + ports: + - "3306" # Random ephemeral port to avoid conflicts + healthcheck: + # Use 127.0.0.1 (TCP) instead of localhost (Unix socket). MySQL treats + # "localhost" as a socket connection, which can be ready before the TCP + # listener — causing dependent services that connect over TCP to fail. + test: ["CMD", "mysqladmin", "ping", "-h", "127.0.0.1", "-proot"] + interval: 5s + timeout: 5s + retries: 10 + + # Queue Database - Messaging infrastructure (messages, offsets, partition leases) + # Separate from app DB to demonstrate queue is pluggable infrastructure + mysql-queue: + image: mysql:8.0 + environment: + MYSQL_ROOT_PASSWORD: root + MYSQL_DATABASE: submitqueue + ports: + - "3306" # Random ephemeral port to avoid conflicts + healthcheck: + test: ["CMD", "mysqladmin", "ping", "-h", "127.0.0.1", "-proot"] + interval: 5s + timeout: 5s + retries: 10 + + gateway-service: + build: + context: ${REPO_ROOT} + dockerfile: example/stovepipe/gateway/server/Dockerfile + ports: + - "8080" # Random ephemeral port to avoid conflicts + environment: + - PORT=:8080 + # Application database connection + - MYSQL_DSN=root:root@tcp(mysql-app:3306)/submitqueue?parseTime=true + # Queue infrastructure connection (separate database) + - QUEUE_MYSQL_DSN=root:root@tcp(mysql-queue:3306)/submitqueue?parseTime=true + # Path to YAML queue configuration baked into the image + - QUEUE_CONFIG_PATH=/root/queues.yaml + depends_on: + mysql-app: + condition: service_healthy + mysql-queue: + condition: service_healthy + + orchestrator-service: + build: + context: ${REPO_ROOT} + dockerfile: example/stovepipe/orchestrator/server/Dockerfile + ports: + - "8080" # Random ephemeral port to avoid conflicts + environment: + - PORT=:8080 + # Application database connection (for request state, batches, etc.) + - MYSQL_DSN=root:root@tcp(mysql-app:3306)/submitqueue?parseTime=true + # Queue infrastructure connection (separate database) + - QUEUE_MYSQL_DSN=root:root@tcp(mysql-queue:3306)/submitqueue?parseTime=true + - HOSTNAME=orchestrator-dev + depends_on: + mysql-app: + condition: service_healthy + mysql-queue: + condition: service_healthy diff --git a/example/stovepipe/gateway/server/docker-compose.yml b/example/stovepipe/gateway/server/docker-compose.yml index e847e253..a1402c90 100644 --- a/example/stovepipe/gateway/server/docker-compose.yml +++ b/example/stovepipe/gateway/server/docker-compose.yml @@ -47,7 +47,7 @@ services: timeout: 5s retries: 10 - stovepipe-service: + gateway-service: build: context: ${REPO_ROOT} dockerfile: example/stovepipe/gateway/server/Dockerfile diff --git a/example/stovepipe/orchestrator/client/BUILD.bazel b/example/stovepipe/orchestrator/client/BUILD.bazel new file mode 100644 index 00000000..070bd6a0 --- /dev/null +++ b/example/stovepipe/orchestrator/client/BUILD.bazel @@ -0,0 +1,19 @@ +load("@rules_go//go:def.bzl", "go_binary", "go_library") + +go_library( + name = "orchestrator_lib", + srcs = ["main.go"], + importpath = "github.com/uber/submitqueue/example/stovepipe/orchestrator/client", + visibility = ["//visibility:private"], + deps = [ + "//stovepipe/orchestrator/protopb", + "@org_golang_google_grpc//:grpc", + "@org_golang_google_grpc//credentials/insecure", + ], +) + +go_binary( + name = "orchestrator", + embed = [":orchestrator_lib"], + visibility = ["//visibility:public"], +) diff --git a/example/stovepipe/orchestrator/client/main.go b/example/stovepipe/orchestrator/client/main.go new file mode 100644 index 00000000..bd511c3b --- /dev/null +++ b/example/stovepipe/orchestrator/client/main.go @@ -0,0 +1,73 @@ +// Copyright (c) 2025 Uber Technologies, Inc. +// +// 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" + "fmt" + "os" + "time" + + pb "github.com/uber/submitqueue/stovepipe/orchestrator/protopb" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials/insecure" +) + +func main() { + addr := flag.String("addr", "localhost:8084", "stovepipe orchestrator server address") + message := flag.String("message", "", "message to send in ping request") + timeout := flag.Duration("timeout", 5*time.Second, "request timeout") + flag.Parse() + + if err := run(*addr, *message, *timeout); err != nil { + fmt.Fprintf(os.Stderr, "Error: %v\n", err) + os.Exit(1) + } +} + +func run(addr, message string, timeout time.Duration) error { + conn, err := grpc.NewClient( + addr, + grpc.WithTransportCredentials(insecure.NewCredentials()), + ) + if err != nil { + return fmt.Errorf("failed to connect: %w", err) + } + defer conn.Close() + + client := pb.NewStovepipeOrchestratorClient(conn) + + ctx, cancel := context.WithTimeout(context.Background(), timeout) + defer cancel() + + req := &pb.PingRequest{ + Message: message, + } + + fmt.Printf("Sending ping to stovepipe orchestrator at %s...\n", addr) + resp, err := client.Ping(ctx, req) + if err != nil { + return fmt.Errorf("ping failed: %w", err) + } + + fmt.Printf("\nResponse:\n") + fmt.Printf(" Message: %s\n", resp.Message) + fmt.Printf(" Service Name: %s\n", resp.ServiceName) + fmt.Printf(" Timestamp: %d (%s)\n", resp.Timestamp, time.Unix(resp.Timestamp, 0)) + fmt.Printf(" Hostname: %s\n", resp.Hostname) + + return nil +} diff --git a/example/stovepipe/orchestrator/server/BUILD.bazel b/example/stovepipe/orchestrator/server/BUILD.bazel new file mode 100644 index 00000000..83dbdfb0 --- /dev/null +++ b/example/stovepipe/orchestrator/server/BUILD.bazel @@ -0,0 +1,27 @@ +load("@rules_go//go:def.bzl", "go_binary", "go_library") + +exports_files( + ["docker-compose.yml"], + visibility = ["//visibility:public"], +) + +go_library( + name = "orchestrator_server_lib", + srcs = ["main.go"], + importpath = "github.com/uber/submitqueue/example/stovepipe/orchestrator/server", + visibility = ["//visibility:private"], + deps = [ + "//stovepipe/orchestrator/controller", + "//stovepipe/orchestrator/protopb", + "@com_github_uber_go_tally_v4//:tally", + "@org_golang_google_grpc//:grpc", + "@org_golang_google_grpc//reflection", + "@org_uber_go_zap//:zap", + ], +) + +go_binary( + name = "orchestrator", + embed = [":orchestrator_server_lib"], + visibility = ["//visibility:public"], +) diff --git a/example/stovepipe/orchestrator/server/Dockerfile b/example/stovepipe/orchestrator/server/Dockerfile new file mode 100644 index 00000000..6c797c7d --- /dev/null +++ b/example/stovepipe/orchestrator/server/Dockerfile @@ -0,0 +1,11 @@ +FROM debian:bookworm-slim + +RUN apt-get update && apt-get install -y ca-certificates && rm -rf /var/lib/apt/lists/* +WORKDIR /root/ + +# Built via: make build-stovepipe-orchestrator-linux +COPY .docker-bin/stovepipe-orchestrator ./orchestrator + +EXPOSE 8080 + +CMD ["./orchestrator"] diff --git a/example/stovepipe/orchestrator/server/docker-compose.yml b/example/stovepipe/orchestrator/server/docker-compose.yml new file mode 100644 index 00000000..28331a03 --- /dev/null +++ b/example/stovepipe/orchestrator/server/docker-compose.yml @@ -0,0 +1,64 @@ +# Docker Compose for Stovepipe orchestrator manual testing +# +# +# IMPORTANT: Before running compose, build the Linux binary: +# make build-stovepipe-orchestrator-linux +# OR +# bazel build --platforms=@rules_go//go/toolchain:linux_amd64 //example/stovepipe/orchestrator/server:orchestrator +# +# Quick start: +# make local-stovepipe-orchestrator-start +# +# After `up`, only the queue schema is applied (`local-init-stovepipe-queue-schema`). + +services: + # Application Database - Stores business data (requests, batches, etc.) + mysql-app: + image: mysql:8.0 + environment: + MYSQL_ROOT_PASSWORD: root + MYSQL_DATABASE: submitqueue + ports: + - "3306" # Random ephemeral port to avoid conflicts + healthcheck: + # Use 127.0.0.1 (TCP) instead of localhost (Unix socket). MySQL treats + # "localhost" as a socket connection, which can be ready before the TCP + # listener — causing dependent services that connect over TCP to fail. + test: ["CMD", "mysqladmin", "ping", "-h", "127.0.0.1", "-proot"] + interval: 5s + timeout: 5s + retries: 10 + + # Queue Database - Messaging infrastructure (messages, offsets, partition leases) + # Separate from app DB to demonstrate queue is pluggable infrastructure + mysql-queue: + image: mysql:8.0 + environment: + MYSQL_ROOT_PASSWORD: root + MYSQL_DATABASE: submitqueue + ports: + - "3306" # Random ephemeral port to avoid conflicts + healthcheck: + test: ["CMD", "mysqladmin", "ping", "-h", "127.0.0.1", "-proot"] + interval: 5s + timeout: 5s + retries: 10 + + orchestrator-service: + build: + context: ${REPO_ROOT} + dockerfile: example/stovepipe/orchestrator/server/Dockerfile + ports: + - "8080" # Random ephemeral port to avoid conflicts + environment: + - PORT=:8080 + # Application database connection (for request state, batches, etc.) + - MYSQL_DSN=root:root@tcp(mysql-app:3306)/submitqueue?parseTime=true + # Queue infrastructure connection (separate database) + - QUEUE_MYSQL_DSN=root:root@tcp(mysql-queue:3306)/submitqueue?parseTime=true + - HOSTNAME=orchestrator-dev + depends_on: + mysql-app: + condition: service_healthy + mysql-queue: + condition: service_healthy diff --git a/example/stovepipe/orchestrator/server/main.go b/example/stovepipe/orchestrator/server/main.go new file mode 100644 index 00000000..1f2b3cc9 --- /dev/null +++ b/example/stovepipe/orchestrator/server/main.go @@ -0,0 +1,150 @@ +// Copyright (c) 2025 Uber Technologies, Inc. +// +// 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" + "errors" + "fmt" + "net" + "os" + "os/signal" + "sync" + "syscall" + "time" + + "github.com/uber-go/tally/v4" + "github.com/uber/submitqueue/stovepipe/orchestrator/controller" + pb "github.com/uber/submitqueue/stovepipe/orchestrator/protopb" + "go.uber.org/zap" + "google.golang.org/grpc" + "google.golang.org/grpc/reflection" +) + +// OrchestratorServer wraps the controller and implements the gRPC service interface. +type OrchestratorServer struct { + pb.UnimplementedStovepipeOrchestratorServer + pingController *controller.PingController +} + +// Ping delegates to the controller. +func (s *OrchestratorServer) Ping(ctx context.Context, req *pb.PingRequest) (*pb.PingResponse, error) { + return s.pingController.Ping(ctx, req) +} + +func main() { + code := 0 + if err := run(); err != nil { + if errors.Is(err, context.Canceled) { + fmt.Println("Stovepipe orchestrator server stopped by signal") + + // Return 143 (128 + SIGTERM) as per POSIX standard if the application receives any termination signal from the OS. Ideally we should return 128+SIGINT for SIGINT and 128+SIGTERM for SIGTERM, + // but it will require a special processing not yet available in the standard library. + code = 128 + int(syscall.SIGTERM) + } else { + fmt.Fprintf(os.Stderr, "Stovepipe orchestrator server failure: %v\n", err) + // TODO: classify errors and implement a binary protocol for exit codes, so far 1 for everything + code = 1 + } + } + os.Exit(code) +} + +func run() error { + ctx, cancel := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM) + defer cancel() + + logger, err := zap.NewDevelopment() + if err != nil { + return fmt.Errorf("failed to create logger: %w", err) + } + defer logger.Sync() + + scope := tally.NewTestScope("stovepipe_orchestrator", nil) + metricsStopCh := make(chan interface{}, 1) + metricsWgDone := sync.WaitGroup{} + metricsWgDone.Add(1) + go func() { + defer metricsWgDone.Done() + + ticker := time.NewTicker(10 * time.Second) + defer ticker.Stop() + + for { + select { + case <-metricsStopCh: + return + case <-ticker.C: + snapshot := scope.Snapshot() + logger.Info("metrics snapshot", + zap.Any("counters", snapshot.Counters()), + zap.Any("gauges", snapshot.Gauges()), + zap.Any("timers", snapshot.Timers()), + ) + } + } + }() + + defer func() { + close(metricsStopCh) + metricsWgDone.Wait() + }() + + grpcServer := grpc.NewServer() + + pingController := controller.NewPingController(logger, scope) + srv := &OrchestratorServer{ + pingController: pingController, + } + pb.RegisterStovepipeOrchestratorServer(grpcServer, srv) + + reflection.Register(grpcServer) + + port := os.Getenv("PORT") + if port == "" { + port = ":8084" + } + listener, err := net.Listen("tcp", port) + if err != nil { + return fmt.Errorf("failed to listen on port %s: %w", port, err) + } + + fmt.Printf("Stovepipe orchestrator gRPC server is running on %s\n", port) + fmt.Println("Press Ctrl+C to stop, or send a SIGTERM.") + + serverErrCh := make(chan error, 1) + go func() { + serverErrCh <- grpcServer.Serve(listener) + }() + + var serverErr error + select { + case <-ctx.Done(): + fmt.Println("Shutting down stovepipe orchestrator server due to interruption signal...") + + err = ctx.Err() + + grpcServer.GracefulStop() + serverErr = <-serverErrCh + case serverErr = <-serverErrCh: + fmt.Println("Shutting down stovepipe orchestrator server due to critical GRPC server error...") + } + + if serverErr != nil { + err = fmt.Errorf("GRPC server exited with error: %w", serverErr) + } + + return err +} diff --git a/stovepipe/README.md b/stovepipe/README.md index 8628ef0f..59bbab64 100644 --- a/stovepipe/README.md +++ b/stovepipe/README.md @@ -2,6 +2,7 @@ Stovepipe service layout: -- `gateway/` — RPC surface, gateway controllers, and generated protobufs +- `gateway/` — Gateway service to check commit validation status and handle API interactions. +- `orchestrator/` — Orchestrator service to process validation workflows - `extension/` — Stovepipe-specific extension implementations - `entity/` — Stovepipe-specific domain entities diff --git a/stovepipe/orchestrator/controller/BUILD.bazel b/stovepipe/orchestrator/controller/BUILD.bazel new file mode 100644 index 00000000..3b10b01d --- /dev/null +++ b/stovepipe/orchestrator/controller/BUILD.bazel @@ -0,0 +1,27 @@ +load("@rules_go//go:def.bzl", "go_library", "go_test") + +go_library( + name = "controller", + srcs = ["ping.go"], + importpath = "github.com/uber/submitqueue/stovepipe/orchestrator/controller", + visibility = ["//visibility:public"], + deps = [ + "//core/metrics", + "//stovepipe/orchestrator/protopb", + "@com_github_uber_go_tally_v4//:tally", + "@org_uber_go_zap//:zap", + ], +) + +go_test( + name = "controller_test", + srcs = ["ping_test.go"], + embed = [":controller"], + deps = [ + "//stovepipe/orchestrator/protopb", + "@com_github_stretchr_testify//assert", + "@com_github_stretchr_testify//require", + "@com_github_uber_go_tally_v4//:tally", + "@org_uber_go_zap//:zap", + ], +) diff --git a/stovepipe/orchestrator/controller/ping.go b/stovepipe/orchestrator/controller/ping.go new file mode 100644 index 00000000..c4b682ba --- /dev/null +++ b/stovepipe/orchestrator/controller/ping.go @@ -0,0 +1,71 @@ +// Copyright (c) 2025 Uber Technologies, Inc. +// +// 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 controller + +import ( + "context" + "os" + "time" + + "github.com/uber-go/tally/v4" + "github.com/uber/submitqueue/core/metrics" + pb "github.com/uber/submitqueue/stovepipe/orchestrator/protopb" + "go.uber.org/zap" +) + +// PingController handles ping business logic for the Stovepipe orchestrator. +type PingController struct { + logger *zap.Logger + metricsScope tally.Scope +} + +// NewPingController creates a new instance of the Stovepipe orchestrator ping controller. +func NewPingController(logger *zap.Logger, scope tally.Scope) *PingController { + return &PingController{ + logger: logger, + metricsScope: scope, + } +} + +// Ping handles the ping request and returns a response. +func (c *PingController) Ping(ctx context.Context, req *pb.PingRequest) (resp *pb.PingResponse, retErr error) { + const opName = "ping" + + op := metrics.Begin(c.metricsScope, opName) + defer func() { op.Complete(retErr) }() + + message := "pong!" + isEcho := false + if req.Message != "" { + message = "echo: " + req.Message + isEcho = true + metrics.NamedCounter(c.metricsScope, opName, "echo_requests", 1) + } + + hostname, _ := os.Hostname() + + c.logger.Info("ping request received", + zap.String("message", req.Message), + zap.Bool("is_echo", isEcho), + zap.String("hostname", hostname), + ) + + return &pb.PingResponse{ + Message: message, + ServiceName: "stovepipe-orchestrator", + Timestamp: time.Now().Unix(), + Hostname: hostname, + }, nil +} diff --git a/stovepipe/orchestrator/controller/ping_test.go b/stovepipe/orchestrator/controller/ping_test.go new file mode 100644 index 00000000..15b7ca20 --- /dev/null +++ b/stovepipe/orchestrator/controller/ping_test.go @@ -0,0 +1,68 @@ +// Copyright (c) 2025 Uber Technologies, Inc. +// +// 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 controller + +import ( + "context" + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/uber-go/tally/v4" + pb "github.com/uber/submitqueue/stovepipe/orchestrator/protopb" + "go.uber.org/zap" +) + +func TestNewPingController(t *testing.T) { + ctrl := NewPingController(zap.NewNop(), tally.NoopScope) + require.NotNil(t, ctrl) +} + +func TestPing_DefaultMessage(t *testing.T) { + ctrl := NewPingController(zap.NewNop(), tally.NoopScope) + ctx := context.Background() + + req := &pb.PingRequest{} + resp, err := ctrl.Ping(ctx, req) + + require.NoError(t, err) + assert.Equal(t, "pong!", resp.Message) +} + +func TestPing_ServiceName(t *testing.T) { + ctrl := NewPingController(zap.NewNop(), tally.NoopScope) + ctx := context.Background() + + req := &pb.PingRequest{} + resp, err := ctrl.Ping(ctx, req) + + require.NoError(t, err) + assert.Equal(t, "stovepipe-orchestrator", resp.ServiceName) +} + +func TestPing_Timestamp(t *testing.T) { + ctrl := NewPingController(zap.NewNop(), tally.NoopScope) + ctx := context.Background() + + before := time.Now().Unix() + req := &pb.PingRequest{} + resp, err := ctrl.Ping(ctx, req) + after := time.Now().Unix() + + require.NoError(t, err) + assert.GreaterOrEqual(t, resp.Timestamp, before) + assert.LessOrEqual(t, resp.Timestamp, after) +} diff --git a/stovepipe/orchestrator/proto/BUILD.bazel b/stovepipe/orchestrator/proto/BUILD.bazel new file mode 100644 index 00000000..68e13e74 --- /dev/null +++ b/stovepipe/orchestrator/proto/BUILD.bazel @@ -0,0 +1,35 @@ +load("@rules_go//go:def.bzl", "go_library") +load("@rules_go//proto:def.bzl", "go_proto_library") +load("@rules_proto//proto:defs.bzl", "proto_library") + +proto_library( + name = "orchestratorpb_proto", + srcs = ["orchestrator.proto"], + visibility = ["//visibility:public"], +) + +# keep +go_proto_library( + name = "orchestratorpb_go_proto", + compilers = [ + "@rules_go//proto:go_proto", + "@rules_go//proto:go_grpc_v2", + ], + importpath = "github.com/uber/submitqueue/stovepipe/orchestrator/proto", + proto = ":orchestratorpb_proto", + visibility = ["//visibility:public"], +) + +go_library( + name = "proto", + embed = [":orchestratorpb_go_proto"], + importpath = "github.com/uber/submitqueue/stovepipe/orchestrator/proto", + visibility = ["//visibility:public"], +) + +go_library( + name = "protopb", + embed = [":orchestratorpb_go_proto"], + importpath = "github.com/uber/submitqueue/stovepipe/orchestrator/protopb", + visibility = ["//visibility:public"], +) diff --git a/stovepipe/orchestrator/proto/orchestrator.proto b/stovepipe/orchestrator/proto/orchestrator.proto new file mode 100644 index 00000000..d34f9494 --- /dev/null +++ b/stovepipe/orchestrator/proto/orchestrator.proto @@ -0,0 +1,46 @@ +// Copyright (c) 2025 Uber Technologies, Inc. +// +// 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 uber.submitqueue.stovepipe.orchestrator; + +option go_package = "github.com/uber/submitqueue/stovepipe/orchestrator/protopb"; +option java_multiple_files = true; +option java_outer_classname = "OrchestratorProto"; +option java_package = "com.uber.submitqueue.stovepipe.orchestrator"; + +// PingRequest is the request for the Ping method +message PingRequest { + // Optional message to include in the ping + string message = 1; +} + +// PingResponse is the response for the Ping method +message PingResponse { + // The response message + string message = 1; + // The service name that handled the request + string service_name = 2; + // Timestamp of when the ping was received + int64 timestamp = 3; + // Hostname of the server that handled the request + string hostname = 4; +} + +// StovepipeOrchestrator provides the Stovepipe orchestrator API. +service StovepipeOrchestrator { + // Ping returns a response indicating the service is alive + rpc Ping(PingRequest) returns (PingResponse) {} +} diff --git a/stovepipe/orchestrator/protopb/BUILD.bazel b/stovepipe/orchestrator/protopb/BUILD.bazel new file mode 100644 index 00000000..698a7494 --- /dev/null +++ b/stovepipe/orchestrator/protopb/BUILD.bazel @@ -0,0 +1,27 @@ +load("@rules_go//go:def.bzl", "go_library") + +go_library( + name = "protopb", + srcs = [ + "orchestrator.pb.go", + "orchestrator.pb.yarpc.go", + "orchestrator_grpc.pb.go", + ], + importpath = "github.com/uber/submitqueue/stovepipe/orchestrator/protopb", + visibility = ["//visibility:public"], + deps = [ + "@com_github_gogo_protobuf//jsonpb", + "@com_github_gogo_protobuf//proto", + "@org_golang_google_grpc//:grpc", + "@org_golang_google_grpc//codes", + "@org_golang_google_grpc//status", + "@org_golang_google_protobuf//reflect/protoreflect", + "@org_golang_google_protobuf//runtime/protoimpl", + "@org_uber_go_fx//:fx", + "@org_uber_go_yarpc//:yarpc", + "@org_uber_go_yarpc//api/transport", + "@org_uber_go_yarpc//api/x/restriction", + "@org_uber_go_yarpc//encoding/protobuf", + "@org_uber_go_yarpc//encoding/protobuf/reflection", + ], +) diff --git a/stovepipe/orchestrator/protopb/orchestrator.pb.go b/stovepipe/orchestrator/protopb/orchestrator.pb.go new file mode 100644 index 00000000..9ff45abf --- /dev/null +++ b/stovepipe/orchestrator/protopb/orchestrator.pb.go @@ -0,0 +1,223 @@ +// Copyright (c) 2025 Uber Technologies, Inc. +// +// 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. + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.36.10 +// protoc v5.27.3 +// source: orchestrator.proto + +package protopb + +import ( + reflect "reflect" + sync "sync" + unsafe "unsafe" + + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// PingRequest is the request for the Ping method +type PingRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Optional message to include in the ping + Message string `protobuf:"bytes,1,opt,name=message,proto3" json:"message,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *PingRequest) Reset() { + *x = PingRequest{} + mi := &file_orchestrator_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *PingRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PingRequest) ProtoMessage() {} + +func (x *PingRequest) ProtoReflect() protoreflect.Message { + mi := &file_orchestrator_proto_msgTypes[0] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PingRequest.ProtoReflect.Descriptor instead. +func (*PingRequest) Descriptor() ([]byte, []int) { + return file_orchestrator_proto_rawDescGZIP(), []int{0} +} + +func (x *PingRequest) GetMessage() string { + if x != nil { + return x.Message + } + return "" +} + +// PingResponse is the response for the Ping method +type PingResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The response message + Message string `protobuf:"bytes,1,opt,name=message,proto3" json:"message,omitempty"` + // The service name that handled the request + ServiceName string `protobuf:"bytes,2,opt,name=service_name,json=serviceName,proto3" json:"service_name,omitempty"` + // Timestamp of when the ping was received + Timestamp int64 `protobuf:"varint,3,opt,name=timestamp,proto3" json:"timestamp,omitempty"` + // Hostname of the server that handled the request + Hostname string `protobuf:"bytes,4,opt,name=hostname,proto3" json:"hostname,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *PingResponse) Reset() { + *x = PingResponse{} + mi := &file_orchestrator_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *PingResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PingResponse) ProtoMessage() {} + +func (x *PingResponse) ProtoReflect() protoreflect.Message { + mi := &file_orchestrator_proto_msgTypes[1] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PingResponse.ProtoReflect.Descriptor instead. +func (*PingResponse) Descriptor() ([]byte, []int) { + return file_orchestrator_proto_rawDescGZIP(), []int{1} +} + +func (x *PingResponse) GetMessage() string { + if x != nil { + return x.Message + } + return "" +} + +func (x *PingResponse) GetServiceName() string { + if x != nil { + return x.ServiceName + } + return "" +} + +func (x *PingResponse) GetTimestamp() int64 { + if x != nil { + return x.Timestamp + } + return 0 +} + +func (x *PingResponse) GetHostname() string { + if x != nil { + return x.Hostname + } + return "" +} + +var File_orchestrator_proto protoreflect.FileDescriptor + +const file_orchestrator_proto_rawDesc = "" + + "\n" + + "\x12orchestrator.proto\x12'uber.submitqueue.stovepipe.orchestrator\"'\n" + + "\vPingRequest\x12\x18\n" + + "\amessage\x18\x01 \x01(\tR\amessage\"\x85\x01\n" + + "\fPingResponse\x12\x18\n" + + "\amessage\x18\x01 \x01(\tR\amessage\x12!\n" + + "\fservice_name\x18\x02 \x01(\tR\vserviceName\x12\x1c\n" + + "\ttimestamp\x18\x03 \x01(\x03R\ttimestamp\x12\x1a\n" + + "\bhostname\x18\x04 \x01(\tR\bhostname2\x8e\x01\n" + + "\x15StovepipeOrchestrator\x12u\n" + + "\x04Ping\x124.uber.submitqueue.stovepipe.orchestrator.PingRequest\x1a5.uber.submitqueue.stovepipe.orchestrator.PingResponse\"\x00B~\n" + + "+com.uber.submitqueue.stovepipe.orchestratorB\x11OrchestratorProtoP\x01Z:github.com/uber/submitqueue/stovepipe/orchestrator/protopbb\x06proto3" + +var ( + file_orchestrator_proto_rawDescOnce sync.Once + file_orchestrator_proto_rawDescData []byte +) + +func file_orchestrator_proto_rawDescGZIP() []byte { + file_orchestrator_proto_rawDescOnce.Do(func() { + file_orchestrator_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_orchestrator_proto_rawDesc), len(file_orchestrator_proto_rawDesc))) + }) + return file_orchestrator_proto_rawDescData +} + +var file_orchestrator_proto_msgTypes = make([]protoimpl.MessageInfo, 2) +var file_orchestrator_proto_goTypes = []any{ + (*PingRequest)(nil), // 0: uber.submitqueue.stovepipe.orchestrator.PingRequest + (*PingResponse)(nil), // 1: uber.submitqueue.stovepipe.orchestrator.PingResponse +} +var file_orchestrator_proto_depIdxs = []int32{ + 0, // 0: uber.submitqueue.stovepipe.orchestrator.StovepipeOrchestrator.Ping:input_type -> uber.submitqueue.stovepipe.orchestrator.PingRequest + 1, // 1: uber.submitqueue.stovepipe.orchestrator.StovepipeOrchestrator.Ping:output_type -> uber.submitqueue.stovepipe.orchestrator.PingResponse + 1, // [1:2] is the sub-list for method output_type + 0, // [0:1] is the sub-list for method input_type + 0, // [0:0] is the sub-list for extension type_name + 0, // [0:0] is the sub-list for extension extendee + 0, // [0:0] is the sub-list for field type_name +} + +func init() { file_orchestrator_proto_init() } +func file_orchestrator_proto_init() { + if File_orchestrator_proto != nil { + return + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: unsafe.Slice(unsafe.StringData(file_orchestrator_proto_rawDesc), len(file_orchestrator_proto_rawDesc)), + NumEnums: 0, + NumMessages: 2, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_orchestrator_proto_goTypes, + DependencyIndexes: file_orchestrator_proto_depIdxs, + MessageInfos: file_orchestrator_proto_msgTypes, + }.Build() + File_orchestrator_proto = out.File + file_orchestrator_proto_goTypes = nil + file_orchestrator_proto_depIdxs = nil +} diff --git a/stovepipe/orchestrator/protopb/orchestrator.pb.yarpc.go b/stovepipe/orchestrator/protopb/orchestrator.pb.yarpc.go new file mode 100644 index 00000000..630fb53b --- /dev/null +++ b/stovepipe/orchestrator/protopb/orchestrator.pb.yarpc.go @@ -0,0 +1,262 @@ +// Code generated by protoc-gen-yarpc-go. DO NOT EDIT. +// source: orchestrator.proto + +package protopb + +import ( + "context" + "io/ioutil" + "reflect" + + "github.com/gogo/protobuf/jsonpb" + "github.com/gogo/protobuf/proto" + "go.uber.org/fx" + "go.uber.org/yarpc" + "go.uber.org/yarpc/api/transport" + "go.uber.org/yarpc/api/x/restriction" + "go.uber.org/yarpc/encoding/protobuf" + "go.uber.org/yarpc/encoding/protobuf/reflection" +) + +var _ = ioutil.NopCloser + +// StovepipeOrchestratorYARPCClient is the YARPC client-side interface for the StovepipeOrchestrator service. +type StovepipeOrchestratorYARPCClient interface { + Ping(context.Context, *PingRequest, ...yarpc.CallOption) (*PingResponse, error) +} + +func newStovepipeOrchestratorYARPCClient(clientConfig transport.ClientConfig, anyResolver jsonpb.AnyResolver, options ...protobuf.ClientOption) StovepipeOrchestratorYARPCClient { + return &_StovepipeOrchestratorYARPCCaller{protobuf.NewStreamClient( + protobuf.ClientParams{ + ServiceName: "uber.submitqueue.stovepipe.orchestrator.StovepipeOrchestrator", + ClientConfig: clientConfig, + AnyResolver: anyResolver, + Options: options, + }, + )} +} + +// NewStovepipeOrchestratorYARPCClient builds a new YARPC client for the StovepipeOrchestrator service. +func NewStovepipeOrchestratorYARPCClient(clientConfig transport.ClientConfig, options ...protobuf.ClientOption) StovepipeOrchestratorYARPCClient { + return newStovepipeOrchestratorYARPCClient(clientConfig, nil, options...) +} + +// StovepipeOrchestratorYARPCServer is the YARPC server-side interface for the StovepipeOrchestrator service. +type StovepipeOrchestratorYARPCServer interface { + Ping(context.Context, *PingRequest) (*PingResponse, error) +} + +type buildStovepipeOrchestratorYARPCProceduresParams struct { + Server StovepipeOrchestratorYARPCServer + AnyResolver jsonpb.AnyResolver +} + +func buildStovepipeOrchestratorYARPCProcedures(params buildStovepipeOrchestratorYARPCProceduresParams) []transport.Procedure { + handler := &_StovepipeOrchestratorYARPCHandler{params.Server} + return protobuf.BuildProcedures( + protobuf.BuildProceduresParams{ + ServiceName: "uber.submitqueue.stovepipe.orchestrator.StovepipeOrchestrator", + UnaryHandlerParams: []protobuf.BuildProceduresUnaryHandlerParams{ + { + MethodName: "Ping", + Handler: protobuf.NewUnaryHandler( + protobuf.UnaryHandlerParams{ + Handle: handler.Ping, + NewRequest: newStovepipeOrchestratorServicePingYARPCRequest, + AnyResolver: params.AnyResolver, + }, + ), + }, + }, + OnewayHandlerParams: []protobuf.BuildProceduresOnewayHandlerParams{}, + StreamHandlerParams: []protobuf.BuildProceduresStreamHandlerParams{}, + }, + ) +} + +// BuildStovepipeOrchestratorYARPCProcedures prepares an implementation of the StovepipeOrchestrator service for YARPC registration. +func BuildStovepipeOrchestratorYARPCProcedures(server StovepipeOrchestratorYARPCServer) []transport.Procedure { + return buildStovepipeOrchestratorYARPCProcedures(buildStovepipeOrchestratorYARPCProceduresParams{Server: server}) +} + +// FxStovepipeOrchestratorYARPCClientParams defines the input +// for NewFxStovepipeOrchestratorYARPCClient. It provides the +// paramaters to get a StovepipeOrchestratorYARPCClient in an +// Fx application. +type FxStovepipeOrchestratorYARPCClientParams struct { + fx.In + + Provider yarpc.ClientConfig + AnyResolver jsonpb.AnyResolver `name:"yarpcfx" optional:"true"` + Restriction restriction.Checker `optional:"true"` +} + +// FxStovepipeOrchestratorYARPCClientResult defines the output +// of NewFxStovepipeOrchestratorYARPCClient. It provides a +// StovepipeOrchestratorYARPCClient to an Fx application. +type FxStovepipeOrchestratorYARPCClientResult struct { + fx.Out + + Client StovepipeOrchestratorYARPCClient + + // We are using an fx.Out struct here instead of just returning a client + // so that we can add more values or add named versions of the client in + // the future without breaking any existing code. +} + +// NewFxStovepipeOrchestratorYARPCClient provides a StovepipeOrchestratorYARPCClient +// to an Fx application using the given name for routing. +// +// fx.Provide( +// protopb.NewFxStovepipeOrchestratorYARPCClient("service-name"), +// ... +// ) +func NewFxStovepipeOrchestratorYARPCClient(name string, options ...protobuf.ClientOption) interface{} { + return func(params FxStovepipeOrchestratorYARPCClientParams) FxStovepipeOrchestratorYARPCClientResult { + cc := params.Provider.ClientConfig(name) + + if params.Restriction != nil { + if namer, ok := cc.GetUnaryOutbound().(transport.Namer); ok { + if err := params.Restriction.Check(protobuf.Encoding, namer.TransportName()); err != nil { + panic(err.Error()) + } + } + } + + return FxStovepipeOrchestratorYARPCClientResult{ + Client: newStovepipeOrchestratorYARPCClient(cc, params.AnyResolver, options...), + } + } +} + +// FxStovepipeOrchestratorYARPCProceduresParams defines the input +// for NewFxStovepipeOrchestratorYARPCProcedures. It provides the +// paramaters to get StovepipeOrchestratorYARPCServer procedures in an +// Fx application. +type FxStovepipeOrchestratorYARPCProceduresParams struct { + fx.In + + Server StovepipeOrchestratorYARPCServer + AnyResolver jsonpb.AnyResolver `name:"yarpcfx" optional:"true"` +} + +// FxStovepipeOrchestratorYARPCProceduresResult defines the output +// of NewFxStovepipeOrchestratorYARPCProcedures. It provides +// StovepipeOrchestratorYARPCServer procedures to an Fx application. +// +// The procedures are provided to the "yarpcfx" value group. +// Dig 1.2 or newer must be used for this feature to work. +type FxStovepipeOrchestratorYARPCProceduresResult struct { + fx.Out + + Procedures []transport.Procedure `group:"yarpcfx"` + ReflectionMeta reflection.ServerMeta `group:"yarpcfx"` +} + +// NewFxStovepipeOrchestratorYARPCProcedures provides StovepipeOrchestratorYARPCServer procedures to an Fx application. +// It expects a StovepipeOrchestratorYARPCServer to be present in the container. +// +// fx.Provide( +// protopb.NewFxStovepipeOrchestratorYARPCProcedures(), +// ... +// ) +func NewFxStovepipeOrchestratorYARPCProcedures() interface{} { + return func(params FxStovepipeOrchestratorYARPCProceduresParams) FxStovepipeOrchestratorYARPCProceduresResult { + return FxStovepipeOrchestratorYARPCProceduresResult{ + Procedures: buildStovepipeOrchestratorYARPCProcedures(buildStovepipeOrchestratorYARPCProceduresParams{ + Server: params.Server, + AnyResolver: params.AnyResolver, + }), + ReflectionMeta: StovepipeOrchestratorReflectionMeta, + } + } +} + +// StovepipeOrchestratorReflectionMeta is the reflection server metadata +// required for using the gRPC reflection protocol with YARPC. +// +// See https://github.com/grpc/grpc/blob/master/doc/server-reflection.md. +var StovepipeOrchestratorReflectionMeta = reflection.ServerMeta{ + ServiceName: "uber.submitqueue.stovepipe.orchestrator.StovepipeOrchestrator", + FileDescriptors: yarpcFileDescriptorClosure96b6e6782baaa298, +} + +type _StovepipeOrchestratorYARPCCaller struct { + streamClient protobuf.StreamClient +} + +func (c *_StovepipeOrchestratorYARPCCaller) Ping(ctx context.Context, request *PingRequest, options ...yarpc.CallOption) (*PingResponse, error) { + responseMessage, err := c.streamClient.Call(ctx, "Ping", request, newStovepipeOrchestratorServicePingYARPCResponse, options...) + if responseMessage == nil { + return nil, err + } + response, ok := responseMessage.(*PingResponse) + if !ok { + return nil, protobuf.CastError(emptyStovepipeOrchestratorServicePingYARPCResponse, responseMessage) + } + return response, err +} + +type _StovepipeOrchestratorYARPCHandler struct { + server StovepipeOrchestratorYARPCServer +} + +func (h *_StovepipeOrchestratorYARPCHandler) Ping(ctx context.Context, requestMessage proto.Message) (proto.Message, error) { + var request *PingRequest + var ok bool + if requestMessage != nil { + request, ok = requestMessage.(*PingRequest) + if !ok { + return nil, protobuf.CastError(emptyStovepipeOrchestratorServicePingYARPCRequest, requestMessage) + } + } + response, err := h.server.Ping(ctx, request) + if response == nil { + return nil, err + } + return response, err +} + +func newStovepipeOrchestratorServicePingYARPCRequest() proto.Message { + return &PingRequest{} +} + +func newStovepipeOrchestratorServicePingYARPCResponse() proto.Message { + return &PingResponse{} +} + +var ( + emptyStovepipeOrchestratorServicePingYARPCRequest = &PingRequest{} + emptyStovepipeOrchestratorServicePingYARPCResponse = &PingResponse{} +) + +var yarpcFileDescriptorClosure96b6e6782baaa298 = [][]byte{ + // orchestrator.proto + []byte{ + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x91, 0x3f, 0x4f, 0xc3, 0x30, + 0x10, 0xc5, 0x31, 0xad, 0x80, 0x5e, 0xbb, 0x60, 0x09, 0x29, 0xaa, 0x18, 0x4a, 0x96, 0x56, 0x42, + 0x72, 0x24, 0xfe, 0x2c, 0x8c, 0xfd, 0x00, 0x10, 0x85, 0x8d, 0x05, 0x25, 0xd1, 0x29, 0xf1, 0xe0, + 0xd8, 0xf5, 0x9d, 0x3b, 0xb2, 0xb1, 0xf2, 0x99, 0x51, 0x52, 0x5a, 0xbc, 0x20, 0x95, 0xcd, 0x77, + 0x7e, 0xef, 0xe9, 0x7e, 0x77, 0x20, 0xad, 0xaf, 0x5b, 0x24, 0xf6, 0x25, 0x5b, 0xaf, 0x9c, 0xb7, + 0x6c, 0xe5, 0x32, 0x54, 0xe8, 0x15, 0x85, 0xca, 0x68, 0xde, 0x04, 0x0c, 0xa8, 0x88, 0xed, 0x16, + 0x9d, 0x76, 0xa8, 0x62, 0x79, 0xba, 0x84, 0x69, 0xae, 0xbb, 0xa6, 0xc0, 0x4d, 0x40, 0x62, 0x99, + 0xc0, 0xb9, 0x41, 0xa2, 0xb2, 0xc1, 0x44, 0x2c, 0xc4, 0x6a, 0x52, 0xec, 0xcb, 0xf4, 0x53, 0xc0, + 0x6c, 0xa7, 0x24, 0x67, 0x3b, 0xc2, 0xbf, 0xa5, 0xf2, 0x06, 0x66, 0x84, 0x7e, 0xab, 0x6b, 0x7c, + 0xef, 0x4a, 0x83, 0xc9, 0xe9, 0xf0, 0x3d, 0xfd, 0xe9, 0x3d, 0x97, 0x06, 0xe5, 0x35, 0x4c, 0x58, + 0x1b, 0x24, 0x2e, 0x8d, 0x4b, 0x46, 0x0b, 0xb1, 0x1a, 0x15, 0xbf, 0x0d, 0x39, 0x87, 0x8b, 0xd6, + 0x12, 0x0f, 0xe6, 0xf1, 0x60, 0x3e, 0xd4, 0x77, 0x5f, 0x02, 0xae, 0x5e, 0xf7, 0x2c, 0x2f, 0x11, + 0x8a, 0x0c, 0x30, 0xee, 0x07, 0x94, 0x0f, 0xea, 0x48, 0x78, 0x15, 0x91, 0xcf, 0x1f, 0xff, 0xe9, + 0xda, 0x6d, 0x21, 0x3d, 0x59, 0x7f, 0xc0, 0x6d, 0x6d, 0xcd, 0xb1, 0xee, 0xf5, 0x65, 0x3c, 0x73, + 0xde, 0x1f, 0x2b, 0x17, 0x6f, 0x4f, 0x8d, 0xe6, 0x36, 0x54, 0xaa, 0xb6, 0x26, 0xeb, 0x83, 0xb2, + 0x28, 0x28, 0x3b, 0x04, 0x65, 0x71, 0x50, 0x36, 0x1c, 0xda, 0x55, 0xd5, 0xd9, 0xf0, 0xb8, 0xff, + 0x0e, 0x00, 0x00, 0xff, 0xff, 0xfa, 0x73, 0xb0, 0x63, 0x07, 0x02, 0x00, 0x00, + }, +} + +func init() { + yarpc.RegisterClientBuilder( + func(clientConfig transport.ClientConfig, structField reflect.StructField) StovepipeOrchestratorYARPCClient { + return NewStovepipeOrchestratorYARPCClient(clientConfig, protobuf.ClientBuilderOptions(clientConfig, structField)...) + }, + ) +} diff --git a/stovepipe/orchestrator/protopb/orchestrator_grpc.pb.go b/stovepipe/orchestrator/protopb/orchestrator_grpc.pb.go new file mode 100644 index 00000000..78695519 --- /dev/null +++ b/stovepipe/orchestrator/protopb/orchestrator_grpc.pb.go @@ -0,0 +1,142 @@ +// Copyright (c) 2025 Uber Technologies, Inc. +// +// 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. + +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.5.1 +// - protoc v5.27.3 +// source: orchestrator.proto + +package protopb + +import ( + context "context" + + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" +) + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.64.0 or later. +const _ = grpc.SupportPackageIsVersion9 + +const ( + StovepipeOrchestrator_Ping_FullMethodName = "/uber.submitqueue.stovepipe.orchestrator.StovepipeOrchestrator/Ping" +) + +// StovepipeOrchestratorClient is the client API for StovepipeOrchestrator service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +// +// StovepipeOrchestrator provides the Stovepipe orchestrator API. +type StovepipeOrchestratorClient interface { + // Ping returns a response indicating the service is alive + Ping(ctx context.Context, in *PingRequest, opts ...grpc.CallOption) (*PingResponse, error) +} + +type stovepipeOrchestratorClient struct { + cc grpc.ClientConnInterface +} + +func NewStovepipeOrchestratorClient(cc grpc.ClientConnInterface) StovepipeOrchestratorClient { + return &stovepipeOrchestratorClient{cc} +} + +func (c *stovepipeOrchestratorClient) Ping(ctx context.Context, in *PingRequest, opts ...grpc.CallOption) (*PingResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(PingResponse) + err := c.cc.Invoke(ctx, StovepipeOrchestrator_Ping_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +// StovepipeOrchestratorServer is the server API for StovepipeOrchestrator service. +// All implementations must embed UnimplementedStovepipeOrchestratorServer +// for forward compatibility. +// +// StovepipeOrchestrator provides the Stovepipe orchestrator API. +type StovepipeOrchestratorServer interface { + // Ping returns a response indicating the service is alive + Ping(context.Context, *PingRequest) (*PingResponse, error) + mustEmbedUnimplementedStovepipeOrchestratorServer() +} + +// UnimplementedStovepipeOrchestratorServer must be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. +type UnimplementedStovepipeOrchestratorServer struct{} + +func (UnimplementedStovepipeOrchestratorServer) Ping(context.Context, *PingRequest) (*PingResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Ping not implemented") +} +func (UnimplementedStovepipeOrchestratorServer) mustEmbedUnimplementedStovepipeOrchestratorServer() {} +func (UnimplementedStovepipeOrchestratorServer) testEmbeddedByValue() {} + +// UnsafeStovepipeOrchestratorServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to StovepipeOrchestratorServer will +// result in compilation errors. +type UnsafeStovepipeOrchestratorServer interface { + mustEmbedUnimplementedStovepipeOrchestratorServer() +} + +func RegisterStovepipeOrchestratorServer(s grpc.ServiceRegistrar, srv StovepipeOrchestratorServer) { + // If the following call pancis, it indicates UnimplementedStovepipeOrchestratorServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } + s.RegisterService(&StovepipeOrchestrator_ServiceDesc, srv) +} + +func _StovepipeOrchestrator_Ping_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(PingRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(StovepipeOrchestratorServer).Ping(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: StovepipeOrchestrator_Ping_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(StovepipeOrchestratorServer).Ping(ctx, req.(*PingRequest)) + } + return interceptor(ctx, in, info, handler) +} + +// StovepipeOrchestrator_ServiceDesc is the grpc.ServiceDesc for StovepipeOrchestrator service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var StovepipeOrchestrator_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "uber.submitqueue.stovepipe.orchestrator.StovepipeOrchestrator", + HandlerType: (*StovepipeOrchestratorServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "Ping", + Handler: _StovepipeOrchestrator_Ping_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "orchestrator.proto", +} diff --git a/test/integration/stovepipe/gateway/suite_test.go b/test/integration/stovepipe/gateway/suite_test.go index aac8bfb2..5874d60d 100644 --- a/test/integration/stovepipe/gateway/suite_test.go +++ b/test/integration/stovepipe/gateway/suite_test.go @@ -74,7 +74,7 @@ func (s *StovepipeGatewayIntegrationSuite) SetupSuite() { testutil.ApplySchema(t, s.log, queueDB, testutil.SchemaDir("extension/queue/mysql/schema")) var conn *grpc.ClientConn - conn, err = s.stack.ConnectGRPC("stovepipe-service", 8080) + conn, err = s.stack.ConnectGRPC("gateway-service", 8080) require.NoError(t, err, "failed to connect to stovepipe gateway") s.client = pb.NewStovepipeGatewayClient(conn) }