Skip to content

Commit d9d93ba

Browse files
committed
refactor: split netinit.py into files
1 parent 57adcad commit d9d93ba

19 files changed

+650
-552
lines changed
File renamed without changes.
File renamed without changes.

python/esxi-netinit/netinit.py

Lines changed: 0 additions & 527 deletions
This file was deleted.

python/esxi-netinit/netinit/__init__.py

Whitespace-only changes.
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
from functools import cached_property
2+
3+
from .esxhost import ESXHost
4+
from .network_data import NetworkData
5+
from .nic import NIC
6+
from .nic_list import NICList
7+
8+
9+
class ESXConfig:
10+
def __init__(self, network_data: NetworkData, dry_run=False) -> None:
11+
self.network_data = network_data
12+
self.dry_run = dry_run
13+
self.host = ESXHost(dry_run)
14+
15+
def add_default_mgmt_interface(
16+
self, portgroup_name, switch_name, interface_name="vmk0"
17+
):
18+
self.host.portgroup_add(portgroup_name=portgroup_name, switch_name=switch_name)
19+
self.host.add_ip_interface(name=interface_name, portgroup_name=portgroup_name)
20+
21+
def clean_default_network_setup(self, portgroup_name, switch_name):
22+
"""Removes default networking setup left by the installer."""
23+
self.host.delete_vmknic(portgroup_name=portgroup_name)
24+
self.host.portgroup_remove(
25+
switch_name=switch_name, portgroup_name=portgroup_name
26+
)
27+
self.host.destroy_vswitch(name=switch_name)
28+
29+
def configure_default_route(self):
30+
"""Configures default route.
31+
32+
If multiple default routes are present, only first one is used.
33+
"""
34+
route = self.network_data.default_route()
35+
self.host.configure_default_route(route.gateway)
36+
37+
def configure_portgroups(self, switch_name="vSwitch0"):
38+
portgroups = []
39+
for link in self.network_data.links:
40+
if link.type == "vlan":
41+
vid = link.vlan_id
42+
pg_name = f"internal_net_vid_{vid}"
43+
self.host.portgroup_add(portgroup_name=pg_name, switch_name=switch_name)
44+
self.host.portgroup_set_vlan(portgroup_name=pg_name, vlan_id=vid)
45+
portgroups.append(pg_name)
46+
return portgroups
47+
48+
def configure_management_interface(self):
49+
mgmt_network = next(
50+
net for net in self.network_data.networks if net.default_routes()
51+
)
52+
return self.host.change_ip(
53+
"vmk0", mgmt_network.ip_address, mgmt_network.netmask
54+
)
55+
56+
def configure_vswitch(self, uplink: NIC, switch_name: str, mtu: int):
57+
"""Sets up vSwitch."""
58+
self.host.create_vswitch(switch_name)
59+
self.host.uplink_add(nic=uplink.name, switch_name=switch_name)
60+
self.host.vswitch_failover_uplinks(
61+
active_uplinks=[uplink.name], name=switch_name
62+
)
63+
self.host.vswitch_security(name=switch_name)
64+
self.host.vswitch_settings(mtu=mtu, name=switch_name)
65+
66+
def configure_requested_dns(self):
67+
"""Configures DNS servers that were provided in network_data.json."""
68+
dns_servers = [
69+
srv.address for srv in self.network_data.services if srv.type == "dns"
70+
]
71+
if not dns_servers:
72+
return
73+
74+
return self.host.configure_dns(servers=dns_servers)
75+
76+
def identify_uplink(self) -> NIC:
77+
eligible_networks = [
78+
net for net in self.network_data.networks if net.default_routes()
79+
]
80+
if len(eligible_networks) != 1:
81+
raise ValueError(
82+
"the network_data.json should only contain a single default route."
83+
"Unable to identify uplink interface"
84+
)
85+
link = eligible_networks[0].link
86+
return self.nics.find_by_mac(link.ethernet_mac_address)
87+
88+
@cached_property
89+
def nics(self):
90+
return NICList()
Lines changed: 267 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,267 @@
1+
import subprocess
2+
3+
4+
class ESXHost:
5+
"""Low level commands for configuring various aspects of ESXi hypervisor."""
6+
7+
def __init__(self, dry_run=False) -> None:
8+
self.dry_run = dry_run
9+
10+
def __execute(self, cmd: list):
11+
if self.dry_run:
12+
print(f"Would execute: {' '.join(cmd)}")
13+
return cmd
14+
else:
15+
subprocess.run(cmd, check=True) # noqa: S603
16+
17+
def add_ip_interface(self, name, portgroup_name):
18+
"""Adds IP interface."""
19+
return self.__execute(
20+
[
21+
"/bin/esxcli",
22+
"network",
23+
"ip",
24+
"interface",
25+
"add",
26+
"--interface-name",
27+
name,
28+
"--portgroup-name",
29+
portgroup_name,
30+
]
31+
)
32+
33+
def configure_default_route(self, gateway):
34+
cmd = [
35+
"/bin/esxcli",
36+
"network",
37+
"ip",
38+
"route",
39+
"ipv4",
40+
"add",
41+
"-g",
42+
gateway,
43+
"-n",
44+
"default",
45+
]
46+
return self.__execute(cmd)
47+
48+
def change_ip(self, interface, ip, netmask):
49+
"""Configures IP address on logical interface."""
50+
cmd = [
51+
"/bin/esxcli",
52+
"network",
53+
"ip",
54+
"interface",
55+
"ipv4",
56+
"set",
57+
"-i",
58+
interface,
59+
"-I",
60+
ip,
61+
"-N",
62+
netmask,
63+
"-t",
64+
"static",
65+
]
66+
return self.__execute(cmd)
67+
68+
def configure_dns(self, servers=None, search=None):
69+
"""Sets up arbitrary DNS servers."""
70+
if not servers:
71+
servers = []
72+
if not search:
73+
search = []
74+
75+
for server in servers:
76+
self.__execute(
77+
[
78+
"/bin/esxcli",
79+
"network",
80+
"ip",
81+
"dns",
82+
"server",
83+
"add",
84+
"--server",
85+
server,
86+
]
87+
)
88+
89+
for domain in search:
90+
self.__execute(
91+
[
92+
"/bin/esxcli",
93+
"network",
94+
"ip",
95+
"dns",
96+
"search",
97+
"add",
98+
"--domain",
99+
domain,
100+
]
101+
)
102+
103+
def create_vswitch(self, name="vSwitch0", ports=256):
104+
"""Creates vSwitch."""
105+
cmd = [
106+
"/bin/esxcli",
107+
"network",
108+
"vswitch",
109+
"standard",
110+
"add",
111+
"--ports",
112+
str(ports),
113+
"--vswitch-name",
114+
str(name),
115+
]
116+
117+
return self.__execute(cmd)
118+
119+
def delete_vmknic(self, portgroup_name):
120+
"""Deletes a vmknic from a portgroup."""
121+
return self.__execute(["/bin/esxcfg-vmknic", "-d", portgroup_name])
122+
123+
def destroy_vswitch(self, name):
124+
cmd = [
125+
"/bin/esxcli",
126+
"network",
127+
"vswitch",
128+
"standard",
129+
"remove",
130+
"--vswitch-name",
131+
name,
132+
]
133+
134+
return self.__execute(cmd)
135+
136+
def portgroup_add(self, portgroup_name, switch_name="vswitch0"):
137+
"""Adds Portgroup to a vSwitch."""
138+
cmd = [
139+
"/bin/esxcli",
140+
"network",
141+
"vswitch",
142+
"standard",
143+
"portgroup",
144+
"add",
145+
"--portgroup-name",
146+
str(portgroup_name),
147+
"--vswitch-name",
148+
str(switch_name),
149+
]
150+
return self.__execute(cmd)
151+
152+
#
153+
def portgroup_remove(self, portgroup_name, switch_name):
154+
"""Removes Portgroup from a vSwitch."""
155+
cmd = [
156+
"/bin/esxcli",
157+
"network",
158+
"vswitch",
159+
"standard",
160+
"portgroup",
161+
"remove",
162+
"--portgroup-name",
163+
str(portgroup_name),
164+
"--vswitch-name",
165+
str(switch_name),
166+
]
167+
return self.__execute(cmd)
168+
169+
def portgroup_set_vlan(self, portgroup_name, vlan_id):
170+
"""Configures VLANid to be used on a portgroup."""
171+
cmd = [
172+
"/bin/esxcli",
173+
"network",
174+
"vswitch",
175+
"standard",
176+
"portgroup",
177+
"set",
178+
"--portgroup-name",
179+
str(portgroup_name),
180+
"--vlan-id",
181+
str(vlan_id),
182+
]
183+
return self.__execute(cmd)
184+
185+
def uplink_add(self, nic, switch_name="vSwitch0"):
186+
"""Adds uplink to a vSwitch."""
187+
cmd = [
188+
"/bin/esxcli",
189+
"network",
190+
"vswitch",
191+
"standard",
192+
"uplink",
193+
"add",
194+
"--uplink-name",
195+
str(nic),
196+
"--vswitch-name",
197+
str(switch_name),
198+
]
199+
return self.__execute(cmd)
200+
201+
def vswitch_settings(self, mtu=9000, cdp="listen", name="vSwitch0"):
202+
cmd = [
203+
"/bin/esxcli",
204+
"network",
205+
"vswitch",
206+
"standard",
207+
"set",
208+
"--mtu",
209+
str(mtu),
210+
"--cdp-status",
211+
cdp,
212+
"--vswitch-name",
213+
str(name),
214+
]
215+
return self.__execute(cmd)
216+
217+
def vswitch_failover_uplinks(
218+
self, active_uplinks=None, standby_uplinks=None, name="vSwitch0"
219+
):
220+
cmd = [
221+
"/bin/esxcli",
222+
"network",
223+
"vswitch",
224+
"standard",
225+
"policy",
226+
"failover",
227+
"set",
228+
]
229+
230+
if active_uplinks:
231+
cmd.extend(["--active-uplinks", ",".join(active_uplinks)])
232+
if standby_uplinks:
233+
cmd.extend(["--standby-uplinks", ",".join(standby_uplinks)])
234+
235+
cmd.extend(
236+
[
237+
"--vswitch-name",
238+
str(name),
239+
]
240+
)
241+
return self.__execute(cmd)
242+
243+
def vswitch_security(
244+
self,
245+
allow_forged_transmits="no",
246+
allow_mac_change="no",
247+
allow_promiscuous="no",
248+
name="vSwitch0",
249+
):
250+
cmd = [
251+
"/bin/esxcli",
252+
"network",
253+
"vswitch",
254+
"standard",
255+
"policy",
256+
"security",
257+
"set",
258+
"--allow-forged-transmits",
259+
allow_forged_transmits,
260+
"--allow-mac-change",
261+
allow_mac_change,
262+
"--allow-promiscuous",
263+
allow_promiscuous,
264+
"--vswitch-name",
265+
str(name),
266+
]
267+
return self.__execute(cmd)
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
from dataclasses import dataclass
2+
from dataclasses import field
3+
4+
5+
@dataclass
6+
class Link:
7+
ethernet_mac_address: str
8+
id: str
9+
mtu: int
10+
type: str
11+
vif_id: str
12+
vlan_id: "int | None" = field(default=None)
13+
vlan_mac_address: "str | None" = field(default=None)
14+
vlan_link: "Link | None" = field(default=None)

0 commit comments

Comments
 (0)