xbp_cli/commands/
network.rs1use 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}