use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub(super) struct ManagedInstance {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub(super) id: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub(super) template_slug: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub(super) host: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub(super) region: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub(super) state: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub(super) relay_eligible: Option<bool>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub(super) current_version_semver: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub(super) last_error: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub(super) claimed_at: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub(super) created_at: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub(super) application_id: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub(super) latest_deployment_id: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub(super) instance_size: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub(super) update_policy: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub(super) update_deferred_until: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub(super) launch_approval_state: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub(super) last_reset_at: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub(super) reset_count: Option<u64>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub(super) pending_update: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub(super) app_claimed_at: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub(super) environment: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub(super) adopted: Option<bool>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub(super) key_generation: Option<u64>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub(super) last_key_rotation_at: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub(super) frontend_url: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub(super) endpoints: Option<std::collections::BTreeMap<String, String>>,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub(super) struct InstanceDeployment {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub(super) id: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub(super) status: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub(super) release_version: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub(super) deployed_by: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub(super) created_at: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub(super) error_message: Option<String>,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub(super) struct StateAccepted {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub(super) state: Option<String>,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub(super) struct RotationAccepted {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub(super) state: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub(super) key_generation: Option<u64>,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub(super) struct FleetRolloutItem {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub(super) instance_id: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub(super) wave: Option<u64>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub(super) state: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub(super) error: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub(super) current_version_semver: Option<String>,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub(super) struct FleetRollout {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub(super) id: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub(super) template_slug: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub(super) target_version_semver: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub(super) state: Option<String>,
#[serde(default)]
pub(super) wave_percents: Vec<u64>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub(super) current_wave: Option<u64>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub(super) failure_threshold_percent: Option<u64>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub(super) started_at: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub(super) finished_at: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub(super) created_at: Option<String>,
#[serde(default)]
pub(super) items: Vec<FleetRolloutItem>,
}
pub(super) const INSTANCE_SIZES: &[&str] = &["pico", "nano", "micro", "small", "medium", "large"];
pub(super) const UPDATE_POLICIES: &[&str] = &["auto", "deferred"];
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub(super) struct AppTemplate {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub(super) slug: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub(super) name: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub(super) description: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub(super) status: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub(super) source_repo: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub(super) cluster_type: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub(super) base_domain: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub(super) frontend_domain: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub(super) default_instance_size: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub(super) supports_key_rotation: Option<bool>,
}
pub(super) const CLUSTER_TYPES: &[&str] = &["org-shared", "platform-shared", "dedicated"];
pub(super) const RELAY_ROUTE_MODES: &[&str] = &["redirect", "forward"];
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub(super) struct RelayRoute {
pub(super) name: String,
pub(super) component: String,
pub(super) path: String,
pub(super) mode: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub(super) callback_url: Option<String>,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub(super) struct RelayConfig {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub(super) template_slug: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub(super) callback_url: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub(super) state_format: Option<String>,
#[serde(default)]
pub(super) routes: Vec<RelayRoute>,
}
pub(super) const TEMPLATE_STATUSES: &[&str] = &["draft", "published", "retired"];
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub(super) struct TemplateVersion {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub(super) id: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub(super) semver: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub(super) git_ref: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub(super) status: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub(super) published_at: Option<String>,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub(super) struct ClaimLink {
pub(super) claim_url: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub(super) expires_at: Option<String>,
}
pub(super) const INSTANCE_STATES: &[&str] = &[
"provisioning",
"provisioning_failed",
"awaiting_claim",
"awaiting_claim_blocked",
"active",
"suspended",
"resetting",
"destroying",
"destroyed",
];
pub(super) const VARIABLE_KINDS: &[&str] = &["static", "generated", "custom"];
pub(super) const VARIABLE_SCOPES: &[&str] = &["application", "service"];
pub(super) const GENERATOR_TYPES: &[&str] = &[
"32-bytes-base64",
"64-bytes-base64",
"hex-key",
"key-material",
"private-pem",
"public-pem",
];
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub(super) struct TemplateVariable {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub(super) key: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub(super) kind: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub(super) scope: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub(super) service_name: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub(super) generator_type: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub(super) required: Option<bool>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub(super) description: Option<String>,
}
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub(super) struct InstanceVariable {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub(super) key: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub(super) kind: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub(super) scope: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub(super) service_name: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub(super) required: Option<bool>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub(super) description: Option<String>,
#[serde(
default,
alias = "isSet",
alias = "set",
skip_serializing_if = "Option::is_none"
)]
pub(super) has_value: Option<bool>,
#[serde(default, skip_serializing)]
pub(super) value: Option<String>,
}
#[derive(Debug, PartialEq, Eq)]
pub(super) enum SetState {
Set,
Missing,
Unknown,
}
impl InstanceVariable {
pub(super) fn set_state(&self) -> SetState {
let known = self
.has_value
.or_else(|| self.value.as_ref().map(|value| !value.is_empty()));
match known {
Some(true) => SetState::Set,
Some(false) => SetState::Missing,
None => SetState::Unknown,
}
}
pub(super) fn blocks_provisioning(&self) -> bool {
self.kind.as_deref() == Some("custom")
&& self.required == Some(true)
&& self.set_state() == SetState::Missing
}
}
pub(super) fn dash(value: &Option<String>) -> &str {
value.as_deref().unwrap_or("-")
}
fn yes_no(value: &Option<bool>) -> &'static str {
match value {
Some(true) => "yes",
Some(false) => "no",
None => "-",
}
}
pub(super) fn required_cell(kind: &Option<String>, required: &Option<bool>) -> &'static str {
match kind.as_deref() {
Some("custom") => yes_no(required),
_ => "-",
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn required_reads_as_a_dash_for_the_kinds_it_cannot_apply_to() {
for kind in ["static", "generated"] {
assert_eq!(
required_cell(&Some(kind.to_string()), &Some(false)),
"-",
"{}",
kind
);
}
assert_eq!(
required_cell(&Some("custom".to_string()), &Some(true)),
"yes"
);
assert_eq!(
required_cell(&Some("custom".to_string()), &Some(false)),
"no"
);
assert_eq!(required_cell(&None, &Some(true)), "-");
}
}