8000 Merge remote-tracking branch 'upstream/edit_interface_spanning_tree' · lindycoder/netman@d7aed74 · GitHub
[go: up one dir, main page]

Skip to content

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit d7aed74

Browse files
author
Martin Roy
committed
Merge remote-tracking branch 'upstream/edit_interface_spanning_tree'
Conflicts: netman/adapters/switches/juniper/base.py
2 parents c486bac + 1104dc1 commit d7aed74

19 files changed

+713
-244
lines changed

netman/__init__.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
14+
import json
1415

1516
import re
1617

@@ -28,3 +29,10 @@ def __getitem__(self, key):
2829

2930

3031
regex = RegexFacilitator()
32+
33+
34+
def raw_or_json(raw_data, data):
35+
posting_data = raw_data
36+
if data is not None:
37+
posting_data = json.dumps(data)
38+
return posting_data

netman/adapters/switches/dell.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,15 @@ def parse_interface_names(self, status_list):
223223

224224
return interfaces
225225

226+
def edit_interface_spanning_tree(self, interface_id, edge=None):
227+
commands = []
228+
if edge is not None:
229+
commands.append("{}spanning-tree portfast".format("" if edge else "no "))
230+
231+
if commands:
232+
with self.config(), self.interface(interface_id):
233+
[self.shell.do(cmd) for cmd in commands]
234+
226235
def read_interface(self, interface_name):
227236
data = self.get_interface_data(interface_name)
228237

netman/adapters/switches/juniper/base.py

Lines changed: 54 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -372,31 +372,23 @@ def remove_interface_description(self, interface_id):
372372
else:
373373
raise UnknownInterface(interface_id)
374374

375-
def enable_interface_spanning_tree(self, interface_id):
376-
update = Update()
377-
update.add_rstp_protocol_interface(to_ele("""
378-
<interface>
379-
<name>%s</name>
380-
<edge />
381-
<no-root-port />
382-
</interface>""" % interface_id))
375+
def edit_interface_spanning_tree(self, interface_id, edge=None):
376+
config = self.query(one_interface(interface_id), one_rstp_protocol_interface(interface_id))
377+
self.get_interface_config(interface_id, config)
378+
379+
if edge is not None:
380+
modifications = _compute_edge_state_modifications(interface_id, edge, config)
381+
382+
if modifications:
383+
update = Update()
384+
update.add_rstp_protocol_interface(to_ele("""
385+
<interface>
386+
<name>{}</name>
387+
{}
388+
</interface>
389+
""".format(interface_id, "".join(modifications))))
383390

384-
try:
385-
self._push(update)
386-
except RPCError:
387-
raise UnknownInterface(interface_id)
388-
389-
def disable_interface_spanning_tree(self, interface_id):
390-
update = Update()
391-
update.add_rstp_protocol_interface(rstp_interface_removal(interface_id))
392-
393-
try:
394-
self._push(update)
395-
except RPCError as e:
396-
if e.severity == "warning":
397-
raise InterfaceSpanningTreeNotEnabled(interface_id)
398-
else:
399-
raise UnknownInterface(interface_id)
391+
self._push(update)
400392

401393
def shutdown_interface(self, interface_id):
402394
update = Update()
@@ -533,11 +525,8 @@ def configure_bond_native_vlan(self, number, vlan):
533525
def remove_bond_native_vlan(self, number):
534526
return self.remove_native_vlan(bond_name(number))
535527

536-
def enable_bond_spanning_tree(self, number):
537-
return self.enable_interface_spanning_tree(bond_name(number))
538-
539-
def disable_bond_spanning_tree(self, number):
540-
return self.disable_interface_spanning_tree(bond_name(number))
528+
def edit_bond_spanning_tree(self, number, edge=None):
529+
return self.edit_interface_spanning_tree(bond_name(number), edge=edge)
541530

542531
def _push(self, configuration):
543532
config = new_ele('config')
@@ -682,6 +671,21 @@ def m():
682671
return m
683672

684673

