From 57e22c01a8cecaa1087e004cf17fcee15363a492 Mon Sep 17 00:00:00 2001 From: jgrusewski Date: Wed, 4 Mar 2026 23:46:36 +0100 Subject: [PATCH] refactor: update K8s, CI, Docker, Prometheus, scripts, and FXT CLI for api rename MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - K8s: rename api-gateway → api manifests, delete web-gateway, update network policies - CI: rename compile/deploy jobs, delete web-gateway jobs - Docker: rename service in compose files - Prometheus: update scrape targets and alert rules - Scripts: update binary references in build/test/cert scripts - FXT CLI: rename api_gateway_url → api_url (with serde alias for compat) Co-Authored-By: Claude Opus 4.6 --- .gitlab-ci.yml | 38 +---- Cargo.lock | 111 +----------- bin/fxt/src/auth/jwt_generator.rs | 8 +- bin/fxt/src/auth/login.rs | 34 ++-- bin/fxt/src/commands/config.rs | 2 +- bin/fxt/src/config.rs | 34 ++-- bin/fxt/src/tui/cockpits/pods.rs | 2 +- bin/fxt/src/tui/data_fetcher.rs | 12 +- bin/fxt/src/tui/event_loop.rs | 2 +- config/prometheus/prometheus.yml | 6 +- config/prometheus/rules/production-alerts.yml | 28 +-- .../rules/service-health-alerts.yml | 10 +- docker-compose.override.yml | 2 +- docker-compose.yml | 9 +- infra/k8s/gitlab/tailscale-proxy.yaml | 4 +- .../gpu-overlays/ml-training-service-gpu.yaml | 2 +- .../k8s/gpu-overlays/trading-service-gpu.yaml | 2 +- infra/k8s/jobs/migrate.yaml | 2 +- .../{api-gateway.yaml => api.yaml} | 12 +- .../network-policies/backtesting-service.yaml | 2 +- .../k8s/network-policies/broker-gateway.yaml | 5 +- .../data-acquisition-service.yaml | 2 +- .../network-policies/ml-training-service.yaml | 2 +- .../trading-agent-service.yaml | 2 +- .../k8s/network-policies/trading-service.yaml | 2 +- infra/k8s/network-policies/web-gateway.yaml | 69 -------- .../services/{api-gateway.yaml => api.yaml} | 44 ++--- infra/k8s/services/backtesting-service.yaml | 2 +- infra/k8s/services/broker-gateway.yaml | 2 +- infra/k8s/services/ml-training-service.yaml | 2 +- infra/k8s/services/trading-agent-service.yaml | 2 +- infra/k8s/services/trading-service.yaml | 2 +- infra/k8s/services/web-gateway.yaml | 161 ------------------ infra/scripts/build-and-push.sh | 20 +-- infra/scripts/smoke-test.sh | 16 +- scripts/enforce_coverage.sh | 2 +- scripts/generate_dev_certs.sh | 2 +- 37 files changed, 142 insertions(+), 517 deletions(-) rename infra/k8s/network-policies/{api-gateway.yaml => api.yaml} (91%) delete mode 100644 infra/k8s/network-policies/web-gateway.yaml rename infra/k8s/services/{api-gateway.yaml => api.yaml} (87%) delete mode 100644 infra/k8s/services/web-gateway.yaml diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index d23e07d98..35d818691 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -37,7 +37,7 @@ variables: CARGO_TERM_COLOR: always # CUDA_COMPUTE_CAP is set at runtime by detect_gpu() — L4=89, H100=90 # Do NOT hardcode here; sccache is partitioned by compute cap below - # Stable JWT secret for api_gateway tests (prevents env-var race between parallel tests) + # Stable JWT secret for api tests (prevents env-var race between parallel tests) JWT_SECRET: "CiTestSecret_Kx7mP9nR2sW5vY8bC3fG6jH1kL4pQ7tZ0uN9dM5eV8xS2wT6yA4zB_64chars_min" # Training data on block storage PVC (mounted at /mnt/training-data by runner) FOXHUNT_DATA_DIR: "/mnt/training-data/futures-baseline" @@ -448,14 +448,14 @@ test: # Each service compiled independently with dependency-aware changes: filters. # sccache shared across jobs — incremental crate compilation is cached. # -------------------------------------------------------------------------- -compile-api-gateway: +compile-api: extends: .compile-service-base variables: - SERVICE_PACKAGE: api-gateway - rules: &rules-api-gateway + SERVICE_PACKAGE: api + rules: &rules-api - if: $CI_COMMIT_BRANCH == "main" && $CI_PIPELINE_SOURCE == "push" changes: - - services/api_gateway/** + - services/api/** - crates/common/** - crates/config/** - crates/trading_engine/** @@ -572,19 +572,6 @@ compile-data-acquisition-service: - Cargo.lock - if: $CI_PIPELINE_SOURCE == "web" || $CI_PIPELINE_SOURCE == "api" -compile-web-gateway: - extends: .compile-service-base - variables: - SERVICE_PACKAGE: web-gateway - rules: &rules-web-gateway - - if: $CI_COMMIT_BRANCH == "main" && $CI_PIPELINE_SOURCE == "push" - changes: - - crates/web-gateway/** - - crates/common/** - - Cargo.toml - - Cargo.lock - - if: $CI_PIPELINE_SOURCE == "web" || $CI_PIPELINE_SOURCE == "api" - # -------------------------------------------------------------------------- # Stage 3a: Compile training binaries (CPU node, CUDA stubs from ci-builder image) # -------------------------------------------------------------------------- @@ -1637,12 +1624,12 @@ infra-drift-check: # Rules use YAML anchors shared with compile jobs — ensures compile+deploy # are created/skipped together. # -------------------------------------------------------------------------- -deploy-api-gateway: +deploy-api: extends: .deploy-service-base - needs: [{job: compile-api-gateway, artifacts: true}] + needs: [{job: compile-api, artifacts: true}] variables: - SERVICE_PACKAGE: api-gateway - rules: *rules-api-gateway + SERVICE_PACKAGE: api + rules: *rules-api deploy-trading-service: extends: .deploy-service-base @@ -1686,13 +1673,6 @@ deploy-data-acquisition-service: SERVICE_PACKAGE: data-acquisition-service rules: *rules-data-acquisition-service -deploy-web-gateway: - extends: .deploy-service-base - needs: [{job: compile-web-gateway, artifacts: true}] - variables: - SERVICE_PACKAGE: web-gateway - rules: *rules-web-gateway - # -------------------------------------------------------------------------- # Stage 4b: Deploy training binaries to MinIO # -------------------------------------------------------------------------- diff --git a/Cargo.lock b/Cargo.lock index 282e78f22..f26ca6890 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -250,82 +250,7 @@ dependencies = [ ] [[package]] -name = "api-gateway" -version = "1.0.0" -dependencies = [ - "anyhow", - "async-stream", - "async-trait", - "axum 0.7.9", - "base32", - "base64 0.22.1", - "bytes", - "chrono", - "clap", - "common", - "config", - "const-oid", - "criterion", - "dashmap 6.1.0", - "futures", - "fxt", - "governor", - "hdrhistogram", - "hex", - "hmac", - "http 1.3.1", - "http-body 1.0.1", - "http-body-util", - "hyper 1.7.0", - "hyper-util", - "image 0.25.8", - "jsonwebtoken", - "k8s-openapi 0.27.0", - "kube 3.0.1", - "lru", - "num-traits", - "ocsp", - "once_cell", - "prometheus", - "prost 0.14.1", - "prost-build", - "qrcode", - "rand 0.8.5", - "redis", - "regex", - "reqwest 0.12.23", - "rust_decimal", - "rustls 0.23.32", - "secrecy 0.8.0", - "serde", - "serde_json", - "sha1", - "sha2", - "sqlx", - "thiserror 1.0.69", - "tokio", - "tokio-stream", - "tokio-test", - "tonic 0.14.2", - "tonic-health", - "tonic-prost", - "tonic-prost-build", - "tonic-reflection", - "totp-rs", - "tower 0.4.13", - "tower-layer", - "tower-service", - "tracing", - "tracing-subscriber", - "trading_engine", - "urlencoding", - "uuid", - "x509-parser", - "zeroize", -] - -[[package]] -name = "api_gateway_load_tests" +name = "api_load_tests" version = "0.1.0" dependencies = [ "anyhow", @@ -1442,7 +1367,6 @@ checksum = "edca88bc138befd0323b20752846e6587272d3b03b0343c8ea28a6f819e6e71f" dependencies = [ "async-trait", "axum-core 0.4.5", - "base64 0.22.1", "bytes", "futures-util", "http 1.3.1", @@ -1461,10 +1385,8 @@ dependencies = [ "serde_json", "serde_path_to_error", "serde_urlencoded", - "sha1", "sync_wrapper 1.0.2", "tokio", - "tokio-tungstenite", "tower 0.5.2", "tower-layer", "tower-service", @@ -11359,7 +11281,7 @@ name = "trading-service" version = "1.0.0" dependencies = [ "anyhow", - "api-gateway", + "api", "async-stream", "async-trait", "axum 0.7.9", @@ -11999,35 +11921,6 @@ dependencies = [ "web-sys", ] -[[package]] -name = "web-gateway" -version = "1.0.0" -dependencies = [ - "anyhow", - "axum 0.7.9", - "chrono", - "common", - "futures-util", - "jsonwebtoken", - "once_cell", - "prometheus", - "prost 0.14.1", - "serde", - "serde_json", - "thiserror 1.0.69", - "tokio", - "tokio-stream", - "tokio-test", - "tonic 0.14.2", - "tonic-prost", - "tonic-prost-build", - "tower 0.4.13", - "tower-http 0.5.2", - "tracing", - "tracing-subscriber", - "uuid", -] - [[package]] name = "web-sys" version = "0.3.81" diff --git a/bin/fxt/src/auth/jwt_generator.rs b/bin/fxt/src/auth/jwt_generator.rs index 043dbaeb1..65ea1e8a6 100644 --- a/bin/fxt/src/auth/jwt_generator.rs +++ b/bin/fxt/src/auth/jwt_generator.rs @@ -1,7 +1,7 @@ //! JWT Token Generation for FXT //! //! Provides JWT token generation for simulated authentication flows. -//! Uses the same configuration as API Gateway for compatibility. +//! Uses the same configuration as the unified API for compatibility. use anyhow::Result; use jsonwebtoken::{encode, EncodingKey, Header}; @@ -9,7 +9,7 @@ use serde::{Deserialize, Serialize}; use std::time::{SystemTime, UNIX_EPOCH}; use uuid::Uuid; -/// JWT claims structure matching API Gateway expectations +/// JWT claims structure matching API expectations #[derive(Debug, Clone, Serialize, Deserialize)] pub struct JwtClaims { /// JWT ID (unique identifier for revocation) @@ -38,7 +38,7 @@ pub struct JwtClaims { pub session_id: Option, } -/// JWT configuration matching API Gateway +/// JWT configuration matching the unified API pub struct JwtConfig { pub secret: String, pub issuer: String, @@ -62,7 +62,7 @@ impl Default for JwtConfig { Self { secret: resolved_secret, issuer: std::env::var("JWT_ISSUER") - .unwrap_or_else(|_| "foxhunt-api-gateway".to_owned()), + .unwrap_or_else(|_| "foxhunt-api".to_owned()), audience: std::env::var("JWT_AUDIENCE") .unwrap_or_else(|_| "foxhunt-services".to_owned()), } diff --git a/bin/fxt/src/auth/login.rs b/bin/fxt/src/auth/login.rs index 61aab9f92..2ef6a9ea0 100644 --- a/bin/fxt/src/auth/login.rs +++ b/bin/fxt/src/auth/login.rs @@ -62,9 +62,9 @@ pub struct RefreshResponse { pub expires_at: u64, } -/// Login client for API Gateway authentication +/// Login client for API authentication pub struct LoginClient { - /// gRPC channel to the API Gateway (used for future gRPC auth calls) + /// gRPC channel to the API (used for future gRPC auth calls) gateway_channel: Channel, } @@ -79,9 +79,9 @@ impl LoginClient { &self.gateway_channel } - /// Check whether an API Gateway URL has been configured in the environment - fn is_api_gateway_available() -> bool { - std::env::var("API_GATEWAY_URL").is_ok() + /// Check whether an API URL has been configured in the environment + fn is_api_available() -> bool { + std::env::var("API_URL").is_ok() } /// Perform interactive login flow @@ -108,11 +108,11 @@ impl LoginClient { // Attempt login let _login_request = LoginRequest { username, password }; - // TODO: Call API Gateway login endpoint via gRPC + // TODO: Call API login endpoint via gRPC // For now, simulate a successful login response - if Self::is_api_gateway_available() { + if Self::is_api_available() { tracing::warn!( - "API Gateway configured but gRPC client not yet implemented -- using simulation" + "API configured but gRPC client not yet implemented -- using simulation" ); } tracing::warn!( @@ -154,11 +154,11 @@ impl LoginClient { password: password.to_owned(), }; - // TODO: Call API Gateway login endpoint via gRPC + // TODO: Call API login endpoint via gRPC // For now, simulate a successful login response - if Self::is_api_gateway_available() { + if Self::is_api_available() { tracing::warn!( - "API Gateway configured but gRPC client not yet implemented -- using simulation" + "API configured but gRPC client not yet implemented -- using simulation" ); } tracing::warn!( @@ -209,10 +209,10 @@ impl LoginClient { totp_code, }; - // TODO: Call API Gateway MFA endpoint via gRPC - if Self::is_api_gateway_available() { + // TODO: Call API MFA endpoint via gRPC + if Self::is_api_available() { tracing::warn!( - "API Gateway configured but gRPC client not yet implemented -- using simulation" + "API configured but gRPC client not yet implemented -- using simulation" ); } tracing::warn!( @@ -250,10 +250,10 @@ impl LoginClient { refresh_token: refresh_token.clone(), }; - // TODO: Call API Gateway refresh endpoint via gRPC - if Self::is_api_gateway_available() { + // TODO: Call API refresh endpoint via gRPC + if Self::is_api_available() { tracing::warn!( - "API Gateway configured but gRPC client not yet implemented -- using simulation" + "API configured but gRPC client not yet implemented -- using simulation" ); } tracing::warn!( diff --git a/bin/fxt/src/commands/config.rs b/bin/fxt/src/commands/config.rs index 9cb6a9457..fa462e73c 100644 --- a/bin/fxt/src/commands/config.rs +++ b/bin/fxt/src/commands/config.rs @@ -257,7 +257,7 @@ impl ConfigCommand { .unwrap_or_else(|| "~/.foxhunt/config.toml".to_owned()); let result = EnvResult { - api_url: config.api_gateway_url, + api_url: config.api_url, config_file: config_path, log_level: config.log_level, token_storage: config.token_storage, diff --git a/bin/fxt/src/config.rs b/bin/fxt/src/config.rs index b97ae31b7..ff87ae747 100644 --- a/bin/fxt/src/config.rs +++ b/bin/fxt/src/config.rs @@ -10,7 +10,7 @@ //! ## Example Config File //! ```toml //! # ~/.foxhunt/config.toml -//! api_gateway_url = "https://api.fxhnt.ai" +//! api_url = "https://api.fxhnt.ai" //! log_level = "info" //! token_storage = "keyring" //! ``` @@ -85,9 +85,9 @@ impl Default for BrokerConfig { /// by CLI arguments or environment variables. #[derive(Debug, Serialize, Deserialize)] pub struct FxtConfig { - /// API Gateway URL (default: ) - #[serde(default = "default_api_gateway_url")] - pub api_gateway_url: String, + /// Unified API URL (default: ) + #[serde(default = "default_api_url", alias = "api_gateway_url")] + pub api_url: String, /// Log level (default: info) #[serde(default = "default_log_level")] @@ -106,7 +106,7 @@ pub struct FxtConfig { pub broker: BrokerConfig, } -fn default_api_gateway_url() -> String { +fn default_api_url() -> String { "https://api.fxhnt.ai".to_owned() } @@ -121,7 +121,7 @@ fn default_token_storage() -> String { impl Default for FxtConfig { fn default() -> Self { Self { - api_gateway_url: default_api_gateway_url(), + api_url: default_api_url(), log_level: default_log_level(), token_storage: default_token_storage(), jwt_secret: None, @@ -141,7 +141,7 @@ impl FxtConfig { /// use fxt::config::FxtConfig; /// /// let config = FxtConfig::load().unwrap(); - /// println!("API Gateway: {}", config.api_gateway_url); + /// println!("API URL: {}", config.api_url); /// ``` pub fn load() -> Result { let config_path = Self::config_path()?; @@ -168,7 +168,7 @@ impl FxtConfig { /// use fxt::config::FxtConfig; /// /// let config = FxtConfig { - /// api_gateway_url: "http://localhost:50051".to_string(), + /// api_url: "http://localhost:50051".to_string(), /// log_level: "debug".to_string(), /// token_storage: "keyring".to_string(), /// jwt_secret: None, @@ -210,7 +210,7 @@ mod tests { fn test_default_config() { // Test that Default trait provides correct values let config = FxtConfig::default(); - assert_eq!(config.api_gateway_url, "https://api.fxhnt.ai"); + assert_eq!(config.api_url, "https://api.fxhnt.ai"); assert_eq!(config.log_level, "info"); assert_eq!(config.token_storage, "keyring"); } @@ -218,7 +218,7 @@ mod tests { #[test] fn test_config_serialization() { let config = FxtConfig { - api_gateway_url: "http://example.com:50051".to_owned(), + api_url: "http://example.com:50051".to_owned(), log_level: "debug".to_owned(), token_storage: "file".to_owned(), jwt_secret: None, @@ -228,7 +228,7 @@ mod tests { let toml_str = toml::to_string(&config).unwrap(); let parsed: FxtConfig = toml::from_str(&toml_str).unwrap(); - assert_eq!(config.api_gateway_url, parsed.api_gateway_url); + assert_eq!(config.api_url, parsed.api_url); assert_eq!(config.log_level, parsed.log_level); assert_eq!(config.token_storage, parsed.token_storage); } @@ -246,15 +246,23 @@ mod tests { // Test that empty TOML string deserializes to defaults let empty_toml = ""; let config: FxtConfig = toml::from_str(empty_toml).unwrap(); - assert_eq!(config.api_gateway_url, "https://api.fxhnt.ai"); + assert_eq!(config.api_url, "https://api.fxhnt.ai"); assert_eq!(config.log_level, "info"); assert_eq!(config.token_storage, "keyring"); } + #[test] + fn test_backwards_compat_alias() { + // Old config files using api_gateway_url must still deserialize correctly. + let toml_str = r#"api_gateway_url = "http://legacy:50051""#; + let config: FxtConfig = toml::from_str(toml_str).unwrap(); + assert_eq!(config.api_url, "http://legacy:50051"); + } + #[test] fn test_config_with_broker_section() { let toml_str = r#" - api_gateway_url = "http://localhost:50051" + api_url = "http://localhost:50051" [broker] gateway_url = "http://broker-gw:50060" diff --git a/bin/fxt/src/tui/cockpits/pods.rs b/bin/fxt/src/tui/cockpits/pods.rs index 82fd2c69b..3a5a14457 100644 --- a/bin/fxt/src/tui/cockpits/pods.rs +++ b/bin/fxt/src/tui/cockpits/pods.rs @@ -54,7 +54,7 @@ impl Cockpit for PodsCockpit { /// Shorten a K8s pod name to its trailing random suffix. /// -/// `api-gateway-7686d84bdd-zl4mn` becomes `zl4mn`. +/// `api-7686d84bdd-zl4mn` becomes `zl4mn`. /// Falls back to the full name if there is no `-` separator. fn shorten_pod_name(name: &str) -> &str { name.rsplit('-').next().unwrap_or(name) diff --git a/bin/fxt/src/tui/data_fetcher.rs b/bin/fxt/src/tui/data_fetcher.rs index d84f24bd8..eaaf3c48d 100644 --- a/bin/fxt/src/tui/data_fetcher.rs +++ b/bin/fxt/src/tui/data_fetcher.rs @@ -1429,14 +1429,14 @@ mod tests { #[test] fn group_pods_groups_by_service() { let pods = vec![ - make_pod("api-1", "api-gateway", true), - make_pod("api-2", "api-gateway", true), + make_pod("api-1", "api", true), + make_pod("api-2", "api", true), make_pod("trade-1", "trading-service", true), make_pod("trade-2", "trading-service", false), ]; let groups = group_pods(pods); assert_eq!(groups.len(), 2); - assert_eq!(groups[0].service, "api-gateway"); + assert_eq!(groups[0].service, "api"); assert_eq!(groups[0].total_count, 2); assert_eq!(groups[0].ready_count, 2); assert_eq!(groups[1].service, "trading-service"); @@ -1448,14 +1448,14 @@ mod tests { fn group_pods_empty_service_becomes_other() { let pods = vec![ make_pod("orphan-1", "", true), - make_pod("api-1", "api-gateway", true), + make_pod("api-1", "api", true), ]; let groups = group_pods(pods); assert_eq!(groups.len(), 2); - // BTreeMap sorts alphabetically: "(other)" < "api-gateway" + // BTreeMap sorts alphabetically: "(other)" < "api" assert_eq!(groups[0].service, "(other)"); assert_eq!(groups[0].total_count, 1); - assert_eq!(groups[1].service, "api-gateway"); + assert_eq!(groups[1].service, "api"); } #[test] diff --git a/bin/fxt/src/tui/event_loop.rs b/bin/fxt/src/tui/event_loop.rs index 06c51f94d..bd164b976 100644 --- a/bin/fxt/src/tui/event_loop.rs +++ b/bin/fxt/src/tui/event_loop.rs @@ -1079,7 +1079,7 @@ mod tests { let mut state = AppState::default(); let services = vec![ ServiceData { - name: "api-gateway".into(), + name: "api".into(), healthy: true, uptime: "5d".into(), version: "v1.0".into(), diff --git a/config/prometheus/prometheus.yml b/config/prometheus/prometheus.yml index aae01c0e4..f256b6167 100644 --- a/config/prometheus/prometheus.yml +++ b/config/prometheus/prometheus.yml @@ -10,15 +10,15 @@ scrape_configs: static_configs: - targets: ['localhost:9090'] - - job_name: 'api_gateway' + - job_name: 'api' static_configs: - - targets: ['api_gateway:9091'] + - targets: ['api:9091'] metrics_path: '/metrics' scrape_interval: 5s relabel_configs: - source_labels: [__address__] target_label: instance - replacement: 'api_gateway' + replacement: 'api' - job_name: 'trading_service' static_configs: diff --git a/config/prometheus/rules/production-alerts.yml b/config/prometheus/rules/production-alerts.yml index 7c444e8ac..d9392e92b 100644 --- a/config/prometheus/rules/production-alerts.yml +++ b/config/prometheus/rules/production-alerts.yml @@ -10,20 +10,20 @@ groups: interval: 15s rules: # P99 Latency > 100ms - CRITICAL - - alert: CriticalP99LatencyAPIGateway + - alert: CriticalP99LatencyAPI expr: | histogram_quantile(0.99, - rate(grpc_server_handling_seconds_bucket{job="api_gateway"}[1m]) + rate(grpc_server_handling_seconds_bucket{job="api"}[1m]) ) > 0.1 for: 1m labels: severity: critical component: latency - service: api_gateway + service: api annotations: - summary: "CRITICAL: API Gateway P99 latency exceeds 100ms" + summary: "CRITICAL: API P99 latency exceeds 100ms" description: | - API Gateway P99 latency is {{ $value | humanizeDuration }} + API P99 latency is {{ $value | humanizeDuration }} Target: < 100ms Current: {{ $value | humanizeDuration }} This impacts all client requests. @@ -69,7 +69,7 @@ groups: # Service Down - CRITICAL - alert: CriticalServiceDown - expr: up{job=~"api_gateway|trading_service|trading_agent_service"} == 0 + expr: up{job=~"api|trading_service|trading_agent_service"} == 0 for: 30s labels: severity: critical @@ -90,22 +90,22 @@ groups: interval: 15s rules: # Error Rate > 1% - WARNING - - alert: HighErrorRateAPIGateway + - alert: HighErrorRateAPI expr: | - sum(rate(grpc_server_handled_total{job="api_gateway",grpc_code!="OK"}[5m])) + sum(rate(grpc_server_handled_total{job="api",grpc_code!="OK"}[5m])) / - sum(rate(grpc_server_handled_total{job="api_gateway"}[5m])) > 0.01 + sum(rate(grpc_server_handled_total{job="api"}[5m])) > 0.01 for: 3m labels: severity: warning component: errors - service: api_gateway + service: api annotations: - summary: "WARNING: API Gateway error rate exceeds 1%" + summary: "WARNING: API error rate exceeds 1%" description: | Error rate: {{ $value | humanizePercentage }} Target: < 1% - Total errors in last 5m: {{ with query "sum(increase(grpc_server_handled_total{job='api_gateway',grpc_code!='OK'}[5m]))" }}{{ . | first | value | humanize }}{{ end }} + Total errors in last 5m: {{ with query "sum(increase(grpc_server_handled_total{job='api',grpc_code!='OK'}[5m]))" }}{{ . | first | value | humanize }}{{ end }} Review error logs immediately. runbook_url: "https://wiki.foxhunt.local/runbooks/high-error-rate" @@ -431,9 +431,9 @@ groups: - alert: DegradedSystemHealth expr: | ( - sum(up{job=~"api_gateway|trading_service|backtesting_service|ml_training_service"}) + sum(up{job=~"api|trading_service|backtesting_service|ml_training_service"}) / - count(up{job=~"api_gateway|trading_service|backtesting_service|ml_training_service"}) + count(up{job=~"api|trading_service|backtesting_service|ml_training_service"}) ) < 0.75 for: 2m labels: diff --git a/config/prometheus/rules/service-health-alerts.yml b/config/prometheus/rules/service-health-alerts.yml index 647d406fe..8716f5d74 100644 --- a/config/prometheus/rules/service-health-alerts.yml +++ b/config/prometheus/rules/service-health-alerts.yml @@ -4,15 +4,15 @@ groups: - name: foxhunt-service-health rules: # Individual Service Health - - alert: APIGatewayDown - expr: up{job="api_gateway"} == 0 + - alert: APIDown + expr: up{job="api"} == 0 for: 1m labels: severity: critical - service: api_gateway + service: api annotations: - summary: "API Gateway is down" - description: "API Gateway has been down for more than 1 minute. All client access is blocked." + summary: "API is down" + description: "API has been down for more than 1 minute. All client access is blocked." - alert: TradingServiceDown expr: up{job="trading_service"} == 0 diff --git a/docker-compose.override.yml b/docker-compose.override.yml index 212110de8..0789f9339 100644 --- a/docker-compose.override.yml +++ b/docker-compose.override.yml @@ -1,7 +1,7 @@ version: '3.8' services: - api_gateway: + api: environment: - JWT_SECRET=YZg5/mpqzH0NehGJXiR1yUgUg74HqdOUj/q9tnVSX+gqZvuzHKI1n0NhL4yP8CkUx7WyrVs3X86OSSxIUA6sxQ== diff --git a/docker-compose.yml b/docker-compose.yml index dea3009ff..0cc871d6a 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -426,11 +426,11 @@ services: restart: unless-stopped # API Gateway - Auth + routing (port 50051) - api_gateway: + api: build: context: . - dockerfile: services/api_gateway/Dockerfile - container_name: foxhunt-api-gateway + dockerfile: services/api/Dockerfile + container_name: foxhunt-api env_file: - .env # Load JWT_SECRET and other config from .env (Wave 147) ports: @@ -446,8 +446,9 @@ services: - BACKTESTING_SERVICE_URL=https://backtesting_service:50053 - ML_TRAINING_SERVICE_URL=https://ml_training_service:50053 - JWT_SECRET=${JWT_SECRET:-dev_secret_key_change_in_production} - - JWT_ISSUER=foxhunt-api-gateway + - JWT_ISSUER=foxhunt-api - JWT_AUDIENCE=foxhunt-services + - CORS_ORIGINS=http://localhost:5173 # TLS Certificate Configuration for Backtesting Service (mTLS) # Using dev CA-signed certificates (matching Backtesting Service CA) - BACKTESTING_TLS_CA_CERT=/tmp/foxhunt/certs/ca/ca-cert.pem diff --git a/infra/k8s/gitlab/tailscale-proxy.yaml b/infra/k8s/gitlab/tailscale-proxy.yaml index 142d80fef..dfbe884d6 100644 --- a/infra/k8s/gitlab/tailscale-proxy.yaml +++ b/infra/k8s/gitlab/tailscale-proxy.yaml @@ -253,7 +253,7 @@ data: ssl_protocols TLSv1.2 TLSv1.3; location / { - grpc_pass grpc://api-gateway.foxhunt.svc.cluster.local:50051; + grpc_pass grpc://api.foxhunt.svc.cluster.local:50051; grpc_read_timeout 3600s; grpc_send_timeout 3600s; grpc_connect_timeout 30s; @@ -271,7 +271,7 @@ data: ssl_protocols TLSv1.2 TLSv1.3; location / { - grpc_pass grpc://api-gateway.foxhunt.svc.cluster.local:50051; + grpc_pass grpc://api.foxhunt.svc.cluster.local:50051; grpc_read_timeout 3600s; grpc_send_timeout 3600s; grpc_connect_timeout 30s; diff --git a/infra/k8s/gpu-overlays/ml-training-service-gpu.yaml b/infra/k8s/gpu-overlays/ml-training-service-gpu.yaml index b4c1aef82..2751c7b7c 100644 --- a/infra/k8s/gpu-overlays/ml-training-service-gpu.yaml +++ b/infra/k8s/gpu-overlays/ml-training-service-gpu.yaml @@ -116,7 +116,7 @@ spec: name: jwt-secret key: secret - name: JWT_ISSUER - value: foxhunt-api-gateway + value: foxhunt-api - name: JWT_AUDIENCE value: foxhunt-services - name: S3_ENDPOINT diff --git a/infra/k8s/gpu-overlays/trading-service-gpu.yaml b/infra/k8s/gpu-overlays/trading-service-gpu.yaml index 938674c43..ea0fbbf9a 100644 --- a/infra/k8s/gpu-overlays/trading-service-gpu.yaml +++ b/infra/k8s/gpu-overlays/trading-service-gpu.yaml @@ -115,7 +115,7 @@ spec: name: jwt-secret key: secret - name: JWT_ISSUER - value: foxhunt-api-gateway + value: foxhunt-api - name: JWT_AUDIENCE value: foxhunt-services - name: QUESTDB_ILP_HOST diff --git a/infra/k8s/jobs/migrate.yaml b/infra/k8s/jobs/migrate.yaml index f1d7755d5..dc39b66a7 100644 --- a/infra/k8s/jobs/migrate.yaml +++ b/infra/k8s/jobs/migrate.yaml @@ -15,7 +15,7 @@ spec: - name: scw-registry containers: - name: migrate - image: rg.fr-par.scw.cloud/foxhunt/api-gateway:latest + image: rg.fr-par.scw.cloud/foxhunt/api:latest command: ["sqlx", "migrate", "run"] env: - name: DB_PASSWORD diff --git a/infra/k8s/network-policies/api-gateway.yaml b/infra/k8s/network-policies/api.yaml similarity index 91% rename from infra/k8s/network-policies/api-gateway.yaml rename to infra/k8s/network-policies/api.yaml index e625eb49c..bb2c9f6e2 100644 --- a/infra/k8s/network-policies/api-gateway.yaml +++ b/infra/k8s/network-policies/api.yaml @@ -1,12 +1,12 @@ apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: - name: api-gateway + name: api namespace: foxhunt spec: podSelector: matchLabels: - app.kubernetes.io/name: api-gateway + app.kubernetes.io/name: api policyTypes: - Ingress - Egress @@ -36,14 +36,6 @@ spec: ports: - protocol: TCP port: 6379 - # Web gateway - - to: - - podSelector: - matchLabels: - app.kubernetes.io/name: web-gateway - ports: - - protocol: TCP - port: 3000 # Downstream gRPC services - to: - podSelector: diff --git a/infra/k8s/network-policies/backtesting-service.yaml b/infra/k8s/network-policies/backtesting-service.yaml index f7870540e..a83e25186 100644 --- a/infra/k8s/network-policies/backtesting-service.yaml +++ b/infra/k8s/network-policies/backtesting-service.yaml @@ -14,7 +14,7 @@ spec: - from: - podSelector: matchLabels: - app.kubernetes.io/name: api-gateway + app.kubernetes.io/name: api ports: - protocol: TCP port: 50053 diff --git a/infra/k8s/network-policies/broker-gateway.yaml b/infra/k8s/network-policies/broker-gateway.yaml index 49fcea889..651012f8b 100644 --- a/infra/k8s/network-policies/broker-gateway.yaml +++ b/infra/k8s/network-policies/broker-gateway.yaml @@ -14,13 +14,10 @@ spec: - from: - podSelector: matchLabels: - app.kubernetes.io/name: api-gateway + app.kubernetes.io/name: api - podSelector: matchLabels: app.kubernetes.io/name: trading-service - - podSelector: - matchLabels: - app.kubernetes.io/name: web-gateway ports: - protocol: TCP port: 50056 diff --git a/infra/k8s/network-policies/data-acquisition-service.yaml b/infra/k8s/network-policies/data-acquisition-service.yaml index 595930573..68b749ec8 100644 --- a/infra/k8s/network-policies/data-acquisition-service.yaml +++ b/infra/k8s/network-policies/data-acquisition-service.yaml @@ -14,7 +14,7 @@ spec: - from: - podSelector: matchLabels: - app.kubernetes.io/name: api-gateway + app.kubernetes.io/name: api ports: - protocol: TCP port: 50057 diff --git a/infra/k8s/network-policies/ml-training-service.yaml b/infra/k8s/network-policies/ml-training-service.yaml index 7d894e030..f629688a5 100644 --- a/infra/k8s/network-policies/ml-training-service.yaml +++ b/infra/k8s/network-policies/ml-training-service.yaml @@ -14,7 +14,7 @@ spec: - from: - podSelector: matchLabels: - app.kubernetes.io/name: api-gateway + app.kubernetes.io/name: api ports: - protocol: TCP port: 50053 diff --git a/infra/k8s/network-policies/trading-agent-service.yaml b/infra/k8s/network-policies/trading-agent-service.yaml index 9aad6f353..78dcc9f19 100644 --- a/infra/k8s/network-policies/trading-agent-service.yaml +++ b/infra/k8s/network-policies/trading-agent-service.yaml @@ -14,7 +14,7 @@ spec: - from: - podSelector: matchLabels: - app.kubernetes.io/name: api-gateway + app.kubernetes.io/name: api ports: - protocol: TCP port: 50055 diff --git a/infra/k8s/network-policies/trading-service.yaml b/infra/k8s/network-policies/trading-service.yaml index 7a7dd964f..e8278e432 100644 --- a/infra/k8s/network-policies/trading-service.yaml +++ b/infra/k8s/network-policies/trading-service.yaml @@ -14,7 +14,7 @@ spec: - from: - podSelector: matchLabels: - app.kubernetes.io/name: api-gateway + app.kubernetes.io/name: api - podSelector: matchLabels: app.kubernetes.io/name: trading-agent-service diff --git a/infra/k8s/network-policies/web-gateway.yaml b/infra/k8s/network-policies/web-gateway.yaml deleted file mode 100644 index 45ec752d0..000000000 --- a/infra/k8s/network-policies/web-gateway.yaml +++ /dev/null @@ -1,69 +0,0 @@ -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: web-gateway - namespace: foxhunt -spec: - podSelector: - matchLabels: - app.kubernetes.io/name: web-gateway - policyTypes: - - Ingress - - Egress - ingress: - - from: - - podSelector: - matchLabels: - app.kubernetes.io/name: api-gateway - - podSelector: - matchLabels: - app.kubernetes.io/name: tailscale-gitlab-proxy - ports: - - protocol: TCP - port: 3000 - egress: - # api-gateway gRPC upstream - - to: - - podSelector: - matchLabels: - app.kubernetes.io/name: api-gateway - ports: - - protocol: TCP - port: 50051 - # Direct gRPC to downstream services - - to: - - podSelector: - matchLabels: - app.kubernetes.io/name: backtesting-service - ports: - - protocol: TCP - port: 50053 - - to: - - podSelector: - matchLabels: - app.kubernetes.io/name: ml-training-service - ports: - - protocol: TCP - port: 50053 - - to: - - podSelector: - matchLabels: - app.kubernetes.io/name: trading-agent-service - ports: - - protocol: TCP - port: 50055 - - to: - - podSelector: - matchLabels: - app.kubernetes.io/name: broker-gateway - ports: - - protocol: TCP - port: 50056 - # Minio (initContainer binary fetch) - - to: - - podSelector: - matchLabels: - app.kubernetes.io/name: minio - ports: - - protocol: TCP - port: 9000 diff --git a/infra/k8s/services/api-gateway.yaml b/infra/k8s/services/api.yaml similarity index 87% rename from infra/k8s/services/api-gateway.yaml rename to infra/k8s/services/api.yaml index 93d4666f6..eccd02573 100644 --- a/infra/k8s/services/api-gateway.yaml +++ b/infra/k8s/services/api.yaml @@ -1,10 +1,10 @@ apiVersion: apps/v1 kind: Deployment metadata: - name: api-gateway + name: api namespace: foxhunt labels: - app.kubernetes.io/name: api-gateway + app.kubernetes.io/name: api app.kubernetes.io/part-of: foxhunt spec: replicas: 1 @@ -15,7 +15,7 @@ spec: maxUnavailable: 1 selector: matchLabels: - app.kubernetes.io/name: api-gateway + app.kubernetes.io/name: api template: metadata: annotations: @@ -23,10 +23,10 @@ spec: gitlab.com/prometheus_port: "9091" gitlab.com/prometheus_path: "/metrics" labels: - app.kubernetes.io/name: api-gateway + app.kubernetes.io/name: api app.kubernetes.io/part-of: foxhunt spec: - serviceAccountName: api-gateway + serviceAccountName: api securityContext: runAsNonRoot: true runAsUser: 1000 @@ -46,16 +46,16 @@ spec: - | set -e rclone copyto \ - ":s3:foxhunt-binaries/services/api-gateway" \ - "/binaries/api-gateway" \ + ":s3:foxhunt-binaries/services/api" \ + "/binaries/api" \ --s3-provider=Minio \ --s3-endpoint=https://minio.foxhunt.svc.cluster.local:9000 \ --s3-access-key-id="${MINIO_ACCESS_KEY}" \ --s3-secret-access-key="${MINIO_SECRET_KEY}" \ --s3-no-check-bucket \ --no-check-certificate - chmod +x /binaries/api-gateway - echo "Fetched api-gateway ($(stat -c%s /binaries/api-gateway) bytes)" + chmod +x /binaries/api + echo "Fetched api ($(stat -c%s /binaries/api) bytes)" env: - name: MINIO_ACCESS_KEY valueFrom: @@ -78,14 +78,14 @@ spec: cpu: 500m memory: 128Mi containers: - - name: api-gateway + - name: api image: rg.fr-par.scw.cloud/foxhunt-ci/foxhunt-runtime:latest securityContext: allowPrivilegeEscalation: false readOnlyRootFilesystem: true capabilities: drop: ["ALL"] - command: ["/binaries/api-gateway"] + command: ["/binaries/api"] ports: - containerPort: 50051 name: grpc @@ -107,7 +107,7 @@ spec: name: jwt-secret key: secret - name: JWT_ISSUER - value: foxhunt-api-gateway + value: foxhunt-api - name: JWT_AUDIENCE value: foxhunt-services - name: TRADING_SERVICE_URL @@ -130,6 +130,8 @@ spec: value: "info,opentelemetry=warn,h2=warn,tonic=warn,hyper=warn" - name: OTEL_EXPORTER_OTLP_ENDPOINT value: "http://tempo.foxhunt.svc.cluster.local:4317" + - name: CORS_ORIGINS + value: "https://dashboard.fxhnt.ai,http://localhost:5173" volumeMounts: - name: binaries mountPath: /binaries @@ -169,14 +171,14 @@ spec: apiVersion: v1 kind: Service metadata: - name: api-gateway + name: api namespace: foxhunt labels: - app.kubernetes.io/name: api-gateway + app.kubernetes.io/name: api app.kubernetes.io/part-of: foxhunt spec: selector: - app.kubernetes.io/name: api-gateway + app.kubernetes.io/name: api ports: - port: 50051 targetPort: 50051 @@ -188,16 +190,16 @@ spec: apiVersion: v1 kind: ServiceAccount metadata: - name: api-gateway + name: api namespace: foxhunt labels: - app.kubernetes.io/name: api-gateway + app.kubernetes.io/name: api app.kubernetes.io/part-of: foxhunt --- apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: - name: api-gateway-pod-reader + name: api-pod-reader namespace: foxhunt rules: - apiGroups: [""] @@ -210,13 +212,13 @@ rules: apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: - name: api-gateway-pod-reader + name: api-pod-reader namespace: foxhunt roleRef: apiGroup: rbac.authorization.k8s.io kind: Role - name: api-gateway-pod-reader + name: api-pod-reader subjects: - kind: ServiceAccount - name: api-gateway + name: api namespace: foxhunt diff --git a/infra/k8s/services/backtesting-service.yaml b/infra/k8s/services/backtesting-service.yaml index a4173be44..da841874c 100644 --- a/infra/k8s/services/backtesting-service.yaml +++ b/infra/k8s/services/backtesting-service.yaml @@ -106,7 +106,7 @@ spec: name: jwt-secret key: secret - name: JWT_ISSUER - value: foxhunt-api-gateway + value: foxhunt-api - name: JWT_AUDIENCE value: foxhunt-services - name: BENZINGA_API_KEY diff --git a/infra/k8s/services/broker-gateway.yaml b/infra/k8s/services/broker-gateway.yaml index 0afa68f49..d2f80493f 100644 --- a/infra/k8s/services/broker-gateway.yaml +++ b/infra/k8s/services/broker-gateway.yaml @@ -106,7 +106,7 @@ spec: name: jwt-secret key: secret - name: JWT_ISSUER - value: foxhunt-api-gateway + value: foxhunt-api - name: JWT_AUDIENCE value: foxhunt-services - name: IBKR_HOST diff --git a/infra/k8s/services/ml-training-service.yaml b/infra/k8s/services/ml-training-service.yaml index b145d4d15..6955e7e10 100644 --- a/infra/k8s/services/ml-training-service.yaml +++ b/infra/k8s/services/ml-training-service.yaml @@ -149,7 +149,7 @@ spec: name: jwt-secret key: secret - name: JWT_ISSUER - value: foxhunt-api-gateway + value: foxhunt-api - name: JWT_AUDIENCE value: foxhunt-services - name: S3_ENDPOINT diff --git a/infra/k8s/services/trading-agent-service.yaml b/infra/k8s/services/trading-agent-service.yaml index 92dfd69c1..a419aead8 100644 --- a/infra/k8s/services/trading-agent-service.yaml +++ b/infra/k8s/services/trading-agent-service.yaml @@ -106,7 +106,7 @@ spec: name: jwt-secret key: secret - name: JWT_ISSUER - value: foxhunt-api-gateway + value: foxhunt-api - name: JWT_AUDIENCE value: foxhunt-services - name: RUST_LOG diff --git a/infra/k8s/services/trading-service.yaml b/infra/k8s/services/trading-service.yaml index d0af79b99..c98e9afab 100644 --- a/infra/k8s/services/trading-service.yaml +++ b/infra/k8s/services/trading-service.yaml @@ -106,7 +106,7 @@ spec: name: jwt-secret key: secret - name: JWT_ISSUER - value: foxhunt-api-gateway + value: foxhunt-api - name: JWT_AUDIENCE value: foxhunt-services - name: QUESTDB_ILP_HOST diff --git a/infra/k8s/services/web-gateway.yaml b/infra/k8s/services/web-gateway.yaml deleted file mode 100644 index 6f99808f2..000000000 --- a/infra/k8s/services/web-gateway.yaml +++ /dev/null @@ -1,161 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - name: web-gateway - namespace: foxhunt - labels: - app.kubernetes.io/name: web-gateway - app.kubernetes.io/part-of: foxhunt -spec: - replicas: 1 - strategy: - type: RollingUpdate - rollingUpdate: - maxSurge: 0 - maxUnavailable: 1 - selector: - matchLabels: - app.kubernetes.io/name: web-gateway - template: - metadata: - annotations: - gitlab.com/prometheus_scrape: "true" - gitlab.com/prometheus_port: "9098" - gitlab.com/prometheus_path: "/metrics" - labels: - app.kubernetes.io/name: web-gateway - app.kubernetes.io/part-of: foxhunt - spec: - securityContext: - runAsNonRoot: true - runAsUser: 1000 - runAsGroup: 1000 - fsGroup: 1000 - seccompProfile: - type: RuntimeDefault - imagePullSecrets: - - name: scw-registry - nodeSelector: - k8s.scaleway.com/pool-name: foxhunt - initContainers: - - name: fetch-binary - image: rg.fr-par.scw.cloud/foxhunt-ci/foxhunt-runtime:latest - command: ["/bin/sh", "-c"] - args: - - | - set -e - RCLONE_FLAGS="--s3-provider=Minio --s3-endpoint=https://minio.foxhunt.svc.cluster.local:9000 --s3-access-key-id=${MINIO_ACCESS_KEY} --s3-secret-access-key=${MINIO_SECRET_KEY} --s3-no-check-bucket --no-check-certificate" - rclone copyto ":s3:foxhunt-binaries/services/web-gateway" "/binaries/web-gateway" $RCLONE_FLAGS - chmod +x /binaries/web-gateway - echo "Fetched web-gateway ($(stat -c%s /binaries/web-gateway) bytes)" - rclone copy ":s3:foxhunt-binaries/static/" "/binaries/static/" $RCLONE_FLAGS - echo "Fetched static assets" - env: - - name: MINIO_ACCESS_KEY - valueFrom: - secretKeyRef: - name: minio-credentials - key: access-key - - name: MINIO_SECRET_KEY - valueFrom: - secretKeyRef: - name: minio-credentials - key: secret-key - volumeMounts: - - name: binaries - mountPath: /binaries - resources: - requests: - cpu: 100m - memory: 64Mi - limits: - cpu: 500m - memory: 256Mi - containers: - - name: web-gateway - image: rg.fr-par.scw.cloud/foxhunt-ci/foxhunt-runtime:latest - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: ["ALL"] - command: ["/binaries/web-gateway"] - ports: - - containerPort: 3000 - name: http - - containerPort: 9098 - name: metrics - env: - - name: JWT_SECRET - valueFrom: - secretKeyRef: - name: jwt-secret - key: secret - - name: TRADING_SERVICE_URL - value: "http://api-gateway:50051" - - name: BACKTESTING_SERVICE_URL - value: "http://backtesting-service:50053" - - name: ML_TRAINING_SERVICE_URL - value: "http://ml-training-service:50053" - - name: TRADING_AGENT_SERVICE_URL - value: "http://trading-agent-service:50055" - - name: BROKER_GATEWAY_SERVICE_URL - value: "http://broker-gateway:50056" - - name: API_GATEWAY_URL - value: "http://api-gateway:50051" - - name: RUST_LOG - value: "info,opentelemetry=warn,h2=warn,tonic=warn,hyper=warn" - - name: OTEL_EXPORTER_OTLP_ENDPOINT - value: "http://tempo.foxhunt.svc.cluster.local:4317" - volumeMounts: - - name: binaries - mountPath: /binaries - readOnly: true - - name: tmp - mountPath: /tmp - readinessProbe: - httpGet: - path: /health - port: 3000 - initialDelaySeconds: 10 - periodSeconds: 10 - livenessProbe: - httpGet: - path: /health - port: 3000 - initialDelaySeconds: 30 - periodSeconds: 15 - failureThreshold: 5 - resources: - requests: - cpu: 100m - memory: 128Mi - limits: - cpu: 250m - memory: 256Mi - volumes: - - name: binaries - emptyDir: - sizeLimit: 500Mi - - name: tmp - emptyDir: - sizeLimit: 50Mi ---- -apiVersion: v1 -kind: Service -metadata: - name: web-gateway - namespace: foxhunt - labels: - app.kubernetes.io/name: web-gateway - app.kubernetes.io/part-of: foxhunt -spec: - selector: - app.kubernetes.io/name: web-gateway - ports: - - port: 3000 - targetPort: 3000 - name: http - - port: 9098 - targetPort: 9098 - name: metrics diff --git a/infra/scripts/build-and-push.sh b/infra/scripts/build-and-push.sh index 6ed567e17..ec428401e 100755 --- a/infra/scripts/build-and-push.sh +++ b/infra/scripts/build-and-push.sh @@ -23,7 +23,7 @@ TIMESTAMP=$(date -u +"%Y%m%d-%H%M%S") # Services built with Dockerfile.service (--build-arg SERVICE=) STANDARD_SERVICES=( - api-gateway + api trading-service trading-agent-service ml-training-service @@ -37,7 +37,6 @@ DRY_RUN=false PARALLEL=1 SELECTED_SERVICES=() SKIP_STANDARD=false -SKIP_WEBGW=false SKIP_TRAINING=false TAG_LATEST=true @@ -49,7 +48,6 @@ Options: --no-push Build only, don't push to registry --dry-run Show what would be built --services "s1 s2" Build only these standard services - --skip-webgw Skip web-gateway build --skip-training Skip training image build --parallel N Run N builds concurrently (default: 1) --no-latest Don't tag images as :latest @@ -62,7 +60,6 @@ while [[ $# -gt 0 ]]; do --no-push) DO_PUSH=false; shift ;; --dry-run) DRY_RUN=true; shift ;; --services) IFS=' ' read -ra SELECTED_SERVICES <<< "$2"; shift 2 ;; - --skip-webgw) SKIP_WEBGW=true; shift ;; --skip-training) SKIP_TRAINING=true; shift ;; --parallel) PARALLEL="$2"; shift 2 ;; --no-latest) TAG_LATEST=false; shift ;; @@ -74,7 +71,6 @@ done # If --services was given, use only those; otherwise use all standard services if [[ ${#SELECTED_SERVICES[@]} -gt 0 ]]; then SERVICES=("${SELECTED_SERVICES[@]}") - SKIP_WEBGW=true SKIP_TRAINING=true else SERVICES=("${STANDARD_SERVICES[@]}") @@ -195,16 +191,6 @@ else done fi -# --------------------------------------------------------------------------- -# Build web-gateway (Dockerfile.web-gateway) -# --------------------------------------------------------------------------- - -if [[ "$SKIP_WEBGW" != "true" ]]; then - echo "" - echo "--- Web Gateway ---" - build_and_tag "web-gateway" "infra/docker/Dockerfile.web-gateway" || true -fi - # --------------------------------------------------------------------------- # Build training image (Dockerfile.training) # --------------------------------------------------------------------------- @@ -227,10 +213,6 @@ if [[ "$DO_PUSH" == "true" ]]; then push_image "$svc" done - if [[ "$SKIP_WEBGW" != "true" ]]; then - push_image "web-gateway" - fi - if [[ "$SKIP_TRAINING" != "true" ]]; then push_image "training" fi diff --git a/infra/scripts/smoke-test.sh b/infra/scripts/smoke-test.sh index e0a62121f..9921c4343 100755 --- a/infra/scripts/smoke-test.sh +++ b/infra/scripts/smoke-test.sh @@ -87,23 +87,23 @@ check "QuestDB HTTP health" \ " # --- 4. Services ---------------------------------------------------------- -section "Services (gRPC + web-gateway)" +section "Services (gRPC + API gateway)" for svc in "${GRPC_SERVICES[@]}"; do check "Pod '${svc}' is Running" \ bash -c "kubectl -n ${NAMESPACE} get pods -l app=${svc} --field-selector=status.phase=Running --no-headers 2>/dev/null | grep -q ." done -check "Pod 'web-gateway' is Running" \ - bash -c "kubectl -n ${NAMESPACE} get pods -l app=web-gateway --field-selector=status.phase=Running --no-headers 2>/dev/null | grep -q ." +check "Pod 'api' is Running" \ + bash -c "kubectl -n ${NAMESPACE} get pods -l app=api --field-selector=status.phase=Running --no-headers 2>/dev/null | grep -q ." -# --- 5. Web gateway health ------------------------------------------------ -section "Web Gateway Health" +# --- 5. API gateway health ------------------------------------------------ +section "API Gateway Health" -check "web-gateway /health returns 200" \ +check "api /health returns 200" \ bash -c " - CLUSTER_IP=\$(kubectl -n ${NAMESPACE} get svc web-gateway -o jsonpath='{.spec.clusterIP}' 2>/dev/null) - PORT=\$(kubectl -n ${NAMESPACE} get svc web-gateway -o jsonpath='{.spec.ports[0].port}' 2>/dev/null) + CLUSTER_IP=\$(kubectl -n ${NAMESPACE} get svc api -o jsonpath='{.spec.clusterIP}' 2>/dev/null) + PORT=\$(kubectl -n ${NAMESPACE} get svc api -o jsonpath='{.spec.ports[0].port}' 2>/dev/null) kubectl -n ${NAMESPACE} run smoke-curl --rm -i --restart=Never --image=curlimages/curl -- \ curl -sf http://\${CLUSTER_IP}:\${PORT}/health " diff --git a/scripts/enforce_coverage.sh b/scripts/enforce_coverage.sh index e99d9ad2c..00cbb76bd 100755 --- a/scripts/enforce_coverage.sh +++ b/scripts/enforce_coverage.sh @@ -29,7 +29,7 @@ PRODUCTION_MODULES=( "config" "common" "services/trading_service" - "services/api_gateway" + "services/api" ) # Print colored message diff --git a/scripts/generate_dev_certs.sh b/scripts/generate_dev_certs.sh index 4ef03c802..0de3a8efb 100755 --- a/scripts/generate_dev_certs.sh +++ b/scripts/generate_dev_certs.sh @@ -72,7 +72,7 @@ DNS.1 = localhost DNS.2 = trading.foxhunt.local DNS.3 = backtesting.foxhunt.local DNS.4 = ml-training.foxhunt.local -DNS.5 = api-gateway.foxhunt.local +DNS.5 = api.foxhunt.local IP.1 = 127.0.0.1 IP.2 = 0.0.0.0 EOF