Skip to content

Commit c0ab2cc

Browse files
Added 'slcli hw vlan-add' and 'slcli hw vlan-list'
1 parent b21f4c1 commit c0ab2cc

File tree

6 files changed

+149
-12
lines changed

6 files changed

+149
-12
lines changed

SoftLayer/CLI/hardware/vlan_add.py

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
"""Trunk a VLAN to this server."""
2+
# :license: MIT, see LICENSE for more details.
3+
4+
import click
5+
6+
import SoftLayer
7+
from SoftLayer.CLI import environment
8+
from SoftLayer.CLI import exceptions
9+
from SoftLayer.CLI import helpers
10+
11+
12+
@click.command(cls=SoftLayer.CLI.command.SLCommand, )
13+
@click.argument('hardware', nargs=1)
14+
@click.argument('vlans', nargs=-1)
15+
@environment.pass_env
16+
def cli(env, hardware, vlans):
17+
"""Trunk a VLAN to this server.
18+
19+
HARDWARE is the id of the server
20+
VLANS is the ID, name, or number of the VLANs you want to add. Multiple vlans can be added at the same time.
21+
It is recommended to use the vlan ID, especially if you have multiple vlans with the same name/number.
22+
"""
23+
24+
h_mgr = SoftLayer.HardwareManager(env.client)
25+
n_mgr = SoftLayer.NetworkManager(env.client)
26+
hw_id = helpers.resolve_id(h_mgr.resolve_ids, hardware, 'hardware')
27+
# Enclosing in quotes is required for any input that has a space in it.
28+
# "Public DAL10" for example needs to be sent to search as \"Public DAL10\"
29+
sl_vlans = n_mgr.search_for_vlan(" ".join(f"\"{v}\"" for v in vlans))
30+
if not sl_vlans:
31+
raise exceptions.ArgumentError(f"No vlans found matching {' '.join(vlans)}")
32+
add_vlans = parse_vlans(sl_vlans)
33+
component_mask = "mask[id, name, port, macAddress, primaryIpAddress]"
34+
# TODO: Add nice output / exception handling
35+
if len(add_vlans['public']) > 0:
36+
components = h_mgr.get_network_components(hw_id, mask=component_mask, space='public')
37+
for c in components:
38+
if c.get('primaryIpAddress'):
39+
h_mgr.trunk_vlan(c.get('id'), add_vlans['public'])
40+
if len(add_vlans['private']) > 0:
41+
components = h_mgr.get_network_components(hw_id, mask=component_mask, space='private')
42+
for c in components:
43+
if c.get('primaryIpAddress'):
44+
h_mgr.trunk_vlan(c.get('id'), add_vlans['private'])
45+
46+
47+
def parse_vlans(vlans):
48+
"""returns a dictionary mapping for public / private vlans"""
49+
50+
pub_vlan = []
51+
pri_vlan = []
52+
for vlan in vlans:
53+
print(f"{vlan.get('networkSpace')} | {vlan.get('id')} -> {vlan.get('vlanNumber')}")
54+
if vlan.get('networkSpace') == "PUBLIC":
55+
pub_vlan.append(vlan)
56+
else:
57+
pri_vlan.append(vlan)
58+
return {"public": pub_vlan, "private": pri_vlan}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
"""List VLANs this server can be attached to."""
2+
# :license: MIT, see LICENSE for more details.
3+
4+
import click
5+
6+
import SoftLayer
7+
from SoftLayer.CLI import environment
8+
from SoftLayer.CLI import formatting
9+
from SoftLayer.CLI import helpers
10+
11+
12+
@click.command(cls=SoftLayer.CLI.command.SLCommand, )
13+
@click.argument('hardware')
14+
@environment.pass_env
15+
def cli(env, hardware):
16+
"""List VLANs this server can be attached to."""
17+
18+
mgr = SoftLayer.HardwareManager(env.client)
19+
hw_id = helpers.resolve_id(mgr.resolve_ids, hardware, 'hardware')
20+
mask = (
21+
"mask[id,primaryIpAddress,"
22+
"networkVlansTrunkable[id,name,vlanNumber,fullyQualifiedName,networkSpace]]"
23+
)
24+
table = formatting.Table([
25+
"ID", "VLAN", "Name", "Space"
26+
])
27+
hw_components = env.client.call('SoftLayer_Hardware_Server', 'getNetworkComponents', id=hw_id, mask=mask)
28+
for component in hw_components:
29+
if component.get('primaryIpAddress'):
30+
for vlan in component.get('networkVlansTrunkable', []):
31+
table.add_row([
32+
vlan.get('id'), vlan.get('fullyQualifiedName'), vlan.get('name'), vlan.get('networkSpace')
33+
])
34+
env.fout(table)

