Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

19 changes: 19 additions & 0 deletions crates/fleet-api/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ pub mod node;
pub mod onboarding;
pub mod operations;
pub mod projects;
pub mod proxmox;
pub mod ready;
pub mod skills;
pub mod system;
Expand Down Expand Up @@ -119,6 +120,12 @@ pub const API_BASE_PATH: &str = "/api/v1";
tailnet::CorrelationCandidateDto,
tailnet::ImportTailnetDeviceRequest,
tailnet::TailnetStatusDto,
proxmox::ConfirmProxmoxFingerprintRequest,
proxmox::CreateProxmoxAccountRequest,
proxmox::ProxmoxAccountDto,
proxmox::ProxmoxDiscoveryDto,
proxmox::ProxmoxFingerprintDto,
proxmox::ProxmoxResourceDto,
node::CreateEnrollmentTokenRequest,
node::EnrollmentTokenCreatedDto,
node::EnrollmentTokenDto,
Expand Down Expand Up @@ -146,6 +153,10 @@ pub const API_BASE_PATH: &str = "/api/v1";
name = "tailnet",
description = "Optional Tailscale discovery: correlated tailnet devices and the import handoff into the onboarding flow. Correlation is evidence only; Fleet identity never derives from Tailscale."
),
(
name = "proxmox",
description = "Proxmox accounts, TLS fingerprint trust, and cluster discovery. The token secret is write-only; discovery is locked until the host fingerprint is confirmed."
),
(
name = "nodes",
description = "Node enrollment and identity: enrollment tokens, node state, and revocation. \
Expand Down Expand Up @@ -208,6 +219,14 @@ pub fn api(state: Arc<operations::ApiState>) -> (Router, utoipa::openapi::OpenAp
.routes(routes!(tailnet::clear_tailnet))
.routes(routes!(tailnet::list_tailnet_devices))
.routes(routes!(tailnet::import_tailnet_device))
.routes(routes!(
proxmox::list_proxmox_accounts,
proxmox::create_proxmox_account

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Retries of these newly exposed Proxmox mutations are not idempotent: the create call conflicts, confirmation repeats its write/audit, and deletion returns 404. Thread a caller-scoped idempotency-key through the Proxmox mutations or route them through the existing idempotent operation mechanism.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At crates/fleet-api/src/lib.rs, line 224:

<comment>Retries of these newly exposed Proxmox mutations are not idempotent: the create call conflicts, confirmation repeats its write/audit, and deletion returns 404. Thread a caller-scoped `idempotency-key` through the Proxmox mutations or route them through the existing idempotent operation mechanism.</comment>

<file context>
@@ -208,6 +219,14 @@ pub fn api(state: Arc<operations::ApiState>) -> (Router, utoipa::openapi::OpenAp
                 .routes(routes!(tailnet::import_tailnet_device))
+                .routes(routes!(
+                    proxmox::list_proxmox_accounts,
+                    proxmox::create_proxmox_account
+                ))
+                .routes(routes!(proxmox::delete_proxmox_account))
</file context>

))
.routes(routes!(proxmox::delete_proxmox_account))
.routes(routes!(proxmox::observe_proxmox_fingerprint))
.routes(routes!(proxmox::confirm_proxmox_fingerprint))
.routes(routes!(proxmox::discover_proxmox_cluster))
.with_state(state),
)
.split_for_parts();
Expand Down
6 changes: 6 additions & 0 deletions crates/fleet-api/src/operations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,10 @@ pub struct ApiState {
/// The project use cases, when the controller was composed with a
/// database; `None` only in document/test states.
pub projects: Option<Arc<fleet_application::project::Projects>>,
/// The Proxmox use cases, when the controller was composed with a
/// database, a secret store, and the provider wired; `None` only in
/// document/test states.
pub proxmox: Option<Arc<fleet_application::proxmox::ProxmoxAccounts>>,
}

impl std::fmt::Debug for ApiState {
Expand All @@ -65,6 +69,7 @@ impl std::fmt::Debug for ApiState {
.field("onboarding", &self.onboarding)
.field("tailnet", &self.tailnet)
.field("projects", &self.projects)
.field("proxmox", &self.proxmox)
.finish()
}
}
Expand Down Expand Up @@ -236,6 +241,7 @@ impl ApiState {
onboarding: None,
tailnet: None,
projects: None,
proxmox: None,
}
}
}
Expand Down
Loading