prepared prod server config
This commit is contained in:
parent
df34fc719c
commit
98459d27ca
29
prod_setting/config1.yaml
Normal file
29
prod_setting/config1.yaml
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
max_cores_per_vm: 4
|
||||||
|
max_vcpu_reservation: 8
|
||||||
|
max_mem_reservation_mb: 25000
|
||||||
|
network_interfaces:
|
||||||
|
- driver: "MACVTAP"
|
||||||
|
device: "eno8303"
|
||||||
|
ipv4:
|
||||||
|
- subnet: "173.234.136.152/29"
|
||||||
|
gateway: "173.234.136.158"
|
||||||
|
reserved_addrs:
|
||||||
|
- "173.234.136.153"
|
||||||
|
- "173.234.136.156"
|
||||||
|
- "173.234.136.157"
|
||||||
|
- "173.234.136.158"
|
||||||
|
- subnet: "173.234.137.16/31"
|
||||||
|
gateway: "173.234.137.30"
|
||||||
|
reserved_addrs:
|
||||||
|
- "173.234.137.16"
|
||||||
|
ipv6:
|
||||||
|
- subnet: "2a0d:3003:b666:a00c:2::/112"
|
||||||
|
gateway: "2a0d:3003:b666:a00c::1"
|
||||||
|
reserved_addrs: []
|
||||||
|
volumes:
|
||||||
|
- path: "/opt/detee_vms/"
|
||||||
|
max_reservation_gb: 200
|
||||||
|
public_port_range:
|
||||||
|
start: 30000
|
||||||
|
end: 50000
|
||||||
|
max_ports_per_vm: 5
|
@ -7,8 +7,8 @@ use std::ops::Range;
|
|||||||
|
|
||||||
#[derive(Deserialize, Debug)]
|
#[derive(Deserialize, Debug)]
|
||||||
pub struct Volume {
|
pub struct Volume {
|
||||||
path: String,
|
pub path: String,
|
||||||
max_reservation: u64,
|
pub max_reservation_gb: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Debug)]
|
#[derive(Deserialize, Debug)]
|
||||||
@ -44,7 +44,7 @@ pub enum InterfaceType {
|
|||||||
pub struct Config {
|
pub struct Config {
|
||||||
pub max_cores_per_vm: usize,
|
pub max_cores_per_vm: usize,
|
||||||
pub max_vcpu_reservation: usize,
|
pub max_vcpu_reservation: usize,
|
||||||
pub max_mem_reservation: usize,
|
pub max_mem_reservation_mb: usize,
|
||||||
pub network_interfaces: Vec<Interface>,
|
pub network_interfaces: Vec<Interface>,
|
||||||
pub volumes: Vec<Volume>,
|
pub volumes: Vec<Volume>,
|
||||||
#[serde(with = "range_format")]
|
#[serde(with = "range_format")]
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
pub(crate) const DEFAULT_OVMF: &str = "/usr/share/edk2/ovmf/OVMF.amdsev.fd";
|
pub(crate) const DEFAULT_OVMF: &str = "/usr/share/edk2/ovmf/OVMF.amdsev.fd";
|
||||||
pub(crate) const VM_BOOT_DIR: &str = "/var/lib/detee/boot/";
|
pub(crate) const VM_BOOT_DIR: &str = "/var/lib/detee/boot/";
|
||||||
pub(crate) const VM_DISK_DIR: &str = "/var/lib/detee/vms/";
|
|
||||||
pub(crate) const VM_CONFIG_DIR: &str = "/etc/detee/daemon/vms/";
|
pub(crate) const VM_CONFIG_DIR: &str = "/etc/detee/daemon/vms/";
|
||||||
pub(crate) const DAEMON_CONFIG_PATH: &str = "/etc/detee/daemon/config.json";
|
pub(crate) const DAEMON_CONFIG_PATH: &str = "/etc/detee/daemon/config.json";
|
||||||
pub(crate) const START_VM_SCRIPT: &str = "/usr/local/bin/detee/start_qemu_vm.sh";
|
pub(crate) const START_VM_SCRIPT: &str = "/usr/local/bin/detee/start_qemu_vm.sh";
|
||||||
|
@ -7,8 +7,8 @@ use crate::config::Config;
|
|||||||
use crate::state::NewVMRequest;
|
use crate::state::NewVMRequest;
|
||||||
|
|
||||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
let mut res = state::Resources::new();
|
let config = Config::from_file("prod_setting/config1.yaml")?;
|
||||||
let config = Config::from_file("test_data/config2.yaml")?;
|
let mut res = state::Resources::new(&config.volumes);
|
||||||
// println!("{:#?}", config);
|
// println!("{:#?}", config);
|
||||||
|
|
||||||
// let config = Config::from_file("test_data/config2.yaml")?;
|
// let config = Config::from_file("test_data/config2.yaml")?;
|
||||||
@ -19,7 +19,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
// println!("{:#?}", config);
|
// println!("{:#?}", config);
|
||||||
// let config = Config::from_file("test_data/config5.yaml")?;
|
// let config = Config::from_file("test_data/config5.yaml")?;
|
||||||
// println!("{:#?}", config);
|
// println!("{:#?}", config);
|
||||||
let new_vm_req = NewVMRequest::from_file("test_data/new_vm_req2.yaml")?;
|
let new_vm_req = NewVMRequest::from_file("test_data/new_vm_req3.yaml")?;
|
||||||
// println!("{:#?}", new_vm_req);
|
// println!("{:#?}", new_vm_req);
|
||||||
|
|
||||||
// let new_vm_req = NewVMRequest::from_file("test_data/new_vm_req2.yaml")?;
|
// let new_vm_req = NewVMRequest::from_file("test_data/new_vm_req2.yaml")?;
|
||||||
|
161
src/state.rs
161
src/state.rs
@ -11,6 +11,7 @@ use std::fs::remove_file;
|
|||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
|
use std::net::{Ipv4Addr, Ipv6Addr};
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
|
|
||||||
@ -28,18 +29,36 @@ pub struct Resources {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Resources {
|
impl Resources {
|
||||||
pub fn new() -> Self {
|
pub fn new(config_volumes: &Vec<crate::config::Volume>) -> Self {
|
||||||
|
let mut storage_pools = Vec::new();
|
||||||
|
for config_vol in config_volumes.iter() {
|
||||||
|
storage_pools.push(StoragePool {
|
||||||
|
path: config_vol.path.clone(),
|
||||||
|
// TODO: check if the storage is actualy available at that path
|
||||||
|
available_gb: config_vol.max_reservation_gb,
|
||||||
|
});
|
||||||
|
}
|
||||||
Resources {
|
Resources {
|
||||||
reserved_vcpus: 0,
|
reserved_vcpus: 0,
|
||||||
reserved_memory: 0,
|
reserved_memory: 0,
|
||||||
reserved_ports: HashSet::new(),
|
reserved_ports: HashSet::new(),
|
||||||
storage_pools: Vec::new(),
|
storage_pools,
|
||||||
reserved_ips: HashSet::new(),
|
reserved_ips: HashSet::new(),
|
||||||
reserved_if_names: HashSet::new(),
|
reserved_if_names: HashSet::new(),
|
||||||
boot_files: HashSet::new(),
|
boot_files: HashSet::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn get_free_ports(&mut self, extra_ports: usize, config: &Config) -> Vec<u16> {
|
|
||||||
|
fn available_storage_pool(&mut self, required_gb: usize) -> Option<String> {
|
||||||
|
self.storage_pools.sort_by_key(|p| p.available_gb);
|
||||||
|
let pool = self.storage_pools.last()?;
|
||||||
|
if pool.available_gb > required_gb {
|
||||||
|
return Some(pool.path.clone());
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn available_ports(&mut self, extra_ports: usize, config: &Config) -> Vec<u16> {
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
let total_ports = extra_ports + 1;
|
let total_ports = extra_ports + 1;
|
||||||
if config.public_port_range.len() < self.reserved_ports.len() + total_ports as usize {
|
if config.public_port_range.len() < self.reserved_ports.len() + total_ports as usize {
|
||||||
@ -62,7 +81,7 @@ impl Resources {
|
|||||||
published_ports
|
published_ports
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_free_vm_name(&mut self) -> String {
|
fn available_if_name(&mut self) -> String {
|
||||||
use rand::{distributions::Alphanumeric, Rng};
|
use rand::{distributions::Alphanumeric, Rng};
|
||||||
loop {
|
loop {
|
||||||
let mut interface_name: String = rand::thread_rng()
|
let mut interface_name: String = rand::thread_rng()
|
||||||
@ -77,7 +96,7 @@ impl Resources {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_free_ipv4(&mut self, config: &Config) -> Option<VMNIC> {
|
fn available_ipv4(&mut self, config: &Config) -> Option<VMNIC> {
|
||||||
for nic in config.network_interfaces.iter() {
|
for nic in config.network_interfaces.iter() {
|
||||||
for range in nic.ipv4.iter() {
|
for range in nic.ipv4.iter() {
|
||||||
for ip in range.subnet.iter().skip(1) {
|
for ip in range.subnet.iter().skip(1) {
|
||||||
@ -87,11 +106,11 @@ impl Resources {
|
|||||||
{
|
{
|
||||||
let if_config = match nic.driver {
|
let if_config = match nic.driver {
|
||||||
crate::config::InterfaceType::MACVTAP => InterfaceConfig::MACVTAP {
|
crate::config::InterfaceType::MACVTAP => InterfaceConfig::MACVTAP {
|
||||||
name: self.get_free_vm_name(),
|
name: self.available_if_name(),
|
||||||
device: nic.device.clone(),
|
device: nic.device.clone(),
|
||||||
},
|
},
|
||||||
crate::config::InterfaceType::IPVTAP => InterfaceConfig::IPVTAP {
|
crate::config::InterfaceType::IPVTAP => InterfaceConfig::IPVTAP {
|
||||||
name: self.get_free_vm_name(),
|
name: self.available_if_name(),
|
||||||
device: nic.device.clone(),
|
device: nic.device.clone(),
|
||||||
},
|
},
|
||||||
crate::config::InterfaceType::Bridge => InterfaceConfig::Bridge {
|
crate::config::InterfaceType::Bridge => InterfaceConfig::Bridge {
|
||||||
@ -99,16 +118,9 @@ impl Resources {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
let mut ips = Vec::new();
|
let mut ips = Vec::new();
|
||||||
let mask = ip
|
|
||||||
.network()
|
|
||||||
.to_string()
|
|
||||||
.split('/')
|
|
||||||
.nth(1)
|
|
||||||
.unwrap()
|
|
||||||
.to_string();
|
|
||||||
ips.push(IPConfig {
|
ips.push(IPConfig {
|
||||||
address: ip.address().to_string(),
|
address: ip.address().to_string(),
|
||||||
mask,
|
mask: calc_ipv4_netmask(ip.address(), range.gateway),
|
||||||
gateway: range.gateway.to_string(),
|
gateway: range.gateway.to_string(),
|
||||||
});
|
});
|
||||||
return Some(VMNIC { if_config, ips });
|
return Some(VMNIC { if_config, ips });
|
||||||
@ -120,7 +132,7 @@ impl Resources {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO: refactor this garbage cause it's only one char different from the previous one
|
// TODO: refactor this garbage cause it's only one char different from the previous one
|
||||||
fn get_free_ipv6(&mut self, config: &Config) -> Option<VMNIC> {
|
fn available_ipv6(&mut self, config: &Config) -> Option<VMNIC> {
|
||||||
for nic in config.network_interfaces.iter() {
|
for nic in config.network_interfaces.iter() {
|
||||||
for range in nic.ipv6.iter() {
|
for range in nic.ipv6.iter() {
|
||||||
for ip in range.subnet.iter().skip(1) {
|
for ip in range.subnet.iter().skip(1) {
|
||||||
@ -130,11 +142,11 @@ impl Resources {
|
|||||||
{
|
{
|
||||||
let if_config = match nic.driver {
|
let if_config = match nic.driver {
|
||||||
crate::config::InterfaceType::MACVTAP => InterfaceConfig::MACVTAP {
|
crate::config::InterfaceType::MACVTAP => InterfaceConfig::MACVTAP {
|
||||||
name: self.get_free_vm_name(),
|
name: self.available_if_name(),
|
||||||
device: nic.device.clone(),
|
device: nic.device.clone(),
|
||||||
},
|
},
|
||||||
crate::config::InterfaceType::IPVTAP => InterfaceConfig::IPVTAP {
|
crate::config::InterfaceType::IPVTAP => InterfaceConfig::IPVTAP {
|
||||||
name: self.get_free_vm_name(),
|
name: self.available_if_name(),
|
||||||
device: nic.device.clone(),
|
device: nic.device.clone(),
|
||||||
},
|
},
|
||||||
crate::config::InterfaceType::Bridge => InterfaceConfig::Bridge {
|
crate::config::InterfaceType::Bridge => InterfaceConfig::Bridge {
|
||||||
@ -142,16 +154,9 @@ impl Resources {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
let mut ips = Vec::new();
|
let mut ips = Vec::new();
|
||||||
let mask = ip
|
|
||||||
.network()
|
|
||||||
.to_string()
|
|
||||||
.split('/')
|
|
||||||
.nth(1)
|
|
||||||
.unwrap()
|
|
||||||
.to_string();
|
|
||||||
ips.push(IPConfig {
|
ips.push(IPConfig {
|
||||||
address: ip.address().to_string(),
|
address: ip.address().to_string(),
|
||||||
mask,
|
mask: calc_ipv6_netmask(ip.address(), range.gateway),
|
||||||
gateway: range.gateway.to_string(),
|
gateway: range.gateway.to_string(),
|
||||||
});
|
});
|
||||||
return Some(VMNIC { if_config, ips });
|
return Some(VMNIC { if_config, ips });
|
||||||
@ -192,7 +197,7 @@ impl Resources {
|
|||||||
|
|
||||||
fn reserve_vm_resources(&mut self, vm: &VM) {
|
fn reserve_vm_resources(&mut self, vm: &VM) {
|
||||||
self.reserved_vcpus += vm.vcpus;
|
self.reserved_vcpus += vm.vcpus;
|
||||||
self.reserved_memory += vm.memory;
|
self.reserved_memory += vm.memory_mb;
|
||||||
for nic in vm.nics.iter() {
|
for nic in vm.nics.iter() {
|
||||||
if let Some(vtap) = nic.if_config.vtap_name() {
|
if let Some(vtap) = nic.if_config.vtap_name() {
|
||||||
self.reserved_if_names.insert(vtap);
|
self.reserved_if_names.insert(vtap);
|
||||||
@ -204,11 +209,18 @@ impl Resources {
|
|||||||
for (host_port, _) in vm.fw_ports.iter() {
|
for (host_port, _) in vm.fw_ports.iter() {
|
||||||
self.reserved_ports.insert(*host_port);
|
self.reserved_ports.insert(*host_port);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for storage_pool in self.storage_pools.iter_mut() {
|
||||||
|
if storage_pool.path == vm.storage_pool_path {
|
||||||
|
storage_pool.available_gb -= vm.disk_size_gb;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn free_vm_resources(&mut self, vm: &VM) {
|
fn free_vm_resources(&mut self, vm: &VM) {
|
||||||
self.reserved_vcpus -= vm.vcpus;
|
self.reserved_vcpus -= vm.vcpus;
|
||||||
self.reserved_memory -= vm.memory;
|
self.reserved_memory -= vm.memory_mb;
|
||||||
for nic in vm.nics.iter() {
|
for nic in vm.nics.iter() {
|
||||||
if let Some(vtap) = nic.if_config.vtap_name() {
|
if let Some(vtap) = nic.if_config.vtap_name() {
|
||||||
self.reserved_if_names.remove(&vtap);
|
self.reserved_if_names.remove(&vtap);
|
||||||
@ -226,7 +238,7 @@ impl Resources {
|
|||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct StoragePool {
|
pub struct StoragePool {
|
||||||
path: String,
|
path: String,
|
||||||
current_reservation: u64,
|
available_gb: usize,
|
||||||
// add mechanic to detect storage tier
|
// add mechanic to detect storage tier
|
||||||
// tier: StorageTier,
|
// tier: StorageTier,
|
||||||
}
|
}
|
||||||
@ -308,11 +320,12 @@ pub struct VM {
|
|||||||
// cpu_type: String,
|
// cpu_type: String,
|
||||||
vcpus: usize,
|
vcpus: usize,
|
||||||
// memory in MB
|
// memory in MB
|
||||||
memory: usize,
|
memory_mb: usize,
|
||||||
// disk size in GB
|
// disk size in GB
|
||||||
disk_size: usize,
|
disk_size_gb: usize,
|
||||||
kernel_sha: String,
|
kernel_sha: String,
|
||||||
dtrfs_sha: String,
|
dtrfs_sha: String,
|
||||||
|
storage_pool_path: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Debug)]
|
#[derive(Deserialize, Debug)]
|
||||||
@ -323,9 +336,9 @@ pub struct NewVMRequest {
|
|||||||
extra_ports: Vec<u16>,
|
extra_ports: Vec<u16>,
|
||||||
public_ipv4: bool,
|
public_ipv4: bool,
|
||||||
public_ipv6: bool,
|
public_ipv6: bool,
|
||||||
disk_size: usize,
|
disk_size_gb: usize,
|
||||||
vcpus: usize,
|
vcpus: usize,
|
||||||
memory: usize,
|
memory_mb: usize,
|
||||||
kernel_url: String,
|
kernel_url: String,
|
||||||
kernel_sha: String,
|
kernel_sha: String,
|
||||||
dtrfs_url: String,
|
dtrfs_url: String,
|
||||||
@ -368,7 +381,7 @@ impl VM {
|
|||||||
if config.max_vcpu_reservation < res.reserved_vcpus.saturating_add(req.vcpus) {
|
if config.max_vcpu_reservation < res.reserved_vcpus.saturating_add(req.vcpus) {
|
||||||
return Err(VMCreationErrors::NotEnoughCPU);
|
return Err(VMCreationErrors::NotEnoughCPU);
|
||||||
}
|
}
|
||||||
if config.max_mem_reservation < res.reserved_memory.saturating_add(req.memory) {
|
if config.max_mem_reservation_mb < res.reserved_memory.saturating_add(req.memory_mb) {
|
||||||
return Err(VMCreationErrors::NotEnoughMemory);
|
return Err(VMCreationErrors::NotEnoughMemory);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -388,13 +401,13 @@ impl VM {
|
|||||||
|
|
||||||
let mut vm_nics = Vec::new();
|
let mut vm_nics = Vec::new();
|
||||||
if req.public_ipv4 {
|
if req.public_ipv4 {
|
||||||
match res.get_free_ipv4(config) {
|
match res.available_ipv4(config) {
|
||||||
Some(vmnic) => vm_nics.push(vmnic),
|
Some(vmnic) => vm_nics.push(vmnic),
|
||||||
None => return Err(VMCreationErrors::IPv4NotAvailable),
|
None => return Err(VMCreationErrors::IPv4NotAvailable),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if req.public_ipv6 {
|
if req.public_ipv6 {
|
||||||
match res.get_free_ipv6(config) {
|
match res.available_ipv6(config) {
|
||||||
Some(mut vmnic) => {
|
Some(mut vmnic) => {
|
||||||
if let Some(mut existing_vmnic) = vm_nics.pop() {
|
if let Some(mut existing_vmnic) = vm_nics.pop() {
|
||||||
if vmnic.if_config.device_name() == existing_vmnic.if_config.device_name() {
|
if vmnic.if_config.device_name() == existing_vmnic.if_config.device_name() {
|
||||||
@ -417,7 +430,7 @@ impl VM {
|
|||||||
let mut host_ports: Vec<u16> = Vec::new();
|
let mut host_ports: Vec<u16> = Vec::new();
|
||||||
let mut port_pairs: Vec<(u16, u16)> = Vec::new();
|
let mut port_pairs: Vec<(u16, u16)> = Vec::new();
|
||||||
if !req.public_ipv4 {
|
if !req.public_ipv4 {
|
||||||
host_ports.append(res.get_free_ports(req.extra_ports.len(), &config).as_mut());
|
host_ports.append(res.available_ports(req.extra_ports.len(), &config).as_mut());
|
||||||
if host_ports.len() == 0 {
|
if host_ports.len() == 0 {
|
||||||
return Err(VMCreationErrors::NotEnoughPorts);
|
return Err(VMCreationErrors::NotEnoughPorts);
|
||||||
}
|
}
|
||||||
@ -427,18 +440,25 @@ impl VM {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let storage_pool_path = match res.available_storage_pool(req.disk_size_gb) {
|
||||||
|
Some(path) => path,
|
||||||
|
None => return Err(VMCreationErrors::NotEnoughStorage),
|
||||||
|
};
|
||||||
|
|
||||||
let vm = VM {
|
let vm = VM {
|
||||||
uuid: req.uuid,
|
uuid: req.uuid,
|
||||||
hostname: req.hostname,
|
hostname: req.hostname,
|
||||||
admin_key: req.admin_key,
|
admin_key: req.admin_key,
|
||||||
nics: vm_nics,
|
nics: vm_nics,
|
||||||
vcpus: req.vcpus,
|
vcpus: req.vcpus,
|
||||||
memory: req.memory,
|
memory_mb: req.memory_mb,
|
||||||
disk_size: req.disk_size,
|
disk_size_gb: req.disk_size_gb,
|
||||||
kernel_sha: req.kernel_sha,
|
kernel_sha: req.kernel_sha,
|
||||||
dtrfs_sha: req.dtrfs_sha,
|
dtrfs_sha: req.dtrfs_sha,
|
||||||
fw_ports: port_pairs,
|
fw_ports: port_pairs,
|
||||||
|
storage_pool_path,
|
||||||
};
|
};
|
||||||
|
|
||||||
res.reserve_vm_resources(&vm);
|
res.reserve_vm_resources(&vm);
|
||||||
Ok(vm)
|
Ok(vm)
|
||||||
}
|
}
|
||||||
@ -477,7 +497,11 @@ impl VM {
|
|||||||
// This means we can enforce the path to the disk.
|
// This means we can enforce the path to the disk.
|
||||||
// This may change in the future as the VM is allowed to have multiple disks.
|
// This may change in the future as the VM is allowed to have multiple disks.
|
||||||
pub fn disk_path(&self) -> String {
|
pub fn disk_path(&self) -> String {
|
||||||
VM_DISK_DIR.to_string() + &self.uuid + ".qcow2"
|
let dir = match self.storage_pool_path.ends_with("/") {
|
||||||
|
true => self.storage_pool_path.clone(),
|
||||||
|
false => self.storage_pool_path.clone() + "/",
|
||||||
|
};
|
||||||
|
dir + &self.uuid + ".qcow2"
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn kernel_params(&self) -> String {
|
pub fn kernel_params(&self) -> String {
|
||||||
@ -520,19 +544,13 @@ impl VM {
|
|||||||
vars += &format!("NAT_PORT_FW={}", ports.trim_end());
|
vars += &format!("NAT_PORT_FW={}", ports.trim_end());
|
||||||
}
|
}
|
||||||
|
|
||||||
vars += &format!(
|
vars += &format!("KERNEL={}\n", VM_BOOT_DIR.to_string() + &self.kernel_sha);
|
||||||
"KERNEL={}\n",
|
vars += &format!("INITRD={}\n", VM_BOOT_DIR.to_string() + &self.dtrfs_sha);
|
||||||
VM_BOOT_DIR.to_string() + &self.kernel_sha
|
|
||||||
);
|
|
||||||
vars += &format!(
|
|
||||||
"INITRD={}\n",
|
|
||||||
VM_BOOT_DIR.to_string() + &self.dtrfs_sha
|
|
||||||
);
|
|
||||||
vars += &format!("PARAMS={}\n", self.kernel_params());
|
vars += &format!("PARAMS={}\n", self.kernel_params());
|
||||||
vars += &format!("CPU_TYPE={}\n", QEMU_VM_CPU_TYPE);
|
vars += &format!("CPU_TYPE={}\n", QEMU_VM_CPU_TYPE);
|
||||||
vars += &format!("VCPUS={}\n", self.vcpus);
|
vars += &format!("VCPUS={}\n", self.vcpus);
|
||||||
vars += &format!("MEMORY={}MB\n", self.memory);
|
vars += &format!("MEMORY={}MB\n", self.memory_mb);
|
||||||
vars += &format!("MAX_MEMORY={}MB\n", self.memory + 256);
|
vars += &format!("MAX_MEMORY={}MB\n", self.memory_mb + 256);
|
||||||
vars += &format!("DISK={}\n", self.disk_path());
|
vars += &format!("DISK={}\n", self.disk_path());
|
||||||
|
|
||||||
let mut file = File::create(VM_CONFIG_DIR.to_string() + &self.uuid)?;
|
let mut file = File::create(VM_CONFIG_DIR.to_string() + &self.uuid)?;
|
||||||
@ -582,7 +600,8 @@ impl VM {
|
|||||||
contents += &format!("[Install]\n");
|
contents += &format!("[Install]\n");
|
||||||
contents += &format!("WantedBy=multi-user.target\n");
|
contents += &format!("WantedBy=multi-user.target\n");
|
||||||
|
|
||||||
let mut file = File::create("/tmp/etc/systemd/system/".to_string() + &self.uuid + ".service")?;
|
let mut file =
|
||||||
|
File::create("/tmp/etc/systemd/system/".to_string() + &self.uuid + ".service")?;
|
||||||
file.write_all(contents.as_bytes())?;
|
file.write_all(contents.as_bytes())?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -598,7 +617,7 @@ impl VM {
|
|||||||
.arg("-f")
|
.arg("-f")
|
||||||
.arg("qcow2")
|
.arg("qcow2")
|
||||||
.arg(self.disk_path())
|
.arg(self.disk_path())
|
||||||
.arg(self.disk_size.to_string() + "G")
|
.arg(self.disk_size_gb.to_string() + "G")
|
||||||
.output()?;
|
.output()?;
|
||||||
if !result.status.success() {
|
if !result.status.success() {
|
||||||
return Err(anyhow!(
|
return Err(anyhow!(
|
||||||
@ -659,3 +678,41 @@ fn compute_sha256<P: AsRef<Path>>(path: P) -> Result<String> {
|
|||||||
let result = hasher.finalize();
|
let result = hasher.finalize();
|
||||||
Ok(format!("{:x}", result))
|
Ok(format!("{:x}", result))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn calc_ipv4_netmask(ip: Ipv4Addr, gateway: Ipv4Addr) -> String {
|
||||||
|
// Convert the IPs to u32 for easier bit manipulation
|
||||||
|
let ip_u32 = u32::from(ip);
|
||||||
|
let gateway_u32 = u32::from(gateway);
|
||||||
|
|
||||||
|
// Find the smallest common prefix
|
||||||
|
let mut prefix_len = 0;
|
||||||
|
for i in 1..=32 {
|
||||||
|
if (ip_u32 >> (32 - i)) == (gateway_u32 >> (32 - i)) {
|
||||||
|
prefix_len = i;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the mask as a string
|
||||||
|
prefix_len.to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn calc_ipv6_netmask(ip: Ipv6Addr, gateway: Ipv6Addr) -> String {
|
||||||
|
// Convert the IPs to u128 for easier bit manipulation
|
||||||
|
let ip_u128 = u128::from(ip);
|
||||||
|
let gateway_u128 = u128::from(gateway);
|
||||||
|
|
||||||
|
// Find the smallest common prefix
|
||||||
|
let mut prefix_len = 0;
|
||||||
|
for i in 1..=128 {
|
||||||
|
if (ip_u128 >> (128 - i)) == (gateway_u128 >> (128 - i)) {
|
||||||
|
prefix_len = i;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the mask as a string
|
||||||
|
prefix_len.to_string()
|
||||||
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
max_cores_per_vm: 4
|
max_cores_per_vm: 4
|
||||||
max_vcpu_reservation: 8
|
max_vcpu_reservation: 8
|
||||||
max_mem_reservation: 16384
|
max_mem_reservation_mb: 16384
|
||||||
network_interfaces:
|
network_interfaces:
|
||||||
- driver: "MACVTAP"
|
- driver: "MACVTAP"
|
||||||
device: "eth0"
|
device: "eth0"
|
||||||
@ -18,7 +18,7 @@ network_interfaces:
|
|||||||
- "2001:db8::5678"
|
- "2001:db8::5678"
|
||||||
volumes:
|
volumes:
|
||||||
- path: "/mnt/storage"
|
- path: "/mnt/storage"
|
||||||
max_reservation: 200
|
max_reservation_gb: 200
|
||||||
public_port_range:
|
public_port_range:
|
||||||
start: 8000
|
start: 8000
|
||||||
end: 9000
|
end: 9000
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
max_cores_per_vm: 16
|
max_cores_per_vm: 16
|
||||||
max_vcpu_reservation: 32
|
max_vcpu_reservation: 32
|
||||||
max_mem_reservation: 1265536
|
max_mem_reservation_mb: 1265536
|
||||||
network_interfaces:
|
network_interfaces:
|
||||||
- driver: "Bridge"
|
- driver: "Bridge"
|
||||||
device: "br0"
|
device: "br0"
|
||||||
@ -27,12 +27,8 @@ network_interfaces:
|
|||||||
- "2001:db8:abcd:1234::dead"
|
- "2001:db8:abcd:1234::dead"
|
||||||
- "2001:db8:abcd:1234::beef"
|
- "2001:db8:abcd:1234::beef"
|
||||||
volumes:
|
volumes:
|
||||||
- path: "/data/volume1"
|
- path: "/etc/detee/daemon/vms/"
|
||||||
max_reservation: 500
|
max_reservation_gb: 500
|
||||||
- path: "/data/volume2"
|
|
||||||
max_reservation: 1000
|
|
||||||
- path: "/backup"
|
|
||||||
max_reservation: 2000
|
|
||||||
public_port_range:
|
public_port_range:
|
||||||
start: 10000
|
start: 10000
|
||||||
end: 11000
|
end: 11000
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
max_cores_per_vm: 12
|
max_cores_per_vm: 12
|
||||||
max_vcpu_reservation: 24
|
max_vcpu_reservation: 24
|
||||||
max_mem_reservation: 49152
|
max_mem_reservation_mb: 49152
|
||||||
network_interfaces:
|
network_interfaces:
|
||||||
- driver: "IPVTAP"
|
- driver: "IPVTAP"
|
||||||
device: "tap0"
|
device: "tap0"
|
||||||
@ -13,7 +13,7 @@ network_interfaces:
|
|||||||
- "2001:db8:abcd:1234::beef"
|
- "2001:db8:abcd:1234::beef"
|
||||||
volumes:
|
volumes:
|
||||||
- path: "/ipv6/volume"
|
- path: "/ipv6/volume"
|
||||||
max_reservation: 600
|
max_reservation_gb: 600
|
||||||
public_port_range:
|
public_port_range:
|
||||||
start: 15000
|
start: 15000
|
||||||
end: 16000
|
end: 16000
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
max_cores_per_vm: 2
|
max_cores_per_vm: 2
|
||||||
max_vcpu_reservation: 4
|
max_vcpu_reservation: 4
|
||||||
max_mem_reservation: 8192
|
max_mem_reservation_mb: 8192
|
||||||
network_interfaces:
|
network_interfaces:
|
||||||
- driver: "MACVTAP"
|
- driver: "MACVTAP"
|
||||||
device: "eth0"
|
device: "eth0"
|
||||||
@ -11,7 +11,7 @@ network_interfaces:
|
|||||||
ipv6: []
|
ipv6: []
|
||||||
volumes:
|
volumes:
|
||||||
- path: "/minimal/volume"
|
- path: "/minimal/volume"
|
||||||
max_reservation: 100
|
max_reservation_gb: 100
|
||||||
public_port_range:
|
public_port_range:
|
||||||
start: 5000
|
start: 5000
|
||||||
end: 5100
|
end: 5100
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
max_cores_per_vm: 8
|
max_cores_per_vm: 8
|
||||||
max_vcpu_reservation: 16
|
max_vcpu_reservation: 16
|
||||||
max_mem_reservation: 32768
|
max_mem_reservation_mb: 32768
|
||||||
network_interfaces:
|
network_interfaces:
|
||||||
- driver: "Bridge"
|
- driver: "Bridge"
|
||||||
device: "br1"
|
device: "br1"
|
||||||
@ -14,7 +14,7 @@ network_interfaces:
|
|||||||
reserved_addrs: []
|
reserved_addrs: []
|
||||||
volumes:
|
volumes:
|
||||||
- path: "/network/volume"
|
- path: "/network/volume"
|
||||||
max_reservation: 750
|
max_reservation_gb: 750
|
||||||
public_port_range:
|
public_port_range:
|
||||||
start: 6000
|
start: 6000
|
||||||
end: 7000
|
end: 7000
|
||||||
|
@ -4,9 +4,9 @@ admin_key: "ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEArandomkeyexample"
|
|||||||
extra_ports: [ ]
|
extra_ports: [ ]
|
||||||
public_ipv4: true
|
public_ipv4: true
|
||||||
public_ipv6: false
|
public_ipv6: false
|
||||||
disk_size: 50
|
disk_size_gb: 50
|
||||||
vcpus: 4
|
vcpus: 4
|
||||||
memory: 8192
|
memory_mb: 8192
|
||||||
kernel_url: "http://pb1n.de/?d25eec"
|
kernel_url: "http://pb1n.de/?d25eec"
|
||||||
kernel_sha: "be29dfef7157bfe860e94e96dcfab2318c5006e92e8d846a3ad7aa804b3b994e"
|
kernel_sha: "be29dfef7157bfe860e94e96dcfab2318c5006e92e8d846a3ad7aa804b3b994e"
|
||||||
dtrfs_url: "http://pb1n.de/?e46db9"
|
dtrfs_url: "http://pb1n.de/?e46db9"
|
||||||
|
@ -4,9 +4,9 @@ admin_key: "ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQAnotherExampleKey"
|
|||||||
extra_ports: []
|
extra_ports: []
|
||||||
public_ipv4: false
|
public_ipv4: false
|
||||||
public_ipv6: false
|
public_ipv6: false
|
||||||
disk_size: 10
|
disk_size_gb: 10
|
||||||
vcpus: 1
|
vcpus: 1
|
||||||
memory: 2048
|
memory_mb: 2048
|
||||||
kernel_url: "http://pb1n.de/?d25eec"
|
kernel_url: "http://pb1n.de/?d25eec"
|
||||||
kernel_sha: "be29dfef7157bfe860e94e96dcfab2318c5006e92e8d846a3ad7aa804b3b994e"
|
kernel_sha: "be29dfef7157bfe860e94e96dcfab2318c5006e92e8d846a3ad7aa804b3b994e"
|
||||||
dtrfs_url: "http://pb1n.de/?e46db9"
|
dtrfs_url: "http://pb1n.de/?e46db9"
|
||||||
|
@ -4,9 +4,9 @@ admin_key: "ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEExtendedKeyExample"
|
|||||||
extra_ports: []
|
extra_ports: []
|
||||||
public_ipv4: true
|
public_ipv4: true
|
||||||
public_ipv6: true
|
public_ipv6: true
|
||||||
disk_size: 200
|
disk_size_gb: 35
|
||||||
vcpus: 2
|
vcpus: 2
|
||||||
memory: 65536
|
memory_mb: 5000
|
||||||
kernel_url: "http://pb1n.de/?d25eec"
|
kernel_url: "http://pb1n.de/?d25eec"
|
||||||
kernel_sha: "be29dfef7157bfe860e94e96dcfab2318c5006e92e8d846a3ad7aa804b3b994e"
|
kernel_sha: "be29dfef7157bfe860e94e96dcfab2318c5006e92e8d846a3ad7aa804b3b994e"
|
||||||
dtrfs_url: "http://pb1n.de/?e46db9"
|
dtrfs_url: "http://pb1n.de/?e46db9"
|
||||||
|
@ -4,9 +4,9 @@ admin_key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAAKeyExampleForTesting"
|
|||||||
extra_ports: [1234, 5678]
|
extra_ports: [1234, 5678]
|
||||||
public_ipv4: false
|
public_ipv4: false
|
||||||
public_ipv6: true
|
public_ipv6: true
|
||||||
disk_size: 25
|
disk_size_gb: 25
|
||||||
vcpus: 2
|
vcpus: 2
|
||||||
memory: 4096
|
memory_mb: 4096
|
||||||
kernel_url: "http://pb1n.de/?d25eec"
|
kernel_url: "http://pb1n.de/?d25eec"
|
||||||
kernel_sha: "be29dfef7157bfe860e94e96dcfab2318c5006e92e8d846a3ad7aa804b3b994e"
|
kernel_sha: "be29dfef7157bfe860e94e96dcfab2318c5006e92e8d846a3ad7aa804b3b994e"
|
||||||
dtrfs_url: "http://pb1n.de/?e46db9"
|
dtrfs_url: "http://pb1n.de/?e46db9"
|
||||||
|
Loading…
Reference in New Issue
Block a user