diff --git a/k8s/README.md b/k8s/README.md index 11b17911..dd42794d 100644 --- a/k8s/README.md +++ b/k8s/README.md @@ -12,6 +12,20 @@ Required secrets in the `towerops` namespace: For local development, the project root `.envrc` is used by direnv. +## Deployment Timestamp + +The application footer displays the deployment timestamp to track when the current version was deployed. This is automatically set using the Kubernetes Downward API: + +```yaml +env: + - name: DEPLOY_TIMESTAMP + valueFrom: + fieldRef: + fieldPath: metadata.creationTimestamp +``` + +The pod's creation timestamp is injected as an environment variable and displayed in the footer as "Last deployed X ago ยท YYYY-MM-DD HH:MM:SS UTC". + ## Deploying Apply all resources using kustomize: diff --git a/k8s/deployment.yaml b/k8s/deployment.yaml index b8bcacb2..b21861ae 100644 --- a/k8s/deployment.yaml +++ b/k8s/deployment.yaml @@ -55,6 +55,10 @@ spec: valueFrom: fieldRef: fieldPath: metadata.namespace + - name: DEPLOY_TIMESTAMP + valueFrom: + fieldRef: + fieldPath: metadata.creationTimestamp - name: RELEASE_DISTRIBUTION value: "name" - name: RELEASE_NODE diff --git a/lib/towerops/application.ex b/lib/towerops/application.ex index ac47ddd6..ed9ceec8 100644 --- a/lib/towerops/application.ex +++ b/lib/towerops/application.ex @@ -5,7 +5,7 @@ defmodule Towerops.Application do use Application - # Capture the build/deploy timestamp at compile time + # Capture the build timestamp at compile time (fallback for development) @build_timestamp DateTime.utc_now() @impl true @@ -49,11 +49,41 @@ defmodule Towerops.Application do end @doc """ - Returns the build/deploy timestamp. + Returns the deployment timestamp. - This timestamp is captured at compile time and represents when the - application was last built/deployed. + In production (Kubernetes), this reads from the DEPLOY_TIMESTAMP environment + variable which should be set during deployment. Falls back to compile time + in development. + + Set DEPLOY_TIMESTAMP in your Kubernetes deployment: + ```yaml + env: + - name: DEPLOY_TIMESTAMP + value: "2026-01-17T12:34:56Z" + ``` + + Or use a downward API to inject the pod creation time: + ```yaml + env: + - name: DEPLOY_TIMESTAMP + valueFrom: + fieldRef: + fieldPath: metadata.creationTimestamp + ``` """ @spec build_timestamp() :: DateTime.t() - def build_timestamp, do: @build_timestamp + def build_timestamp do + case System.get_env("DEPLOY_TIMESTAMP") do + nil -> + # Development/fallback: use compile time + @build_timestamp + + timestamp_string -> + # Production: parse from environment variable + case DateTime.from_iso8601(timestamp_string) do + {:ok, datetime, _offset} -> datetime + {:error, _} -> @build_timestamp + end + end + end end