Skip to main content

xbp_cli/commands/
network.rs

1use crate::cli::commands::{
2    NetworkConfigSubCommand, NetworkFloatingIpSubCommand, NetworkHetznerSubCommand,
3    NetworkHetznerVswitchSubCommand, NetworkSubCommand,
4};
5use crate::sdk::network::{
6    add_floating_ip, list_floating_ips, list_network_config_sources, AddFloatingIpRequest,
7};
8use crate::sdk::network_hetzner::{setup_hetzner_vswitch, SetupHetznerVswitchRequest};
9use anyhow::Result;
10
11pub async fn run_network(command: NetworkSubCommand, _debug: bool) -> Result<()> {
12    match command {
13        NetworkSubCommand::FloatingIp(floating_ip) => match floating_ip.command {
14            NetworkFloatingIpSubCommand::Add {
15                ip,
16                cidr,
17                interface,
18                label,
19                apply,
20                dry_run,
21            } => {
22                let response = add_floating_ip(AddFloatingIpRequest {
23                    ip,
24                    cidr,
25                    interface,
26                    label,
27                    apply,
28                    dry_run,
29                })
30                .await?;
31                println!("{}", serde_json::to_string_pretty(&response)?);
32            }
33            NetworkFloatingIpSubCommand::List { json } => {
34                let response = list_floating_ips().await?;
35                if json {
36                    println!("{}", serde_json::to_string_pretty(&response)?);
37                } else {
38                    print_floating_ips_table(&response.items);
39                }
40            }
41        },
42        NetworkSubCommand::Config(config) => match config.command {
43            NetworkConfigSubCommand::List { json } => {
44                let response = list_network_config_sources().await?;
45                if json {
46                    println!("{}", serde_json::to_string_pretty(&response)?);
47                } else {
48                    print_network_config_sources_table(
49                        &response.sources,
50                        response.detected_backend,
51                    );
52                }
53            }
54        },
55        NetworkSubCommand::Hetzner(hetzner) => match hetzner.command {
56            NetworkHetznerSubCommand::Vswitch(vswitch) => match vswitch.command {
57                NetworkHetznerVswitchSubCommand::Setup {
58                    ip,
59                    cidr,
60                    interface,
61                    vlan_id,
62                    mtu,
63                    gateway,
64                    route_cidr,
65                    apply,
66                    dry_run,
67                } => {
68                    let response = setup_hetzner_vswitch(SetupHetznerVswitchRequest {
69                        ip,
70                        cidr: Some(cidr),
71                        interface,
72                        vlan_id,
73                        mtu,
74                        gateway,
75                        route_cidr,
76                        apply,
77                        dry_run,
78                    })
79                    .await?;
80                    println!("{}", serde_json::to_string_pretty(&response)?);
81                }
82            },
83        },
84    }
85
86    Ok(())
87}
88
89fn print_floating_ips_table(items: &[crate::sdk::network::FloatingIpEntry]) {
90    if items.is_empty() {
91        println!("No floating IP entries found.");
92        return;
93    }
94
95    println!(
96        "{:<8} {:<14} {:<20} {:<8} {:<10} SOURCE",
97        "BACKEND", "INTERFACE", "IP/CIDR", "RUNTIME", "CONFIG"
98    );
99    println!("{}", "-".repeat(96));
100    for item in items {
101        println!(
102            "{:<8} {:<14} {:<20} {:<8} {:<10} {}",
103            item.backend,
104            item.interface,
105            item.address_cidr,
106            if item.runtime { "yes" } else { "no" },
107            if item.config { "yes" } else { "no" },
108            item.source_file.as_deref().unwrap_or("-"),
109        );
110    }
111}
112
113fn print_network_config_sources_table(
114    sources: &[crate::sdk::network::NetworkConfigSource],
115    detected_backend: crate::sdk::network::NetworkBackend,
116) {
117    println!("Detected backend: {}", detected_backend);
118    if sources.is_empty() {
119        println!("No network config sources discovered.");
120        return;
121    }
122
123    println!("{:<8} {:<6} PATH", "BACKEND", "EXISTS");
124    println!("{}", "-".repeat(96));
125    for source in sources {
126        println!(
127            "{:<8} {:<6} {}",
128            source.backend,
129            if source.exists { "yes" } else { "no" },
130            source.path
131        );
132    }
133}