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
33 changes: 33 additions & 0 deletions Cargo.lock

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

7 changes: 4 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,13 @@ dialoguer = { version = "0.12.0" }
directories = "6.0.0"
dlmgr = "0.3.1"
duct = { version = "1.1.1" }
fs2 = "0.4.3"
futures-util = { version = "0.3" }
hex-literal = "1.1.0"
home = { version = "0.5.12" }
humansize = "2"
qemu_img_cmd_types = { path = "libs/qemu_img_cmd_types" }
pem = "3.0.6"
qemu_img_cmd_types = { path = "libs/qemu_img_cmd_types" }
rcgen = { version = "0.14.7", features = ["crypto","ring", "x509-parser"] }
reqwest = { version = "0.13.2", features = ["json", "query", "rustls"] }
rustls = "0.23.37"
Expand All @@ -37,10 +38,10 @@ tempfile = "3.27.0"
time = "0.3.47"
tokio = { version = "1.50.0", features = ["rt", "macros", "io-std", "fs"] }
tokio-tungstenite = { version = "0.28.0", features = ["rustls-tls-webpki-roots", "stream", "connect"], default-features = false }
url = { version = "2.5.0" }
x509-parser = "0.18.1"
unicode-segmentation = "1.12.0"
url = { version = "2.5.0" }
which = "8.0.2"
x509-parser = "0.18.1"


[build-dependencies]
Expand Down
97 changes: 97 additions & 0 deletions src/api/cluster_vm_api/entities.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
// =============================================================================
// AUTO-GENERATED — DO NOT EDIT
// =============================================================================

use serde::{Deserialize, Serialize};

pub type Ipv4Network = String;

/// If dhcp is enabled, ip and gateway must be null. If dhcp is disabled, ip and gateway must be provided and valid.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AddressConfig {
pub dhcp: bool,
#[serde(skip_serializing_if = "Option::is_none")]
pub gateway: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub ip: Option<Ipv4Network>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DnsConfiguration {
pub nameservers: Vec<String>,
}

/// An identifier that uniquely identifies an event, user, resource object, etc in Gallium's platform.
pub type GalliumSlug = String;

/// Path parameters for ListVirtualMachines GET /cluster-api/{cluster_id}/vm/{kube_ns}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ListVirtualMachinesPathParams {
pub cluster_id: GalliumSlug,
pub kube_ns: String,
}