SoftLayer/CLI/routes.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -315,6 +315,8 @@
315315
('hardware:notification-add', 'SoftLayer.CLI.hardware.notification_add:cli'),
316316
('hardware:notification-delete', 'SoftLayer.CLI.hardware.notification_delete:cli'),
317317
('hardware:create-credential', 'SoftLayer.CLI.hardware.create_credential:cli'),
318+
('hardware:vlan-list', 'SoftLayer.CLI.hardware.vlan_list:cli'),
319+
('hardware:vlan-add', 'SoftLayer.CLI.hardware.vlan_add:cli'),
318320

319321
('securitygroup', 'SoftLayer.CLI.securitygroup'),
320322
('securitygroup:list', 'SoftLayer.CLI.securitygroup.list:cli'),

SoftLayer/managers/hardware.py

Lines changed: 32 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1164,22 +1164,42 @@ def get_components(self, hardware_id, mask=None, filter_component=None):
11641164
"createDate": {
11651165
"operation": "orderBy",
11661166
"options": [
1167-
{
1168-
"name": "sort",
1169-
"value": [
1170-
"DESC"
1171-
]
1172-
},
1173-
{
1174-
"name": "sortOrder",
1175-
"value": [
1176-
1
1177-
]}]}
1178-
}}}}
1167+
{"name": "sort", "value": ["DESC"]},
1168+
{"name": "sortOrder", "value": [1]}
1169+
]
1170+
}
1171+
}
1172+
}}}
11791173

11801174
return self.client.call('Hardware_Server', 'getComponents',
11811175
mask=mask, filter=filter_component, id=hardware_id)
11821176

1177+
def get_network_components(self, hardware_id, mask=None, space=None):
1178+
"""Calls SoftLayer_Hardware_Server::getNetworkComponents()
1179+
1180+
:param int hardware_id: SoftLayer_Hardware_Server id
1181+
:param string mask: The object mask to use if you do not want the default
1182+
:param string space: 'public', 'private', or None for both.
1183+
:returns: https://sldn.softlayer.com/reference/datatypes/SoftLayer_Network_Component/
1184+
"""
1185+
1186+
if mask is None:
1187+
mask = "mask[uplinkComponent, router, redundancyEnabledFlag, redundancyCapableFlag]"
1188+
method = "getNetworkComponents"
1189+
if space == "public":
1190+
method = "getFrontendNetworkComponents"
1191+
elif space == "private":
1192+
method = "getBackendNetworkComponents"
1193+
return self.client.call("SoftLayer_Hardware_Server", method, id=hardware_id, mask=mask)
1194+
1195+
def trunk_vlan(self, component_id, vlans):
1196+
"""Calls SoftLayer_Network_Component::addNetworkVlanTrunks()
1197+
1198+
:param int component_id: SoftLayer_Network_Component id
1199+
:param list vlans: list of SoftLayer_Network_Vlan objects to add. Each object needs at least id or vlanNumber
1200+
"""
1201+
return self.client.call('SoftLayer_Network_Component', 'addNetworkVlanTrunks', vlans, id=component_id)
1202+
11831203
def get_sensors(self, hardware_id):
11841204
"""Returns Hardware sensor data"""
11851205
return self.client.call('Hardware', 'getSensorData', id=hardware_id)

SoftLayer/managers/network.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ def __init__(self, client):
8181
self.subnet = client['Network_Subnet']
8282
self.network_storage = self.client['Network_Storage']
8383
self.security_group = self.client['Network_SecurityGroup']
84+
self.resolvers = [self.search_for_vlan]
8485

8586
def add_global_ip(self, version=4, test_order=False):
8687
"""Adds a global IP address to the account.
@@ -887,3 +888,17 @@ def clear_route(self, identifier):
887888
returns true or false.
888889
"""
889890
return self.client.call('SoftLayer_Network_Subnet', 'clearRoute', id=identifier)
891+
892+
def search_for_vlan(self, vlan):
893+
"""Returns a list of matching VLAN objects.
894+
895+
:param string vlan: Could be either vlan name, number, id, or fully qualified name
896+
:return list: List of SoftLayer_Network_Vlan objects
897+
"""
898+
899+
query = f"_objectType:SoftLayer_Network_Vlan {vlan}"
900+
mask = "mask[resource(SoftLayer_Network_Vlan)[id,name,vlanNumber,fullyQualifiedName,networkSpace]]"
901+
902+
results = self.client.call('SoftLayer_Search', 'advancedSearch', query, mask=mask)
903+
# This returns JUST the Network_Vlan information, none of the search information.
904+
return [result.get('resource') for result in results]

docs/cli/hardware.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,3 +147,11 @@ This function updates the firmware of a server. If already at the latest version
147147
.. click:: SoftLayer.CLI.hardware.create_credential:cli
148148
:prog: hardware create-credential
149149
:show-nested:
150+
151+
.. click:: SoftLayer.CLI.hardware.vlan_add:cli
152+
:prog: hardware vlan_add
153+
:show-nested:
154+
155+
.. click:: SoftLayer.CLI.hardware.vlan_list:cli
156+
:prog: hardware vlan_list
157+
:show-nested:

0 commit comments

Comments
 (0)