nanocld_client/
vm.rs

1use ntex::{io, rt, ws};
2
3use nanocl_error::http_client::HttpClientResult;
4use nanocl_error::io::FromIo;
5
6use nanocl_stubs::generic::{GenericFilterNsp, GenericNspQuery};
7use nanocl_stubs::vm::{Vm, VmInspect, VmSummary};
8use nanocl_stubs::vm_spec::{VmSpecPartial, VmSpecUpdate};
9
10use crate::NanocldClient;
11
12impl NanocldClient {
13  /// ## Default path for vms
14  const VM_PATH: &'static str = "/vms";
15
16  /// Create a new virtual machine in the system.
17  pub async fn create_vm(
18    &self,
19    vm: &VmSpecPartial,
20    namespace: Option<&str>,
21  ) -> HttpClientResult<Vm> {
22    let res = self
23      .send_post(
24        Self::VM_PATH,
25        Some(vm),
26        Some(&GenericNspQuery::new(namespace)),
27      )
28      .await?;
29    Self::res_json(res).await
30  }
31
32  /// List existing vms
33  ///
34  /// ## Example
35  ///
36  /// ```no_run,ignore
37  /// use nanocld_client::NanocldClient;
38  ///
39  /// let client = NanocldClient::connect_to("http://localhost:8585", None);
40  /// let res = client.list_vm(None).await;
41  /// ```
42  pub async fn list_vm(
43    &self,
44    query: Option<&GenericFilterNsp>,
45  ) -> HttpClientResult<Vec<VmSummary>> {
46    let query = Self::convert_query(query)?;
47    let res = self.send_get(Self::VM_PATH, Some(query)).await?;
48    Self::res_json(res).await
49  }
50
51  /// Delete a vm by it's name and namespace
52  ///
53  /// ## Example
54  ///
55  /// ```no_run,ignore
56  /// use nanocld_client::NanocldClient;
57  ///
58  /// let client = NanocldClient::connect_to("http://localhost:8585", None);
59  /// let res = client.delete_vm("my-vm", None).await;
60  /// ```
61  pub async fn delete_vm(
62    &self,
63    name: &str,
64    namespace: Option<&str>,
65  ) -> HttpClientResult<()> {
66    self
67      .send_delete(
68        &format!("{}/{name}", Self::VM_PATH),
69        Some(&GenericNspQuery::new(namespace)),
70      )
71      .await?;
72    Ok(())
73  }
74
75  /// Inspect a vm by it's name and namespace
76  /// And get detailed information about it
77  ///
78  /// ## Example
79  ///
80  /// ```no_run,ignore
81  /// use nanocld_client::NanocldClient;
82  ///
83  /// let client = NanocldClient::connect_to("http://localhost:8585", None);
84  /// let res = client.inspect_vm("my-vm", None).await;
85  /// ```
86  pub async fn inspect_vm(
87    &self,
88    name: &str,
89    namespace: Option<&str>,
90  ) -> HttpClientResult<VmInspect> {
91    let res = self
92      .send_get(
93        &format!("{}/{name}/inspect", Self::VM_PATH),
94        Some(&GenericNspQuery::new(namespace)),
95      )
96      .await?;
97    Self::res_json(res).await
98  }
99
100  /// Patch a vm by it's name and namespace to update it's spec
101  pub async fn patch_vm(
102    &self,
103    name: &str,
104    vm: &VmSpecUpdate,
105    namespace: Option<&str>,
106  ) -> HttpClientResult<()> {
107    self
108      .send_patch(
109        &format!("{}/{name}", Self::VM_PATH),
110        Some(vm),
111        Some(&GenericNspQuery::new(namespace)),
112      )
113      .await?;
114    Ok(())
115  }
116
117  /// Attach to a vm by it's name and namespace
118  /// and return websocket stream to send input and receive output from the vm tty
119  ///
120  /// ## Example
121  ///
122  /// ```no_run,ignore
123  /// use nanocld_client::NanocldClient;
124  ///
125  /// let client = NanocldClient::connect_to("http://localhost:8585", None);
126  /// let res = client.attach_vm("my-vm", None).await;
127  /// ```
128  pub async fn attach_vm(
129    &self,
130    name: &str,
131    namespace: Option<&str>,
132  ) -> HttpClientResult<ws::WsConnection<io::Base>> {
133    let qs = if let Some(namespace) = namespace {
134      format!("?Namespace={}", namespace)
135    } else {
136      "".to_owned()
137    };
138    let url = format!("{}/{}/vms/{name}/attach{qs}", self.url, &self.version);
139    // open websockets connection over http transport
140    #[cfg(not(target_os = "windows"))]
141    {
142      let con = match &self.unix_socket {
143        Some(path) => ws::WsClient::build(&url)
144          .connector(ntex::service::fn_service(|_| async move {
145            Ok::<_, _>(rt::unix_connect(&path).await?)
146          }))
147          .finish()
148          .map_err(|err| err.map_err_context(|| path))?
149          .connect()
150          .await
151          .map_err(|err| err.map_err_context(|| path))?,
152        None => ws::WsClient::build(&url)
153          .finish()
154          .map_err(|err| err.map_err_context(|| &self.url))?
155          .connect()
156          .await
157          .map_err(|err| err.map_err_context(|| &self.url))?,
158      };
159      Ok(con)
160    }
161    #[cfg(target_os = "windows")]
162    {
163      let con = ws::WsClient::build(&url)
164        .finish()
165        .map_err(|err| err.map_err_context(|| &self.url))?
166        .connect()
167        .await
168        .map_err(|err| err.map_err_context(|| &self.url))?;
169      Ok(con)
170    }
171  }
172}