bloat now has endpoints for removal
This commit is contained in:
+12
@@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"db_name": "SQLite",
|
||||||
|
"query": "DELETE FROM device_identifiers WHERE device_id = ?1 AND identifier_key = ?2",
|
||||||
|
"describe": {
|
||||||
|
"columns": [],
|
||||||
|
"parameters": {
|
||||||
|
"Right": 2
|
||||||
|
},
|
||||||
|
"nullable": []
|
||||||
|
},
|
||||||
|
"hash": "72aadefca9851a8becdd2dcce54b646aff095b64cef9837f5e8e4ea8dde71d02"
|
||||||
|
}
|
||||||
+12
@@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"db_name": "SQLite",
|
||||||
|
"query": "DELETE FROM device_identifiers WHERE device_id = ?1 AND identifier_key = ?2",
|
||||||
|
"describe": {
|
||||||
|
"columns": [],
|
||||||
|
"parameters": {
|
||||||
|
"Right": 2
|
||||||
|
},
|
||||||
|
"nullable": []
|
||||||
|
},
|
||||||
|
"hash": "72aadefca9851a8becdd2dcce54b646aff095b64cef9837f5e8e4ea8dde71d02"
|
||||||
|
}
|
||||||
@@ -6,7 +6,7 @@ mod stats;
|
|||||||
|
|
||||||
pub use devices::{
|
pub use devices::{
|
||||||
attach_device_identifier, attach_observation_identifier, create_known_device,
|
attach_device_identifier, attach_observation_identifier, create_known_device,
|
||||||
forget_known_device, list_known_devices, merge_known_device,
|
detach_device_identifier, forget_known_device, list_known_devices, merge_known_device,
|
||||||
};
|
};
|
||||||
pub use enroll::{
|
pub use enroll::{
|
||||||
EnrollTokenStatus, IssueEnrollTokenResponse, RevokeAgentResponse, RevokeEnrollTokenResponse,
|
EnrollTokenStatus, IssueEnrollTokenResponse, RevokeAgentResponse, RevokeEnrollTokenResponse,
|
||||||
|
|||||||
@@ -198,6 +198,32 @@ pub async fn attach_observation_identifier(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn detach_device_identifier(
|
||||||
|
State(state): State<AppState>,
|
||||||
|
AxumPath((device_id, identifier_key)): AxumPath<(String, String)>,
|
||||||
|
) -> Result<impl IntoResponse, (StatusCode, Json<serde_json::Value>)> {
|
||||||
|
match state
|
||||||
|
.store
|
||||||
|
.detach_device_identifier(&device_id, &identifier_key)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(Some(device)) => Ok((StatusCode::OK, Json(known_device_response(device)))),
|
||||||
|
Ok(None) => Err(json_error(
|
||||||
|
StatusCode::NOT_FOUND,
|
||||||
|
"known_device_not_found",
|
||||||
|
"known device not found",
|
||||||
|
)),
|
||||||
|
Err(err) => {
|
||||||
|
warn!(error = %err, "failed to detach device identifier");
|
||||||
|
Err(json_error(
|
||||||
|
StatusCode::BAD_REQUEST,
|
||||||
|
"detach_device_identifier_failed",
|
||||||
|
&err.to_string(),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn merge_known_device(
|
pub async fn merge_known_device(
|
||||||
State(state): State<AppState>,
|
State(state): State<AppState>,
|
||||||
AxumPath(device_id): AxumPath<String>,
|
AxumPath(device_id): AxumPath<String>,
|
||||||
|
|||||||
@@ -12,11 +12,11 @@ pub use commands::{list_agents, run_command};
|
|||||||
pub use control::{
|
pub use control::{
|
||||||
EnrollTokenStatus, IssueEnrollTokenResponse, RevokeAgentResponse, RevokeEnrollTokenResponse,
|
EnrollTokenStatus, IssueEnrollTokenResponse, RevokeAgentResponse, RevokeEnrollTokenResponse,
|
||||||
StateStatsResponse, attach_device_identifier, attach_observation_identifier,
|
StateStatsResponse, attach_device_identifier, attach_observation_identifier,
|
||||||
create_known_device, enroll, forget_known_device, healthz, issue_enroll_token,
|
create_known_device, detach_device_identifier, enroll, forget_known_device, healthz,
|
||||||
list_agent_observation_history, list_agent_observations, list_enroll_tokens,
|
issue_enroll_token, list_agent_observation_history, list_agent_observations,
|
||||||
list_fleet_devices, list_known_devices, merge_known_device, refresh_fleet_devices,
|
list_enroll_tokens, list_fleet_devices, list_known_devices, merge_known_device,
|
||||||
request_agent_observation_sync, revoke_agent, revoke_enroll_token, set_agent_nickname,
|
refresh_fleet_devices, request_agent_observation_sync, revoke_agent, revoke_enroll_token,
|
||||||
state_stats, upload_agent_observations, wake_fleet_device,
|
set_agent_nickname, state_stats, upload_agent_observations, wake_fleet_device,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn json_error(
|
pub fn json_error(
|
||||||
|
|||||||
@@ -130,6 +130,10 @@ fn control_api_routes() -> Router<AppState> {
|
|||||||
"/api/v1/control/devices/{device_id}/identifiers",
|
"/api/v1/control/devices/{device_id}/identifiers",
|
||||||
post(api::attach_device_identifier),
|
post(api::attach_device_identifier),
|
||||||
)
|
)
|
||||||
|
.route(
|
||||||
|
"/api/v1/control/devices/{device_id}/identifiers/{identifier_key}",
|
||||||
|
axum::routing::delete(api::detach_device_identifier),
|
||||||
|
)
|
||||||
.route(
|
.route(
|
||||||
"/api/v1/control/devices/{device_id}/identifiers/from-observation",
|
"/api/v1/control/devices/{device_id}/identifiers/from-observation",
|
||||||
post(api::attach_observation_identifier),
|
post(api::attach_observation_identifier),
|
||||||
|
|||||||
@@ -337,6 +337,52 @@ mod tests {
|
|||||||
cleanup_dir(&dir);
|
cleanup_dir(&dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn device_identifier_can_be_detached_manually() {
|
||||||
|
let (store, dir) = make_store().await;
|
||||||
|
let created = store
|
||||||
|
.create_known_device(KnownDeviceInput {
|
||||||
|
display_name: "lda".into(),
|
||||||
|
pinned: true,
|
||||||
|
notes: None,
|
||||||
|
identifiers: vec![
|
||||||
|
DeviceIdentifierInput {
|
||||||
|
kind: "mac".into(),
|
||||||
|
value: "aa:bb:cc:dd:ee:ff".into(),
|
||||||
|
},
|
||||||
|
DeviceIdentifierInput {
|
||||||
|
kind: "ip".into(),
|
||||||
|
value: "192.168.1.2".into(),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
.expect("known device should create");
|
||||||
|
|
||||||
|
let updated = store
|
||||||
|
.detach_device_identifier(&created.device_id, "ip:192.168.1.2")
|
||||||
|
.await
|
||||||
|
.expect("identifier detach should succeed")
|
||||||
|
.expect("device should exist");
|
||||||
|
|
||||||
|
assert_eq!(updated.identifiers.len(), 1);
|
||||||
|
assert_eq!(
|
||||||
|
updated.identifiers[0].identifier_key,
|
||||||
|
"mac:aa:bb:cc:dd:ee:ff"
|
||||||
|
);
|
||||||
|
|
||||||
|
let unmatched = store
|
||||||
|
.lookup_known_device_by_identifier(DeviceIdentifierInput {
|
||||||
|
kind: "ip".into(),
|
||||||
|
value: "192.168.1.2".into(),
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
.expect("lookup should succeed");
|
||||||
|
assert!(unmatched.is_none());
|
||||||
|
|
||||||
|
cleanup_dir(&dir);
|
||||||
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn merge_known_devices_moves_identifiers_and_deletes_source() {
|
async fn merge_known_devices_moves_identifiers_and_deletes_source() {
|
||||||
let (store, dir) = make_store().await;
|
let (store, dir) = make_store().await;
|
||||||
|
|||||||
@@ -196,6 +196,51 @@ impl Store {
|
|||||||
self.attach_device_identifier(device_id, input).await
|
self.attach_device_identifier(device_id, input).await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn detach_device_identifier(
|
||||||
|
&self,
|
||||||
|
device_id: &str,
|
||||||
|
identifier_key: &str,
|
||||||
|
) -> Result<Option<KnownDevice>> {
|
||||||
|
let now = now_unix();
|
||||||
|
let now_i64 = i64::try_from(now).context("known device timestamp overflow")?;
|
||||||
|
let mut tx = self
|
||||||
|
.pool
|
||||||
|
.begin()
|
||||||
|
.await
|
||||||
|
.context("failed starting device identifier detach transaction")?;
|
||||||
|
let exists = sqlx::query_scalar!(
|
||||||
|
r#"SELECT COUNT(*) as "count!: i64" FROM known_devices WHERE device_id = ?1"#,
|
||||||
|
device_id
|
||||||
|
)
|
||||||
|
.fetch_one(&mut *tx)
|
||||||
|
.await
|
||||||
|
.context("failed checking known device existence")?;
|
||||||
|
if exists == 0 {
|
||||||
|
return Ok(None);
|
||||||
|
}
|
||||||
|
|
||||||
|
sqlx::query!(
|
||||||
|
"DELETE FROM device_identifiers WHERE device_id = ?1 AND identifier_key = ?2",
|
||||||
|
device_id,
|
||||||
|
identifier_key
|
||||||
|
)
|
||||||
|
.execute(&mut *tx)
|
||||||
|
.await
|
||||||
|
.context("failed detaching device identifier")?;
|
||||||
|
sqlx::query!(
|
||||||
|
"UPDATE known_devices SET updated_at_unix = ?1 WHERE device_id = ?2",
|
||||||
|
now_i64,
|
||||||
|
device_id
|
||||||
|
)
|
||||||
|
.execute(&mut *tx)
|
||||||
|
.await
|
||||||
|
.context("failed updating known device timestamp")?;
|
||||||
|
tx.commit()
|
||||||
|
.await
|
||||||
|
.context("failed committing device identifier detach transaction")?;
|
||||||
|
self.get_known_device(device_id).await
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg_attr(not(test), allow(dead_code))]
|
#[cfg_attr(not(test), allow(dead_code))]
|
||||||
pub async fn lookup_known_device_by_identifier(
|
pub async fn lookup_known_device_by_identifier(
|
||||||
&self,
|
&self,
|
||||||
|
|||||||
Reference in New Issue
Block a user