Can create networks
This commit is contained in:
		@@ -38,4 +38,4 @@ image = "0.24.7"
 | 
				
			|||||||
rand = "0.8.5"
 | 
					rand = "0.8.5"
 | 
				
			||||||
bytes = "1.5.0"
 | 
					bytes = "1.5.0"
 | 
				
			||||||
tokio = "1.32.0"
 | 
					tokio = "1.32.0"
 | 
				
			||||||
futures = "0.3.28"
 | 
					futures = "0.3.28"
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,11 +1,12 @@
 | 
				
			|||||||
use crate::app_config::AppConfig;
 | 
					use crate::app_config::AppConfig;
 | 
				
			||||||
use crate::libvirt_lib_structures::{DomainState, DomainXML, DomainXMLUuid};
 | 
					use crate::libvirt_lib_structures::{DomainState, DomainXML, NetworkXML, XMLUuid};
 | 
				
			||||||
use crate::libvirt_rest_structures::*;
 | 
					use crate::libvirt_rest_structures::*;
 | 
				
			||||||
use actix::{Actor, Context, Handler, Message};
 | 
					use actix::{Actor, Context, Handler, Message};
 | 
				
			||||||
use image::ImageOutputFormat;
 | 
					use image::ImageOutputFormat;
 | 
				
			||||||
use std::io::Cursor;
 | 
					use std::io::Cursor;
 | 
				
			||||||
use virt::connect::Connect;
 | 
					use virt::connect::Connect;
 | 
				
			||||||
use virt::domain::Domain;
 | 
					use virt::domain::Domain;
 | 
				
			||||||
 | 
					use virt::network::Network;
 | 
				
			||||||
use virt::stream::Stream;
 | 
					use virt::stream::Stream;
 | 
				
			||||||
use virt::sys;
 | 
					use virt::sys;
 | 
				
			||||||
use virt::sys::VIR_DOMAIN_XML_SECURE;
 | 
					use virt::sys::VIR_DOMAIN_XML_SECURE;
 | 
				
			||||||
@@ -63,11 +64,11 @@ impl Handler<GetHypervisorInfo> for LibVirtActor {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Message)]
 | 
					#[derive(Message)]
 | 
				
			||||||
#[rtype(result = "anyhow::Result<Vec<DomainXMLUuid>>")]
 | 
					#[rtype(result = "anyhow::Result<Vec<XMLUuid>>")]
 | 
				
			||||||
