-
Notifications
You must be signed in to change notification settings - Fork 546
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'kderynski-master' into 0.30
- Loading branch information
Showing
13 changed files
with
477 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
IBM Networking Operating System | ||
------- | ||
|
||
Rollback | ||
~~~~~~~~ | ||
|
||
Rollback is simply implemented by reading current running configuration before any load actions. Rollback function executes load replace and commit. | ||
|
||
|
||
Atomic Changes | ||
~~~~~~~~~~~~~~ | ||
|
||
IBM plugin uses netconf to load configuration on to device. It seems that configuration is executed line by line but we can be sure that all lines will be executed. There are three options for error handling: stop-on-error, continue-on-error and rollback-on-error. Plugin uses rollback-on-error option in case of merge operation. However replace operation uses continue-on-error option. In case of typo in configuration, device will inform plugin about error but execute all the rest lines. Plugin will revert configuration using rollback function from the plugin. I do not use rollback-on-error for replace operation because in case of error device is left without any configuration. It seems like a bug. It will be investigated further. Moreover it seems that replace option wipe out whole configuration on device at the first step, so this option is good for provisioning of new device and it is not recomended for device in production. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,143 @@ | ||
# | ||
# Copyright 2015 Kamil Derynski, Opera Software ASA | ||
# | ||
# Licensed under the Apache License, Version 2.0 (the "License"); you may not | ||
# use this file except in compliance with the License. You may obtain a copy of | ||
# the License at | ||
# | ||
# http://www.apache.org/licenses/LICENSE-2.0 | ||
# | ||
# Unless required by applicable law or agreed to in writing, software | ||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | ||
# License for the specific language governing permissions and limitations under | ||
# the License. | ||
|
||
from base import NetworkDriver | ||
from exceptions import ReplaceConfigException, MergeConfigException | ||
from bnclient import bnclient | ||
import difflib | ||
import sys | ||
from StringIO import StringIO | ||
|
||
|
||
class IBMDriver(NetworkDriver): | ||
|
||
def __init__(self, hostname, username, password, timeout=60): | ||
self.hostname = hostname | ||
self.username = username | ||
self.password = password | ||
self.timeout = timeout | ||
self.argv = ['', '-u', username, '-p', password, hostname] | ||
self.bnc = bnclient.bnclient(self.argv) | ||
self.config_replace = False | ||
self.config = {"running": "", "candidate": "", "rollback": ""} | ||
self.filename_running = "/tmp/" + hostname + "-running.conf" | ||
self.filename_candidate = None | ||
self.filename_rollback = "/tmp/" + hostname + "-rollback.conf" | ||
self.error = StringIO() | ||
|
||
def str2argv(self, str=''): | ||
return str.split(' ') | ||
|
||
def open(self): | ||
self.bnc.connect() | ||
self.bnc.sendhello() | ||
self._get_config(self.filename_rollback) | ||
|
||
def close(self): | ||
self.bnc.close() | ||
|
||
def _bnc_cmd(self, file, operation, error_option): | ||
cmd = "-o edit-config -t running -f " | ||
cmd += file | ||
cmd += " -d " + operation | ||
cmd += " -r " + error_option | ||
return cmd | ||
|
||
def _write_memory(self): | ||
cmd = "-o copy-config -t startup -s running" | ||
return cmd | ||
|
||
def _send_rpc(self, cmd): | ||
self.error = StringIO() | ||
old_stdout = sys.stdout | ||
sys.stdout = self.error | ||
self.bnc.sendrpc(self.str2argv(cmd)) | ||
sys.stdout = old_stdout | ||
|
||
def _get_config(self, filename): | ||
self.bnc.sendrpc(self.str2argv("-o get -f " + filename)) | ||
|
||
def _load_config(self, filename, config): | ||
self._get_config(self.filename_rollback) | ||
if filename is None: | ||
configuration = config | ||
else: | ||
with open(filename) as f: | ||
configuration = f.read() | ||
self.config['candidate'] = configuration | ||
self.filename_candidate = filename | ||
f.close() | ||
|
||
def load_replace_candidate(self, filename=None, config=None): | ||
self.config_replace = True | ||
self._load_config(filename, config) | ||
|
||
def load_merge_candidate(self, filename=None, config=None): | ||
self.config_replace = False | ||
self._load_config(filename, config) | ||
|
||
def compare_config(self): | ||
result = '' | ||
if self.config_replace: | ||
self._get_config(self.filename_running) | ||
with open(self.filename_running, 'r') as running: | ||
with open(self.filename_candidate, 'r') as candidate: | ||
diff = difflib.unified_diff( | ||
running.readlines(), | ||
candidate.readlines(), | ||
fromfile='running', | ||
tofile='candidate', | ||
) | ||
for line in diff: | ||
for prefix in ('---', '+++', '@@'): | ||
if line.startswith(prefix): | ||
break | ||
else: | ||
result += line | ||
else: | ||
result = self.config['candidate'] | ||
return str(result).strip() | ||
|
||
def _commit_replace(self): | ||
cmd = self._bnc_cmd(self.filename_candidate, "replace", "continue-on-error") | ||
self._send_rpc(cmd) | ||
if self.error.getvalue(): | ||
self.rollback() | ||
raise ReplaceConfigException(self.error.getvalue()) | ||
|
||
def _commit_merge(self): | ||
cmd = self._bnc_cmd(self.filename_candidate, "merge", "rollback-on-error") | ||
self._send_rpc(cmd) | ||
if self.error.getvalue(): | ||
self.discard_config() | ||
raise MergeConfigException(self.error.getvalue()) | ||
|
||
def commit_config(self): | ||
if self.config_replace: | ||
self._commit_replace() | ||
else: | ||
self._commit_merge() | ||
cmd = self._write_memory() | ||
self._send_rpc(cmd) | ||
|
||
def discard_config(self): | ||
self.filename_candidate = self.filename_running | ||
self.config['candidate'] = self.config['running'] | ||
|
||
def rollback(self): | ||
cmd = self._bnc_cmd(self.filename_rollback, "replace", "rollback-on-error") | ||
self._send_rpc(cmd) | ||
cmd = self._write_memory() | ||
self._send_rpc(cmd) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
# Copyright 2015 Spotify AB. All rights reserved. | ||
# | ||
# The contents of this file are licensed under the Apache License, Version 2.0 | ||
# (the "License"); you may not use this file except in compliance with the | ||
# License. You may obtain a copy of the License at | ||
# | ||
# http://www.apache.org/licenses/LICENSE-2.0 | ||
# | ||
# Unless required by applicable law or agreed to in writing, software | ||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | ||
# License for the specific language governing permissions and limitations under | ||
# the License. | ||
|
||
import unittest | ||
|
||
from napalm.ibm import IBMDriver | ||
from base import TestNetworkDriver | ||
|
||
|
||
class TestIBMDriver(unittest.TestCase, TestNetworkDriver): | ||
|
||
@classmethod | ||
def setUpClass(cls): | ||
hostname = '10.20.18.253' | ||
username = 'admin' | ||
password = 'admin' | ||
cls.vendor = 'ibm' | ||
|
||
cls.device = IBMDriver(hostname, username, password, timeout=60) | ||
cls.device.open() | ||
cls.device.load_replace_candidate(filename='%s/initial.conf' % cls.vendor) | ||
cls.device.commit_config() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
version "7.11.2" | ||
switch-type "IBM Networking Operating System RackSwitch G8052" | ||
iscli-new | ||
! | ||
! | ||
|
||
! | ||
! | ||
! | ||
no system dhcp | ||
no system default-ip | ||
hostname "test-sw2" | ||
! | ||
! | ||
interface port XGE2 | ||
description "port 50 uplink" | ||
switchport mode trunk | ||
exit | ||
! | ||
vlan 18 | ||
name "sysadmin" | ||
! | ||
! | ||
spanning-tree stp 18 vlan 18 | ||
! | ||
! | ||
! | ||
! | ||
! | ||
! | ||
! | ||
interface ip 18 | ||
ip address 10.20.18.253 255.255.255.0 | ||
vlan 18 | ||
enable | ||
exit | ||
! | ||
ip gateway 1 address 10.20.18.1 | ||
ip gateway 1 enable | ||
! | ||
! | ||
! | ||
! | ||
! | ||
! | ||
! | ||
! | ||
! | ||
end | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
interface port 1 | ||
description "test description" | ||
switchport mode trunk | ||
switchport trunk allowed vlan 27,2000 | ||
switchport trunk native vlan 27 | ||
spanning-tree portfast | ||
exit | ||
! | ||
|
||
vlan 27 | ||
name "install" | ||
! | ||
vlan 2000 | ||
name "another test" | ||
! |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
hostname "test-sw2" | ||
! | ||
! | ||
-interface port 1 | ||
- description "test description" | ||
- switchport mode trunk | ||
- switchport trunk allowed vlan 27,2000 | ||
- switchport trunk native vlan 27 | ||
- spanning-tree portfast | ||
- exit | ||
-! | ||
interface port XGE2 | ||
description "port 50 uplink" | ||
switchport mode trunk | ||
vlan 18 | ||
name "sysadmin" | ||
! | ||
-vlan 27 | ||
- name "install" | ||
-! | ||
-vlan 2000 | ||
- name "another test" | ||
-! | ||
-! | ||
! | ||
spanning-tree stp 18 vlan 18 | ||
-! | ||
-spanning-tree stp 27 vlan 27 | ||
-! | ||
-spanning-tree stp 95 vlan 2000 | ||
! | ||
! | ||
! |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
inrface port 1 | ||
description "test description" | ||
switchport mode trunk | ||
switchport trunk allowed vlan 27,2000 | ||
switchport trunk native vlan 27 | ||
spanning-tree portfast | ||
exit | ||
! | ||
|
||
vlan 27 | ||
name "install" | ||
! | ||
vlan 2000 | ||
name "another test" | ||
! |
Oops, something went wrong.