Skip to content

Commit

Permalink
wip action
Browse files Browse the repository at this point in the history
  • Loading branch information
leon3s committed Jan 14, 2024
1 parent 9efd2c3 commit abce518
Show file tree
Hide file tree
Showing 7 changed files with 95 additions and 65 deletions.
3 changes: 3 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,17 @@
"dotenv",
"dotenvy",
"errno",
"iface",
"Insertable",
"keygen",
"metrs",
"Metrsd",
"nanocl",
"Nanocld",
"ncproxy",
"nstore",
"ntex",
"qcow",
"schemars",
"statefile",
"utoipa"
Expand Down
14 changes: 12 additions & 2 deletions bin/nanocld/src/models/system.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
use std::sync::Arc;

use ntex::rt;
use nanocl_error::io::{IoResult, FromIo, IoError};
use nanocl_error::{
io::{IoResult, FromIo, IoError},
http::HttpResult,
};
use nanocl_stubs::{
config::DaemonConfig,
system::{Event, EventPartial, NativeEventAction, EventActor, EventKind},
};

use crate::{vars, utils, repositories::generic::*};
use crate::{vars, utils, repositories::generic::*, objects::generic::StateAction};

use super::{Pool, EventDb, RawEventEmitter, RawEventClient, TaskManager};

Expand Down Expand Up @@ -82,6 +85,13 @@ impl SystemState {
Ok(system_state)
}

pub async fn exec_action<A>(&self, action: A) -> HttpResult<A::StateActionOut>
where
A: StateAction,
{
action.fn_action(self).await
}

