use std::net::Ipv4Addr;
use indexmap::IndexMap;
use isoloom_plan::{Environment, MachinePlan, MachineShape};
use isoloom_render::{router, trunks};
use crate::appliances;
use crate::file::{Attachment, Block, Ipam, Network};
use crate::ipv6;
use crate::machine::Machine;
pub(crate) fn declared(env: &Environment, ts: &[trunks::Trunk]) -> IndexMap<String, Network> {
let mut out: IndexMap<String, Network> = env
.networks
.iter()
.map(|(name, n)| {
let subnet = Block {
subnet: n.cidr.clone(),
gateway: Some(n.host.to_string()),
ip_range: None,
};
(name.clone(), ipv6::network(n, subnet, internal(env, name)))
})
.collect();
for t in ts {
out.insert(
trunks::link_network(t),
Network {
internal: true,
..Network::default()
},
);
}
if !appliances::appliances(env.spec()).is_empty() {
let subnet = Block {
subnet: appliances::MGMT_CIDR.into(),
gateway: None,
ip_range: None,
};
out.insert(
appliances::MGMT_NETWORK.into(),
Network {
ipam: Some(Ipam { config: vec![subnet] }),
..Network::default()
},
);
}
out
}
pub(crate) fn internal(env: &Environment, network: &str) -> bool {
let offline = env.networks.get(network).is_some_and(|n| !n.internet);
let publishes = env
.machines
.values()
.any(|m| m.shape == MachineShape::Container && m.addresses.contains_key(network) && !m.ports.is_empty());
offline && !router::routed(env.spec()) && !publishes
}
pub(crate) fn docker_address(env: &Environment, network: &str) -> Ipv4Addr {
env.networks.get(network).map_or(Ipv4Addr::UNSPECIFIED, |n| n.host)
}
pub(crate) fn attachments(env: &Environment, plan: &MachinePlan) -> IndexMap<String, Option<Attachment>> {
let aliases: Vec<String> = plan.names.iter().skip(1).cloned().collect();
plan.addresses
.iter()
.map(|(n, a)| {
let at = Attachment {
aliases: aliases.clone(),
..ipv6::attachment(env, plan, n, *a)
};
(n.clone(), Some(at))
})
.collect()
}
pub(crate) fn extra_hosts(env: &Environment, m: Machine<'_>) -> Vec<String> {
let ts = trunks::containers(env.spec());
let shared = |other: &str, n: &str| m.spec.networks.contains_key(n) && !trunks::carried(&ts, m.name, n) && !trunks::carried(&ts, other, n);
env.machines
.iter()
.filter(|(o, om)| o.as_str() != m.name && !om.addresses.is_empty() && !om.addresses.keys().any(|n| shared(o, n)))
.flat_map(|(o, om)| {
let a = env.address_for(m.name, o);
om.names.iter().map(move |n| format!("{n}:{a}"))
})
.collect()
}