diff --git a/.github/actions/redeploy-ecs-service/action.yml b/.github/actions/redeploy-ecs-service/action.yml new file mode 100644 index 00000000000..b459d94b6c4 --- /dev/null +++ b/.github/actions/redeploy-ecs-service/action.yml @@ -0,0 +1,48 @@ +name: Redeploy ECS service +description: Force a new ECS service deployment with optional role assumption + +inputs: + AWS_ACCESS_KEY_ID: + description: AWS access key id + required: true + AWS_SECRET_ACCESS_KEY: + description: AWS secret access key + required: true + AWS_SESSION_TOKEN: + description: AWS session token + required: true + AWS_REGION: + description: AWS region + required: true + ECS_CLUSTER_NAME: + description: ECS cluster name + required: true + ECS_SERVICE_NAME: + description: ECS service name + required: true + ROLE_ARN: + description: IAM role ARN to assume for deployment (cross-account) + required: false + +runs: + using: composite + steps: + - name: Configure AWS credentials + uses: aws-actions/configure-aws-credentials@7474bc4690e29a8392af63c5b98e7449536d5c3a # v4.3.1 + with: + aws-access-key-id: ${{ inputs.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: ${{ inputs.AWS_SECRET_ACCESS_KEY }} + aws-session-token: ${{ inputs.AWS_SESSION_TOKEN }} + aws-region: ${{ inputs.AWS_REGION }} + role-to-assume: ${{ inputs.ROLE_ARN }} + + - name: Redeploy ECS service + env: + ECS_CLUSTER_NAME: ${{ inputs.ECS_CLUSTER_NAME }} + ECS_SERVICE_NAME: ${{ inputs.ECS_SERVICE_NAME }} + shell: bash + run: | + aws ecs update-service \ + --cluster "${ECS_CLUSTER_NAME}" \ + --service "${ECS_SERVICE_NAME}" \ + --force-new-deployment 1> /dev/null diff --git a/.github/workflows/hash-backend-cd.yml b/.github/workflows/hash-backend-cd.yml index db368ab4d2b..64fab96b4b6 100644 --- a/.github/workflows/hash-backend-cd.yml +++ b/.github/workflows/hash-backend-cd.yml @@ -49,6 +49,37 @@ env: HASH_TEMPORAL_ECS_CLUSTER_NAME: h-temporal-prod-usea1-ecs HASH_TEMPORAL_SERVICE_NAME: h-temporal-prod-usea1-svc + STAGING_AWS_REGION: eu-central-1 + STAGING_APP_CLUSTER_NAME: h-stage-euc1-app + STAGING_APP_DEPLOY_ROLE_ARN: arn:aws:iam::054238437032:role/h-stage-euc1-app-deploy + STAGING_APP_GRAPH_SERVICE_NAME: h-stage-euc1-app-graph + STAGING_APP_GRAPH_TEST_SERVICE_NAME: h-stage-euc1-app-graph-test + STAGING_APP_TYPE_FETCHER_SERVICE_NAME: h-stage-euc1-app-type-fetcher + STAGING_APP_API_SERVICE_NAME: h-stage-euc1-app-api + STAGING_WORKER_CLUSTER_NAME: h-stage-euc1-worker + STAGING_WORKER_DEPLOY_ROLE_ARN: arn:aws:iam::054238437032:role/h-stage-euc1-worker-deploy + STAGING_WORKER_AI_TS_SERVICE_NAME: h-stage-euc1-worker-ai-ts + STAGING_WORKER_INTEGRATION_SERVICE_NAME: h-stage-euc1-worker-integration + STAGING_AUTH_CLUSTER_NAME: h-stage-euc1-auth + STAGING_AUTH_DEPLOY_ROLE_ARN: arn:aws:iam::054238437032:role/h-stage-euc1-auth-deploy + STAGING_AUTH_KRATOS_SERVICE_NAME: h-stage-euc1-auth-kratos + STAGING_AUTH_HYDRA_SERVICE_NAME: h-stage-euc1-auth-hydra + + PRODUCTION_AWS_REGION: eu-central-1 + PRODUCTION_APP_CLUSTER_NAME: h-prod-euc1-app + PRODUCTION_APP_DEPLOY_ROLE_ARN: arn:aws:iam::597482567121:role/h-prod-euc1-app-deploy + PRODUCTION_APP_GRAPH_SERVICE_NAME: h-prod-euc1-app-graph + PRODUCTION_APP_TYPE_FETCHER_SERVICE_NAME: h-prod-euc1-app-type-fetcher + PRODUCTION_APP_API_SERVICE_NAME: h-prod-euc1-app-api + PRODUCTION_WORKER_CLUSTER_NAME: h-prod-euc1-worker + PRODUCTION_WORKER_DEPLOY_ROLE_ARN: arn:aws:iam::597482567121:role/h-prod-euc1-worker-deploy + PRODUCTION_WORKER_AI_TS_SERVICE_NAME: h-prod-euc1-worker-ai-ts + PRODUCTION_WORKER_INTEGRATION_SERVICE_NAME: h-prod-euc1-worker-integration + PRODUCTION_AUTH_CLUSTER_NAME: h-prod-euc1-auth + PRODUCTION_AUTH_DEPLOY_ROLE_ARN: arn:aws:iam::597482567121:role/h-prod-euc1-auth-deploy + PRODUCTION_AUTH_KRATOS_SERVICE_NAME: h-prod-euc1-auth-kratos + PRODUCTION_AUTH_HYDRA_SERVICE_NAME: h-prod-euc1-auth-hydra + name: HASH backend deployment jobs: build-graph: @@ -104,6 +135,8 @@ jobs: ROLE_ARN: ${{ env.ARTIFACTS_ECR_ROLE_ARN }} IMAGE_NAME: ${{ github.repository }}/graph GITHUB_TOKEN: ${{ github.token }} + BUILD_ARGS: | + ENABLE_TEST_SERVER=yes build-api: name: Build and push HASH api image @@ -431,24 +464,6 @@ jobs: BUILD_ARGS: | TEMPORAL_VERSION=${{ env.HASH_TEMPORAL_VERSION }} - - name: Push to artifacts ECR - uses: ./.github/actions/docker-build-push - with: - SHORTNAME: "temporal-migrate" - CONTEXT_PATH: ${{ github.workspace }}/apps/hash-external-services/temporal - DOCKERFILE_LOCATION: ${{ github.workspace }}/apps/hash-external-services/temporal/migrate.Dockerfile - AWS_ACCESS_KEY_ID: ${{ steps.secrets.outputs.AWS_ACCESS_KEY_ID }} - AWS_SECRET_ACCESS_KEY: ${{ steps.secrets.outputs.AWS_SECRET_ACCESS_KEY }} - AWS_SESSION_TOKEN: ${{ steps.secrets.outputs.AWS_SESSION_TOKEN }} - AWS_REGION: ${{ env.ARTIFACTS_AWS_REGION }} - AWS_ECR_URL: ${{ env.ARTIFACTS_ECR_URL }} - ROLE_ARN: ${{ env.ARTIFACTS_ECR_ROLE_ARN }} - IMAGE_NAME: ${{ github.repository }}/temporal-migrate - GITHUB_TOKEN: ${{ github.token }} - IMAGE_TAG: ${{ env.HASH_TEMPORAL_VERSION }} - BUILD_ARGS: | - TEMPORAL_VERSION=${{ env.HASH_TEMPORAL_VERSION }} - build-temporal-setup: name: Build and push Temporal Setup image runs-on: ubuntu-24.04-arm @@ -491,24 +506,6 @@ jobs: BUILD_ARGS: | TEMPORAL_VERSION=${{ env.HASH_TEMPORAL_VERSION }} - - name: Push to artifacts ECR - uses: ./.github/actions/docker-build-push - with: - SHORTNAME: "temporal-setup" - CONTEXT_PATH: ${{ github.workspace }}/apps/hash-external-services/temporal - DOCKERFILE_LOCATION: ${{ github.workspace }}/apps/hash-external-services/temporal/setup.Dockerfile - AWS_ACCESS_KEY_ID: ${{ steps.secrets.outputs.AWS_ACCESS_KEY_ID }} - AWS_SECRET_ACCESS_KEY: ${{ steps.secrets.outputs.AWS_SECRET_ACCESS_KEY }} - AWS_SESSION_TOKEN: ${{ steps.secrets.outputs.AWS_SESSION_TOKEN }} - AWS_REGION: ${{ env.ARTIFACTS_AWS_REGION }} - AWS_ECR_URL: ${{ env.ARTIFACTS_ECR_URL }} - ROLE_ARN: ${{ env.ARTIFACTS_ECR_ROLE_ARN }} - IMAGE_NAME: ${{ github.repository }}/temporal-setup - GITHUB_TOKEN: ${{ github.token }} - IMAGE_TAG: ${{ env.HASH_TEMPORAL_VERSION }} - BUILD_ARGS: | - TEMPORAL_VERSION=${{ env.HASH_TEMPORAL_VERSION }} - deploy-graph: name: Deploy HASH graph images runs-on: ubuntu-latest @@ -535,16 +532,70 @@ jobs: aws/creds/prod-deploy secret_key | AWS_SECRET_ACCESS_KEY ; aws/creds/prod-deploy security_token | AWS_SESSION_TOKEN - - uses: ./.github/actions/docker-ecr-login + - name: Redeploy service + uses: ./.github/actions/redeploy-ecs-service with: AWS_ACCESS_KEY_ID: ${{ steps.secrets.outputs.AWS_ACCESS_KEY_ID }} AWS_SECRET_ACCESS_KEY: ${{ steps.secrets.outputs.AWS_SECRET_ACCESS_KEY }} AWS_SESSION_TOKEN: ${{ steps.secrets.outputs.AWS_SESSION_TOKEN }} AWS_REGION: ${{ env.AWS_REGION }} + ECS_CLUSTER_NAME: ${{ env.HASH_ECS_CLUSTER_NAME }} + ECS_SERVICE_NAME: ${{ env.HASH_GRAPH_SERVICE_NAME }} - - name: Redeploy HASH graph service - run: | - aws ecs update-service --cluster ${{ env.HASH_ECS_CLUSTER_NAME }} --service ${{ env.HASH_GRAPH_SERVICE_NAME }} --force-new-deployment 1> /dev/null + - name: Redeploy graph staging service + uses: ./.github/actions/redeploy-ecs-service + with: + AWS_ACCESS_KEY_ID: ${{ steps.secrets.outputs.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ steps.secrets.outputs.AWS_SECRET_ACCESS_KEY }} + AWS_SESSION_TOKEN: ${{ steps.secrets.outputs.AWS_SESSION_TOKEN }} + AWS_REGION: ${{ env.STAGING_AWS_REGION }} + ECS_CLUSTER_NAME: ${{ env.STAGING_APP_CLUSTER_NAME }} + ECS_SERVICE_NAME: ${{ env.STAGING_APP_GRAPH_SERVICE_NAME }} + ROLE_ARN: ${{ env.STAGING_APP_DEPLOY_ROLE_ARN }} + + - name: Redeploy graph-test staging service + uses: ./.github/actions/redeploy-ecs-service + with: + AWS_ACCESS_KEY_ID: ${{ steps.secrets.outputs.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ steps.secrets.outputs.AWS_SECRET_ACCESS_KEY }} + AWS_SESSION_TOKEN: ${{ steps.secrets.outputs.AWS_SESSION_TOKEN }} + AWS_REGION: ${{ env.STAGING_AWS_REGION }} + ECS_CLUSTER_NAME: ${{ env.STAGING_APP_CLUSTER_NAME }} + ECS_SERVICE_NAME: ${{ env.STAGING_APP_GRAPH_TEST_SERVICE_NAME }} + ROLE_ARN: ${{ env.STAGING_APP_DEPLOY_ROLE_ARN }} + + - name: Redeploy type-fetcher staging service + uses: ./.github/actions/redeploy-ecs-service + with: + AWS_ACCESS_KEY_ID: ${{ steps.secrets.outputs.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ steps.secrets.outputs.AWS_SECRET_ACCESS_KEY }} + AWS_SESSION_TOKEN: ${{ steps.secrets.outputs.AWS_SESSION_TOKEN }} + AWS_REGION: ${{ env.STAGING_AWS_REGION }} + ECS_CLUSTER_NAME: ${{ env.STAGING_APP_CLUSTER_NAME }} + ECS_SERVICE_NAME: ${{ env.STAGING_APP_TYPE_FETCHER_SERVICE_NAME }} + ROLE_ARN: ${{ env.STAGING_APP_DEPLOY_ROLE_ARN }} + + - name: Redeploy graph production service + uses: ./.github/actions/redeploy-ecs-service + with: + AWS_ACCESS_KEY_ID: ${{ steps.secrets.outputs.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ steps.secrets.outputs.AWS_SECRET_ACCESS_KEY }} + AWS_SESSION_TOKEN: ${{ steps.secrets.outputs.AWS_SESSION_TOKEN }} + AWS_REGION: ${{ env.PRODUCTION_AWS_REGION }} + ECS_CLUSTER_NAME: ${{ env.PRODUCTION_APP_CLUSTER_NAME }} + ECS_SERVICE_NAME: ${{ env.PRODUCTION_APP_GRAPH_SERVICE_NAME }} + ROLE_ARN: ${{ env.PRODUCTION_APP_DEPLOY_ROLE_ARN }} + + - name: Redeploy type-fetcher production service + uses: ./.github/actions/redeploy-ecs-service + with: + AWS_ACCESS_KEY_ID: ${{ steps.secrets.outputs.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ steps.secrets.outputs.AWS_SECRET_ACCESS_KEY }} + AWS_SESSION_TOKEN: ${{ steps.secrets.outputs.AWS_SESSION_TOKEN }} + AWS_REGION: ${{ env.PRODUCTION_AWS_REGION }} + ECS_CLUSTER_NAME: ${{ env.PRODUCTION_APP_CLUSTER_NAME }} + ECS_SERVICE_NAME: ${{ env.PRODUCTION_APP_TYPE_FETCHER_SERVICE_NAME }} + ROLE_ARN: ${{ env.PRODUCTION_APP_DEPLOY_ROLE_ARN }} deploy-app: name: Deploy HASH app images @@ -576,16 +627,81 @@ jobs: aws/creds/prod-deploy secret_key | AWS_SECRET_ACCESS_KEY ; aws/creds/prod-deploy security_token | AWS_SESSION_TOKEN - - uses: ./.github/actions/docker-ecr-login + - name: Redeploy service + uses: ./.github/actions/redeploy-ecs-service with: AWS_ACCESS_KEY_ID: ${{ steps.secrets.outputs.AWS_ACCESS_KEY_ID }} AWS_SECRET_ACCESS_KEY: ${{ steps.secrets.outputs.AWS_SECRET_ACCESS_KEY }} AWS_SESSION_TOKEN: ${{ steps.secrets.outputs.AWS_SESSION_TOKEN }} AWS_REGION: ${{ env.AWS_REGION }} + ECS_CLUSTER_NAME: ${{ env.HASH_ECS_CLUSTER_NAME }} + ECS_SERVICE_NAME: ${{ env.HASH_APP_SERVICE_NAME }} + + - name: Redeploy API staging service + uses: ./.github/actions/redeploy-ecs-service + with: + AWS_ACCESS_KEY_ID: ${{ steps.secrets.outputs.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ steps.secrets.outputs.AWS_SECRET_ACCESS_KEY }} + AWS_SESSION_TOKEN: ${{ steps.secrets.outputs.AWS_SESSION_TOKEN }} + AWS_REGION: ${{ env.STAGING_AWS_REGION }} + ECS_CLUSTER_NAME: ${{ env.STAGING_APP_CLUSTER_NAME }} + ECS_SERVICE_NAME: ${{ env.STAGING_APP_API_SERVICE_NAME }} + ROLE_ARN: ${{ env.STAGING_APP_DEPLOY_ROLE_ARN }} + + - name: Redeploy kratos staging service + uses: ./.github/actions/redeploy-ecs-service + with: + AWS_ACCESS_KEY_ID: ${{ steps.secrets.outputs.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ steps.secrets.outputs.AWS_SECRET_ACCESS_KEY }} + AWS_SESSION_TOKEN: ${{ steps.secrets.outputs.AWS_SESSION_TOKEN }} + AWS_REGION: ${{ env.STAGING_AWS_REGION }} + ECS_CLUSTER_NAME: ${{ env.STAGING_AUTH_CLUSTER_NAME }} + ECS_SERVICE_NAME: ${{ env.STAGING_AUTH_KRATOS_SERVICE_NAME }} + ROLE_ARN: ${{ env.STAGING_AUTH_DEPLOY_ROLE_ARN }} + + - name: Redeploy hydra staging service + uses: ./.github/actions/redeploy-ecs-service + with: + AWS_ACCESS_KEY_ID: ${{ steps.secrets.outputs.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ steps.secrets.outputs.AWS_SECRET_ACCESS_KEY }} + AWS_SESSION_TOKEN: ${{ steps.secrets.outputs.AWS_SESSION_TOKEN }} + AWS_REGION: ${{ env.STAGING_AWS_REGION }} + ECS_CLUSTER_NAME: ${{ env.STAGING_AUTH_CLUSTER_NAME }} + ECS_SERVICE_NAME: ${{ env.STAGING_AUTH_HYDRA_SERVICE_NAME }} + ROLE_ARN: ${{ env.STAGING_AUTH_DEPLOY_ROLE_ARN }} + + - name: Redeploy API production service + uses: ./.github/actions/redeploy-ecs-service + with: + AWS_ACCESS_KEY_ID: ${{ steps.secrets.outputs.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ steps.secrets.outputs.AWS_SECRET_ACCESS_KEY }} + AWS_SESSION_TOKEN: ${{ steps.secrets.outputs.AWS_SESSION_TOKEN }} + AWS_REGION: ${{ env.PRODUCTION_AWS_REGION }} + ECS_CLUSTER_NAME: ${{ env.PRODUCTION_APP_CLUSTER_NAME }} + ECS_SERVICE_NAME: ${{ env.PRODUCTION_APP_API_SERVICE_NAME }} + ROLE_ARN: ${{ env.PRODUCTION_APP_DEPLOY_ROLE_ARN }} + + - name: Redeploy kratos production service + uses: ./.github/actions/redeploy-ecs-service + with: + AWS_ACCESS_KEY_ID: ${{ steps.secrets.outputs.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ steps.secrets.outputs.AWS_SECRET_ACCESS_KEY }} + AWS_SESSION_TOKEN: ${{ steps.secrets.outputs.AWS_SESSION_TOKEN }} + AWS_REGION: ${{ env.PRODUCTION_AWS_REGION }} + ECS_CLUSTER_NAME: ${{ env.PRODUCTION_AUTH_CLUSTER_NAME }} + ECS_SERVICE_NAME: ${{ env.PRODUCTION_AUTH_KRATOS_SERVICE_NAME }} + ROLE_ARN: ${{ env.PRODUCTION_AUTH_DEPLOY_ROLE_ARN }} - - name: Redeploy HASH backend service - run: | - aws ecs update-service --cluster ${{ env.HASH_ECS_CLUSTER_NAME }} --service ${{ env.HASH_APP_SERVICE_NAME }} --force-new-deployment 1> /dev/null + - name: Redeploy hydra production service + uses: ./.github/actions/redeploy-ecs-service + with: + AWS_ACCESS_KEY_ID: ${{ steps.secrets.outputs.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ steps.secrets.outputs.AWS_SECRET_ACCESS_KEY }} + AWS_SESSION_TOKEN: ${{ steps.secrets.outputs.AWS_SESSION_TOKEN }} + AWS_REGION: ${{ env.PRODUCTION_AWS_REGION }} + ECS_CLUSTER_NAME: ${{ env.PRODUCTION_AUTH_CLUSTER_NAME }} + ECS_SERVICE_NAME: ${{ env.PRODUCTION_AUTH_HYDRA_SERVICE_NAME }} + ROLE_ARN: ${{ env.PRODUCTION_AUTH_DEPLOY_ROLE_ARN }} deploy-workers: name: Deploy HASH worker images @@ -616,16 +732,59 @@ jobs: aws/creds/prod-deploy secret_key | AWS_SECRET_ACCESS_KEY ; aws/creds/prod-deploy security_token | AWS_SESSION_TOKEN - - uses: ./.github/actions/docker-ecr-login + - name: Redeploy service + uses: ./.github/actions/redeploy-ecs-service with: AWS_ACCESS_KEY_ID: ${{ steps.secrets.outputs.AWS_ACCESS_KEY_ID }} AWS_SECRET_ACCESS_KEY: ${{ steps.secrets.outputs.AWS_SECRET_ACCESS_KEY }} AWS_SESSION_TOKEN: ${{ steps.secrets.outputs.AWS_SESSION_TOKEN }} AWS_REGION: ${{ env.AWS_REGION }} + ECS_CLUSTER_NAME: ${{ env.HASH_ECS_CLUSTER_NAME }} + ECS_SERVICE_NAME: ${{ env.HASH_WORKER_SERVICE_NAME }} - - name: Redeploy HASH worker service - run: | - aws ecs update-service --cluster ${{ env.HASH_ECS_CLUSTER_NAME }} --service ${{ env.HASH_WORKER_SERVICE_NAME }} --force-new-deployment 1> /dev/null + - name: Redeploy AI-TS staging service + uses: ./.github/actions/redeploy-ecs-service + with: + AWS_ACCESS_KEY_ID: ${{ steps.secrets.outputs.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ steps.secrets.outputs.AWS_SECRET_ACCESS_KEY }} + AWS_SESSION_TOKEN: ${{ steps.secrets.outputs.AWS_SESSION_TOKEN }} + AWS_REGION: ${{ env.STAGING_AWS_REGION }} + ECS_CLUSTER_NAME: ${{ env.STAGING_WORKER_CLUSTER_NAME }} + ECS_SERVICE_NAME: ${{ env.STAGING_WORKER_AI_TS_SERVICE_NAME }} + ROLE_ARN: ${{ env.STAGING_WORKER_DEPLOY_ROLE_ARN }} + + - name: Redeploy Integration staging service + uses: ./.github/actions/redeploy-ecs-service + with: + AWS_ACCESS_KEY_ID: ${{ steps.secrets.outputs.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ steps.secrets.outputs.AWS_SECRET_ACCESS_KEY }} + AWS_SESSION_TOKEN: ${{ steps.secrets.outputs.AWS_SESSION_TOKEN }} + AWS_REGION: ${{ env.STAGING_AWS_REGION }} + ECS_CLUSTER_NAME: ${{ env.STAGING_WORKER_CLUSTER_NAME }} + ECS_SERVICE_NAME: ${{ env.STAGING_WORKER_INTEGRATION_SERVICE_NAME }} + ROLE_ARN: ${{ env.STAGING_WORKER_DEPLOY_ROLE_ARN }} + + - name: Redeploy AI-TS production service + uses: ./.github/actions/redeploy-ecs-service + with: + AWS_ACCESS_KEY_ID: ${{ steps.secrets.outputs.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ steps.secrets.outputs.AWS_SECRET_ACCESS_KEY }} + AWS_SESSION_TOKEN: ${{ steps.secrets.outputs.AWS_SESSION_TOKEN }} + AWS_REGION: ${{ env.PRODUCTION_AWS_REGION }} + ECS_CLUSTER_NAME: ${{ env.PRODUCTION_WORKER_CLUSTER_NAME }} + ECS_SERVICE_NAME: ${{ env.PRODUCTION_WORKER_AI_TS_SERVICE_NAME }} + ROLE_ARN: ${{ env.PRODUCTION_WORKER_DEPLOY_ROLE_ARN }} + + - name: Redeploy Integration production service + uses: ./.github/actions/redeploy-ecs-service + with: + AWS_ACCESS_KEY_ID: ${{ steps.secrets.outputs.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ steps.secrets.outputs.AWS_SECRET_ACCESS_KEY }} + AWS_SESSION_TOKEN: ${{ steps.secrets.outputs.AWS_SESSION_TOKEN }} + AWS_REGION: ${{ env.PRODUCTION_AWS_REGION }} + ECS_CLUSTER_NAME: ${{ env.PRODUCTION_WORKER_CLUSTER_NAME }} + ECS_SERVICE_NAME: ${{ env.PRODUCTION_WORKER_INTEGRATION_SERVICE_NAME }} + ROLE_ARN: ${{ env.PRODUCTION_WORKER_DEPLOY_ROLE_ARN }} deploy-temporal: name: Deploy Temporal images @@ -654,16 +813,15 @@ jobs: aws/creds/prod-deploy secret_key | AWS_SECRET_ACCESS_KEY ; aws/creds/prod-deploy security_token | AWS_SESSION_TOKEN - - uses: ./.github/actions/docker-ecr-login + - name: Redeploy service + uses: ./.github/actions/redeploy-ecs-service with: AWS_ACCESS_KEY_ID: ${{ steps.secrets.outputs.AWS_ACCESS_KEY_ID }} AWS_SECRET_ACCESS_KEY: ${{ steps.secrets.outputs.AWS_SECRET_ACCESS_KEY }} AWS_SESSION_TOKEN: ${{ steps.secrets.outputs.AWS_SESSION_TOKEN }} AWS_REGION: ${{ env.AWS_REGION }} - - - name: Redeploy Temporal service - run: | - aws ecs update-service --cluster ${{ env.HASH_TEMPORAL_ECS_CLUSTER_NAME }} --service ${{ env.HASH_TEMPORAL_SERVICE_NAME }} --force-new-deployment 1> /dev/null + ECS_CLUSTER_NAME: ${{ env.HASH_TEMPORAL_ECS_CLUSTER_NAME }} + ECS_SERVICE_NAME: ${{ env.HASH_TEMPORAL_SERVICE_NAME }} notify-slack: name: Notify Slack on failure diff --git a/apps/hash-graph/package.json b/apps/hash-graph/package.json index 0d10d62af37..e7f9b4533b8 100644 --- a/apps/hash-graph/package.json +++ b/apps/hash-graph/package.json @@ -4,8 +4,8 @@ "private": true, "license": "AGPL-3", "scripts": { - "build:docker": "docker buildx build --build-arg PROFILE=production --tag hash-graph --file docker/Dockerfile ../../ --load", - "build:docker:dev": "docker buildx build --build-arg PROFILE=dev --tag hash-graph --file docker/Dockerfile ../../ --load", + "build:docker": "docker buildx build --build-arg PROFILE=production --build-arg ENABLE_TEST_SERVER=yes --tag hash-graph --file docker/Dockerfile ../../ --load", + "build:docker:dev": "docker buildx build --build-arg PROFILE=dev --build-arg ENABLE_TEST_SERVER=yes --tag hash-graph --file docker/Dockerfile ../../ --load", "compile": "cargo build --bin hash-graph --all-features", "compile:release": "cargo build --bin hash-graph --all-features --release", "doc:dependency-diagram": "cargo run -p hash-repo-chores -- dependency-diagram --output docs/dependency-diagram.mmd --root hash-graph --root-deps-and-dependents --link-mode non-roots --include-dev-deps --include-build-deps --logging-console-level info", diff --git a/apps/hash-graph/src/subcommand/server.rs b/apps/hash-graph/src/subcommand/server.rs index 85f9cc8a742..afd95a89650 100644 --- a/apps/hash-graph/src/subcommand/server.rs +++ b/apps/hash-graph/src/subcommand/server.rs @@ -376,7 +376,7 @@ pub async fn server(args: ServerArgs) -> Result<(), Report> { } pub async fn healthcheck(address: HttpAddress) -> Result<(), Report> { - let request_url = format!("http://{address}/api-doc/openapi.json"); + let request_url = format!("http://{address}/health"); timeout( Duration::from_secs(10), diff --git a/apps/hash-graph/src/subcommand/test_server.rs b/apps/hash-graph/src/subcommand/test_server.rs index 94af85a5663..bc151d57e86 100644 --- a/apps/hash-graph/src/subcommand/test_server.rs +++ b/apps/hash-graph/src/subcommand/test_server.rs @@ -91,7 +91,7 @@ pub async fn test_server(args: TestServerArgs) -> Result<(), Report> } pub async fn healthcheck(address: HttpAddress) -> Result<(), Report> { - let request_url = format!("http://{address}/snapshot"); + let request_url = format!("http://{address}/health"); timeout( Duration::from_secs(10), diff --git a/libs/@local/graph/api/src/rest/mod.rs b/libs/@local/graph/api/src/rest/mod.rs index 7031cab4252..1fc64e27714 100644 --- a/libs/@local/graph/api/src/rest/mod.rs +++ b/libs/@local/graph/api/src/rest/mod.rs @@ -336,12 +336,14 @@ where pub fn openapi_only_router() -> Router { let open_api_doc = OpenApiDocumentation::openapi(); - Router::new().nest( - "/api-doc", - Router::new() - .route("/openapi.json", get(|| async { Json(open_api_doc) })) - .route("/models/{*path}", get(serve_static_schema)), - ) + Router::new() + .route("/health", get(async || "Healthy".into_response())) + .nest( + "/api-doc", + Router::new() + .route("/openapi.json", get(|| async { Json(open_api_doc) })) + .route("/models/{*path}", get(serve_static_schema)), + ) } /// A [`Router`] that serves all of the REST API routes, and the `OpenAPI` specification. diff --git a/libs/@local/graph/test-server/src/lib.rs b/libs/@local/graph/test-server/src/lib.rs index b77f9c53425..04f980a675f 100644 --- a/libs/@local/graph/test-server/src/lib.rs +++ b/libs/@local/graph/test-server/src/lib.rs @@ -12,8 +12,8 @@ use std::collections::HashMap; use axum::{ Extension, Router, body::Body, - response::Response, - routing::{delete, post}, + response::{IntoResponse as _, Response}, + routing::{delete, get, post}, }; use error_stack::Report; use futures::TryStreamExt as _; @@ -32,6 +32,7 @@ use uuid::Uuid; pub fn routes(store_pool: PostgresStorePool) -> Router { Router::new() .layer(http_tracing_layer::HttpTracingLayer) + .route("/health", get(async || "Healthy".into_response())) .route("/snapshot", post(restore_snapshot)) .route("/accounts", delete(delete_accounts)) .route("/data-types", delete(delete_data_types)) diff --git a/libs/@local/telemetry/src/traces/sentry.rs b/libs/@local/telemetry/src/traces/sentry.rs index 290af3fb1a7..15262b391aa 100644 --- a/libs/@local/telemetry/src/traces/sentry.rs +++ b/libs/@local/telemetry/src/traces/sentry.rs @@ -28,6 +28,7 @@ use tracing_subscriber::{Layer, registry::LookupSpan}; pub enum SentryEnvironment { #[default] Development, + Staging, Production, } @@ -35,6 +36,7 @@ impl fmt::Display for SentryEnvironment { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Self::Development => fmt.write_str("development"), + Self::Staging => fmt.write_str("staging"), Self::Production => fmt.write_str("production"), } }