feat: fill in ipv6 addresses
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
2025-03-28 11:19:11 +00:00
parent d18f32e897
commit 603099e947
4 changed files with 108 additions and 36 deletions

View File

@ -57,9 +57,6 @@ async fn main() -> Result<(), Error> {
}
let db: Arc<dyn LNVpsDb> = Arc::new(db);
// run data migrations
run_data_migrations(db.clone(), &settings).await?;
let nostr_client = if let Some(ref c) = settings.nostr {
let cx = Client::builder().signer(Keys::parse(&c.nsec)?).build();
for r in &c.relays {
@ -78,6 +75,9 @@ async fn main() -> Result<(), Error> {
let provisioner = settings.get_provisioner(db.clone(), node.clone(), exchange.clone());
provisioner.init().await?;
// run data migrations
run_data_migrations(db.clone(), provisioner.clone(), &settings).await?;
let mut worker = Worker::new(
db.clone(),
provisioner.clone(),

View File

@ -0,0 +1,49 @@
use crate::data_migration::DataMigration;
use crate::provisioner::{LNVpsProvisioner, NetworkProvisioner};
use ipnetwork::IpNetwork;
use lnvps_db::LNVpsDb;
use std::future::Future;
use std::pin::Pin;
use std::str::FromStr;
use std::sync::Arc;
use log::info;
pub struct Ip6InitDataMigration {
db: Arc<dyn LNVpsDb>,
provisioner: Arc<LNVpsProvisioner>,
}
impl Ip6InitDataMigration {
pub fn new(db: Arc<dyn LNVpsDb>, provisioner: Arc<LNVpsProvisioner>) -> Ip6InitDataMigration {
Self { db, provisioner }
}
}
impl DataMigration for Ip6InitDataMigration {
fn migrate(&self) -> Pin<Box<dyn Future<Output = anyhow::Result<()>> + Send>> {
let db = self.db.clone();
let provisioner = self.provisioner.clone();
Box::pin(async move {
let net = NetworkProvisioner::new(db.clone());
let vms = db.list_vms().await?;
for vm in vms {
let host = db.get_host(vm.host_id).await?;
let ips = db.list_vm_ip_assignments(vm.id).await?;
// if no ipv6 address is picked already pick one
if ips.iter().all(|i| {
IpNetwork::from_str(&i.ip)
.map(|i| i.is_ipv4())
.unwrap_or(false)
})
{
let ips_pick = net.pick_ip_for_region(host.region_id).await?;
if let Some(mut v6) = ips_pick.ip6 {
info!("Assigning ip {} to vm {}", v6.ip, vm.id);
provisioner.assign_available_v6_to_vm(&vm, &mut v6).await?;
}
}
}
Ok(())
})
}
}

View File

@ -6,18 +6,23 @@ use log::{error, info};
use std::future::Future;
use std::pin::Pin;
use std::sync::Arc;
use crate::data_migration::ip6_init::Ip6InitDataMigration;
use crate::provisioner::LNVpsProvisioner;
mod dns;
mod ip6_init;
/// Basic data migration to run at startup
pub trait DataMigration: Send + Sync {
fn migrate(&self) -> Pin<Box<dyn Future<Output = Result<()>> + Send>>;
}
pub async fn run_data_migrations(db: Arc<dyn LNVpsDb>, settings: &Settings) -> Result<()> {
let mut migrations: Vec<Arc<dyn DataMigration>> = vec![];
pub async fn run_data_migrations(db: Arc<dyn LNVpsDb>, lnvps: Arc<LNVpsProvisioner>, settings: &Settings) -> Result<()> {
let mut migrations: Vec<Box<dyn DataMigration>> = vec![];
migrations.push(Box::new(Ip6InitDataMigration::new(db.clone(), lnvps.clone())));
if let Some(d) = DnsDataMigration::new(db.clone(), settings) {
migrations.push(Arc::new(d));
migrations.push(Box::new(d));
}
info!("Running {} data migrations", migrations.len());

View File

@ -3,7 +3,9 @@ use crate::exchange::{Currency, CurrencyAmount, ExchangeRateService};
use crate::fiat::FiatPaymentService;
use crate::host::{get_host_client, FullVmInfo};
use crate::lightning::{AddInvoiceRequest, LightningNode};
use crate::provisioner::{CostResult, HostCapacityService, NetworkProvisioner, PricingEngine};
use crate::provisioner::{
AvailableIp, CostResult, HostCapacityService, NetworkProvisioner, PricingEngine,
};
use crate::router::{ArpEntry, MikrotikRouter, OvhDedicatedServerVMacRouter, Router};
use crate::settings::{ProvisionerConfig, Settings};
use anyhow::{bail, ensure, Context, Result};
@ -284,6 +286,47 @@ impl LNVpsProvisioner {
})
}
pub async fn assign_available_v4_to_vm(
&self,
vm: &Vm,
v4: &AvailableIp,
) -> Result<VmIpAssignment> {
let mut assignment = VmIpAssignment {
vm_id: vm.id,
ip_range_id: v4.range_id,
ip: v4.ip.ip().to_string(),
..Default::default()
};
self.save_ip_assignment(&mut assignment).await?;
Ok(assignment)
}
pub async fn assign_available_v6_to_vm(
&self,
vm: &Vm,
v6: &mut AvailableIp,
) -> Result<VmIpAssignment> {
match v6.mode {
// it's a bit awkward, but we need to update the IP AFTER its been picked
// simply because sometimes we don't know the MAC of the NIC yet
IpRangeAllocationMode::SlaacEui64 => {
let mac = NetworkProvisioner::parse_mac(&vm.mac_address)?;
let addr = NetworkProvisioner::calculate_eui64(&mac, &v6.ip)?;
v6.ip = IpNetwork::new(addr, v6.ip.prefix())?;
}
_ => {}
}
let mut assignment = VmIpAssignment {
vm_id: vm.id,
ip_range_id: v6.range_id,
ip: v6.ip.ip().to_string(),
..Default::default()
};
self.save_ip_assignment(&mut assignment).await?;
Ok(assignment)
}
async fn allocate_ips(&self, vm_id: u64) -> Result<Vec<VmIpAssignment>> {
let mut vm = self.db.get_vm(vm_id).await?;
let existing_ips = self.db.list_vm_ip_assignments(vm_id).await?;
@ -299,12 +342,7 @@ impl LNVpsProvisioner {
let mut assignments = vec![];
match ip.ip4 {
Some(v4) => {
let mut assignment = VmIpAssignment {
vm_id,
ip_range_id: v4.range_id,
ip: v4.ip.ip().to_string(),
..Default::default()
};
let mut assignment = self.assign_available_v4_to_vm(&vm, &v4).await?;
//generate mac address from ip assignment
let mac = self.get_mac_for_assignment(&host, &vm, &assignment).await?;
@ -312,33 +350,13 @@ impl LNVpsProvisioner {
assignment.arp_ref = mac.id; // store ref if we got one
self.db.update_vm(&vm).await?;
self.save_ip_assignment(&mut assignment).await?;
assignments.push(assignment);
}
/// TODO: add expected number of IPS per templates
None => bail!("Cannot provision VM without an IPv4 address"),
}
match ip.ip6 {
Some(mut v6) => {
match v6.mode {
// it's a bit awkward but we need to update the IP AFTER its been picked
// simply because sometimes we dont know the MAC of the NIC yet
IpRangeAllocationMode::SlaacEui64 => {
let mac = NetworkProvisioner::parse_mac(&vm.mac_address)?;
let addr = NetworkProvisioner::calculate_eui64(&mac, &v6.ip)?;
v6.ip = IpNetwork::new(addr, v6.ip.prefix())?;
}
_ => {}
}
let mut assignment = VmIpAssignment {
vm_id,
ip_range_id: v6.range_id,
ip: v6.ip.ip().to_string(),
..Default::default()
};
self.save_ip_assignment(&mut assignment).await?;
assignments.push(assignment);
}
None => {}
if let Some(mut v6) = ip.ip6 {
assignments.push(self.assign_available_v6_to_vm(&vm, &mut v6).await?);
}
Ok(assignments)