From 600e47d4aa71de2eada4e260a41968f5d7f9cc2d Mon Sep 17 00:00:00 2001 From: hochikong <1097225749@qq.com> Date: Mon, 5 Sep 2016 14:55:11 +0800 Subject: Fix some logic error in commit() Fix the readme add a new exception rewrite the error handle in router.py --- README.md | 77 +++++++++-------------- vymgmt/base_exceptions/base.py | 8 +++ vymgmt/mgmt_common.py | 33 ++++++++-- vymgmt/router.py | 136 +++++++++++++++++++++++++++++------------ 4 files changed, 164 insertions(+), 90 deletions(-) diff --git a/README.md b/README.md index f697cbc..3abbc47 100755 --- a/README.md +++ b/README.md @@ -16,29 +16,28 @@ Use this library to send the configuration commands to VyOS. ###Requirement:pexpect(pxssh) +###Platform:Python2 and 3 + ##Basic Example Set a description for eth0: >>> from vymgmt.router import Router >>> vyos = Router('192.168.225.2','vyos:vyos') >>> vyos.login() - 'Result : Login successfully.' >>> vyos.configure() - 'Result : Active configure mode successfully.' >>> vyos.set("interfaces ethernet eth0 description 'eth0'") - 'Result : Configured successfully' + >>> vyos.status() + {'save': 'No', 'status': 'login', 'configure': 'Yes', 'commit': 'No'} >>> vyos.commit() - 'Result : Commit successfully.' >>> vyos.status() - {'status': 'login', 'commit': 'Yes', 'save': 'No', 'configure': 'Yes'} - >>> vyos.exit() - 'Error : You should save first.' + {'save': 'No', 'status': 'login', 'configure': 'Yes', 'commit': 'Yes'} >>> vyos.save() - 'Result : Save successfully.' + >>> vyos.status() + {'save': 'Yes', 'status': 'login', 'configure': 'Yes', 'commit': 'Yes'} >>> vyos.exit() - 'Result : Exit configure mode successfully.' >>> vyos.logout() - 'Result : Logout successfully.' + >>> vyos.status() + {'save': None, 'status': 'logout', 'configure': None, 'commit': None} Because we have save the configuration,so if you reboot the VyOS system but the static router still works. @@ -78,14 +77,12 @@ You should import class Router from vymgmt.router,the use address and "username: Then,you can use login() to login vyos1: >>> vyos1.login() - 'Result : Login successfully.' -If there are no problems,this method will return a string message to user. +If there are no problems,this method will return nothing to user. By now,you can use configure() and execute configuration commands: >>> vyos1.configure() - 'Result : Active configure mode successfully.' You can use status() method to get the status of this instance: @@ -115,9 +112,8 @@ Oh,NO!I just forgot the netmask.But you can see,if your input has mistakes,this Now,let's use a correct configuration: >>> vyos1.set("interfaces ethernet eth1 address '192.168.10.5/24'") - 'Result : Configured successfully' -Well,I set address for eth1 now. +Well,I have set the address for eth1 now. Let's check the status now: @@ -129,12 +125,10 @@ You can see,"commit" and "save" are "No",so,you must commit and save it. Commit: >>> vyos1.commit() - 'Result : Commit successfully.' Save it: >>> vyos1.save() - 'Result : Save successfully.' Let's check the status again: @@ -144,9 +138,7 @@ Let's check the status again: You see,the value of "commit" and "save" have changed to "Yes",now I can exit the configure mode and logout.But if you don't commit and save,you still can use "vyos1.exit(force=True)" to exit and discard what you have configured: >>> vyos1.exit() - 'Result : Exit configure mode successfully.' >>> vyos1.logout() - 'Result : Logout successfully.' >>> vyos1.status() {'status': 'logout', 'commit': None, 'save': None, 'configure': None} @@ -181,60 +173,53 @@ I have set two test vms' gateway.Now login vyos1,configure the rip network: >>> from vymgmt.router import Router >>> vyos1 = Router('192.168.225.2','vyos:vyos') >>> vyos1.login() - 'Result : Login successfully.' >>> vyos1.configure() - 'Result : Active configure mode successfully.' First,we should add a new lo address: >>> vyos1.set("interfaces loopback lo address 1.1.1.1/32") - 'Result : Configured successfully' Then configure rip networks: >>> vyos1.set("protocols rip network 192.168.225.0/24") - 'Result : Configured successfully' >>> vyos1.set("protocols rip network 192.168.10.0/24") - 'Result : Configured successfully' And the last step: >>> vyos1.set("protocols rip redistribute connected") - 'Result : Configured successfully' -Sometimes,you may forget to commit or save,the library will return a message and refuse to exit: +Sometimes,you may forget to commit or save,the library will raise an exception and refuse to exit: >>> vyos1.status() {'status': 'login', 'commit': 'No', 'save': 'No', 'configure': 'Yes'} - >>> vyos1.exit() - 'Error : You should commit first.' + >>> vyos1.exit() + Traceback (most recent call last): + File "", line 1, in + File "build/bdist.linux-x86_64/egg/vymgmt/router.py", line 233, in exit + vymgmt.base_exceptions.base.MaintenanceError: + Error : You should commit first. >>> vyos1.save() - 'Error : You need to commit first!' + Traceback (most recent call last): + File "", line 1, in + File "build/bdist.linux-x86_64/egg/vymgmt/router.py", line 185, in save + vymgmt.base_exceptions.base.MaintenanceError: + Error : You need to commit first! Therefore,we should execute commit() and save(): >>> vyos1.commit() - 'Result : Commit successfully.' >>> vyos1.save() - 'Result : Save successfully.' Then on vyos2,we can configure rip network: >>> vyos2 = Router('192.168.10.6','vyos:vyos') >>> vyos2.login() - 'Result : Login successfully.' >>> vyos2.configure() - 'Result : Active configure mode successfully.' >>> vyos2.set("protocols rip network 192.168.10.0/24") - 'Result : Configured successfully' >>> vyos2.set("protocols rip network 192.168.157.0/24") - 'Result : Configured successfully' >>> vyos2.set("protocols rip redistribute connected") - 'Result : Configured successfully' >>> vyos2.commit() - 'Result : Commit successfully.' >>> vyos2.save() - 'Result : Save successfully.' Then check it on test1: @@ -265,15 +250,6 @@ On test3: rtt min/avg/max/mdev = 1.036/1.241/1.381/0.127 ms Now,maybe you are understand how to use this library to configure VyOS. - - - - - - - - - #All Methods ##status(): @@ -322,7 +298,7 @@ Basic 'set' method,execute the set command in VyOS. Example: config: "interfaces ethernet eth0 description 'eth0'" -The minimal c method. +The minimal configuration method. ##delete(config) Basic 'delete' method,execute the delete command in VyOS. @@ -382,6 +358,11 @@ This exception class is for all failures which do not covered by exceptions abov When this exception raise,the error message from VyOS will displayed. +##vymgmt.base_exceptions.MaintenanceError() + +This exception class is for all maintenance method such login(),logout(),configure() has errors. + +When this exception raise,the error message from VyOS will displayed. diff --git a/vymgmt/base_exceptions/base.py b/vymgmt/base_exceptions/base.py index dc80840..839224b 100644 --- a/vymgmt/base_exceptions/base.py +++ b/vymgmt/base_exceptions/base.py @@ -13,3 +13,11 @@ class CommonError(Error): def __str__(self): return prefix + self.error_message + + +class MaintenanceError(Error): + def __init__(self, message): + self.error_message = message + + def __str__(self): + return prefix + self.error_message diff --git a/vymgmt/mgmt_common.py b/vymgmt/mgmt_common.py index 1ccb96a..1153c54 100644 --- a/vymgmt/mgmt_common.py +++ b/vymgmt/mgmt_common.py @@ -1,5 +1,7 @@ # Copyright (c) 2016 Hochikong +CODEC = 'utf8' + def messenger(obj, config): """This method used for sending configuration to VyOS @@ -11,8 +13,9 @@ def messenger(obj, config): try: obj.sendline(config) obj.prompt() - if len(obj.before) > obj.before.index('\r\n') + 2: - return obj.before + result = decodetool(obj.before, CODEC) + if len(result) > result.index('\r\n') + 2: + return result else: return "Result : Configured successfully" except Exception as e: @@ -26,12 +29,34 @@ def committer(obj, config): :param config: A configuration string :return: A message or an error """ + exception_string = "enhanced syslogd: rsyslogd" try: obj.sendline(config) obj.prompt() - if len(obj.before) > obj.before.index('\r\n') + 2: - return obj.before + result = decodetool(obj.before, CODEC) + if len(result) > result.index('\r\n') + 2: + if exception_string in result: + return "Result : Commit successfully" + else: + return result else: return "Result : Commit successfully" except Exception as e: return e + + +def decodetool(target, codec): + """This method is used for decoding obj.before to string when run this + library under python3 + + :param target: The obj.before + :param codec: The codec use to decode + :return: + """ + try: + if type(target) == str: + return target + if type(target) == bytes: + return target.decode(codec) + except Exception as e: + return e diff --git a/vymgmt/router.py b/vymgmt/router.py index 15fea9e..6b342f7 100644 --- a/vymgmt/router.py +++ b/vymgmt/router.py @@ -1,11 +1,11 @@ # Copyright (c) 2016 Hochikong -from pxssh import pxssh +from pexpect import pxssh from .mgmt_common import messenger, committer from .base_exceptions.exceptions_for_set_and_delete import ConfigPathError, ConfigValueError from .base_exceptions.exceptions_for_commit import CommitFailed, CommitConflict -from .base_exceptions.base import CommonError +from .base_exceptions.base import CommonError, MaintenanceError from .error_distinguish import distinguish_for_set, distinguish_for_delete, distinguish_for_commit @@ -21,7 +21,7 @@ class Router(object): self.__divi = self.__cred.index(":") self.__username = ''.join(self.__cred[:self.__divi]) self.__passwd = ''.join(self.__cred[self.__divi+1:]) - self.__conn = pxssh() + self.__conn = pxssh.pxssh() self.__status = {"status": None, "commit": None, "save": None, "configure": None} self.__basic_string = {0: 'set ', 1: 'delete '} @@ -37,43 +37,54 @@ class Router(object): :return: A message or an error """ + has_error = None try: if self.__conn.login(self.__address, self.__username, self.__passwd) is True: self.__status["status"] = "login" - return "Result : Login successfully." else: - return "Error : Connect Failed." + has_error = 'Type1' except Exception as e: return e + if has_error == 'Type1': + raise MaintenanceError("Error : Connect Failed.") + def logout(self): """Logout the router :return: A message or an error """ + has_error = None try: if self.__status["commit"] == "No": - return "Error : You should commit and exit configure mode first." + has_error = 'Type1' if self.__status["save"] == "No": - return "Error : You should save and exit configure mode first." + has_error = 'Type2' if self.__status["configure"] == "Yes": - return "Error : You should exit configure mode first." + has_error = 'Type3' self.__conn.close() self.__status["status"] = "logout" self.__status["configure"] = None - self.__conn = pxssh() - return "Result : Logout successfully." + self.__conn = pxssh.pxssh() except Exception as e: return e + if has_error == 'Type1': + raise MaintenanceError("Error : You should commit and exit configure mode first.") + if has_error == 'Type2': + raise MaintenanceError("Error : You should save and exit configure mode first.") + if has_error == 'Type3': + raise MaintenanceError("Error : You should exit configure mode first.") + def configure(self): """Enter the VyOS configure mode :return: A message or an error """ + has_error = None try: if self.__status["status"] == "login": if self.__status["configure"] is not "Yes": @@ -81,40 +92,55 @@ class Router(object): self.__conn.prompt(0) self.__conn.set_unique_prompt() self.__status["configure"] = "Yes" - return "Result : Active configure mode successfully." else: - return "Error : In configure mode now!" + has_error = 'Type1' else: - return "Error : Router object not connect to a router." + has_error = 'Type2' except Exception as e: return e + if has_error == 'Type1': + raise MaintenanceError("Error : In configure mode now!") + if has_error == 'Type2': + raise MaintenanceError("Error : Router object not connect to a router.") + def commit(self): """Commit the configuration changes :return: A message or an error """ + has_error = None + result = None + res = None try: if self.__status["status"] == "login": if self.__status["configure"] == "Yes": if self.__status["commit"] is None: - return "Error : You don't need to commit." + has_error = 'Type1' if self.__status["commit"] == "No": res = committer(self.__conn, "commit") if "Result" in res: self.__status["commit"] = "Yes" - return "Result : Commit successfully." else: result = distinguish_for_commit(res) else: - return "Error : You have commit!" + has_error = 'Type2' else: - return "Error : Router not in configure mode!" + has_error = 'Type3' else: - return "Error : Router object not connect to a router." + has_error = 'Type4' except Exception as e: return e + if has_error == 'Type1': + raise MaintenanceError("Error : You don't need to commit.") + if has_error == 'Type2': + raise MaintenanceError("Error : You have commit!") + if has_error == 'Type3': + raise MaintenanceError("Error : Router not in configure mode!") + if has_error == 'Type4': + raise MaintenanceError("Error : Router object not connect to a router.") + if result == "CommitFailed": raise CommitFailed(res) elif result == "CommitConflict": @@ -125,36 +151,50 @@ class Router(object): :return: A message or an error """ + has_error = None try: if self.__status["status"] == "login": if self.__status["configure"] == "Yes": if self.__status["commit"] == "Yes": if self.__status["save"] is None: - return "Error : You don't need to save." + has_error = 'Type1' if self.__status["save"] == "No": self.__conn.sendline("save") self.__conn.prompt(0) self.__status["save"] = "Yes" - return "Result : Save successfully." else: - return "Error : You have saved!" + has_error = 'Type2' elif self.__status["commit"] is None: - return "Error : You don't need to save." + has_error = 'Type3' else: - return "Error : You need to commit first!" + has_error = 'Type4' else: - return "Error : Router not in configure mode!" + has_error = 'Type5' else: - return "Error : Router object not connect to a router." + has_error = 'Type6' except Exception as e: return e + if has_error == 'Type1': + raise MaintenanceError("Error : You don't need to save.") + if has_error == 'Type2': + raise MaintenanceError("Error : You have saved!") + if has_error == 'Type3': + raise MaintenanceError("Error : You don't need to save.") + if has_error == 'Type4': + raise MaintenanceError("Error : You need to commit first!") + if has_error == 'Type5': + raise MaintenanceError("Error : Router not in configure mode!") + if has_error == 'Type6': + raise MaintenanceError("Error : Router object not connect to a router.") + def exit(self, force=False): """Exit VyOS configure mode :param force: True or False :return: A message or an error """ + has_error = None try: if self.__status["status"] == "login": if self.__status["configure"] == "Yes": @@ -164,7 +204,6 @@ class Router(object): self.__status["configure"] = "No" self.__status["save"] = None self.__status["commit"] = None - return "Result : Exit configure mode successfully." else: if self.__status["commit"] == "Yes": if self.__status["save"] == "Yes": @@ -173,23 +212,30 @@ class Router(object): self.__status["configure"] = "No" self.__status["save"] = None self.__status["commit"] = None - return "Result : Exit configure mode successfully." else: - return "Error : You should save first." + has_error = 'Type1' elif self.__status["commit"] is None: self.__conn.sendline("exit") self.__conn.prompt() self.__status['configure'] = "No" - return "Result : Exit configure mode successfully." else: - return "Error : You should commit first." + has_error = 'Type2' else: - return "Error : You are not in configure mode,need not exit." + has_error = 'Type3' else: - return "Error : Router object not connect to a router." + has_error = 'Type4' except Exception as e: return e + if has_error == 'Type1': + raise MaintenanceError("Error : You should save first.") + if has_error == 'Type2': + raise MaintenanceError("Error : You should commit first.") + if has_error == 'Type3': + raise MaintenanceError("Error : You are not in configure mode,no need to exit.") + if has_error == 'Type4': + raise MaintenanceError("Error : Router object not connect to a router.") + def set(self, config): """Basic 'set' method,execute the set command in VyOS @@ -197,6 +243,9 @@ class Router(object): e.g. 'protocols static route ... next-hop ... distance ...' :return: A message or an error """ + has_error = None + result = None + res = None full_config = self.__basic_string[0] + config try: if self.__status["status"] == "login": @@ -211,16 +260,20 @@ class Router(object): pass else: self.__status["save"] = "No" - return res else: result = distinguish_for_set(res) else: - return "Error : You are not in configure mode." + has_error = 'Type1' else: - return "Error : Router object not connect to a router." + has_error = 'Type2' except Exception as e: return e + if has_error == 'Type1': + raise MaintenanceError("Error : You are not in configure mode.") + if has_error == 'Type2': + raise MaintenanceError("Error : Router object not connect to a router.") + if result == "ConfigPathError": raise ConfigPathError(res) elif result == "ConfigValueError": @@ -235,6 +288,9 @@ class Router(object): e.g. 'protocols static route ... next-hop ... distance ...' :return: A message or an error """ + has_error = None + result = None + res = None full_config = self.__basic_string[1] + config try: if self.__status["status"] == "login": @@ -249,16 +305,20 @@ class Router(object): pass else: self.__status["save"] = "No" - return res else: result = distinguish_for_delete(res) else: - return "Error : You are not in configure mode." + has_error = 'Type1' else: - return "Error : Router object not connect to a router." + has_error = 'Type2' except Exception as e: return e + if has_error == 'Type1': + raise MaintenanceError("Error : You are not in configure mode.") + if has_error == 'Type2': + raise MaintenanceError("Error : Router object not connect to a router.") + if result == "ConfigPathError": raise ConfigPathError(res) elif result == "ConfigValueError": -- cgit v1.2.3