-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathsetup_cloudinit_device.py
More file actions
238 lines (187 loc) · 7.38 KB
/
Copy pathsetup_cloudinit_device.py
File metadata and controls
238 lines (187 loc) · 7.38 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
"""
Network Bridge Configuration Script
Creates and configures a bridge interface for cloud-init VM networks
"""
import subprocess
import os
import sys
import argparse
import ipaddress
from dotenv import load_dotenv
sys.stdout.reconfigure(line_buffering=True)
# Load environment variables
load_dotenv()
IPTABLES_FILE = os.getenv("IPTABLES_FILE","/etc/iptables-backend/iptables.sh")
from monitoring.utils.script_helper import (
log_info, log_debug, log_error, log_warning, log_success, log_section,
run_cmd, Timer, time_function, DEBUG_MODE
)
# Configuration Constants
BRIDGE_NAME = os.getenv("CLOUD_INIT_NETWORK_DEVICE", "vmbr-cloud")
BRIDGE_IP = os.getenv("CLOUD_INIT_NETWORK_DEVICE_IP", "10.32.0.1")
BRIDGE_CIDR = os.getenv("CLOUD_INIT_NETWORK_DEVICE_CIDR", "20")
TARGET_NETWORK = os.getenv("CLOUD_INIT_NETWORK_SUBNET", "10.32.0.0/20")
def check_bridge_exists():
"""Verify if bridge interface already exists in system"""
result = run_cmd(f'ip link show {BRIDGE_NAME}', check=False, shell=True)
return result.returncode == 0
def check_config_exists():
"""Check if bridge configuration exists in network interfaces file"""
try:
with open('/etc/network/interfaces', 'r') as f:
content = f.read()
return BRIDGE_NAME in content
except FileNotFoundError:
log_warning("Network interfaces file not found")
return False
except PermissionError:
log_error("Permission denied reading network interfaces file")
return False
@time_function
def create_bridge_temp():
"""Create temporary bridge interface"""
log_section("Creating temporary bridge interface")
commands = [
f'ip link add name {BRIDGE_NAME} type bridge',
f'ip link set dev {BRIDGE_NAME} up',
f'ip address add {BRIDGE_IP}/{BRIDGE_CIDR} dev {BRIDGE_NAME}'
]
for cmd in commands:
result = run_cmd(cmd, shell=True)
if result.returncode != 0:
log_error(f"Failed to execute: {cmd}")
raise RuntimeError(f"Bridge creation failed at step: {cmd}")
log_success("Temporary bridge created successfully")
@time_function
def enable_ip_forwarding():
"""Enable IP forwarding temporarily and permanently"""
log_section("Configuring IP forwarding")
# Enable temporarily
result = run_cmd('sysctl -w net.ipv4.ip_forward=1', shell=True)
if result.returncode != 0:
log_warning("Failed to enable IP forwarding temporarily")
# Enable permanently
sysctl_conf = '/etc/sysctl.d/99-sysctl.conf'
try:
with open(sysctl_conf, 'r') as f:
content = f.read()
if 'net.ipv4.ip_forward=1' not in content:
with open(sysctl_conf, 'a') as f:
f.write('\nnet.ipv4.ip_forward=1\n')
log_success("Permanently enabled IP forwarding")
else:
log_info("IP forwarding already enabled in sysctl configuration")
except (FileNotFoundError, PermissionError) as e:
log_error(f"Failed to update sysctl configuration: {e}")
@time_function
def setup_nat_and_firewall():
"""Configure NAT masquerading and firewall rules"""
log_section("Setting up NAT and firewall rules")
rules = [
f'iptables -t nat -A POSTROUTING -s {TARGET_NETWORK} -o vmbr0 -j MASQUERADE',
f'iptables -A FORWARD -s {TARGET_NETWORK} -o vmbr0 -j ACCEPT',
f'iptables -A FORWARD -d {TARGET_NETWORK} -i vmbr0 -m state --state RELATED,ESTABLISHED -j ACCEPT'
]
for rule in rules:
result = run_cmd(rule, check=False, shell=True)
if result.returncode != 0:
log_warning(f"Failed to set up rule: {rule}")
else:
try:
with open(IPTABLES_FILE, "a") as f:
f.write(rule + "\n")
except Exception as e:
log_warning(f"Failed to write rule to {IPTABLES_FILE}: {e}")
log_success("NAT and firewall rules configured")
@time_function
def add_to_interfaces():
"""Add persistent bridge configuration to network interfaces file"""
log_section("Adding persistent bridge configuration")
config_content = f'''
# Cloud-Init VM Network Bridge
auto {BRIDGE_NAME}
iface {BRIDGE_NAME} inet static
address {BRIDGE_IP}/{BRIDGE_CIDR}
bridge-ports none
bridge-stp off
bridge-fd 0
post-up echo 1 > /proc/sys/net/ipv4/ip_forward
'''
try:
with open('/etc/network/interfaces', 'a') as f:
f.write(config_content)
log_success("Successfully updated network interfaces file")
except PermissionError:
log_warning("Insufficient permissions, using sudo to append configuration")
result = run_cmd(f'echo "{config_content}" >> /etc/network/interfaces', check=False, shell=True)
if result.returncode != 0:
log_error("Failed to update network interfaces file even with sudo")
raise
@time_function
def validate_configuration():
"""Validate the current configuration parameters"""
log_section("Validating configuration parameters")
# Validate IP address format
try:
ipaddress.IPv4Address(BRIDGE_IP.split('/')[0])
except ipaddress.AddressValueError:
raise ValueError(f"Invalid bridge IP address: {BRIDGE_IP}")
# Validate CIDR
try:
cidr = int(BRIDGE_CIDR)
if not (0 <= cidr <= 32):
raise ValueError(f"Invalid CIDR: {BRIDGE_CIDR}")
except ValueError:
raise ValueError(f"Invalid CIDR format: {BRIDGE_CIDR}")
# Validate target network
try:
ipaddress.IPv4Network(TARGET_NETWORK, strict=False)
except ipaddress.NetmaskValueError:
raise ValueError(f"Invalid target network: {TARGET_NETWORK}")
log_success("Configuration validation passed")
@time_function
def main():
"""Main execution function"""
global DEBUG_MODE
parser = argparse.ArgumentParser(description="Network Bridge Configuration Script")
parser.add_argument("-d", "--debug", action="store_true", help="Enable debug output")
args = parser.parse_args()
DEBUG_MODE = args.debug
log_section(f"Creating Cloud-Init bridge: {BRIDGE_NAME}")
# Validate configuration before proceeding
try:
validate_configuration()
except ValueError as e:
log_error(f"Configuration validation failed: {e}")
sys.exit(1)
# Check if bridge already exists
if check_bridge_exists():
log_error(f"Bridge {BRIDGE_NAME} already exists in system")
sys.exit(1)
if check_config_exists():
log_error(f"Bridge {BRIDGE_NAME} already configured in network interfaces")
sys.exit(1)
try:
with Timer():
# Create temporary bridge
create_bridge_temp()
# Enable IP forwarding
enable_ip_forwarding()
# Setup NAT and firewall
setup_nat_and_firewall()
# Add persistent configuration
add_to_interfaces()
log_section("Bridge Configuration Summary")
log_success("Successfully created Cloud-Init bridge")
log_info(f"Bridge name: {BRIDGE_NAME}")
log_info(f"Gateway IP: {BRIDGE_IP}/{BRIDGE_CIDR}")
log_info(f"VM Network: {TARGET_NETWORK}")
except Exception as e:
log_error(f"Bridge configuration failed: {e}")
sys.exit(1)
if __name__ == "__main__":
# Ensure script runs as root
if os.geteuid() != 0:
log_error("This script must be run as root")
sys.exit(1)
main()