674+
def one_rstp_protocol_interface(interface_id):
675+
def m():
676+
return to_ele("""
677+
<protocols>
678+
<rstp>
679+
<interface>
680+
<name>{}</name>
681+
</interface>
682+
</rstp>
1066A 683+
</protocols>
684+
""".format(interface_id))
685+
686+
return m
687+
688+
685689
class Update(object):
686690
def __init__(self):
687691
self.root = new_ele("configuration")
@@ -995,3 +999,24 @@ def value_of(xpath_result, transformer=None):
995999
return node.text if transformer is None else transformer(node.text)
9961000
else:
9971001
return None
1002+
1003+
1004+
def _compute_edge_state_modifications(interface_id, edge, config):
1005+
modifications = []
1006+
rstp_node = first(config.xpath("data/configuration/protocols/rstp/interface/name[text()=\"{0:s}\"]/.."
1007+
.format(interface_id)))
1008+
if rstp_node is not None:
1009+
edge_node = first(rstp_node.xpath("edge"))
1010+
no_root_port_node = first(rstp_node.xpath("no-root-port"))
1011+
1012+
if edge is True:
1013+
if edge_node is None:
1014+
modifications.append("<edge />")
1015+
if no_root_port_node is None:
1016+
modifications.append("<no-root-port />")
1017+
elif edge is False:
1018+
if edge_node is not None:
1019+
modifications.append("<edge operation=\"delete\" />")
1020+
if no_root_port_node is not None:
1021+
modifications.append("<no-root-port operation=\"delete\" />")
1022+
return modifications

netman/adapters/switches/remote.py

Lines changed: 29 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import uuid
1919

2020
import requests
21+
from netman import raw_or_json
2122

2223
from netman.core.objects.exceptions import NetmanException
2324
from netman.core.objects.access_groups import IN, OUT
@@ -97,7 +98,7 @@ def set_vlan_access_group(self, vlan_number, direction, name):
9798
self.put('/vlans/{vlan_number}/access-groups/{direction}'.format(
9899
vlan_number=vlan_number,
99100
direction={IN: 'in', OUT: 'out'}[direction]
100-
), data=name)
101+
), raw_data=name)
101102

102103
def remove_vlan_access_group(self, vlan_number, direction):
103104
self.delete('/vlans/{vlan_number}/access-groups/{direction}'.format(
@@ -119,37 +120,37 @@ def remove_ip_from_vlan(self, vlan_number, ip_network):
119120
def set_vlan_vrf(self, vlan_number, vrf_name):
120121
self.put('/vlans/{vlan_number}/vrf-forwarding'.format(
121122
vlan_number=vlan_number
122-
), data=str(vrf_name))
123+
), raw_data=str(vrf_name))
123124

124125
def remove_vlan_vrf(self, vlan_number):
125126
self.delete('/vlans/{vlan_number}/vrf-forwarding'.format(vlan_number=vlan_number))
126127

127128
def set_access_mode(self, interface_id):
128-
self.put("/interfaces/" + interface_id + '/port-mode', data='access')
129+
self.put("/interfaces/" + interface_id + '/port-mode', raw_data='access')
129130

130131
def set_trunk_mode(self, interface_id):
131-
self.put("/interfaces/" + interface_id + '/port-mode', data='trunk')
132+
self.put("/interfaces/" + interface_id + '/port-mode', raw_data='trunk')
132133

133134
def set_bond_access_mode(self, bond_number):
134-
self.put("/bonds/" + str(bond_number) + '/port-mode', data='access')
135+
self.put("/bonds/" + str(bond_number) + '/port-mode', raw_data='access')
135136

136137
def set_bond_trunk_mode(self, bond_number):
137-
self.put("/bonds/" + str(bond_number) + '/port-mode', data='trunk')
138+
self.put("/bonds/" + str(bond_number) + '/port-mode', raw_data='trunk')
138139

139140
def set_access_vlan(self, interface_id, vlan):
140-
self.put("/interfaces/" + interface_id + '/access-vlan', data=str(vlan))
141+
self.put("/interfaces/" + interface_id + '/access-vlan', raw_data=str(vlan))
141142

142143
def remove_access_vlan(self, interface_id):
143144
self.delete("/interfaces/" + interface_id + '/access-vlan')
144145

145146
def configure_native_vlan(self, interface_id, vlan):
146-
self.put("/interfaces/" + interface_id + '/trunk-native-vlan', data=str(vlan))
147+
self.put("/interfaces/" + interface_id + '/trunk-native-vlan', raw_data=str(vlan))
147148

148149
def remove_native_vlan(self, interface_id):
149150
self.delete("/interfaces/" + interface_id + '/trunk-native-vlan')
150151

151152
def configure_bond_native_vlan(self, bond_number, vlan):
152-
self.put("/bonds/" + str(bond_number) + '/trunk-native-vlan', data=str(vlan))
153+
self.put("/bonds/" + str(bond_number) + '/trunk-native-vlan', raw_data=str(vlan))
153154

154155
def remove_bond_native_vlan(self, bond_number):
155156
self.delete("/bonds/" + str(bond_number) + '/trunk-native-vlan')
@@ -167,28 +168,29 @@ def remove_bond_trunk_vlan(self, bond_number, vlan):
167168
self.delete("/bonds/" + str(bond_number) + '/trunk-vlans/' + str(vlan))
168169

