jax_daemon/http_server/api/v0/mounts/
create.rs1use axum::extract::{Json, State};
4use axum::response::{IntoResponse, Response};
5use reqwest::{Client, RequestBuilder, Url};
6use serde::{Deserialize, Serialize};
7use uuid::Uuid;
8
9use crate::database::models::FuseMount;
10use crate::http_server::api::client::ApiRequest;
11use crate::ServiceState;
12
13#[derive(Debug, Clone, Serialize, Deserialize)]
15pub struct CreateMountRequest {
16 pub bucket_id: Uuid,
17 pub mount_point: String,
18 #[serde(default)]
19 pub auto_mount: bool,
20 #[serde(default)]
21 pub read_only: bool,
22 pub cache_size_mb: Option<u32>,
23 pub cache_ttl_secs: Option<u32>,
24}
25
26#[derive(Debug, Clone, Serialize, Deserialize)]
28pub struct CreateMountResponse {
29 pub mount: MountInfo,
30}
31
32#[derive(Debug, Clone, Serialize, Deserialize)]
34pub struct MountInfo {
35 pub mount_id: Uuid,
36 pub bucket_id: Uuid,
37 pub mount_point: String,
38 pub enabled: bool,
39 pub auto_mount: bool,
40 pub read_only: bool,
41 pub cache_size_mb: u32,
42 pub cache_ttl_secs: u32,
43 pub status: String,
44 pub error_message: Option<String>,
45 pub created_at: String,
46 pub updated_at: String,
47}
48
49impl From<FuseMount> for MountInfo {
50 fn from(m: FuseMount) -> Self {
51 Self {
52 mount_id: *m.mount_id,
53 bucket_id: *m.bucket_id,
54 mount_point: m.mount_point,
55 enabled: *m.enabled,
56 auto_mount: *m.auto_mount,
57 read_only: *m.read_only,
58 cache_size_mb: m.cache_size_mb as u32,
59 cache_ttl_secs: m.cache_ttl_secs as u32,
60 status: m.status.as_str().to_string(),
61 error_message: m.error_message,
62 created_at: m.created_at.to_string(),
63 updated_at: m.updated_at.to_string(),
64 }
65 }
66}
67
68pub async fn handler(
69 State(state): State<ServiceState>,
70 Json(req): Json<CreateMountRequest>,
71) -> Result<impl IntoResponse, CreateMountError> {
72 let mount_manager = state.mount_manager().read().await;
73 let mount_manager = mount_manager
74 .as_ref()
75 .ok_or(CreateMountError::MountManagerUnavailable)?;
76
77 let mount = mount_manager
78 .create_mount(
79 req.bucket_id,
80 &req.mount_point,
81 req.auto_mount,
82 req.read_only,
83 req.cache_size_mb,
84 req.cache_ttl_secs,
85 )
86 .await?;
87
88 Ok((
89 http::StatusCode::CREATED,
90 Json(CreateMountResponse {
91 mount: mount.into(),
92 }),
93 )
94 .into_response())
95}
96
97#[derive(Debug, thiserror::Error)]
98pub enum CreateMountError {
99 #[error("Mount manager unavailable")]
100 MountManagerUnavailable,
101 #[error("Mount error: {0}")]
102 Mount(#[from] crate::fuse::MountError),
103}
104
105impl IntoResponse for CreateMountError {
106 fn into_response(self) -> Response {
107 match self {
108 CreateMountError::MountManagerUnavailable => (
109 http::StatusCode::SERVICE_UNAVAILABLE,
110 "Mount manager not available",
111 )
112 .into_response(),
113 CreateMountError::Mount(e) => {
114 (http::StatusCode::BAD_REQUEST, format!("Mount error: {}", e)).into_response()
115 }
116 }
117 }
118}
119
120impl ApiRequest for CreateMountRequest {
121 type Response = CreateMountResponse;
122
123 fn build_request(self, base_url: &Url, client: &Client) -> RequestBuilder {
124 let full_url = base_url.join("/api/v0/mounts/").unwrap();
125 client.post(full_url).json(&self)
126 }
127}