Can define network filters
This commit is contained in:
		@@ -1,4 +1,5 @@
 | 
			
		||||
use crate::libvirt_client::LibVirtClient;
 | 
			
		||||
use actix_http::StatusCode;
 | 
			
		||||
use actix_web::body::BoxBody;
 | 
			
		||||
use actix_web::{web, HttpResponse};
 | 
			
		||||
use std::error::Error;
 | 
			
		||||
@@ -32,8 +33,15 @@ impl Display for HttpErr {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl actix_web::error::ResponseError for HttpErr {
 | 
			
		||||
    fn status_code(&self) -> StatusCode {
 | 
			
		||||
        match self {
 | 
			
		||||
            HttpErr::Err(_) => StatusCode::INTERNAL_SERVER_ERROR,
 | 
			
		||||
            HttpErr::HTTPResponse(r) => r.status(),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    fn error_response(&self) -> HttpResponse<BoxBody> {
 | 
			
		||||
        log::error!("Error while processing request! {}", self);
 | 
			
		||||
 | 
			
		||||
        HttpResponse::InternalServerError().body("Failed to execute request!")
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -112,10 +112,15 @@ pub async fn update(
 | 
			
		||||
    id: web::Path<SingleVMUUidReq>,
 | 
			
		||||
    req: web::Json<VMInfo>,
 | 
			
		||||
) -> HttpResult {
 | 
			
		||||
    let mut domain = req.0.as_tomain().map_err(|e| {
 | 
			
		||||
        log::error!("Failed to extract domain info! {e}");
 | 
			
		||||
        HttpResponse::BadRequest().json(format!("Failed to extract domain info! {e}"))
 | 
			
		||||
    })?;
 | 
			
		||||
    let mut domain = match req.0.as_tomain() {
 | 
			
		||||
        Ok(d) => d,
 | 
			
		||||
        Err(e) => {
 | 
			
		||||
            log::error!("Failed to extract domain info! {e}");
 | 
			
		||||
            return Ok(
 | 
			
		||||
                HttpResponse::BadRequest().json(format!("Failed to extract domain info! {e}"))
 | 
			
		||||
            );
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    domain.uuid = Some(id.uid);
 | 
			
		||||
    if let Err(e) = client.update_domain(req.0, domain).await {
 | 
			
		||||
 
 | 
			
		||||
@@ -63,6 +63,24 @@ pub struct NetIntModelXML {
 | 
			
		||||
    pub r#type: String,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(serde::Serialize, serde::Deserialize)]
 | 
			
		||||
#[serde(rename = "filterref")]
 | 
			
		||||
pub struct NetIntFilterParameterXML {
 | 
			
		||||
    #[serde(rename = "@name")]
 | 
			
		||||
    pub name: String,
 | 
			
		||||
    #[serde(rename = "@value")]
 | 
			
		||||
    pub value: String,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(serde::Serialize, serde::Deserialize)]
 | 
			
		||||
#[serde(rename = "filterref")]
 | 
			
		||||
pub struct NetIntfilterRefXML {
 | 
			
		||||
    #[serde(rename = "@filter")]
 | 
			
		||||
    pub filter: String,
 | 
			
		||||
    #[serde(rename = "parameter", default)]
 | 
			
		||||
    pub parameters: Vec<NetIntFilterParameterXML>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(serde::Serialize, serde::Deserialize)]
 | 
			
		||||
#[serde(rename = "interface")]
 | 
			
		||||
pub struct DomainNetInterfaceXML {
 | 
			
		||||
@@ -73,6 +91,8 @@ pub struct DomainNetInterfaceXML {
 | 
			
		||||
    pub source: Option<NetIntSourceXML>,
 | 
			
		||||
    #[serde(skip_serializing_if = "Option::is_none")]
 | 
			
		||||
    pub model: Option<NetIntModelXML>,
 | 
			
		||||
    #[serde(skip_serializing_if = "Option::is_none")]
 | 
			
		||||
    pub filterref: Option<NetIntfilterRefXML>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(serde::Serialize, serde::Deserialize)]
 | 
			
		||||
 
 | 
			
		||||
@@ -24,11 +24,24 @@ pub enum VMArchitecture {
 | 
			
		||||
    X86_64,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(serde::Serialize, serde::Deserialize)]
 | 
			
		||||
pub struct NWFilterParam {
 | 
			
		||||
    name: String,
 | 
			
		||||
    value: String,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(serde::Serialize, serde::Deserialize)]
 | 
			
		||||
pub struct NWFilterRef {
 | 
			
		||||
    name: String,
 | 
			
		||||
    parameters: Vec<NWFilterParam>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(serde::Serialize, serde::Deserialize)]
 | 
			
		||||
pub struct Network {
 | 
			
		||||
    mac: String,
 | 
			
		||||
    #[serde(flatten)]
 | 
			
		||||
    r#type: NetworkType,
 | 
			
		||||
    mac: String,
 | 
			
		||||
    nwfilterref: Option<NWFilterRef>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(serde::Serialize, serde::Deserialize)]
 | 
			
		||||
@@ -157,6 +170,67 @@ impl VMInfo {
 | 
			
		||||
            false => (None, None),
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        // Process network card
 | 
			
		||||
        let mut networks = vec![];
 | 
			
		||||
        for n in &self.networks {
 | 
			
		||||
            let mac = NetMacAddress {
 | 
			
		||||
                address: n.mac.to_string(),
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            let model = Some(NetIntModelXML {
 | 
			
		||||
                r#type: "virtio".to_string(),
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            let filterref = if let Some(n) = &n.nwfilterref {
 | 
			
		||||
                if !regex!("^[a-zA-Z0-9\\_\\-]+$").is_match(&n.name) {
 | 
			
		||||
                    log::error!("Filter ref name {} is invalid", n.name);
 | 
			
		||||
                    return Err(StructureExtraction("Network filter ref name is invalid!").into());
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                for p in &n.parameters {
 | 
			
		||||
                    if !regex!("^[a-zA-Z0-9_-]+$").is_match(&p.name) {
 | 
			
		||||
                        return Err(StructureExtraction(
 | 
			
		||||
                            "Network filter ref parameter name is invalid!",
 | 
			
		||||
                        )
 | 
			
		||||
                        .into());
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                Some(NetIntfilterRefXML {
 | 
			
		||||
                    filter: n.name.to_string(),
 | 
			
		||||
                    parameters: n
 | 
			
		||||
                        .parameters
 | 
			
		||||
                        .iter()
 | 
			
		||||
                        .map(|f| NetIntFilterParameterXML {
 | 
			
		||||
                            name: f.name.to_string(),
 | 
			
		||||
                            value: f.value.to_string(),
 | 
			
		||||
                        })
 | 
			
		||||
                        .collect(),
 | 
			
		||||
                })
 | 
			
		||||
            } else {
 | 
			
		||||
                None
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            networks.push(match &n.r#type {
 | 
			
		||||
                NetworkType::UserspaceSLIRPStack => DomainNetInterfaceXML {
 | 
			
		||||
                    mac,
 | 
			
		||||
                    r#type: "user".to_string(),
 | 
			
		||||
                    source: None,
 | 
			
		||||
                    model,
 | 
			
		||||
                    filterref,
 | 
			
		||||
                },
 | 
			
		||||
                NetworkType::DefinedNetwork { network } => DomainNetInterfaceXML {
 | 
			
		||||
                    mac,
 | 
			
		||||
                    r#type: "network".to_string(),
 | 
			
		||||
                    source: Some(NetIntSourceXML {
 | 
			
		||||
                        network: network.to_string(),
 | 
			
		||||
                    }),
 | 
			
		||||
                    model,
 | 
			
		||||
                    filterref,
 | 
			
		||||
                },
 | 
			
		||||
            })
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Check disks name for duplicates
 | 
			
		||||
        for disk in &self.disks {
 | 
			
		||||
            if self.disks.iter().filter(|d| d.name == disk.name).count() > 1 {
 | 
			
		||||
@@ -164,7 +238,8 @@ impl VMInfo {
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Apply disks configuration
 | 
			
		||||
        // Apply disks configuration. Starting from now, the function should ideally never fail due to
 | 
			
		||||
        // bad user input
 | 
			
		||||
        for disk in &self.disks {
 | 
			
		||||
            disk.check_config()?;
 | 
			
		||||
            disk.apply_config(uuid)?;
 | 
			
		||||
@@ -199,34 +274,6 @@ impl VMInfo {
 | 
			
		||||
            })
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let mut networks = vec![];
 | 
			
		||||
        for n in &self.networks {
 | 
			
		||||
            networks.push(match &n.r#type {
 | 
			
		||||
                NetworkType::UserspaceSLIRPStack => DomainNetInterfaceXML {
 | 
			
		||||
                    mac: NetMacAddress {
 | 
			
		||||
                        address: n.mac.to_string(),
 | 
			
		||||
                    },
 | 
			
		||||
                    r#type: "user".to_string(),
 | 
			
		||||
                    source: None,
 | 
			
		||||
                    model: Some(NetIntModelXML {
 | 
			
		||||
                        r#type: "virtio".to_string(),
 | 
			
		||||
                    }),
 | 
			
		||||
                },
 | 
			
		||||
                NetworkType::DefinedNetwork { network } => DomainNetInterfaceXML {
 | 
			
		||||
                    mac: NetMacAddress {
 | 
			
		||||
                        address: n.mac.to_string(),
 | 
			
		||||
                    },
 | 
			
		||||
                    r#type: "network".to_string(),
 | 
			
		||||
                    source: Some(NetIntSourceXML {
 | 
			
		||||
                        network: network.to_string(),
 | 
			
		||||
                    }),
 | 
			
		||||
                    model: Some(NetIntModelXML {
 | 
			
		||||
                        r#type: "virtio".to_string(),
 | 
			
		||||
                    }),
 | 
			
		||||
                },
 | 
			
		||||
            })
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Ok(DomainXML {
 | 
			
		||||
            r#type: "kvm".to_string(),
 | 
			
		||||
            name: self.name.to_string(),
 | 
			
		||||
@@ -376,6 +423,17 @@ impl VMInfo {
 | 
			
		||||
                                )));
 | 
			
		||||
                            }
 | 
			
		||||
                        },
 | 
			
		||||
                        nwfilterref: d.filterref.as_ref().map(|f| NWFilterRef {
 | 
			
		||||
                            name: f.filter.to_string(),
 | 
			
		||||
                            parameters: f
 | 
			
		||||
                                .parameters
 | 
			
		||||
                                .iter()
 | 
			
		||||
                                .map(|p| NWFilterParam {
 | 
			
		||||
                                    name: p.name.to_string(),
 | 
			
		||||
                                    value: p.value.to_string(),
 | 
			
		||||
                                })
 | 
			
		||||
                                .collect(),
 | 
			
		||||
                        }),
 | 
			
		||||
                    })
 | 
			
		||||
                })
 | 
			
		||||
                .collect::<Result<Vec<_>, _>>()?,
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user