169170
def set_interface_description(self, interface_id, description):
170-
self.put("/interfaces/" + interface_id + '/description', data=description)
171+
self.put("/interfaces/" + interface_id + '/description', raw_data=description)
171172

172173
def remove_interface_description(self, interface_id):
173174
self.delete("/interfaces/" + interface_id + '/description')
174175

175176
def set_bond_description(self, bond_number, description):
176-
self.put("/bonds/" + str(bond_number) + '/description', data=description)
177+
self.put("/bonds/" + str(bond_number) + '/description', raw_data=description)
177178

178179
def remove_bond_description(self, bond_number):
179180
self.delete("/bonds/" + str(bond_number) + '/description')
180181

181-
def enable_interface_spanning_tree(self, interface_id):
182-
self.put("/interfaces/" + interface_id + '/spanning-tree', data='true')
182+
def edit_interface_spanning_tree(self, interface_id, edge=None):
183+
data = {}
184+
if edge is not None:
185+
data["edge"] = edge
183186

184-
def disable_interface_spanning_tree(self, interface_id):
185-
self.put("/interfaces/" + interface_id + '/spanning-tree', data='false')
187+
self.put("/interfaces/" + interface_id + '/spanning-tree', data=data)
186188

187189
def openup_interface(self, interface_id):
188-
self.put("/interfaces/" + interface_id + '/shutdown', data='false')
190+
self.put("/interfaces/" + interface_id + '/shutdown', raw_data='false')
189191

190192
def shutdown_interface(self, interface_id):
191-
self.put("/interfaces/" + interface_id + '/shutdown', data='true')
193+
self.put("/interfaces/" + interface_id + '/shutdown', raw_data='true')
192194

193195
def add_bond(self, number):
194196
self.post("/bonds", data={'number': number})
@@ -197,19 +199,20 @@ def remove_bond(self, number):
197199
self.delete("/bonds/" + str(number))
198200

199201
def add_interface_to_bond(self, interface, bond_number):
200-
self.put("/interfaces/" + interface + '/bond-master', data=str(bond_number))
202+
self.put("/interfaces/" + interface + '/bond-master', raw_data=str(bond_number))
201203

202204
def remove_interface_from_bond(self, interface):
203205
self.delete("/interfaces/" + interface + '/bond-master')
204206

205207
def set_bond_link_speed(self, number, speed):
206-
self.put("/bonds/{0}/link-speed".format(number), data=speed)
208+
self.put("/bonds/{0}/link-speed".format(number), raw_data=speed)
207209

208-
def enable_bond_spanning_tree(self, number):
209-
self.put("/bonds/{0}/spanning-tree".format(number), data='true')
210+
def edit_bond_spanning_tree(self, number, edge=None):
211+
data = {}
212+
if edge is not None:
213+
data["edge"] = edge
210214

211-
def disable_bond_spanning_tree(self, number):
212-
self.put("/bonds/{0}/spanning-tree".format(number), data='false')
215+
self.put("/bonds/{0}/spanning-tree".format(number), data=data)
213216

214217
def add_vrrp_group(self, vlan_number, group_id, ips=None, priority=None, hello_interval=None, dead_interval=None,
215218
track_id=None, track_decrement=None):
@@ -233,13 +236,10 @@ def get(self, relative_url):
233236
return self.validated(self.requests.get(**self.request(relative_url)))
234237

235238
def post(self, relative_url, data=None, raw_data=None):
236-
posting_data = raw_data
237-
if data is not None:
238-
posting_data = json.dumps(data)
239-
return self.validated(self.requests.post(data=posting_data, **self.request(relative_url)))
239+
return self.validated(self.requests.post(data=raw_or_json(raw_data, data), **self.request(relative_url)))
240240

241-
def put(self, relative_url, data=None):
242-
return self.validated(self.requests.put(data=data, **self.request(relative_url)))
241+
def put(self, relative_url, data=None, raw_data=None):
242+
return self.validated(self.requests.put(data=raw_or_json(raw_data, data), **self.request(relative_url)))
243243

244244
def delete(self, relative_url):
245245
return self.validated(self.requests.delete(**self.request(relative_url)))

netman/api/switch_api.py

Lines changed: 19 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
from netman.api.validators import Switch, is_boolean, is_vlan_number, Interface, Vlan, resource, content, is_ip_network, \
2323
IPNetworkResource, is_access_group_name, Direction, is_vlan, is_bond, Bond, \
2424
is_bond_link_speed, is_bond_number, is_description, is_vrf_name, \
25-
is_vrrp_group, VrrpGroup
25+
is_vrrp_group, VrrpGroup, is_dict_with, optional, is_type
2626