pub async fn emit_event(&self, new_ev: EventPartial) -> IoResult<()> {
let ev: Event = EventDb::create_try_from(new_ev, &self.pool)
.await?
Expand Down
13 changes: 13 additions & 0 deletions bin/nanocld/src/objects/generic/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use nanocl_error::http::HttpResult;

mod create;
mod delete;
mod patch;
Expand All @@ -11,3 +13,14 @@ pub use patch::*;
pub use put::*;
pub use inspect::*;
pub use process::*;

use crate::models::SystemState;

pub trait StateAction {
type StateActionOut;

async fn fn_action(

Check warning on line 22 in bin/nanocld/src/objects/generic/mod.rs

View workflow job for this annotation

GitHub Actions / clippy

use of `async fn` in public traits is discouraged as auto trait bounds cannot be specified

warning: use of `async fn` in public traits is discouraged as auto trait bounds cannot be specified --> bin/nanocld/src/objects/generic/mod.rs:22:3 | 22 | async fn fn_action( | ^^^^^ | = note: you can suppress this lint if you plan to use the trait only in your own code, or do not care about auto traits like `Send` on the `Future` = note: `#[warn(async_fn_in_trait)]` on by default help: you can alternatively desugar to a normal `fn` that returns `impl Future` and add any desired bounds such as `Send`, but these cannot be relaxed without a breaking API change | 22 ~ fn fn_action( 23 | &self, 24 | state: &SystemState, 25 ~ ) -> impl std::future::Future<Output = HttpResult<Self::StateActionOut>> + Send; |
&self,
state: &SystemState,
) -> HttpResult<Self::StateActionOut>;
}
6 changes: 4 additions & 2 deletions bin/nanocld/src/objects/vm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use nanocl_stubs::{
};

use crate::{
utils,
utils::{self, vm_image::ActionVmDelete},
repositories::generic::*,
models::{
VmDb, SystemState, VmObjCreateIn, VmImageDb, SpecDb, VmObjPutIn,
Expand Down Expand Up @@ -87,7 +87,9 @@ impl ObjDelByPk for VmDb {
VmDb::del_process_by_pk(&container_name, Some(options), state).await?;
VmDb::del_by_pk(pk, &state.pool).await?;
SpecDb::del_by_kind_key(pk, &state.pool).await?;
utils::vm_image::delete_by_name(&vm.spec.disk.image, &state.pool).await?;
state
.exec_action(ActionVmDelete(&vm.spec.disk.image))
.await?;
Ok(vm)
}
}
Expand Down
4 changes: 2 additions & 2 deletions bin/nanocld/src/services/vm_image.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use nanocl_stubs::{
};

use crate::{
utils,
utils::{self, vm_image::ActionVmDelete},
repositories::generic::*,
models::{SystemState, VmImageDb},
};
Expand Down Expand Up @@ -212,7 +212,7 @@ pub async fn delete_vm_image(
path: web::types::Path<(String, String)>,
) -> HttpResult<web::HttpResponse> {
let name = path.1.to_owned();
utils::vm_image::delete_by_name(&name, &state.pool).await?;
state.exec_action(ActionVmDelete(&name)).await?;
Ok(web::HttpResponse::Ok().into())
}

Expand Down
4 changes: 2 additions & 2 deletions bin/nanocld/src/utils/vm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ pub async fn create_instance(
state: &SystemState,
) -> HttpResult<()> {
let mut labels: HashMap<String, String> = HashMap::new();
let vmimagespath = format!("{}/vms/images", state.config.state_dir);
let img_path = format!("{}/vms/images", state.config.state_dir);
labels.insert("io.nanocl.v".to_owned(), vm.spec.vm_key.clone());
labels.insert("io.nanocl.n".to_owned(), vm.namespace_name.clone());
let mut args: Vec<String> =
Expand Down Expand Up @@ -102,7 +102,7 @@ pub async fn create_instance(
.clone()
.unwrap_or(vm.namespace_name.to_owned()),
),
binds: Some(vec![format!("{vmimagespath}:{vmimagespath}")]),
binds: Some(vec![format!("{img_path}:{img_path}")]),
devices: Some(devices),
cap_add: Some(vec!["NET_ADMIN".into()]),
..Default::default()
Expand Down
116 changes: 59 additions & 57 deletions bin/nanocld/src/utils/vm_image.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,25 +9,35 @@ use nanocl_stubs::vm_image::{VmImageCloneStream, VmImageResizePayload};

use crate::{
utils,
objects::generic::*,
repositories::generic::*,
models::{Pool, VmImageDb, QemuImgInfo, VmImageUpdateDb, SystemState},
};

/// Delete a vm image from the database and from the filesystem
pub async fn delete_by_name(name: &str, pool: &Pool) -> HttpResult<()> {
let vm_image = VmImageDb::read_by_pk(name, pool).await?;
let children = VmImageDb::read_by_parent(name, pool).await?;
if !children.is_empty() {
return Err(HttpError::conflict(format!(
"Vm image {name} has children images please delete them first"
)));
}
let filepath = vm_image.path.clone();
if let Err(err) = fs::remove_file(&filepath).await {
log::warn!("Error while deleting the file {filepath}: {err}");
pub struct ActionVmDelete<'a>(pub &'a str);

impl<'a> StateAction for ActionVmDelete<'a> {
type StateActionOut = ();

async fn fn_action(
&self,
state: &SystemState,
) -> HttpResult<Self::StateActionOut> {
let name = self.0;
let vm_image = VmImageDb::read_by_pk(name, &state.pool).await?;
let children = VmImageDb::read_by_parent(name, &state.pool).await?;
if !children.is_empty() {
return Err(HttpError::conflict(format!(
"Vm image {name} has children images please delete them first"
)));

Check warning on line 32 in bin/nanocld/src/utils/vm_image.rs

View check run for this annotation

Codecov / codecov/patch

bin/nanocld/src/utils/vm_image.rs#L30-L32

Added lines #L30 - L32 were not covered by tests
}
let filepath = vm_image.path.clone();
if let Err(err) = fs::remove_file(&filepath).await {
log::warn!("Error while deleting the file {filepath}: {err}");

Check warning on line 36 in bin/nanocld/src/utils/vm_image.rs

View check run for this annotation

Codecov / codecov/patch

bin/nanocld/src/utils/vm_image.rs#L36

Added line #L36 was not covered by tests
}
VmImageDb::del_by_pk(name, &state.pool).await?;
Ok(())
}
VmImageDb::del_by_pk(name, pool).await?;
Ok(())
}

/// Get the info of a vm image using qemu-img info command and parse the output
Expand Down Expand Up @@ -69,8 +79,8 @@ pub async fn create_snap(
if VmImageDb::read_by_pk(name, &state.pool).await.is_ok() {
return Err(HttpError::conflict(format!("Vm image {name} already used")));
}
let imagepath = image.path.clone();
let snapshotpath =
let img_path = image.path.clone();
let snapshot_path =
format!("{}/vms/images/{}.img", state.config.state_dir, name);
let output = Command::new("qemu-img")
.args([
Expand All @@ -80,8 +90,8 @@ pub async fn create_snap(
"-f",
"qcow2",
"-b",
&imagepath,
&snapshotpath,
&img_path,
&snapshot_path,
])
.output()
.await
Expand All @@ -97,28 +107,28 @@ pub async fn create_snap(
)?;
let size = format!("{size}G");
let output = Command::new("qemu-img")
.args(["resize", &snapshotpath, &size])
.args(["resize", &snapshot_path, &size])
.output()
.await
.map_err(|err| {
HttpError::internal_server_error(format!(
"Failed to resize snapshot {imagepath}: {err}"
"Failed to resize snapshot {img_path}: {err}"

Check warning on line 115 in bin/nanocld/src/utils/vm_image.rs

View check run for this annotation

Codecov / codecov/patch

bin/nanocld/src/utils/vm_image.rs#L115

Added line #L115 was not covered by tests
))
})?;
output.status.success().then_some(()).ok_or(
HttpError::internal_server_error(format!(
"Failed to resize snapshot {name}: {output:#?}"
)),
)?;
let image_info = get_info(&snapshotpath).await?;
let img_info = get_info(&snapshot_path).await?;
let snap_image = VmImageDb {
name: name.to_owned(),
created_at: chrono::Utc::now().naive_utc(),
kind: "Snapshot".into(),
path: snapshotpath.clone(),
format: image_info.format,
size_actual: image_info.actual_size,
size_virtual: image_info.virtual_size,
path: snapshot_path.clone(),
format: img_info.format,
size_actual: img_info.actual_size,
size_virtual: img_info.virtual_size,
parent: Some(image.name.clone()),
};
let snap_image = VmImageDb::create_from(snap_image, &state.pool).await?;
Expand Down Expand Up @@ -148,19 +158,11 @@ pub async fn clone(
let daemon_conf = state.config.clone();
let pool = Arc::clone(&state.pool);
rt::spawn(async move {
let imagepath = image.path.clone();
let newbasepath =
let img_path = image.path.clone();
let base_path =

Check warning on line 162 in bin/nanocld/src/utils/vm_image.rs

View check run for this annotation

Codecov / codecov/patch

bin/nanocld/src/utils/vm_image.rs#L161-L162

Added lines #L161 - L162 were not covered by tests
format!("{}/vms/images/{}.img", daemon_conf.state_dir, name);
let mut child = match Command::new("qemu-img")
.args([
"convert",
"-p",
"-O",
"qcow2",
"-c",
&imagepath,
&newbasepath,
])
.args(["convert", "-p", "-O", "qcow2", "-c", &img_path, &base_path])

Check warning on line 165 in bin/nanocld/src/utils/vm_image.rs

View check run for this annotation

Codecov / codecov/patch

bin/nanocld/src/utils/vm_image.rs#L165

Added line #L165 was not covered by tests
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()
Expand All @@ -184,7 +186,7 @@ pub async fn clone(
}
Ok(stdout) => stdout,
};
let txpg = tx.clone();
let tx_ptr = tx.clone();

Check warning on line 189 in bin/nanocld/src/utils/vm_image.rs

View check run for this annotation

Codecov / codecov/patch

bin/nanocld/src/utils/vm_image.rs#L189

Added line #L189 was not covered by tests
rt::spawn(async move {
let mut buf = [0; 1024];
loop {
Expand All @@ -201,7 +203,7 @@ pub async fn clone(
.unwrap();
let stream = VmImageCloneStream::Progress(progress);
let stream = serde_json::to_string(&stream).unwrap();
let _ = txpg.send(Ok(Bytes::from(format!("{stream}\r\n"))));
let _ = tx_ptr.send(Ok(Bytes::from(format!("{stream}\r\n"))));

Check warning on line 206 in bin/nanocld/src/utils/vm_image.rs

View check run for this annotation

Codecov / codecov/patch

bin/nanocld/src/utils/vm_image.rs#L206

Added line #L206 was not covered by tests
}
_ => break,
}
Expand Down Expand Up @@ -230,21 +232,21 @@ pub async fn clone(
let _ = tx.send(Err(err.clone()));
return Err(err);
};
let image_info = match get_info(&newbasepath).await {
let img_info = match get_info(&base_path).await {

Check warning on line 235 in bin/nanocld/src/utils/vm_image.rs

View check run for this annotation

Codecov / codecov/patch

bin/nanocld/src/utils/vm_image.rs#L235

Added line #L235 was not covered by tests
Err(err) => {
let _ = tx.send(Err(err.clone()));
return Err(err);
}
Ok(image_info) => image_info,
Ok(img_info) => img_info,

Check warning on line 240 in bin/nanocld/src/utils/vm_image.rs

View check run for this annotation

Codecov / codecov/patch

bin/nanocld/src/utils/vm_image.rs#L240

Added line #L240 was not covered by tests
};
let new_base_image = VmImageDb {
name: name.to_owned(),
created_at: chrono::Utc::now().naive_utc(),
kind: "Base".into(),
path: newbasepath.clone(),
format: image_info.format,
size_actual: image_info.actual_size,
size_virtual: image_info.virtual_size,
path: base_path.clone(),
format: img_info.format,
size_actual: img_info.actual_size,
size_virtual: img_info.virtual_size,

Check warning on line 249 in bin/nanocld/src/utils/vm_image.rs

View check run for this annotation

Codecov / codecov/patch

bin/nanocld/src/utils/vm_image.rs#L246-L249

Added lines #L246 - L249 were not covered by tests
parent: None,
};
let vm = match VmImageDb::create_from(new_base_image, &pool).await {
Expand All @@ -268,15 +270,15 @@ pub async fn resize(
payload: &VmImageResizePayload,
pool: &Pool,
) -> HttpResult<VmImageDb> {
let imagepath = image.path.clone();
let img_path = image.path.clone();

Check warning on line 273 in bin/nanocld/src/utils/vm_image.rs

View check run for this annotation

Codecov / codecov/patch

bin/nanocld/src/utils/vm_image.rs#L273

Added line #L273 was not covered by tests
let size = format!("{}G", payload.size);
let mut args = vec!["resize"];
if payload.shrink {
args.push("--shrink");
}
args.push(&imagepath);
args.push(&img_path);

Check warning on line 279 in bin/nanocld/src/utils/vm_image.rs

View check run for this annotation

Codecov / codecov/patch

bin/nanocld/src/utils/vm_image.rs#L279

Added line #L279 was not covered by tests
args.push(&size);
let ouput =
let output =

Check warning on line 281 in bin/nanocld/src/utils/vm_image.rs

View check run for this annotation

Codecov / codecov/patch

bin/nanocld/src/utils/vm_image.rs#L281

Added line #L281 was not covered by tests
Command::new("qemu-img")
.args(args)
.output()
Expand All @@ -286,18 +288,18 @@ pub async fn resize(
"Unable to resize image {err}"
))
})?;
if !ouput.status.success() {
let output = String::from_utf8(ouput.stdout).unwrap_or_default();
if !output.status.success() {
let output = String::from_utf8(output.stdout).unwrap_or_default();

Check warning on line 292 in bin/nanocld/src/utils/vm_image.rs

View check run for this annotation

Codecov / codecov/patch

bin/nanocld/src/utils/vm_image.rs#L291-L292

Added lines #L291 - L292 were not covered by tests
return Err(HttpError::internal_server_error(format!(
"Unable to resize image {output}"
)));
}
let image_info = get_info(&imagepath).await?;
let img_info = get_info(&img_path).await?;

Check warning on line 297 in bin/nanocld/src/utils/vm_image.rs

View check run for this annotation

Codecov / codecov/patch

bin/nanocld/src/utils/vm_image.rs#L297

Added line #L297 was not covered by tests
let res = VmImageDb::update_pk(
&image.name,
VmImageUpdateDb {
size_actual: image_info.actual_size,
size_virtual: image_info.virtual_size,
size_actual: img_info.actual_size,
size_virtual: img_info.virtual_size,

Check warning on line 302 in bin/nanocld/src/utils/vm_image.rs

View check run for this annotation

Codecov / codecov/patch

bin/nanocld/src/utils/vm_image.rs#L301-L302

Added lines #L301 - L302 were not covered by tests
},
pool,
)
Expand All @@ -322,21 +324,21 @@ pub async fn create(
pool: &Pool,
) -> HttpResult<VmImageDb> {
// Get image info
let image_info = match utils::vm_image::get_info(filepath).await {
let img_info = match utils::vm_image::get_info(filepath).await {
Err(err) => {
let fp2 = filepath.to_owned();
let _ = web::block(move || std::fs::remove_file(fp2)).await;
return Err(err);
}
Ok(image_info) => image_info,
Ok(img_info) => img_info,
};
let vm_image = VmImageDb {
name: name.to_owned(),
created_at: chrono::Utc::now().naive_utc(),
kind: "Base".into(),
format: image_info.format,
size_actual: image_info.actual_size,
size_virtual: image_info.virtual_size,
format: img_info.format,
size_actual: img_info.actual_size,
size_virtual: img_info.virtual_size,
path: filepath.to_owned(),
parent: None,
};
Expand Down

0 comments on commit abce518

Please sign in to comment.