/// MAC address as a string
pub type MacAddress = String;

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct VmNetworkInterfaceConfiguration {
#[serde(skip_serializing_if = "Option::is_none")]
pub dns: Option<DnsConfiguration>,
#[serde(skip_serializing_if = "Option::is_none")]
pub ip: Option<AddressConfig>,
#[serde(rename = "macAddr")]
#[serde(skip_serializing_if = "Option::is_none")]
pub mac_addr: Option<MacAddress>,
#[serde(skip_serializing_if = "Option::is_none")]
pub network: Option<String>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum VirtualMachineStatus {
Stopped,
Provisioning,
Starting,
Running,
Paused,
Stopping,
Terminating,
Migrating,
Unknown,
Error,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct VirtualMachineVolume {
pub bootable: bool,
#[serde(skip_serializing_if = "Option::is_none")]
pub bus: Option<String>,
#[serde(rename = "volumeKubeName")]
pub volume_kube_name: String,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct VirtualMachine {
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
pub interfaces: Vec<VmNetworkInterfaceConfiguration>,
#[serde(rename = "kubeName")]
pub kube_name: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub name: Option<String>,
pub status: VirtualMachineStatus,
pub volumes: Vec<VirtualMachineVolume>,
}

/// Response for ListVirtualMachines GET /cluster-api/{cluster_id}/vm/{kube_ns}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct VirtualMachineListResponse {
pub items: Vec<VirtualMachine>,
}

// =============================================================================
// GET /cluster-api/{cluster_id}/vm/{kube_ns} ListVirtualMachines
// List existing virtual machines
// Security: bearerAuth
// =============================================================================
// (no request body)
38 changes: 38 additions & 0 deletions src/api/cluster_vm_api/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
use crate::api::ApiClient;
use crate::api::cluster_vm_api::entities::{
ListVirtualMachinesPathParams, VirtualMachineListResponse,
};
use crate::api::errors::ApiClientError;
use derive_more::Constructor;
use reqwest::Method;
use std::sync::Arc;

#[allow(unused)]
pub mod entities;
#[derive(Constructor)]
pub struct ClusterVmApi {
api_client: Arc<ApiClient>,
}

impl ClusterVmApi {
pub async fn list_virtual_machines(
&self,
path_params: &ListVirtualMachinesPathParams,
) -> Result<VirtualMachineListResponse, ApiClientError> {
let response = self
.api_client
.request_authed(
Method::GET,
&[
"cluster-api",
&path_params.cluster_id,
"vm",
&path_params.kube_ns,
],
)?
.send()
.await?;

self.api_client.deser_response(response).await
}
}
6 changes: 6 additions & 0 deletions src/api/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use crate::api::common_api::entities::GalliumApiErrorResponse;
use crate::api::errors::ApiClientError;

use crate::api::cluster_vm_api::ClusterVmApi;
use crate::api::command_v2_api::CommandApi;
use crate::api::login_api::LoginApi;
use crate::api::storage_api::StorageApi;
Expand All @@ -11,6 +12,7 @@ use serde::de::DeserializeOwned;
use std::sync::Arc;
use url::Url;

pub mod cluster_vm_api;
pub mod command_v2_api;
mod common_api;
pub mod errors;
Expand Down Expand Up @@ -114,6 +116,10 @@ impl ApiClient {
}
}

pub fn cluster_vm_api(self: &Arc<Self>) -> ClusterVmApi {
ClusterVmApi::new(self.clone())
}

pub fn login_api(self: &Arc<Self>) -> LoginApi {
LoginApi::new(self.clone())
}
Expand Down
49 changes: 49 additions & 0 deletions src/api/storage_api/entities.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,48 @@ pub struct ListDiskPoolsPathParams {
pub cluster_id: GalliumSlug,
}

/// Path parameters for ListVolumes GET /cluster-api/{cluster_id}/volume/{kube_ns}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ListVolumesPathParams {
pub cluster_id: GalliumSlug,
pub kube_ns: String,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum VolumeTypeLabel {
TemplateImage,
Iso,
UserStorage,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Volume {
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
#[serde(rename = "kubeName")]
pub kube_name: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub name: Option<String>,
/// The total size of the volume
#[serde(rename = "sizeBytes")]
pub size_bytes: u64,
#[serde(rename = "storageClass")]
pub storage_class: String,
/// The amount of data that is actually allocated within the volume (actualSize in longhorn terminology). NOTE: Space free-ed by the OS may not be reliably reclaimed.
#[serde(rename = "usedSizeBytes")]
#[serde(skip_serializing_if = "Option::is_none")]
pub used_size_bytes: Option<u64>,
#[serde(rename = "volumeType")]
#[serde(skip_serializing_if = "Option::is_none")]
pub volume_type: Option<VolumeTypeLabel>,
}

/// Response for ListVolumes GET /cluster-api/{cluster_id}/volume/{kube_ns}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct VolumeListResponse {
pub volumes: Vec<Volume>,
}

// =============================================================================
// POST /cluster-api/{cluster_id}/volume/{kube_ns}/{kube_name}/nbd/export ExportNbdVolume
// Command to export a volume via NBD
Expand Down Expand Up @@ -120,3 +162,10 @@ pub struct VolumeNbdImportRequest {
// Security: bearerAuth
// =============================================================================
// (no request body)

// =============================================================================
// GET /cluster-api/{cluster_id}/volume/{kube_ns} ListVolumes
// List existing volumes
// Security: bearerAuth
// =============================================================================
// (no request body)
24 changes: 23 additions & 1 deletion src/api/storage_api/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ use crate::api::errors::ApiClientError;
use crate::api::ApiClient;
use crate::api::storage_api::entities::{
CmdSubmitResponse, DiskPoolListResponse, ExportNbdVolumePathParams, ImportNbdVolumePathParams,
ListDiskPoolsPathParams, VolumeNbdExportRequest, VolumeNbdImportRequest,
ListDiskPoolsPathParams, ListVolumesPathParams, VolumeListResponse, VolumeNbdExportRequest,
VolumeNbdImportRequest,
};
use derive_more::Constructor;
use reqwest::Method;
Expand Down Expand Up @@ -79,4 +80,25 @@ impl StorageApi {
.await?;
self.api_client.deser_response(response).await
}

pub async fn list_volumes(
&self,
path_params: &ListVolumesPathParams,
) -> Result<VolumeListResponse, ApiClientError> {
let response = self
.api_client
.request_authed(
Method::GET,
&[
"cluster-api",
&path_params.cluster_id,
"volume",
&path_params.kube_ns,
],
)?
.send()
.await?;

self.api_client.deser_response(response).await
}
}
1 change: 1 addition & 0 deletions src/helpers/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ pub mod helper_cmd_error;
pub mod mtls;
pub mod nbd;
pub mod qemu;
pub mod ui;
17 changes: 9 additions & 8 deletions src/helpers/qemu/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,19 +122,20 @@ impl QemuImgConvert {
}
}

pub async fn qemu_img_convert(
qemu_img: QemuImgCmdProvider,
args: QemuImgConvert,
) -> (
Arc<QemuConvertProgressProvider>,
JoinHandle<Result<Option<Output>, std::io::Error>>,
) {
pub struct ConvertTask {
pub progress: Arc<QemuConvertProgressProvider>,
pub handle: JoinHandle<Result<Option<Output>, std::io::Error>>,
}
pub async fn qemu_img_convert(qemu_img: QemuImgCmdProvider, args: QemuImgConvert) -> ConvertTask {
let convert_progress_provider = Arc::new(QemuConvertProgressProvider::default());
let convert_progress_provider2 = convert_progress_provider.clone();
let task_handle = tokio::task::spawn_blocking(move || {
let reader = args.build_expression(qemu_img).reader()?;
report_progress(convert_progress_provider2, reader)
});

(convert_progress_provider, task_handle)
ConvertTask {
progress: convert_progress_provider,
handle: task_handle,
}
}
1 change: 1 addition & 0 deletions src/helpers/ui/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub mod transfer_progress_ui;
Loading