2727

2828
class SwitchApi(SwitchApiBase):
@@ -54,7 +54,7 @@ def hook_to(self, server):
5454
server.add_url_rule('/switches/<hostname>/interfaces/<path:interface_id>/bond-master', view_func=self.remove_interface_from_bond, methods=['DELETE'])
5555
server.add_url_rule('/switches/<hostname>/interfaces/<path:interface_id>/description', view_func=self.set_interface_description, methods=['PUT'])
5656
server.add_url_rule('/switches/<hostname>/interfaces/<path:interface_id>/description', view_func=self.remove_interface_description, methods=['DELETE'])
57-
server.add_url_rule('/switches/<hostname>/interfaces/<path:interface_id>/spanning-tree', view_func=self.set_interface_spanning_tree, methods=['PUT'])
57+
server.add_url_rule('/switches/<hostname>/interfaces/<path:interface_id>/spanning-tree', view_func=self.edit_interface_spanning_tree, methods=['PUT'])
5858
server.add_url_rule('/switches/<hostname>/bonds', view_func=self.get_bonds, methods=['GET'])
5959
server.add_url_rule('/switches/<hostname>/bonds', view_func=self.add_bond, methods=['POST'])
6060
server.add_url_rule('/switches/<hostname>/bonds/<bond_number>', view_func=self.get_bond, methods=['GET'])
@@ -69,7 +69,7 @@ def hook_to(self, server):
6969
server.add_url_rule('/switches/<hostname>/bonds/<bond_number>/trunk-native-vlan', view_func=self.remove_bond_native_vlan, methods=['DELETE'])
7070
server.add_url_rule('/switches/<hostname>/bonds/<bond_number>/description', view_func=self.set_bond_description, methods=['PUT'])
7171
server.add_url_rule('/switches/<hostname>/bonds/<bond_number>/description', view_func=self.remove_bond_description, methods=['DELETE'])
72-
server.add_url_rule('/switches/<hostname>/bonds/<bond_number>/spanning-tree', view_func=self.set_bond_spanning_tree, methods=['PUT'])
72+
server.add_url_rule('/switches/<hostname>/bonds/<bond_number>/spanning-tree', view_func=self.edit_bond_spanning_tree, methods=['PUT'])
7373
return self
7474

7575
@to_response
@@ -679,40 +679,36 @@ def remove_bond_description(self, switch, bond_number):
679679
return 204, None
680680

681681
@to_response
682-
@content(is_boolean)
682+
@content(is_dict_with(
683+
edge=optional(is_type(bool))))
683684
@resource(Switch, Bond)
684-
def set_bond_spanning_tree(self, switch, bond_number, state):
685+
def edit_bond_spanning_tree(self, switch, bond_number, **params):
685686
"""
686-
Enable spanning tree on a bonded interface
687+
Edit bond spanning tree properties
687688
688-
:arg str hostname: Hostname or IP of the switch
689-
:arg int bond_number: Bond number
689+
:arg bool edge: Activates edge mode
690690
:body:
691-
.. true / false
691+
.. literalinclude:: ../../../tests/api/fixtures/put_switch_hostname_interfaces_intname_spanningtree.json
692692
"""
693-
if state:
694-
switch.enable_bond_spanning_tree(bond_number)
695-
else:
696-
switch.disable_bond_spanning_tree(bond_number)
693+
694+
switch.edit_bond_spanning_tree(bond_number, **params)
697695

698696
return 204, None
699697

700698
@to_response
701-
@content(is_boolean)
699+
@content(is_dict_with(
700+
edge=optional(is_type(bool))))
702701
@resource(Switch, Interface)
703-
def set_interface_spanning_tree(self, switch, interface_id, state):
702+
def edit_interface_spanning_tree(self, switch, interface_id, **params):
704703
"""
705-
Enable spanning tree on an interface
704+
Edit interface spanning tree properties
706705
707-
:arg str hostname: Hostname or IP of the switch
708-
:arg str interface_id: Interface name (ex. ``FastEthernet0/1``, ``ethernet1/11``)
706+
:arg bool edge: Activates edge mode
709707
:body:
710-
.. true / false
708+
.. literalinclude:: ../../../tests/api/fixtures/put_switch_hostname_interfaces_intname_spanningtree.json
711709
"""
712-
if state:
713-
switch.enable_interface_spanning_tree(interface_id)
714-
else:
715-
switch.disable_interface_spanning_tree(interface_id)
710+
711+
switch.edit_interface_spanning_tree(interface_id, **params)
716712

717713
return 204, None
718714

0 commit comments

Comments
 (0)
0