-
Notifications
You must be signed in to change notification settings - Fork 107
pipeline-manager: track pipeline lifecycle history #4593
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| CREATE TABLE IF NOT EXISTS pipeline_lifecycle_events ( | ||
| event_id uuid PRIMARY KEY DEFAULT gen_random_uuid(), | ||
| pipeline_id uuid NOT NULL, | ||
| tenant_id uuid NOT NULL, | ||
| deployment_resources_status varchar NOT NULL, | ||
| deployment_runtime_status varchar, | ||
| deployment_runtime_desired_status varchar, | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. storage_status |
||
| info text, | ||
| recorded_at TIMESTAMP NOT NULL DEFAULT now(), | ||
| FOREIGN KEY (pipeline_id) REFERENCES pipeline(id) ON DELETE CASCADE, | ||
| FOREIGN KEY (tenant_id) REFERENCES tenant(id) ON DELETE CASCADE | ||
| ); | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,80 @@ | ||
| use actix_web::{ | ||
| get, | ||
| web::{self, Data as WebData, ReqData}, | ||
| HttpResponse, | ||
| }; | ||
|
|
||
| use crate::{ | ||
| api::{examples, main::ServerState}, | ||
| db::{storage::Storage, types::tenant::TenantId}, | ||
| error::ManagerError, | ||
| }; | ||
|
|
||
| /// Query parameters for lifecycle events endpoint. | ||
| #[derive(serde::Deserialize)] | ||
| pub struct EventsParameters { | ||
| pub max_events: u32, | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Default? I think last 20 makes sense. |
||
| } | ||
|
|
||
| /// Get lifecycle events for a pipeline. | ||
| /// | ||
| /// Returns a list of lifecycle events for the specified pipeline. | ||
| /// The number of events returned is controlled by the `max_events` query parameter. | ||
| /// | ||
| /// # Parameters | ||
| /// - `pipeline_name`: Unique pipeline name (path parameter) | ||
| /// - `max_events`: Maximum number of events to return (query parameter, required) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Mention default. |
||
| /// | ||
| /// # Returns | ||
| /// - 200 OK: List of lifecycle events for the pipeline | ||
| /// - 404 NOT_FOUND: Pipeline with that name does not exist | ||
| /// - 503 SERVICE_UNAVAILABLE: Disconnected or timeout during response | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think this specific 503 can happen, nothing is being HTTP interacted with? |
||
| /// - 500 INTERNAL_SERVER_ERROR: Internal error | ||
| #[utoipa::path( | ||
| context_path = "/v0", | ||
| security(("JSON web token (JWT) or API key" = [])), | ||
| params( | ||
| ("pipeline_name" = String, Path, description = "Unique pipeline name"), | ||
| ("max_events" = u32, Query, description = "Maximum number of events to return") | ||
| ), | ||
| responses( | ||
| (status = OK | ||
| , description = "List of lifecycle events for the pipeline" | ||
| , content_type = "application/json" | ||
| , body = Vec<PipelineLifecycleEvent>), | ||
| (status = NOT_FOUND | ||
| , description = "Pipeline with that name does not exist" | ||
| , body = ErrorResponse | ||
| , example = json!(examples::error_unknown_pipeline_name())), | ||
| (status = SERVICE_UNAVAILABLE | ||
| , body = ErrorResponse | ||
| , examples( | ||
| ("Disconnected during response" = (value = json!(examples::error_pipeline_interaction_disconnected()))), | ||
| ("Response timeout" = (value = json!(examples::error_pipeline_interaction_timeout()))) | ||
| ) | ||
| ), | ||
| (status = INTERNAL_SERVER_ERROR, body = ErrorResponse), | ||
| ), | ||
| tag = "Pipeline interaction" | ||
| )] | ||
| #[get("/pipelines/{pipeline_name}/lifecycle_events")] | ||
| pub(crate) async fn get_pipeline_lifecycle_events( | ||
| state: WebData<ServerState>, | ||
| tenant_id: ReqData<TenantId>, | ||
| path: web::Path<String>, | ||
| query: web::Query<EventsParameters>, | ||
| ) -> Result<HttpResponse, ManagerError> { | ||
| let pipeline_name = path.into_inner(); | ||
| let max_events = query.max_events; | ||
|
|
||
| let events = state | ||
| .db | ||
| .lock() | ||
| .await | ||
| .get_pipeline_lifecycle_events(*tenant_id, &pipeline_name, max_events) | ||
| .await?; | ||
|
|
||
| Ok(HttpResponse::Ok() | ||
| .content_type("application/json") | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think .json() already sets the content type by itself. |
||
| .json(events)) | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| use chrono::NaiveDateTime; | ||
| use serde::{Deserialize, Serialize}; | ||
| use utoipa::ToSchema; | ||
| use uuid::Uuid; | ||
|
|
||
| // Pipeline Lifecycle Events | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Description of what it represent? |
||
| #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, ToSchema)] | ||
| pub struct PipelineLifecycleEvent { | ||
| pub event_id: Uuid, | ||
| pub deployment_resources_status: String, | ||
| pub deployment_runtime_status: Option<String>, | ||
| pub deployment_runtime_desired_status: Option<String>, | ||
| pub info: Option<String>, | ||
| pub recorded_at: NaiveDateTime, | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -251,6 +251,14 @@ pub struct CommonConfig { | |
| /// `/path/to/tls.key`). | ||
| #[arg(long)] | ||
| pub https_tls_key_path: Option<String>, | ||
|
|
||
| /// Retention period for pipeline lifecycle events (in days). | ||
| #[arg(long, default_value_t = 7)] | ||
| pub lifecycle_events_retention_days: u16, | ||
|
|
||
| /// Frequency at which pipeline lifecycle events are cleaned up (in seconds). | ||
swanandx marked this conversation as resolved.
Show resolved
Hide resolved
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Frequency (in seconds) at which pipeline lifecycle events that have surpassed the retention period are cleaned up. |
||
| #[arg(long, default_value_t = 60 * 60)] | ||
| pub lifecycle_events_cleanup_frequency_secs: u64, | ||
| } | ||
|
|
||
| impl CommonConfig { | ||
|
|
@@ -398,6 +406,8 @@ impl CommonConfig { | |
| enable_https: false, | ||
| https_tls_cert_path: None, | ||
| https_tls_key_path: None, | ||
| lifecycle_events_retention_days: 7, | ||
| lifecycle_events_cleanup_frequency_secs: 60 * 60, | ||
| } | ||
| } | ||
| } | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also:
deployment_resources_desired_status