pub struct GetDomainsListReq;
 | 
					pub struct GetDomainsListReq;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl Handler<GetDomainsListReq> for LibVirtActor {
 | 
					impl Handler<GetDomainsListReq> for LibVirtActor {
 | 
				
			||||||
    type Result = anyhow::Result<Vec<DomainXMLUuid>>;
 | 
					    type Result = anyhow::Result<Vec<XMLUuid>>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn handle(&mut self, _msg: GetDomainsListReq, _ctx: &mut Self::Context) -> Self::Result {
 | 
					    fn handle(&mut self, _msg: GetDomainsListReq, _ctx: &mut Self::Context) -> Self::Result {
 | 
				
			||||||
        log::debug!("Get full list of domains");
 | 
					        log::debug!("Get full list of domains");
 | 
				
			||||||
@@ -75,7 +76,7 @@ impl Handler<GetDomainsListReq> for LibVirtActor {
 | 
				
			|||||||
        let mut ids = Vec::with_capacity(domains.len());
 | 
					        let mut ids = Vec::with_capacity(domains.len());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        for d in domains {
 | 
					        for d in domains {
 | 
				
			||||||
            ids.push(DomainXMLUuid::parse_from_str(&d.get_uuid_string()?)?);
 | 
					            ids.push(XMLUuid::parse_from_str(&d.get_uuid_string()?)?);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        Ok(ids)
 | 
					        Ok(ids)
 | 
				
			||||||
@@ -84,7 +85,7 @@ impl Handler<GetDomainsListReq> for LibVirtActor {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#[derive(Message)]
 | 
					#[derive(Message)]
 | 
				
			||||||
#[rtype(result = "anyhow::Result<DomainXML>")]
 | 
					#[rtype(result = "anyhow::Result<DomainXML>")]
 | 
				
			||||||
pub struct GetDomainXMLReq(pub DomainXMLUuid);
 | 
					pub struct GetDomainXMLReq(pub XMLUuid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl Handler<GetDomainXMLReq> for LibVirtActor {
 | 
					impl Handler<GetDomainXMLReq> for LibVirtActor {
 | 
				
			||||||
    type Result = anyhow::Result<DomainXML>;
 | 
					    type Result = anyhow::Result<DomainXML>;
 | 
				
			||||||
@@ -99,11 +100,11 @@ impl Handler<GetDomainXMLReq> for LibVirtActor {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Message)]
 | 
					#[derive(Message)]
 | 
				
			||||||
#[rtype(result = "anyhow::Result<DomainXMLUuid>")]
 | 
					#[rtype(result = "anyhow::Result<XMLUuid>")]
 | 
				
			||||||
pub struct DefineDomainReq(pub DomainXML);
 | 
					pub struct DefineDomainReq(pub DomainXML);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl Handler<DefineDomainReq> for LibVirtActor {
 | 
					impl Handler<DefineDomainReq> for LibVirtActor {
 | 
				
			||||||
    type Result = anyhow::Result<DomainXMLUuid>;
 | 
					    type Result = anyhow::Result<XMLUuid>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn handle(&mut self, mut msg: DefineDomainReq, _ctx: &mut Self::Context) -> Self::Result {
 | 
					    fn handle(&mut self, mut msg: DefineDomainReq, _ctx: &mut Self::Context) -> Self::Result {
 | 
				
			||||||
        // A issue with the disks definition serialization needs them to be serialized aside
 | 
					        // A issue with the disks definition serialization needs them to be serialized aside
 | 
				
			||||||
@@ -121,14 +122,14 @@ impl Handler<DefineDomainReq> for LibVirtActor {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        log::debug!("Define domain:\n{}", xml);
 | 
					        log::debug!("Define domain:\n{}", xml);
 | 
				
			||||||
        let domain = Domain::define_xml(&self.m, &xml)?;
 | 
					        let domain = Domain::define_xml(&self.m, &xml)?;
 | 
				
			||||||
        DomainXMLUuid::parse_from_str(&domain.get_uuid_string()?)
 | 
					        XMLUuid::parse_from_str(&domain.get_uuid_string()?)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Message)]
 | 
					#[derive(Message)]
 | 
				
			||||||
#[rtype(result = "anyhow::Result<()>")]
 | 
					#[rtype(result = "anyhow::Result<()>")]
 | 
				
			||||||
pub struct DeleteDomainReq {
 | 
					pub struct DeleteDomainReq {
 | 
				
			||||||
    pub id: DomainXMLUuid,
 | 
					    pub id: XMLUuid,
 | 
				
			||||||
    pub keep_files: bool,
 | 
					    pub keep_files: bool,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -162,7 +163,7 @@ impl Handler<DeleteDomainReq> for LibVirtActor {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#[derive(Message)]
 | 
					#[derive(Message)]
 | 
				
			||||||
#[rtype(result = "anyhow::Result<DomainState>")]
 | 
					#[rtype(result = "anyhow::Result<DomainState>")]
 | 
				
			||||||
pub struct GetDomainStateReq(pub DomainXMLUuid);
 | 
					pub struct GetDomainStateReq(pub XMLUuid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl Handler<GetDomainStateReq> for LibVirtActor {
 | 
					impl Handler<GetDomainStateReq> for LibVirtActor {
 | 
				
			||||||
    type Result = anyhow::Result<DomainState>;
 | 
					    type Result = anyhow::Result<DomainState>;
 | 
				
			||||||
@@ -188,7 +189,7 @@ impl Handler<GetDomainStateReq> for LibVirtActor {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#[derive(Message)]
 | 
					#[derive(Message)]
 | 
				
			||||||
#[rtype(result = "anyhow::Result<()>")]
 | 
					#[rtype(result = "anyhow::Result<()>")]
 | 
				
			||||||
pub struct StartDomainReq(pub DomainXMLUuid);
 | 
					pub struct StartDomainReq(pub XMLUuid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl Handler<StartDomainReq> for LibVirtActor {
 | 
					impl Handler<StartDomainReq> for LibVirtActor {
 | 
				
			||||||
    type Result = anyhow::Result<()>;
 | 
					    type Result = anyhow::Result<()>;
 | 
				
			||||||
@@ -203,7 +204,7 @@ impl Handler<StartDomainReq> for LibVirtActor {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#[derive(Message)]
 | 
					#[derive(Message)]
 | 
				
			||||||
#[rtype(result = "anyhow::Result<()>")]
 | 
					#[rtype(result = "anyhow::Result<()>")]
 | 
				
			||||||
pub struct ShutdownDomainReq(pub DomainXMLUuid);
 | 
					pub struct ShutdownDomainReq(pub XMLUuid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl Handler<ShutdownDomainReq> for LibVirtActor {
 | 
					impl Handler<ShutdownDomainReq> for LibVirtActor {
 | 
				
			||||||
    type Result = anyhow::Result<()>;
 | 
					    type Result = anyhow::Result<()>;
 | 
				
			||||||
@@ -218,7 +219,7 @@ impl Handler<ShutdownDomainReq> for LibVirtActor {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#[derive(Message)]
 | 
					#[derive(Message)]
 | 
				
			||||||
#[rtype(result = "anyhow::Result<()>")]
 | 
					#[rtype(result = "anyhow::Result<()>")]
 | 
				
			||||||
pub struct KillDomainReq(pub DomainXMLUuid);
 | 
					pub struct KillDomainReq(pub XMLUuid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl Handler<KillDomainReq> for LibVirtActor {
 | 
					impl Handler<KillDomainReq> for LibVirtActor {
 | 
				
			||||||
    type Result = anyhow::Result<()>;
 | 
					    type Result = anyhow::Result<()>;
 | 
				
			||||||
@@ -233,7 +234,7 @@ impl Handler<KillDomainReq> for LibVirtActor {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#[derive(Message)]
 | 
					#[derive(Message)]
 | 
				
			||||||
#[rtype(result = "anyhow::Result<()>")]
 | 
					#[rtype(result = "anyhow::Result<()>")]
 | 
				
			||||||
pub struct ResetDomainReq(pub DomainXMLUuid);
 | 
					pub struct ResetDomainReq(pub XMLUuid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl Handler<ResetDomainReq> for LibVirtActor {
 | 
					impl Handler<ResetDomainReq> for LibVirtActor {
 | 
				
			||||||
    type Result = anyhow::Result<()>;
 | 
					    type Result = anyhow::Result<()>;
 | 
				
			||||||
@@ -248,7 +249,7 @@ impl Handler<ResetDomainReq> for LibVirtActor {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#[derive(Message)]
 | 
					#[derive(Message)]
 | 
				
			||||||
#[rtype(result = "anyhow::Result<()>")]
 | 
					#[rtype(result = "anyhow::Result<()>")]
 | 
				
			||||||
pub struct SuspendDomainReq(pub DomainXMLUuid);
 | 
					pub struct SuspendDomainReq(pub XMLUuid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl Handler<SuspendDomainReq> for LibVirtActor {
 | 
					impl Handler<SuspendDomainReq> for LibVirtActor {
 | 
				
			||||||
    type Result = anyhow::Result<()>;
 | 
					    type Result = anyhow::Result<()>;
 | 
				
			||||||
@@ -263,7 +264,7 @@ impl Handler<SuspendDomainReq> for LibVirtActor {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#[derive(Message)]
 | 
					#[derive(Message)]
 | 
				
			||||||
#[rtype(result = "anyhow::Result<()>")]
 | 
					#[rtype(result = "anyhow::Result<()>")]
 | 
				
			||||||
pub struct ResumeDomainReq(pub DomainXMLUuid);
 | 
					pub struct ResumeDomainReq(pub XMLUuid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl Handler<ResumeDomainReq> for LibVirtActor {
 | 
					impl Handler<ResumeDomainReq> for LibVirtActor {
 | 
				
			||||||
    type Result = anyhow::Result<()>;
 | 
					    type Result = anyhow::Result<()>;
 | 
				
			||||||
@@ -278,7 +279,7 @@ impl Handler<ResumeDomainReq> for LibVirtActor {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#[derive(Message)]
 | 
					#[derive(Message)]
 | 
				
			||||||
#[rtype(result = "anyhow::Result<Vec<u8>>")]
 | 
					#[rtype(result = "anyhow::Result<Vec<u8>>")]
 | 
				
			||||||
pub struct ScreenshotDomainReq(pub DomainXMLUuid);
 | 
					pub struct ScreenshotDomainReq(pub XMLUuid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl Handler<ScreenshotDomainReq> for LibVirtActor {
 | 
					impl Handler<ScreenshotDomainReq> for LibVirtActor {
 | 
				
			||||||
    type Result = anyhow::Result<Vec<u8>>;
 | 
					    type Result = anyhow::Result<Vec<u8>>;
 | 
				
			||||||
@@ -311,7 +312,7 @@ impl Handler<ScreenshotDomainReq> for LibVirtActor {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#[derive(Message)]
 | 
					#[derive(Message)]
 | 
				
			||||||
#[rtype(result = "anyhow::Result<bool>")]
 | 
					#[rtype(result = "anyhow::Result<bool>")]
 | 
				
			||||||
pub struct IsDomainAutostart(pub DomainXMLUuid);
 | 
					pub struct IsDomainAutostart(pub XMLUuid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl Handler<IsDomainAutostart> for LibVirtActor {
 | 
					impl Handler<IsDomainAutostart> for LibVirtActor {
 | 
				
			||||||
    type Result = anyhow::Result<bool>;
 | 
					    type Result = anyhow::Result<bool>;
 | 
				
			||||||
@@ -328,7 +329,7 @@ impl Handler<IsDomainAutostart> for LibVirtActor {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#[derive(Message)]
 | 
					#[derive(Message)]
 | 
				
			||||||
#[rtype(result = "anyhow::Result<()>")]
 | 
					#[rtype(result = "anyhow::Result<()>")]
 | 
				
			||||||
pub struct SetDomainAutostart(pub DomainXMLUuid, pub bool);
 | 
					pub struct SetDomainAutostart(pub XMLUuid, pub bool);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl Handler<SetDomainAutostart> for LibVirtActor {
 | 
					impl Handler<SetDomainAutostart> for LibVirtActor {
 | 
				
			||||||
    type Result = anyhow::Result<()>;
 | 
					    type Result = anyhow::Result<()>;
 | 
				
			||||||
@@ -344,3 +345,35 @@ impl Handler<SetDomainAutostart> for LibVirtActor {
 | 
				
			|||||||
        Ok(())
 | 
					        Ok(())
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Message)]
 | 
				
			||||||
 | 
					#[rtype(result = "anyhow::Result<XMLUuid>")]
 | 
				
			||||||
 | 
					pub struct DefineNetwork(pub NetworkXML);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl Handler<DefineNetwork> for LibVirtActor {
 | 
				
			||||||
 | 
					    type Result = anyhow::Result<XMLUuid>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn handle(&mut self, mut msg: DefineNetwork, _ctx: &mut Self::Context) -> Self::Result {
 | 
				
			||||||
 | 
					        log::debug!("Define network: {:?}", msg.0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // A issue with the IPs definition serialization needs them to be serialized aside
 | 
				
			||||||
 | 
					        let mut ips_xml = Vec::with_capacity(msg.0.ips.len());
 | 
				
			||||||
 | 
					        for ip in msg.0.ips {
 | 
				
			||||||
 | 
					            log::debug!("Serialize {ip:?}");
 | 
				
			||||||
 | 
					            let ip_xml = serde_xml_rs::to_string(&ip)?;
 | 
				
			||||||
 | 
					            let start_offset = ip_xml.find("<ip").unwrap();
 | 
				
			||||||
 | 
					            ips_xml.push(ip_xml[start_offset..].to_string());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        msg.0.ips = vec![];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let mut network_xml = serde_xml_rs::to_string(&msg.0)?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let ips_xml = ips_xml.join("\n");
 | 
				
			||||||
 | 
					        network_xml = network_xml.replacen("</network>", &format!("{ips_xml}</network>"), 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        log::debug!("Define network XML: {network_xml}");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let network = Network::define_xml(&self.m, &network_xml)?;
 | 
				
			||||||
 | 
					        XMLUuid::parse_from_str(&network.get_uuid_string()?)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,4 +1,4 @@
 | 
				
			|||||||
use crate::libvirt_lib_structures::DomainXMLUuid;
 | 
					use crate::libvirt_lib_structures::XMLUuid;
 | 
				
			||||||
use crate::utils::rand_utils::rand_str;
 | 
					use crate::utils::rand_utils::rand_str;
 | 
				
			||||||
use crate::utils::time_utils::time;
 | 
					use crate::utils::time_utils::time;
 | 
				
			||||||
use actix::{Actor, Addr, AsyncContext, Context, Handler, Message};
 | 
					use actix::{Actor, Addr, AsyncContext, Context, Handler, Message};
 | 
				
			||||||
@@ -19,7 +19,7 @@ enum VNCTokenError {
 | 
				
			|||||||
#[derive(Debug, Clone)]
 | 
					#[derive(Debug, Clone)]
 | 
				
			||||||
struct VNCToken {
 | 
					struct VNCToken {
 | 
				
			||||||
    token: String,
 | 
					    token: String,
 | 
				
			||||||
    vm: DomainXMLUuid,
 | 
					    vm: XMLUuid,
 | 
				
			||||||
    expire: u64,
 | 
					    expire: u64,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -45,7 +45,7 @@ impl Actor for VNCTokensActor {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#[derive(Message)]
 | 
					#[derive(Message)]
 | 
				
			||||||
#[rtype(result = "anyhow::Result<String>")]
 | 
					#[rtype(result = "anyhow::Result<String>")]
 | 
				
			||||||
pub struct IssueTokenReq(DomainXMLUuid);
 | 
					pub struct IssueTokenReq(XMLUuid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl Handler<IssueTokenReq> for VNCTokensActor {
 | 
					impl Handler<IssueTokenReq> for VNCTokensActor {
 | 
				
			||||||
    type Result = anyhow::Result<String>;
 | 
					    type Result = anyhow::Result<String>;
 | 
				
			||||||
@@ -63,11 +63,11 @@ impl Handler<IssueTokenReq> for VNCTokensActor {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Message)]
 | 
					#[derive(Message)]
 | 
				
			||||||
#[rtype(result = "anyhow::Result<DomainXMLUuid>")]
 | 
					#[rtype(result = "anyhow::Result<XMLUuid>")]
 | 
				
			||||||
pub struct ConsumeTokenReq(String);
 | 
					pub struct ConsumeTokenReq(String);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl Handler<ConsumeTokenReq> for VNCTokensActor {
 | 
					impl Handler<ConsumeTokenReq> for VNCTokensActor {
 | 
				
			||||||
    type Result = anyhow::Result<DomainXMLUuid>;
 | 
					    type Result = anyhow::Result<XMLUuid>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn handle(&mut self, msg: ConsumeTokenReq, _ctx: &mut Self::Context) -> Self::Result {
 | 
					    fn handle(&mut self, msg: ConsumeTokenReq, _ctx: &mut Self::Context) -> Self::Result {
 | 
				
			||||||
        log::debug!("Attempt to consume a token {:?}", msg.0);
 | 
					        log::debug!("Attempt to consume a token {:?}", msg.0);
 | 
				
			||||||
@@ -97,12 +97,12 @@ impl VNCTokensManager {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Issue a new VNC access token for a domain
 | 
					    /// Issue a new VNC access token for a domain
 | 
				
			||||||
    pub async fn issue_token(&self, id: DomainXMLUuid) -> anyhow::Result<String> {
 | 
					    pub async fn issue_token(&self, id: XMLUuid) -> anyhow::Result<String> {
 | 
				
			||||||
        self.0.send(IssueTokenReq(id)).await?
 | 
					        self.0.send(IssueTokenReq(id)).await?
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Consume a VNC access token
 | 
					    /// Consume a VNC access token
 | 
				
			||||||
    pub async fn consume_token(&self, token: String) -> anyhow::Result<DomainXMLUuid> {
 | 
					    pub async fn consume_token(&self, token: String) -> anyhow::Result<XMLUuid> {
 | 
				
			||||||
        self.0.send(ConsumeTokenReq(token)).await?
 | 
					        self.0.send(ConsumeTokenReq(token)).await?
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,4 +1,4 @@
 | 
				
			|||||||
use crate::libvirt_lib_structures::DomainXMLUuid;
 | 
					use crate::libvirt_lib_structures::XMLUuid;
 | 
				
			||||||
use clap::Parser;
 | 
					use clap::Parser;
 | 
				
			||||||
use std::path::{Path, PathBuf};
 | 
					use std::path::{Path, PathBuf};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -167,7 +167,7 @@ impl AppConfig {
 | 
				
			|||||||
        self.storage_path().join("disks")
 | 
					        self.storage_path().join("disks")
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pub fn vm_storage_path(&self, id: DomainXMLUuid) -> PathBuf {
 | 
					    pub fn vm_storage_path(&self, id: XMLUuid) -> PathBuf {
 | 
				
			||||||
        self.disks_storage_path().join(id.as_string())
 | 
					        self.disks_storage_path().join(id.as_string())
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,6 +7,7 @@ use std::io::ErrorKind;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
pub mod auth_controller;
 | 
					pub mod auth_controller;
 | 
				
			||||||
pub mod iso_controller;
 | 
					pub mod iso_controller;
 | 
				
			||||||
 | 
					pub mod network_controller;
 | 
				
			||||||
pub mod server_controller;
 | 
					pub mod server_controller;
 | 
				
			||||||
pub mod vm_controller;
 | 
					pub mod vm_controller;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										23
									
								
								virtweb_backend/src/controllers/network_controller.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								virtweb_backend/src/controllers/network_controller.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,23 @@
 | 
				
			|||||||
 | 
					use crate::controllers::{HttpResult, LibVirtReq};
 | 
				
			||||||
 | 
					use crate::libvirt_lib_structures::XMLUuid;
 | 
				
			||||||
 | 
					use crate::libvirt_rest_structures::NetworkInfo;
 | 
				
			||||||
 | 
					use actix_web::{web, HttpResponse};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(serde::Serialize, serde::Deserialize)]
 | 
				
			||||||
 | 
					struct NetworkID {
 | 
				
			||||||
 | 
					    id: XMLUuid,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Create a new network
 | 
				
			||||||
 | 
					pub async fn create(client: LibVirtReq, req: web::Json<NetworkInfo>) -> HttpResult {
 | 
				
			||||||
 | 
					    let network = match req.0.to_virt_network() {
 | 
				
			||||||
 | 
					        Ok(d) => d,
 | 
				
			||||||
 | 
					        Err(e) => {
 | 
				
			||||||
 | 
					            log::error!("Failed to extract network info! {e}");
 | 
				
			||||||
 | 
					            return Ok(HttpResponse::BadRequest().body(e.to_string()));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    let id = client.update_network(network).await?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Ok(HttpResponse::Ok().json(NetworkID { id }))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -1,7 +1,7 @@
 | 
				
			|||||||
use crate::actors::vnc_actor::VNCActor;
 | 
					use crate::actors::vnc_actor::VNCActor;
 | 
				
			||||||
use crate::actors::vnc_tokens_actor::VNCTokensManager;
 | 
					use crate::actors::vnc_tokens_actor::VNCTokensManager;
 | 
				
			||||||
use crate::controllers::{HttpResult, LibVirtReq};
 | 
					use crate::controllers::{HttpResult, LibVirtReq};
 | 
				
			||||||
use crate::libvirt_lib_structures::{DomainState, DomainXMLUuid};
 | 
					use crate::libvirt_lib_structures::{DomainState, XMLUuid};
 | 
				
			||||||
use crate::libvirt_rest_structures::VMInfo;
 | 
					use crate::libvirt_rest_structures::VMInfo;
 | 
				
			||||||
use actix_web::{web, HttpRequest, HttpResponse};
 | 
					use actix_web::{web, HttpRequest, HttpResponse};
 | 
				
			||||||
use actix_web_actors::ws;
 | 
					use actix_web_actors::ws;
 | 
				
			||||||
@@ -15,7 +15,7 @@ struct VMInfoAndState {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#[derive(serde::Serialize)]
 | 
					#[derive(serde::Serialize)]
 | 
				
			||||||
struct VMUuid {
 | 
					struct VMUuid {
 | 
				
			||||||
    uuid: DomainXMLUuid,
 | 
					    uuid: XMLUuid,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Create a new VM
 | 
					/// Create a new VM
 | 
				
			||||||
@@ -52,7 +52,7 @@ pub async fn list_all(client: LibVirtReq) -> HttpResult {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#[derive(serde::Deserialize)]
 | 
					#[derive(serde::Deserialize)]
 | 
				
			||||||
pub struct SingleVMUUidReq {
 | 
					pub struct SingleVMUUidReq {
 | 
				
			||||||
    uid: DomainXMLUuid,
 | 
					    uid: XMLUuid,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Get the information about a single VM
 | 
					/// Get the information about a single VM
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,6 @@
 | 
				
			|||||||
use crate::actors::libvirt_actor;
 | 
					use crate::actors::libvirt_actor;
 | 
				
			||||||
use crate::actors::libvirt_actor::LibVirtActor;
 | 
					use crate::actors::libvirt_actor::LibVirtActor;
 | 
				
			||||||
use crate::libvirt_lib_structures::{DomainState, DomainXML, DomainXMLUuid};
 | 
					use crate::libvirt_lib_structures::{DomainState, DomainXML, NetworkXML, XMLUuid};
 | 
				
			||||||
use crate::libvirt_rest_structures::HypervisorInfo;
 | 
					use crate::libvirt_rest_structures::HypervisorInfo;
 | 
				
			||||||
use actix::Addr;
 | 
					use actix::Addr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -24,74 +24,76 @@ impl LibVirtClient {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Get the information about a single domain
 | 
					    /// Get the information about a single domain
 | 
				
			||||||
    pub async fn get_single_domain(&self, id: DomainXMLUuid) -> anyhow::Result<DomainXML> {
 | 
					    pub async fn get_single_domain(&self, id: XMLUuid) -> anyhow::Result<DomainXML> {
 | 
				
			||||||
        self.0.send(libvirt_actor::GetDomainXMLReq(id)).await?
 | 
					        self.0.send(libvirt_actor::GetDomainXMLReq(id)).await?
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Update a domain
 | 
					    /// Update a domain
 | 
				
			||||||
    pub async fn update_domain(&self, xml: DomainXML) -> anyhow::Result<DomainXMLUuid> {
 | 
					    pub async fn update_domain(&self, xml: DomainXML) -> anyhow::Result<XMLUuid> {
 | 
				
			||||||
        self.0.send(libvirt_actor::DefineDomainReq(xml)).await?
 | 
					        self.0.send(libvirt_actor::DefineDomainReq(xml)).await?
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Delete a domain
 | 
					    /// Delete a domain
 | 
				
			||||||
    pub async fn delete_domain(&self, id: DomainXMLUuid, keep_files: bool) -> anyhow::Result<()> {
 | 
					    pub async fn delete_domain(&self, id: XMLUuid, keep_files: bool) -> anyhow::Result<()> {
 | 
				
			||||||
        self.0
 | 
					        self.0
 | 
				
			||||||
            .send(libvirt_actor::DeleteDomainReq { id, keep_files })
 | 
					            .send(libvirt_actor::DeleteDomainReq { id, keep_files })
 | 
				
			||||||
            .await?
 | 
					            .await?
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Get the state of a domain
 | 
					    /// Get the state of a domain
 | 
				
			||||||
    pub async fn get_domain_state(&self, id: DomainXMLUuid) -> anyhow::Result<DomainState> {
 | 
					    pub async fn get_domain_state(&self, id: XMLUuid) -> anyhow::Result<DomainState> {
 | 
				
			||||||
        self.0.send(libvirt_actor::GetDomainStateReq(id)).await?
 | 
					        self.0.send(libvirt_actor::GetDomainStateReq(id)).await?
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Start a domain
 | 
					    /// Start a domain
 | 
				
			||||||
    pub async fn start_domain(&self, id: DomainXMLUuid) -> anyhow::Result<()> {
 | 
					    pub async fn start_domain(&self, id: XMLUuid) -> anyhow::Result<()> {
 | 
				
			||||||
        self.0.send(libvirt_actor::StartDomainReq(id)).await?
 | 
					        self.0.send(libvirt_actor::StartDomainReq(id)).await?
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Shutdown a domain
 | 
					    /// Shutdown a domain
 | 
				
			||||||
    pub async fn shutdown_domain(&self, id: DomainXMLUuid) -> anyhow::Result<()> {
 | 
					    pub async fn shutdown_domain(&self, id: XMLUuid) -> anyhow::Result<()> {
 | 
				
			||||||
        self.0.send(libvirt_actor::ShutdownDomainReq(id)).await?
 | 
					        self.0.send(libvirt_actor::ShutdownDomainReq(id)).await?
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Kill a domain
 | 
					    /// Kill a domain
 | 
				
			||||||
    pub async fn kill_domain(&self, id: DomainXMLUuid) -> anyhow::Result<()> {
 | 
					    pub async fn kill_domain(&self, id: XMLUuid) -> anyhow::Result<()> {
 | 
				
			||||||
        self.0.send(libvirt_actor::KillDomainReq(id)).await?
 | 
					        self.0.send(libvirt_actor::KillDomainReq(id)).await?
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Reset a domain
 | 
					    /// Reset a domain
 | 
				
			||||||
    pub async fn reset_domain(&self, id: DomainXMLUuid) -> anyhow::Result<()> {
 | 
					    pub async fn reset_domain(&self, id: XMLUuid) -> anyhow::Result<()> {
 | 
				
			||||||
        self.0.send(libvirt_actor::ResetDomainReq(id)).await?
 | 
					        self.0.send(libvirt_actor::ResetDomainReq(id)).await?
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Suspend a domain
 | 
					    /// Suspend a domain
 | 
				
			||||||
    pub async fn suspend_domain(&self, id: DomainXMLUuid) -> anyhow::Result<()> {
 | 
					    pub async fn suspend_domain(&self, id: XMLUuid) -> anyhow::Result<()> {
 | 
				
			||||||
        self.0.send(libvirt_actor::SuspendDomainReq(id)).await?
 | 
					        self.0.send(libvirt_actor::SuspendDomainReq(id)).await?
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Resume a domain
 | 
					    /// Resume a domain
 | 
				
			||||||
    pub async fn resume_domain(&self, id: DomainXMLUuid) -> anyhow::Result<()> {
 | 
					    pub async fn resume_domain(&self, id: XMLUuid) -> anyhow::Result<()> {
 | 
				
			||||||
        self.0.send(libvirt_actor::ResumeDomainReq(id)).await?
 | 
					        self.0.send(libvirt_actor::ResumeDomainReq(id)).await?
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Take a screenshot of the domain
 | 
					    /// Take a screenshot of the domain
 | 
				
			||||||
    pub async fn screenshot_domain(&self, id: DomainXMLUuid) -> anyhow::Result<Vec<u8>> {
 | 
					    pub async fn screenshot_domain(&self, id: XMLUuid) -> anyhow::Result<Vec<u8>> {
 | 
				
			||||||
        self.0.send(libvirt_actor::ScreenshotDomainReq(id)).await?
 | 
					        self.0.send(libvirt_actor::ScreenshotDomainReq(id)).await?
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Get auto-start status of a domain
 | 
					    /// Get auto-start status of a domain
 | 
				
			||||||
    pub async fn is_domain_autostart(&self, id: DomainXMLUuid) -> anyhow::Result<bool> {
 | 
					    pub async fn is_domain_autostart(&self, id: XMLUuid) -> anyhow::Result<bool> {
 | 
				
			||||||
        self.0.send(libvirt_actor::IsDomainAutostart(id)).await?
 | 
					        self.0.send(libvirt_actor::IsDomainAutostart(id)).await?
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pub async fn set_domain_autostart(
 | 
					    /// Update autostart value of a domain
 | 
				
			||||||
        &self,
 | 
					    pub async fn set_domain_autostart(&self, id: XMLUuid, autostart: bool) -> anyhow::Result<()> {
 | 
				
			||||||
        id: DomainXMLUuid,
 | 
					 | 
				
			||||||
        autostart: bool,
 | 
					 | 
				
			||||||
    ) -> anyhow::Result<()> {
 | 
					 | 
				
			||||||
        self.0
 | 
					        self.0
 | 
				
			||||||
            .send(libvirt_actor::SetDomainAutostart(id, autostart))
 | 
					            .send(libvirt_actor::SetDomainAutostart(id, autostart))
 | 
				
			||||||
            .await?
 | 
					            .await?
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Update a network configuration
 | 
				
			||||||
 | 
					    pub async fn update_network(&self, network: NetworkXML) -> anyhow::Result<XMLUuid> {
 | 
				
			||||||
 | 
					        self.0.send(libvirt_actor::DefineNetwork(network)).await?
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,9 @@
 | 
				
			|||||||
#[derive(serde::Serialize, serde::Deserialize, Clone, Copy, Debug)]
 | 
					use std::net::{IpAddr, Ipv4Addr};
 | 
				
			||||||
pub struct DomainXMLUuid(pub uuid::Uuid);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl DomainXMLUuid {
 | 
					#[derive(serde::Serialize, serde::Deserialize, Clone, Copy, Debug)]
 | 
				
			||||||
 | 
					pub struct XMLUuid(pub uuid::Uuid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl XMLUuid {
 | 
				
			||||||
    pub fn parse_from_str(s: &str) -> anyhow::Result<Self> {
 | 
					    pub fn parse_from_str(s: &str) -> anyhow::Result<Self> {
 | 
				
			||||||
        Ok(Self(uuid::Uuid::parse_str(s)?))
 | 
					        Ok(Self(uuid::Uuid::parse_str(s)?))
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -188,7 +190,7 @@ pub struct DomainXML {
 | 
				
			|||||||
    pub r#type: String,
 | 
					    pub r#type: String,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pub name: String,
 | 
					    pub name: String,
 | 
				
			||||||
    pub uuid: Option<DomainXMLUuid>,
 | 
					    pub uuid: Option<XMLUuid>,
 | 
				
			||||||
    pub genid: Option<uuid::Uuid>,
 | 
					    pub genid: Option<uuid::Uuid>,
 | 
				
			||||||
    pub title: Option<String>,
 | 
					    pub title: Option<String>,
 | 
				
			||||||
    pub description: Option<String>,
 | 
					    pub description: Option<String>,
 | 
				
			||||||
@@ -218,3 +220,89 @@ pub enum DomainState {
 | 
				
			|||||||
    PowerManagementSuspended,
 | 
					    PowerManagementSuspended,
 | 
				
			||||||
    Other,
 | 
					    Other,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Network forward information
 | 
				
			||||||
 | 
					#[derive(serde::Serialize, serde::Deserialize, Debug)]
 | 
				
			||||||
 | 
					#[serde(rename = "forward")]
 | 
				
			||||||
 | 
					pub struct NetworkForwardXML {
 | 
				
			||||||
 | 
					    #[serde(rename(serialize = "@mode"))]
 | 
				
			||||||
 | 
					    pub mode: String,
 | 
				
			||||||
 | 
					    #[serde(
 | 
				
			||||||
 | 
					        default,
 | 
				
			||||||
 | 
					        rename(serialize = "@mode"),
 | 
				
			||||||
 | 
					        skip_serializing_if = "Option::is_none"
 | 
				
			||||||
 | 
					    )]
 | 
				
			||||||
 | 
					    pub dev: Option<String>,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Network DNS information
 | 
				
			||||||
 | 
					#[derive(serde::Serialize, serde::Deserialize, Debug)]
 | 
				
			||||||
 | 
					#[serde(rename = "dns")]
 | 
				
			||||||
 | 
					pub struct NetworkDNSXML {
 | 
				
			||||||
 | 
					    pub forwarder: NetworkDNSForwarderXML,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Network DNS information
 | 
				
			||||||
 | 
					#[derive(serde::Serialize, serde::Deserialize, Debug)]
 | 
				
			||||||
 | 
					#[serde(rename = "fowarder")]
 | 
				
			||||||
 | 
					pub struct NetworkDNSForwarderXML {
 | 
				
			||||||
 | 
					    /// Address of the DNS server
 | 
				
			||||||
 | 
					    #[serde(rename(serialize = "@addr"))]
 | 
				
			||||||
 | 
					    pub addr: Ipv4Addr,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Network DNS information
 | 
				
			||||||
 | 
					#[derive(serde::Serialize, serde::Deserialize, Debug)]
 | 
				
			||||||
 | 
					#[serde(rename = "domain")]
 | 
				
			||||||
 | 
					pub struct NetworkDomainXML {
 | 
				
			||||||
 | 
					    #[serde(rename(serialize = "@name"))]
 | 
				
			||||||
 | 
					    pub name: String,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Network ip information
 | 
				
			||||||
 | 
					#[derive(serde::Serialize, serde::Deserialize, Debug)]
 | 
				
			||||||
 | 
					#[serde(rename = "ip")]
 | 
				
			||||||
 | 
					pub struct NetworkIPXML {
 | 
				
			||||||
 | 
					    #[serde(default, rename(serialize = "@family"))]
 | 
				
			||||||
 | 
					    pub family: String,
 | 
				
			||||||
 | 
					    #[serde(rename(serialize = "@address"))]
 | 
				
			||||||
 | 
					    pub address: IpAddr,
 | 
				
			||||||
 | 
					    #[serde(rename(serialize = "@prefix"))]
 | 
				
			||||||
 | 
					    pub prefix: u32,
 | 
				
			||||||
 | 
					    pub dhcp: Option<NetworkDHCPXML>,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(serde::Serialize, serde::Deserialize, Debug)]
 | 
				
			||||||
 | 
					#[serde(rename = "dhcp")]
 | 
				
			||||||
 | 
					pub struct NetworkDHCPXML {
 | 
				
			||||||
 | 
					    pub range: NetworkDHCPRangeXML,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(serde::Serialize, serde::Deserialize, Debug)]
 | 
				
			||||||
 | 
					#[serde(rename = "dhcp")]
 | 
				
			||||||
 | 
					pub struct NetworkDHCPRangeXML {
 | 
				
			||||||
 | 
					    #[serde(rename(serialize = "@start"))]
 | 
				
			||||||
 | 
					    pub start: IpAddr,
 | 
				
			||||||
 | 
					    #[serde(rename(serialize = "@end"))]
 | 
				
			||||||
 | 
					    pub end: IpAddr,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Network information, see https://libvirt.org/formatnetwork.html
 | 
				
			||||||
 | 
					#[derive(serde::Serialize, serde::Deserialize, Debug)]
 | 
				
			||||||
 | 
					#[serde(rename = "network")]
 | 
				
			||||||
 | 
					pub struct NetworkXML {
 | 
				
			||||||
 | 
					    pub name: String,
 | 
				
			||||||
 | 
					    #[serde(skip_serializing_if = "Option::is_none")]
 | 
				
			||||||
 | 
					    pub uuid: Option<XMLUuid>,
 | 
				
			||||||
 | 
					    #[serde(skip_serializing_if = "Option::is_none")]
 | 
				
			||||||
 | 
					    pub title: Option<String>,
 | 
				
			||||||
 | 
					    #[serde(skip_serializing_if = "Option::is_none")]
 | 
				
			||||||
 | 
					    pub description: Option<String>,
 | 
				
			||||||
 | 
					    #[serde(skip_serializing_if = "Option::is_none")]
 | 
				
			||||||
 | 
					    pub forward: Option<NetworkForwardXML>,
 | 
				
			||||||
 | 
					    #[serde(skip_serializing_if = "Option::is_none")]
 | 
				
			||||||
 | 
					    pub dns: Option<NetworkDNSXML>,
 | 
				
			||||||
 | 
					    #[serde(skip_serializing_if = "Option::is_none")]
 | 
				
			||||||
 | 
					    pub domain: Option<NetworkDomainXML>,
 | 
				
			||||||
 | 
					    pub ips: Vec<NetworkIPXML>,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,13 +2,15 @@ use crate::app_config::AppConfig;
 | 
				
			|||||||
use crate::constants;
 | 
					use crate::constants;
 | 
				
			||||||
use crate::libvirt_lib_structures::{
 | 
					use crate::libvirt_lib_structures::{
 | 
				
			||||||
    DevicesXML, DiskBootXML, DiskDriverXML, DiskReadOnlyXML, DiskSourceXML, DiskTargetXML, DiskXML,
 | 
					    DevicesXML, DiskBootXML, DiskDriverXML, DiskReadOnlyXML, DiskSourceXML, DiskTargetXML, DiskXML,
 | 
				
			||||||
    DomainMemoryXML, DomainXML, DomainXMLUuid, FeaturesXML, GraphicsXML, OSLoaderXML, OSTypeXML,
 | 
					    DomainMemoryXML, DomainXML, FeaturesXML, GraphicsXML, NetworkDHCPRangeXML, NetworkDHCPXML,
 | 
				
			||||||
    ACPIXML, OSXML,
 | 
					    NetworkDNSForwarderXML, NetworkDNSXML, NetworkDomainXML, NetworkForwardXML, NetworkIPXML,
 | 
				
			||||||
 | 
					    NetworkXML, OSLoaderXML, OSTypeXML, XMLUuid, ACPIXML, OSXML,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
use crate::libvirt_rest_structures::LibVirtStructError::StructureExtraction;
 | 
					use crate::libvirt_rest_structures::LibVirtStructError::StructureExtraction;
 | 
				
			||||||
use crate::utils::disks_utils::Disk;
 | 
					use crate::utils::disks_utils::Disk;
 | 
				
			||||||
use crate::utils::files_utils;
 | 
					use crate::utils::files_utils;
 | 
				
			||||||
use lazy_regex::regex;
 | 
					use lazy_regex::regex;
 | 
				
			||||||
 | 
					use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
 | 
				
			||||||
use std::ops::{Div, Mul};
 | 
					use std::ops::{Div, Mul};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(thiserror::Error, Debug)]
 | 
					#[derive(thiserror::Error, Debug)]
 | 
				
			||||||
@@ -63,8 +65,8 @@ pub enum VMArchitecture {
 | 
				
			|||||||
pub struct VMInfo {
 | 
					pub struct VMInfo {
 | 
				
			||||||
    /// VM name (alphanumeric characters only)
 | 
					    /// VM name (alphanumeric characters only)
 | 
				
			||||||
    pub name: String,
 | 
					    pub name: String,
 | 
				
			||||||
    pub uuid: Option<DomainXMLUuid>,
 | 
					    pub uuid: Option<XMLUuid>,
 | 
				
			||||||
    pub genid: Option<DomainXMLUuid>,
 | 
					    pub genid: Option<XMLUuid>,
 | 
				
			||||||
    pub title: Option<String>,
 | 
					    pub title: Option<String>,
 | 
				
			||||||
    pub description: Option<String>,
 | 
					    pub description: Option<String>,
 | 
				
			||||||
    pub boot_type: BootType,
 | 
					    pub boot_type: BootType,
 | 
				
			||||||
@@ -77,7 +79,8 @@ pub struct VMInfo {
 | 
				
			|||||||
    pub iso_file: Option<String>,
 | 
					    pub iso_file: Option<String>,
 | 
				
			||||||
    /// Storage - https://access.redhat.com/documentation/fr-fr/red_hat_enterprise_linux/6/html/virtualization_administration_guide/sect-virtualization-virtualized_block_devices-adding_storage_devices_to_guests#sect-Virtualization-Adding_storage_devices_to_guests-Adding_file_based_storage_to_a_guest
 | 
					    /// Storage - https://access.redhat.com/documentation/fr-fr/red_hat_enterprise_linux/6/html/virtualization_administration_guide/sect-virtualization-virtualized_block_devices-adding_storage_devices_to_guests#sect-Virtualization-Adding_storage_devices_to_guests-Adding_file_based_storage_to_a_guest
 | 
				
			||||||
    pub disks: Vec<Disk>,
 | 
					    pub disks: Vec<Disk>,
 | 
				
			||||||
    // TODO : network interface
 | 
					    // TODO : network interfaces
 | 
				
			||||||
 | 
					    // TODO : number of CPUs
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl VMInfo {
 | 
					impl VMInfo {
 | 
				
			||||||
@@ -93,7 +96,7 @@ impl VMInfo {
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
            n
 | 
					            n
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            DomainXMLUuid::new_random()
 | 
					            XMLUuid::new_random()
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if let Some(n) = &self.genid {
 | 
					        if let Some(n) = &self.genid {
 | 
				
			||||||
@@ -252,7 +255,7 @@ impl VMInfo {
 | 
				
			|||||||
        Ok(Self {
 | 
					        Ok(Self {
 | 
				
			||||||
            name: domain.name,
 | 
					            name: domain.name,
 | 
				
			||||||
            uuid: domain.uuid,
 | 
					            uuid: domain.uuid,
 | 
				
			||||||
            genid: domain.genid.map(DomainXMLUuid),
 | 
					            genid: domain.genid.map(XMLUuid),
 | 
				
			||||||
            title: domain.title,
 | 
					            title: domain.title,
 | 
				
			||||||
            description: domain.description,
 | 
					            description: domain.description,
 | 
				
			||||||
            boot_type: match domain.os.loader {
 | 
					            boot_type: match domain.os.loader {
 | 
				
			||||||
@@ -314,6 +317,114 @@ fn convert_to_mb(unit: &str, value: usize) -> anyhow::Result<usize> {
 | 
				
			|||||||
    Ok((value as f64).mul(fact.div((1000 * 1000) as f64)).ceil() as usize)
 | 
					    Ok((value as f64).mul(fact.div((1000 * 1000) as f64)).ceil() as usize)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(serde::Serialize, serde::Deserialize, Copy, Clone, Debug)]
 | 
				
			||||||
 | 
					pub enum NetworkForwardMode {
 | 
				
			||||||
 | 
					    NAT,
 | 
				
			||||||
 | 
					    Isolated,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(serde::Serialize, serde::Deserialize, Clone, Debug)]
 | 
				
			||||||
 | 
					pub struct IPV4Config {
 | 
				
			||||||
 | 
					    bridge_address: Ipv4Addr,
 | 
				
			||||||
 | 
					    prefix: u32,
 | 
				
			||||||
 | 
					    dhcp_range: Option<[Ipv4Addr; 2]>,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(serde::Serialize, serde::Deserialize, Clone, Debug)]
 | 
				
			||||||
 | 
					pub struct IPV6Config {
 | 
				
			||||||
 | 
					    bridge_address: Ipv6Addr,
 | 
				
			||||||
 | 
					    prefix: u32,
 | 
				
			||||||
 | 
					    dhcp_range: Option<[Ipv6Addr; 2]>,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Network configuration
 | 
				
			||||||
 | 
					#[derive(serde::Serialize, serde::Deserialize, Clone, Debug)]
 | 
				
			||||||
 | 
					pub struct NetworkInfo {
 | 
				
			||||||
 | 
					    name: String,
 | 
				
			||||||
 | 
					    uuid: Option<XMLUuid>,
 | 
				
			||||||
 | 
					    title: Option<String>,
 | 
				
			||||||
 | 
					    description: Option<String>,
 | 
				
			||||||
 | 
					    forward_mode: NetworkForwardMode,
 | 
				
			||||||
 | 
					    device: Option<String>,
 | 
				
			||||||
 | 
					    dns_server: Option<Ipv4Addr>,
 | 
				
			||||||
 | 
					    domain: Option<String>,
 | 
				
			||||||
 | 
					    ip_v4: Option<IPV4Config>,
 | 
				
			||||||
 | 
					    ip_v6: Option<IPV6Config>,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl NetworkInfo {
 | 
				
			||||||
 | 
					    pub fn to_virt_network(self) -> anyhow::Result<NetworkXML> {
 | 
				
			||||||
 | 
					        if !regex!("^[a-zA-Z0-9]+$").is_match(&self.name) {
 | 
				
			||||||
 | 
					            return Err(StructureExtraction("network name is invalid!").into());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if let Some(n) = &self.title {
 | 
				
			||||||
 | 
					            if n.contains('\n') {
 | 
				
			||||||
 | 
					                return Err(StructureExtraction("Network title contain newline char!").into());
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if let Some(dev) = &self.device {
 | 
				
			||||||
 | 
					            if !regex!("^[a-zA-Z0-9]+$").is_match(dev) {
 | 
				
			||||||
 | 
					                return Err(StructureExtraction("Network device name is invalid!").into());
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let mut ips = Vec::with_capacity(2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if let Some(ipv4) = self.ip_v4 {
 | 
				
			||||||
 | 
					            if ipv4.prefix > 32 {
 | 
				
			||||||
 | 
					                return Err(StructureExtraction("IPv4 prefix is invalid!").into());
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            ips.push(NetworkIPXML {
 | 
				
			||||||
 | 
					                family: "ipv4".to_string(),
 | 
				
			||||||
 | 
					                address: IpAddr::V4(ipv4.bridge_address),
 | 
				
			||||||
 | 
					                prefix: ipv4.prefix,
 | 
				
			||||||
 | 
					                dhcp: ipv4.dhcp_range.map(|[start, end]| NetworkDHCPXML {
 | 
				
			||||||
 | 
					                    range: NetworkDHCPRangeXML {
 | 
				
			||||||
 | 
					                        start: IpAddr::V4(start),
 | 
				
			||||||
 | 
					                        end: IpAddr::V4(end),
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                }),
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if let Some(ipv6) = self.ip_v6 {
 | 
				
			||||||
 | 
					            ips.push(NetworkIPXML {
 | 
				
			||||||
 | 
					                family: "ipv6".to_string(),
 | 
				
			||||||
 | 
					                address: IpAddr::V6(ipv6.bridge_address),
 | 
				
			||||||
 | 
					                prefix: ipv6.prefix,
 | 
				
			||||||
 | 
					                dhcp: ipv6.dhcp_range.map(|[start, end]| NetworkDHCPXML {
 | 
				
			||||||
 | 
					                    range: NetworkDHCPRangeXML {
 | 
				
			||||||
 | 
					                        start: IpAddr::V6(start),
 | 
				
			||||||
 | 
					                        end: IpAddr::V6(end),
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                }),
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Ok(NetworkXML {
 | 
				
			||||||
 | 
					            name: self.name,
 | 
				
			||||||
 | 
					            uuid: self.uuid,
 | 
				
			||||||
 | 
					            title: self.title,
 | 
				
			||||||
 | 
					            description: self.description,
 | 
				
			||||||
 | 
					            forward: match self.forward_mode {
 | 
				
			||||||
 | 
					                NetworkForwardMode::NAT => Some(NetworkForwardXML {
 | 
				
			||||||
 | 
					                    mode: "nat".to_string(),
 | 
				
			||||||
 | 
					                    dev: self.device,
 | 
				
			||||||
 | 
					                }),
 | 
				
			||||||
 | 
					                NetworkForwardMode::Isolated => None,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            dns: self.dns_server.map(|addr| NetworkDNSXML {
 | 
				
			||||||
 | 
					                forwarder: NetworkDNSForwarderXML { addr },
 | 
				
			||||||
 | 
					            }),
 | 
				
			||||||
 | 
					            domain: self.domain.map(|name| NetworkDomainXML { name }),
 | 
				
			||||||
 | 
					            ips,
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[cfg(test)]
 | 
					#[cfg(test)]
 | 
				
			||||||
mod test {
 | 
					mod test {
 | 
				
			||||||
    use crate::libvirt_rest_structures::convert_to_mb;
 | 
					    use crate::libvirt_rest_structures::convert_to_mb;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -22,7 +22,7 @@ use virtweb_backend::constants::{
 | 
				
			|||||||
    MAX_INACTIVITY_DURATION, MAX_SESSION_DURATION, SESSION_COOKIE_NAME,
 | 
					    MAX_INACTIVITY_DURATION, MAX_SESSION_DURATION, SESSION_COOKIE_NAME,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
use virtweb_backend::controllers::{
 | 
					use virtweb_backend::controllers::{
 | 
				
			||||||
    auth_controller, iso_controller, server_controller, vm_controller,
 | 
					    auth_controller, iso_controller, network_controller, server_controller, vm_controller,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
use virtweb_backend::libvirt_client::LibVirtClient;
 | 
					use virtweb_backend::libvirt_client::LibVirtClient;
 | 
				
			||||||
use virtweb_backend::middlewares::auth_middleware::AuthChecker;
 | 
					use virtweb_backend::middlewares::auth_middleware::AuthChecker;
 | 
				
			||||||
@@ -176,6 +176,11 @@ async fn main() -> std::io::Result<()> {
 | 
				
			|||||||
                web::get().to(vm_controller::vnc_token),
 | 
					                web::get().to(vm_controller::vnc_token),
 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
            .route("/api/vnc", web::get().to(vm_controller::vnc))
 | 
					            .route("/api/vnc", web::get().to(vm_controller::vnc))
 | 
				
			||||||
 | 
					            // Network controller
 | 
				
			||||||
 | 
					            .route(
 | 
				
			||||||
 | 
					                "/api/network/create",
 | 
				
			||||||
 | 
					                web::post().to(network_controller::create),
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
    })
 | 
					    })
 | 
				
			||||||
    .bind(&AppConfig::get().listen_address)?
 | 
					    .bind(&AppConfig::get().listen_address)?
 | 
				
			||||||
    .run()
 | 
					    .run()
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,6 @@
 | 
				
			|||||||
use crate::app_config::AppConfig;
 | 
					use crate::app_config::AppConfig;
 | 
				
			||||||
use crate::constants;
 | 
					use crate::constants;
 | 
				
			||||||
use crate::libvirt_lib_structures::DomainXMLUuid;
 | 
					use crate::libvirt_lib_structures::XMLUuid;
 | 
				
			||||||
use crate::utils::files_utils;
 | 
					use crate::utils::files_utils;
 | 
				
			||||||
use lazy_regex::regex;
 | 
					use lazy_regex::regex;
 | 
				
			||||||
use std::os::linux::fs::MetadataExt;
 | 
					use std::os::linux::fs::MetadataExt;
 | 
				
			||||||
@@ -78,13 +78,13 @@ impl Disk {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Get disk path
 | 
					    /// Get disk path
 | 
				
			||||||
    pub fn disk_path(&self, id: DomainXMLUuid) -> PathBuf {
 | 
					    pub fn disk_path(&self, id: XMLUuid) -> PathBuf {
 | 
				
			||||||
        let domain_dir = AppConfig::get().vm_storage_path(id);
 | 
					        let domain_dir = AppConfig::get().vm_storage_path(id);
 | 
				
			||||||
        domain_dir.join(&self.name)
 | 
					        domain_dir.join(&self.name)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Apply disk configuration
 | 
					    /// Apply disk configuration
 | 
				
			||||||
    pub fn apply_config(&self, id: DomainXMLUuid) -> anyhow::Result<()> {
 | 
					    pub fn apply_config(&self, id: XMLUuid) -> anyhow::Result<()> {
 | 
				
			||||||
        self.check_config()?;
 | 
					        self.check_config()?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let file = self.disk_path(id);
 | 
					        let file = self.disk_path(id);
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user