From e20cf6edff4902abd2b4be63c8368cbf2e96b1f6 Mon Sep 17 00:00:00 2001 From: Elisa Jasinska Date: Sat, 21 Mar 2015 00:31:29 +0000 Subject: [PATCH 01/17] working on merge_config --- ansible/eos_install_config | 62 ++++++++++++++++++++++++++------------ pyEOS/eos.py | 24 +++++++++++++++ 2 files changed, 67 insertions(+), 19 deletions(-) diff --git a/ansible/eos_install_config b/ansible/eos_install_config index cb94939..abc854d 100644 --- a/ansible/eos_install_config +++ b/ansible/eos_install_config @@ -30,10 +30,13 @@ DOCUMENTATION = ''' module: eos_install_config author: David Barroso version_added: "1.0.0" -short_description: Replaces the configuration taken from a file on a device running EOS. +short_description: + Takes configuration from a file oiand loads it onto a device running EOS. description: - This library will take the configuration from a file and load it into a device running EOS. The old configuration - will be replaced using the feature 'config replace terminal: force'. The use this module you need to enable access + This library will take the configuration from a file and load it into a + device running EOS. The old configuration will be either replaced by + using the feature 'config replace terminal: force', or merged with the + running configuration. To use this module you need to enable access to the device via the eAPI. requirements: @@ -42,26 +45,39 @@ requirements: options: hostname: description: IP or FQDN of the device you want to connect to - required: true + required: True username: description: Username - required: true + required: True password: description: Password - required: true + required: True use_ssl: - description: If set to True we will connect via https, if False we will use http instead. Default is True. - required: false + description: + If set to True we will connect via https, if False we will use + http instead. Default is True. + required: False config_file: - description: Where to load the configuration from. - required: true + description: + File to load the configuration from. + required: True commit_changes: - description: If set to True the configuration will be actually replaced. If the set to False, we will not - apply the changes, just check the differences. - required: true + description: + If set to True the commit will be performed. If set to False, + we will not apply the changes, only check the differences. + Default: False. + required: False + replace_config: + description: + If set to True the entire configuration on the device will be + replaced during the commit. If set to False, we will merge the + new config with the existing one. Default: False. + required: False diff_file: - description: A file where to store the "diff" between the running configuration and the new configuration. If - it's not set the diff between configurations is not saved. + description: + A file where to store the "diff" between the running + configuration and the new configuration. If it's not set the + diff between configurations is not saved. required: False ''' @@ -79,7 +95,8 @@ EXAMPLES = ''' password=p4ssw0rd use_ssl=False config_file=~/spotify/network-ansible/compiled/{{ inventory_hostname }}/running.conf - commit_changes={{commit_changes}} + commit_changes={{ commit_changes }} + replace_config={{ replace_config }} diff_file=logs/{{ inventory_hostname }}.log From the CLI we would trigger the playbook like: @@ -107,7 +124,8 @@ def main(): password=dict(required=True), use_ssl=dict(required=False, default=True), config_file=dict(required=True), - commit_changes=dict(required=True), + commit_changes=dict(required=False, default=False), + replace_config=dict(required=False, default=False), diff_file=dict(required=False, default=None), ), supports_check_mode=True @@ -120,10 +138,13 @@ def main(): config_file = module.params['config_file'] commit_changes = module.params['commit_changes'] + replace_config = module.params['replace_config'] diff_file = module.params['diff_file'] if commit_changes.__class__ is str: commit_changes = ast.literal_eval(commit_changes) + if replace_config.__class__ is str: + replace_config = ast.literal_eval(replace_config) if use_ssl.__class__ is str: use_ssl = ast.literal_eval(use_ssl) @@ -142,7 +163,10 @@ def main(): module.exit_json(changed=False, msg=diff) else: if len(diff) > 0: - device.replace_config() + if replace_config: + device.replace_config() + else: + device.merge_config() module.exit_json(changed=changed, msg=diff) logger.info('DEVICE=%s CHANGED=%s STATUS=%s' % (hostname, len(changed.splitlines())), 'OK') @@ -151,4 +175,4 @@ def main(): from ansible.module_utils.basic import * -main() \ No newline at end of file +main() diff --git a/pyEOS/eos.py b/pyEOS/eos.py index 199ab6e..7b22c14 100644 --- a/pyEOS/eos.py +++ b/pyEOS/eos.py @@ -198,6 +198,30 @@ def replace_config(self, config=None, force=False): else: raise exceptions.CommandError(result[1]['messages'][0]) + def merge_config(self, config=None, force=False): + """ + Applies the configuration changes on the device. You can either commit the changes on the candidate_config + attribute or you can send the desired configuration as a string. Note that the current configuration of the + device is merged with the new configuration. + + :param config: String containing the desired configuration. If set to None the candidate_config will be used + + """ + if config is None: + config = self.candidate_config.to_string() + + body = { + 'cmd': 'configure', + 'input': config + } + self.original_config = self.get_config(format='text') + result = self.run_commands([body]) + + if 'Invalid' not in result[1]['messages'][0]: + return result + else: + raise exceptions.CommandError(result[1]['messages'][0]) + def rollback(self): """ If used after a commit, the configuration will be reverted to the previous state. From 62e02d512fb95d11a9101914a15711e5d437f920 Mon Sep 17 00:00:00 2001 From: Elisa Jasinska Date: Sun, 22 Mar 2015 22:29:09 +0000 Subject: [PATCH 02/17] adding merge_config --- pyEOS/eos.py | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/pyEOS/eos.py b/pyEOS/eos.py index 7b22c14..865eb2b 100644 --- a/pyEOS/eos.py +++ b/pyEOS/eos.py @@ -157,17 +157,29 @@ def load_candidate_config(self, filename=None, config=None): else: self.candidate_config.load_config(config=config) - def compare_config(self): + def compare_replace_config(self): """ - :return: A string showing the difference between the running_config and the candidate_config. The running_config is - loaded automatically just before doing the comparison so there is no neeed for you to do it. + :return: A string showing the difference between the running_config + and the candidate_config, assuming the entire running conf will be + replaced by the candidate. The running_config is loaded + automatically just before doing the comparison so there is no + neeed for you to do it. """ # We get the config in text format because you get better printability by parsing and using an OrderedDict self.load_running_config() return self.running_config.compare_config(self.candidate_config) + def compare_merge_config(self): + """ + + :return: A string showing the commands that are going to be applied + to the router. + """ + + return self.candidate_config + def replace_config(self, config=None, force=False): """ Applies the configuration changes on the device. You can either commit the changes on the candidate_config @@ -198,7 +210,7 @@ def replace_config(self, config=None, force=False): else: raise exceptions.CommandError(result[1]['messages'][0]) - def merge_config(self, config=None, force=False): + def merge_config(self, config=None): """ Applies the configuration changes on the device. You can either commit the changes on the candidate_config attribute or you can send the desired configuration as a string. Note that the current configuration of the @@ -210,12 +222,11 @@ def merge_config(self, config=None, force=False): if config is None: config = self.candidate_config.to_string() - body = { - 'cmd': 'configure', - 'input': config - } - self.original_config = self.get_config(format='text') - result = self.run_commands([body]) + commands = config.split('\n') + if 'configure' is not commands[0]: + commands.insert(0, 'configure') + + result = self.run_commands([commands]) if 'Invalid' not in result[1]['messages'][0]: return result From a057d9e08b14b55a9bb06989f90a4cf2f6df7f5f Mon Sep 17 00:00:00 2001 From: Elisa Jasinska Date: Sun, 22 Mar 2015 22:40:07 +0000 Subject: [PATCH 03/17] adding merge_config --- ansible/eos_install_config | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ansible/eos_install_config b/ansible/eos_install_config index abc854d..efb4794 100644 --- a/ansible/eos_install_config +++ b/ansible/eos_install_config @@ -152,8 +152,9 @@ def main(): device.open() device.load_candidate_config(filename=config_file) - #content of the - diff = device.compare_config() + diff = device.compare_merge_config() + if replace_config: + diff = device.compare_replace_config() changed = len(diff) > 0 if diff_file is not None: From b089ab373f9bca82e39e30f30177a51dc4a105f6 Mon Sep 17 00:00:00 2001 From: Elisa Jasinska Date: Mon, 23 Mar 2015 13:04:22 +0000 Subject: [PATCH 04/17] adding a few changes as per the commentary on pull/2 --- ansible/eos_install_config | 36 +++++++++++++-------------- pyEOS/eos.py | 50 ++++++++++++++++++-------------------- 2 files changed, 42 insertions(+), 44 deletions(-) diff --git a/ansible/eos_install_config b/ansible/eos_install_config index efb4794..cc48614 100644 --- a/ansible/eos_install_config +++ b/ansible/eos_install_config @@ -31,7 +31,7 @@ module: eos_install_config author: David Barroso version_added: "1.0.0" short_description: - Takes configuration from a file oiand loads it onto a device running EOS. + Takes configuration from a file and loads it onto a device running EOS. description: This library will take the configuration from a file and load it into a device running EOS. The old configuration will be either replaced by @@ -45,40 +45,40 @@ requirements: options: hostname: description: IP or FQDN of the device you want to connect to - required: True + required: true username: description: Username - required: True + required: true password: description: Password - required: True + required: true use_ssl: description: - If set to True we will connect via https, if False we will use - http instead. Default is True. - required: False + If set to true we will connect via https, if false we will use + http instead. Default is true. + required: false config_file: description: File to load the configuration from. - required: True + required: true commit_changes: description: - If set to True the commit will be performed. If set to False, + If set to true the commit will be performed. If set to false, we will not apply the changes, only check the differences. - Default: False. - required: False + Default: false. + required: false replace_config: description: - If set to True the entire configuration on the device will be - replaced during the commit. If set to False, we will merge the - new config with the existing one. Default: False. - required: False + If set to true the entire configuration on the device will be + replaced during the commit. If set to false, we will merge the + new config with the existing one. Default: false. + required: false diff_file: description: A file where to store the "diff" between the running configuration and the new configuration. If it's not set the - diff between configurations is not saved. - required: False + diff between configurations is not saved. Default: none. + required: false ''' EXAMPLES = ''' @@ -93,7 +93,7 @@ EXAMPLES = ''' hostname={{ inventory_hostname }} username=admin password=p4ssw0rd - use_ssl=False + use_ssl=false config_file=~/spotify/network-ansible/compiled/{{ inventory_hostname }}/running.conf commit_changes={{ commit_changes }} replace_config={{ replace_config }} diff --git a/pyEOS/eos.py b/pyEOS/eos.py index 865eb2b..b08e0df 100644 --- a/pyEOS/eos.py +++ b/pyEOS/eos.py @@ -27,7 +27,8 @@ def __init__(self, hostname, username, password, use_ssl=True): The object will contain the following interesting attributes: * **running_config** - The configuration retrieved from the device using the method load_running_config - * **candidate_config** - The configuration we desire for the device. Can be populated using the method load_candidate_config + * **candidate_config** - The configuration we desire for the device. Can be populated using the method + load_candidate_config :param hostname: IP or FQDN of the device you want to connect to :param username: Username @@ -71,9 +72,13 @@ def run_commands(self, commands, version=1, auto_format=False, format='json', ti :param commands: List of commands you want to run :param version: Version of the eAPI you want to connect to. By default is 1. - :param auto_format: If set to True API calls not supporting returning JSON messages will be converted automatically to text. By default is False. - :param format: Format you want to get; 'json' or 'text'. By default is json. This will trigger a CommandUnconverted exception if set to 'json' and auto_format is set to False. It will return text if set to 'json' but auto_format is set to True. - :param timestamps: This will return some useful information like when was the command executed and how long it took. + :param auto_format: If set to True API calls not supporting returning JSON messages will be converted + automatically to text. By default it is False. + :param format: Format you want to get; 'json' or 'text'. By default it is json. This will trigger a + CommandUnconverted exception if set to 'json' and auto_format is set to False. It will return text if set + to 'json' but auto_format is set to True. + :param timestamps: This will return some useful information like when was the command executed and how long + it took. """ @@ -117,11 +122,15 @@ def run_commands(self, commands, version=1, auto_format=False, format='json', ti else: raise exceptions.UnknownError((code, error)) - return result + if 'Invalid' not in result[1]['messages'][0]: + return result + else: + raise exceptions.CommandError(result[1]['messages'][0]) def close(self): """ - Dummy, method. Today it does not do anything but it would be interesting to use it to fake closing a connection. + Dummy, method. Today it does not do anything but it would be interesting to use it to fake closing a + connection. """ pass @@ -146,9 +155,10 @@ def load_running_config(self): def load_candidate_config(self, filename=None, config=None): """ Populates the attribute candidate_config with the desired configuration. You can populate it from a file or - from a string. If you send both a filename and a string containing the configuration, the file takes precedence. + from a string. If you send both a filename and a string containing the configuration, the file takes + precedence. - :param filename: Path to the file containing the desired configuration. By default is None. + :param filename: Path to the file containing the desired configuration. By default it is None. :param config: String containing the desired configuration. """ @@ -160,11 +170,9 @@ def load_candidate_config(self, filename=None, config=None): def compare_replace_config(self): """ - :return: A string showing the difference between the running_config - and the candidate_config, assuming the entire running conf will be - replaced by the candidate. The running_config is loaded - automatically just before doing the comparison so there is no - neeed for you to do it. + :return: A string showing the difference between the running_config and the candidate_config, assuming the + entire running conf will be replaced by the candidate. The running_config is loaded automatically just + before doing the comparison so there is no neeed for you to do it. """ # We get the config in text format because you get better printability by parsing and using an OrderedDict @@ -196,19 +204,14 @@ def replace_config(self, config=None, force=False): if force: force_text = 'force' else: - force_text = 'no-force' + force_text = '' body = { 'cmd': 'configure replace terminal: %s' % force_text, 'input': config } self.original_config = self.get_config(format='text') - result = self.run_commands([body]) - - if 'Invalid' not in result[1]['messages'][0]: - return result - else: - raise exceptions.CommandError(result[1]['messages'][0]) + return self.run_commands([body]) def merge_config(self, config=None): """ @@ -226,12 +229,7 @@ def merge_config(self, config=None): if 'configure' is not commands[0]: commands.insert(0, 'configure') - result = self.run_commands([commands]) - - if 'Invalid' not in result[1]['messages'][0]: - return result - else: - raise exceptions.CommandError(result[1]['messages'][0]) + return self.run_commands([commands]) def rollback(self): """ From 07cd5d6f320a1616fd1e14349dedaa95b88effad Mon Sep 17 00:00:00 2001 From: Elisa Jasinska Date: Mon, 23 Mar 2015 18:18:26 +0000 Subject: [PATCH 05/17] david wins --- ansible/eos_install_config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ansible/eos_install_config b/ansible/eos_install_config index cc48614..7d12ea5 100644 --- a/ansible/eos_install_config +++ b/ansible/eos_install_config @@ -124,7 +124,7 @@ def main(): password=dict(required=True), use_ssl=dict(required=False, default=True), config_file=dict(required=True), - commit_changes=dict(required=False, default=False), + commit_changes=dict(required=True), replace_config=dict(required=False, default=False), diff_file=dict(required=False, default=None), ), From f32c7b7ea00f696270274231843edcec8b17bbbf Mon Sep 17 00:00:00 2001 From: Elisa Jasinska Date: Mon, 23 Mar 2015 18:24:41 +0000 Subject: [PATCH 06/17] now where we agreed on 120 char width... --- ansible/eos_install_config | 37 ++++++++++++------------------------- 1 file changed, 12 insertions(+), 25 deletions(-) diff --git a/ansible/eos_install_config b/ansible/eos_install_config index 7d12ea5..d4ed0dc 100644 --- a/ansible/eos_install_config +++ b/ansible/eos_install_config @@ -30,14 +30,10 @@ DOCUMENTATION = ''' module: eos_install_config author: David Barroso version_added: "1.0.0" -short_description: - Takes configuration from a file and loads it onto a device running EOS. -description: - This library will take the configuration from a file and load it into a - device running EOS. The old configuration will be either replaced by - using the feature 'config replace terminal: force', or merged with the - running configuration. To use this module you need to enable access - to the device via the eAPI. +short_description: Takes configuration from a file and loads it onto a device running EOS. +description: This library will take the configuration from a file and load it into a device running EOS. The old + configuration will be either replaced by using the feature 'config replace terminal: force', or merged with the + running configuration. To use this module you need to enable access to the device via the eAPI. requirements: - pyEOS @@ -53,31 +49,22 @@ options: description: Password required: true use_ssl: - description: - If set to true we will connect via https, if false we will use - http instead. Default is true. + description: If set to true we will connect via https, if false we will use http instead. Default is true. required: false config_file: - description: - File to load the configuration from. + description: File to load the configuration from. required: true commit_changes: - description: - If set to true the commit will be performed. If set to false, - we will not apply the changes, only check the differences. - Default: false. + description: If set to true the commit will be performed. If set to false, we will not apply the changes, + only check the differences. Default: false. required: false replace_config: - description: - If set to true the entire configuration on the device will be - replaced during the commit. If set to false, we will merge the - new config with the existing one. Default: false. + description: If set to true the entire configuration on the device will be replaced during the commit. If + set to false, we will merge the new config with the existing one. Default: false. required: false diff_file: - description: - A file where to store the "diff" between the running - configuration and the new configuration. If it's not set the - diff between configurations is not saved. Default: none. + description: A file where to store the "diff" between the running configuration and the new configuration. + If it's not set the diff between configurations is not saved. Default: none. required: false ''' From 3207c5df22eeb974f183fa6a9372ae8e4e5dbcdc Mon Sep 17 00:00:00 2001 From: Elisa Jasinska Date: Mon, 23 Mar 2015 18:27:22 +0000 Subject: [PATCH 07/17] compare_config -> compare_replace_config in tests and doc --- docs/first_steps.rst | 6 +++--- test/unit/TestEOS.py | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/first_steps.rst b/docs/first_steps.rst index 9ec7ed4..59b56c1 100644 --- a/docs/first_steps.rst +++ b/docs/first_steps.rst @@ -309,7 +309,7 @@ Or just check an interface configuration:: You can also read configuration from a file, compare the running config with the candidate config:: >>> device.load_candidate_config('tests/config.txt') - >>> print device.compare_config() + >>> print device.compare_replace_config() + hostname NEWHOSTNAME - hostname eapi-lab interface Ethernet1 @@ -321,7 +321,7 @@ You can commit the configuration if you are happy:: >>> device.commit() [{u'_meta': {u'execStartTime': 1418660581.91, u'execDuration': 0.00144815444946}}, {u'messages': [u"enter input line by line; when done enter one or more control-d\n! Preserving static routes. Use 'no ip routing delete-static-routes' to clear them.\n! Preserving static routes. Use 'no ip routing delete-static-routes' to clear them.\n"], u'_meta': {u'execStartTime': 1418660581.91, u'execDuration': 9.50796413422}}] - >>> print device.compare_config() + >>> print device.compare_replace_config() >>> @@ -329,7 +329,7 @@ And even rollback if you regret it:: >>> device.rollback() [{u'_meta': {u'execStartTime': 1418660622.75, u'execDuration': 0.00146913528442}}, {u'messages': [u"enter input line by line; when done enter one or more control-d\n! Preserving static routes. Use 'no ip routing delete-static-routes' to clear them.\n! Preserving static routes. Use 'no ip routing delete-static-routes' to clear them.\n"], u'_meta': {u'execStartTime': 1418660622.75, u'execDuration': 9.6508910656}}] - >>> print device.compare_config() + >>> print device.compare_replace_config() + hostname NEWHOSTNAME - hostname eapi-lab interface Ethernet1 diff --git a/test/unit/TestEOS.py b/test/unit/TestEOS.py index 25fb770..2dbc7d7 100644 --- a/test/unit/TestEOS.py +++ b/test/unit/TestEOS.py @@ -58,21 +58,21 @@ def test_arbitrary_command(self): def test_loading_config(self): self.device.load_candidate_config(filename=config.config_file_1) self.device.replace_config() - diff = self.device.compare_config() + diff = self.device.compare_replace_config() self.assertEqual(len(diff), 0) def test_loading_modified_config_and_diff(self): self.device.load_candidate_config(filename=config.config_file_2) - diff = self.device.compare_config() + diff = self.device.compare_replace_config() self.assertGreater(len(diff), 0) def test_loading_modified_config_replace_config_and_rollback(self): self.device.load_candidate_config(filename=config.config_file_2) - orig_diff = self.device.compare_config() + orig_diff = self.device.compare_replace_config() self.device.replace_config() - replace_config_diff = self.device.compare_config() + replace_config_diff = self.device.compare_replace_config() self.device.rollback() - last_diff = self.device.compare_config() + last_diff = self.device.compare_replace_config() result = (orig_diff == last_diff) and ( len(replace_config_diff) == 0 ) @@ -81,4 +81,4 @@ def test_loading_modified_config_replace_config_and_rollback(self): def test_get_interface_config(self): self.device.load_running_config() interface = self.device.running_config['interface Ethernet2'] - self.assertGreater(len(interface), 0) \ No newline at end of file + self.assertGreater(len(interface), 0) From 9eb3f45815e1234308c98299e8439d65234cbc0b Mon Sep 17 00:00:00 2001 From: Elisa Jasinska Date: Tue, 24 Mar 2015 16:06:49 +0000 Subject: [PATCH 08/17] ok ok, i give up --- ansible/eos_install_config | 18 ++---------------- pyEOS/eos.py | 29 +---------------------------- test/unit/TestEOS.py | 10 +++++----- 3 files changed, 8 insertions(+), 49 deletions(-) diff --git a/ansible/eos_install_config b/ansible/eos_install_config index d4ed0dc..5249095 100644 --- a/ansible/eos_install_config +++ b/ansible/eos_install_config @@ -58,10 +58,6 @@ options: description: If set to true the commit will be performed. If set to false, we will not apply the changes, only check the differences. Default: false. required: false - replace_config: - description: If set to true the entire configuration on the device will be replaced during the commit. If - set to false, we will merge the new config with the existing one. Default: false. - required: false diff_file: description: A file where to store the "diff" between the running configuration and the new configuration. If it's not set the diff between configurations is not saved. Default: none. @@ -83,7 +79,6 @@ EXAMPLES = ''' use_ssl=false config_file=~/spotify/network-ansible/compiled/{{ inventory_hostname }}/running.conf commit_changes={{ commit_changes }} - replace_config={{ replace_config }} diff_file=logs/{{ inventory_hostname }}.log From the CLI we would trigger the playbook like: @@ -112,7 +107,6 @@ def main(): use_ssl=dict(required=False, default=True), config_file=dict(required=True), commit_changes=dict(required=True), - replace_config=dict(required=False, default=False), diff_file=dict(required=False, default=None), ), supports_check_mode=True @@ -125,13 +119,10 @@ def main(): config_file = module.params['config_file'] commit_changes = module.params['commit_changes'] - replace_config = module.params['replace_config'] diff_file = module.params['diff_file'] if commit_changes.__class__ is str: commit_changes = ast.literal_eval(commit_changes) - if replace_config.__class__ is str: - replace_config = ast.literal_eval(replace_config) if use_ssl.__class__ is str: use_ssl = ast.literal_eval(use_ssl) @@ -139,9 +130,7 @@ def main(): device.open() device.load_candidate_config(filename=config_file) - diff = device.compare_merge_config() - if replace_config: - diff = device.compare_replace_config() + diff = device.compare_config() changed = len(diff) > 0 if diff_file is not None: @@ -151,10 +140,7 @@ def main(): module.exit_json(changed=False, msg=diff) else: if len(diff) > 0: - if replace_config: - device.replace_config() - else: - device.merge_config() + device.merge_config() module.exit_json(changed=changed, msg=diff) logger.info('DEVICE=%s CHANGED=%s STATUS=%s' % (hostname, len(changed.splitlines())), 'OK') diff --git a/pyEOS/eos.py b/pyEOS/eos.py index b08e0df..e21e27b 100644 --- a/pyEOS/eos.py +++ b/pyEOS/eos.py @@ -167,7 +167,7 @@ def load_candidate_config(self, filename=None, config=None): else: self.candidate_config.load_config(config=config) - def compare_replace_config(self): + def compare_config(self): """ :return: A string showing the difference between the running_config and the candidate_config, assuming the @@ -179,15 +179,6 @@ def compare_replace_config(self): self.load_running_config() return self.running_config.compare_config(self.candidate_config) - def compare_merge_config(self): - """ - - :return: A string showing the commands that are going to be applied - to the router. - """ - - return self.candidate_config - def replace_config(self, config=None, force=False): """ Applies the configuration changes on the device. You can either commit the changes on the candidate_config @@ -213,24 +204,6 @@ def replace_config(self, config=None, force=False): self.original_config = self.get_config(format='text') return self.run_commands([body]) - def merge_config(self, config=None): - """ - Applies the configuration changes on the device. You can either commit the changes on the candidate_config - attribute or you can send the desired configuration as a string. Note that the current configuration of the - device is merged with the new configuration. - - :param config: String containing the desired configuration. If set to None the candidate_config will be used - - """ - if config is None: - config = self.candidate_config.to_string() - - commands = config.split('\n') - if 'configure' is not commands[0]: - commands.insert(0, 'configure') - - return self.run_commands([commands]) - def rollback(self): """ If used after a commit, the configuration will be reverted to the previous state. diff --git a/test/unit/TestEOS.py b/test/unit/TestEOS.py index 2dbc7d7..0836001 100644 --- a/test/unit/TestEOS.py +++ b/test/unit/TestEOS.py @@ -58,21 +58,21 @@ def test_arbitrary_command(self): def test_loading_config(self): self.device.load_candidate_config(filename=config.config_file_1) self.device.replace_config() - diff = self.device.compare_replace_config() + diff = self.device.compare_config() self.assertEqual(len(diff), 0) def test_loading_modified_config_and_diff(self): self.device.load_candidate_config(filename=config.config_file_2) - diff = self.device.compare_replace_config() + diff = self.device.compare_config() self.assertGreater(len(diff), 0) def test_loading_modified_config_replace_config_and_rollback(self): self.device.load_candidate_config(filename=config.config_file_2) - orig_diff = self.device.compare_replace_config() + orig_diff = self.device.compare_config() self.device.replace_config() - replace_config_diff = self.device.compare_replace_config() + replace_config_diff = self.device.compare_config() self.device.rollback() - last_diff = self.device.compare_replace_config() + last_diff = self.device.compare_config() result = (orig_diff == last_diff) and ( len(replace_config_diff) == 0 ) From c088113645c147b918fb252c7d6587e9f0e43e5e Mon Sep 17 00:00:00 2001 From: Elisa Jasinska Date: Tue, 24 Mar 2015 16:14:23 +0000 Subject: [PATCH 09/17] until arista supports commit and we see how to implement that... bye --- ansible/eos_install_config | 6 +++--- docs/first_steps.rst | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/ansible/eos_install_config b/ansible/eos_install_config index 5249095..c62a61f 100644 --- a/ansible/eos_install_config +++ b/ansible/eos_install_config @@ -32,8 +32,8 @@ author: David Barroso version_added: "1.0.0" short_description: Takes configuration from a file and loads it onto a device running EOS. description: This library will take the configuration from a file and load it into a device running EOS. The old - configuration will be either replaced by using the feature 'config replace terminal: force', or merged with the - running configuration. To use this module you need to enable access to the device via the eAPI. + configuration will be replaced by using the feature 'config replace terminal: force'. To use this module you + need to enable access to the device via the eAPI. requirements: - pyEOS @@ -140,7 +140,7 @@ def main(): module.exit_json(changed=False, msg=diff) else: if len(diff) > 0: - device.merge_config() + device.replace_config() module.exit_json(changed=changed, msg=diff) logger.info('DEVICE=%s CHANGED=%s STATUS=%s' % (hostname, len(changed.splitlines())), 'OK') diff --git a/docs/first_steps.rst b/docs/first_steps.rst index 59b56c1..9ec7ed4 100644 --- a/docs/first_steps.rst +++ b/docs/first_steps.rst @@ -309,7 +309,7 @@ Or just check an interface configuration:: You can also read configuration from a file, compare the running config with the candidate config:: >>> device.load_candidate_config('tests/config.txt') - >>> print device.compare_replace_config() + >>> print device.compare_config() + hostname NEWHOSTNAME - hostname eapi-lab interface Ethernet1 @@ -321,7 +321,7 @@ You can commit the configuration if you are happy:: >>> device.commit() [{u'_meta': {u'execStartTime': 1418660581.91, u'execDuration': 0.00144815444946}}, {u'messages': [u"enter input line by line; when done enter one or more control-d\n! Preserving static routes. Use 'no ip routing delete-static-routes' to clear them.\n! Preserving static routes. Use 'no ip routing delete-static-routes' to clear them.\n"], u'_meta': {u'execStartTime': 1418660581.91, u'execDuration': 9.50796413422}}] - >>> print device.compare_replace_config() + >>> print device.compare_config() >>> @@ -329,7 +329,7 @@ And even rollback if you regret it:: >>> device.rollback() [{u'_meta': {u'execStartTime': 1418660622.75, u'execDuration': 0.00146913528442}}, {u'messages': [u"enter input line by line; when done enter one or more control-d\n! Preserving static routes. Use 'no ip routing delete-static-routes' to clear them.\n! Preserving static routes. Use 'no ip routing delete-static-routes' to clear them.\n"], u'_meta': {u'execStartTime': 1418660622.75, u'execDuration': 9.6508910656}}] - >>> print device.compare_replace_config() + >>> print device.compare_config() + hostname NEWHOSTNAME - hostname eapi-lab interface Ethernet1 From 3d968eb90a5d6aabaef4d753f22f9366b8d8b589 Mon Sep 17 00:00:00 2001 From: Elisa Jasinska Date: Sat, 21 Mar 2015 00:31:29 +0000 Subject: [PATCH 10/17] working on merge_config --- ansible/eos_install_config | 62 ++++++++++++++++++++++++++------------ pyEOS/eos.py | 24 +++++++++++++++ 2 files changed, 67 insertions(+), 19 deletions(-) diff --git a/ansible/eos_install_config b/ansible/eos_install_config index cb94939..abc854d 100644 --- a/ansible/eos_install_config +++ b/ansible/eos_install_config @@ -30,10 +30,13 @@ DOCUMENTATION = ''' module: eos_install_config author: David Barroso version_added: "1.0.0" -short_description: Replaces the configuration taken from a file on a device running EOS. +short_description: + Takes configuration from a file oiand loads it onto a device running EOS. description: - This library will take the configuration from a file and load it into a device running EOS. The old configuration - will be replaced using the feature 'config replace terminal: force'. The use this module you need to enable access + This library will take the configuration from a file and load it into a + device running EOS. The old configuration will be either replaced by + using the feature 'config replace terminal: force', or merged with the + running configuration. To use this module you need to enable access to the device via the eAPI. requirements: @@ -42,26 +45,39 @@ requirements: options: hostname: description: IP or FQDN of the device you want to connect to - required: true + required: True username: description: Username - required: true + required: True password: description: Password - required: true + required: True use_ssl: - description: If set to True we will connect via https, if False we will use http instead. Default is True. - required: false + description: + If set to True we will connect via https, if False we will use + http instead. Default is True. + required: False config_file: - description: Where to load the configuration from. - required: true + description: + File to load the configuration from. + required: True commit_changes: - description: If set to True the configuration will be actually replaced. If the set to False, we will not - apply the changes, just check the differences. - required: true + description: + If set to True the commit will be performed. If set to False, + we will not apply the changes, only check the differences. + Default: False. + required: False + replace_config: + description: + If set to True the entire configuration on the device will be + replaced during the commit. If set to False, we will merge the + new config with the existing one. Default: False. + required: False diff_file: - description: A file where to store the "diff" between the running configuration and the new configuration. If - it's not set the diff between configurations is not saved. + description: + A file where to store the "diff" between the running + configuration and the new configuration. If it's not set the + diff between configurations is not saved. required: False ''' @@ -79,7 +95,8 @@ EXAMPLES = ''' password=p4ssw0rd use_ssl=False config_file=~/spotify/network-ansible/compiled/{{ inventory_hostname }}/running.conf - commit_changes={{commit_changes}} + commit_changes={{ commit_changes }} + replace_config={{ replace_config }} diff_file=logs/{{ inventory_hostname }}.log From the CLI we would trigger the playbook like: @@ -107,7 +124,8 @@ def main(): password=dict(required=True), use_ssl=dict(required=False, default=True), config_file=dict(required=True), - commit_changes=dict(required=True), + commit_changes=dict(required=False, default=False), + replace_config=dict(required=False, default=False), diff_file=dict(required=False, default=None), ), supports_check_mode=True @@ -120,10 +138,13 @@ def main(): config_file = module.params['config_file'] commit_changes = module.params['commit_changes'] + replace_config = module.params['replace_config'] diff_file = module.params['diff_file'] if commit_changes.__class__ is str: commit_changes = ast.literal_eval(commit_changes) + if replace_config.__class__ is str: + replace_config = ast.literal_eval(replace_config) if use_ssl.__class__ is str: use_ssl = ast.literal_eval(use_ssl) @@ -142,7 +163,10 @@ def main(): module.exit_json(changed=False, msg=diff) else: if len(diff) > 0: - device.replace_config() + if replace_config: + device.replace_config() + else: + device.merge_config() module.exit_json(changed=changed, msg=diff) logger.info('DEVICE=%s CHANGED=%s STATUS=%s' % (hostname, len(changed.splitlines())), 'OK') @@ -151,4 +175,4 @@ def main(): from ansible.module_utils.basic import * -main() \ No newline at end of file +main() diff --git a/pyEOS/eos.py b/pyEOS/eos.py index 35de3bc..4891757 100644 --- a/pyEOS/eos.py +++ b/pyEOS/eos.py @@ -202,6 +202,30 @@ def replace_config(self, config=None, force=False): else: raise exceptions.CommandError(result[1]['messages'][0]) + def merge_config(self, config=None, force=False): + """ + Applies the configuration changes on the device. You can either commit the changes on the candidate_config + attribute or you can send the desired configuration as a string. Note that the current configuration of the + device is merged with the new configuration. + + :param config: String containing the desired configuration. If set to None the candidate_config will be used + + """ + if config is None: + config = self.candidate_config.to_string() + + body = { + 'cmd': 'configure', + 'input': config + } + self.original_config = self.get_config(format='text') + result = self.run_commands([body]) + + if 'Invalid' not in result[1]['messages'][0]: + return result + else: + raise exceptions.CommandError(result[1]['messages'][0]) + def rollback(self): """ If used after a commit, the configuration will be reverted to the previous state. From f21e79a01ea9b51f86a593cadd7fbc6d41ca9b59 Mon Sep 17 00:00:00 2001 From: Elisa Jasinska Date: Sun, 22 Mar 2015 22:29:09 +0000 Subject: [PATCH 11/17] adding merge_config --- pyEOS/eos.py | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/pyEOS/eos.py b/pyEOS/eos.py index 4891757..4209ce3 100644 --- a/pyEOS/eos.py +++ b/pyEOS/eos.py @@ -161,17 +161,29 @@ def load_candidate_config(self, filename=None, config=None): else: self.candidate_config.load_config(config=config) - def compare_config(self): + def compare_replace_config(self): """ - :return: A string showing the difference between the running_config and the candidate_config. The running_config is - loaded automatically just before doing the comparison so there is no neeed for you to do it. + :return: A string showing the difference between the running_config + and the candidate_config, assuming the entire running conf will be + replaced by the candidate. The running_config is loaded + automatically just before doing the comparison so there is no + neeed for you to do it. """ # We get the config in text format because you get better printability by parsing and using an OrderedDict self.load_running_config() return self.running_config.compare_config(self.candidate_config) + def compare_merge_config(self): + """ + + :return: A string showing the commands that are going to be applied + to the router. + """ + + return self.candidate_config + def replace_config(self, config=None, force=False): """ Applies the configuration changes on the device. You can either commit the changes on the candidate_config @@ -202,7 +214,7 @@ def replace_config(self, config=None, force=False): else: raise exceptions.CommandError(result[1]['messages'][0]) - def merge_config(self, config=None, force=False): + def merge_config(self, config=None): """ Applies the configuration changes on the device. You can either commit the changes on the candidate_config attribute or you can send the desired configuration as a string. Note that the current configuration of the @@ -214,12 +226,11 @@ def merge_config(self, config=None, force=False): if config is None: config = self.candidate_config.to_string() - body = { - 'cmd': 'configure', - 'input': config - } - self.original_config = self.get_config(format='text') - result = self.run_commands([body]) + commands = config.split('\n') + if 'configure' is not commands[0]: + commands.insert(0, 'configure') + + result = self.run_commands([commands]) if 'Invalid' not in result[1]['messages'][0]: return result From 73c3cebcb61de79c18591da6496687e36327c0be Mon Sep 17 00:00:00 2001 From: Elisa Jasinska Date: Sun, 22 Mar 2015 22:40:07 +0000 Subject: [PATCH 12/17] adding merge_config --- ansible/eos_install_config | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ansible/eos_install_config b/ansible/eos_install_config index abc854d..efb4794 100644 --- a/ansible/eos_install_config +++ b/ansible/eos_install_config @@ -152,8 +152,9 @@ def main(): device.open() device.load_candidate_config(filename=config_file) - #content of the - diff = device.compare_config() + diff = device.compare_merge_config() + if replace_config: + diff = device.compare_replace_config() changed = len(diff) > 0 if diff_file is not None: From fb8113e6ed8c62672d5ac46dff50a5b1097de05c Mon Sep 17 00:00:00 2001 From: Elisa Jasinska Date: Mon, 23 Mar 2015 13:04:22 +0000 Subject: [PATCH 13/17] adding a few changes as per the commentary on pull/2 --- ansible/eos_install_config | 36 ++++++++++++++-------------- pyEOS/eos.py | 48 ++++++++++++++++++-------------------- 2 files changed, 41 insertions(+), 43 deletions(-) diff --git a/ansible/eos_install_config b/ansible/eos_install_config index efb4794..cc48614 100644 --- a/ansible/eos_install_config +++ b/ansible/eos_install_config @@ -31,7 +31,7 @@ module: eos_install_config author: David Barroso version_added: "1.0.0" short_description: - Takes configuration from a file oiand loads it onto a device running EOS. + Takes configuration from a file and loads it onto a device running EOS. description: This library will take the configuration from a file and load it into a device running EOS. The old configuration will be either replaced by @@ -45,40 +45,40 @@ requirements: options: hostname: description: IP or FQDN of the device you want to connect to - required: True + required: true username: description: Username - required: True + required: true password: description: Password - required: True + required: true use_ssl: description: - If set to True we will connect via https, if False we will use - http instead. Default is True. - required: False + If set to true we will connect via https, if false we will use + http instead. Default is true. + required: false config_file: description: File to load the configuration from. - required: True + required: true commit_changes: description: - If set to True the commit will be performed. If set to False, + If set to true the commit will be performed. If set to false, we will not apply the changes, only check the differences. - Default: False. - required: False + Default: false. + required: false replace_config: description: - If set to True the entire configuration on the device will be - replaced during the commit. If set to False, we will merge the - new config with the existing one. Default: False. - required: False + If set to true the entire configuration on the device will be + replaced during the commit. If set to false, we will merge the + new config with the existing one. Default: false. + required: false diff_file: description: A file where to store the "diff" between the running configuration and the new configuration. If it's not set the - diff between configurations is not saved. - required: False + diff between configurations is not saved. Default: none. + required: false ''' EXAMPLES = ''' @@ -93,7 +93,7 @@ EXAMPLES = ''' hostname={{ inventory_hostname }} username=admin password=p4ssw0rd - use_ssl=False + use_ssl=false config_file=~/spotify/network-ansible/compiled/{{ inventory_hostname }}/running.conf commit_changes={{ commit_changes }} replace_config={{ replace_config }} diff --git a/pyEOS/eos.py b/pyEOS/eos.py index 4209ce3..fd49963 100644 --- a/pyEOS/eos.py +++ b/pyEOS/eos.py @@ -27,7 +27,8 @@ def __init__(self, hostname, username, password, use_ssl=True): The object will contain the following interesting attributes: * **running_config** - The configuration retrieved from the device using the method load_running_config - * **candidate_config** - The configuration we desire for the device. Can be populated using the method load_candidate_config + * **candidate_config** - The configuration we desire for the device. Can be populated using the method + load_candidate_config :param hostname: IP or FQDN of the device you want to connect to :param username: Username @@ -71,9 +72,13 @@ def run_commands(self, commands, version=1, auto_format=False, format='json', ti :param commands: List of commands you want to run :param version: Version of the eAPI you want to connect to. By default is 1. - :param auto_format: If set to True API calls not supporting returning JSON messages will be converted automatically to text. By default is False. - :param format: Format you want to get; 'json' or 'text'. By default is json. This will trigger a CommandUnconverted exception if set to 'json' and auto_format is set to False. It will return text if set to 'json' but auto_format is set to True. - :param timestamps: This will return some useful information like when was the command executed and how long it took. + :param auto_format: If set to True API calls not supporting returning JSON messages will be converted + automatically to text. By default it is False. + :param format: Format you want to get; 'json' or 'text'. By default it is json. This will trigger a + CommandUnconverted exception if set to 'json' and auto_format is set to False. It will return text if set + to 'json' but auto_format is set to True. + :param timestamps: This will return some useful information like when was the command executed and how long + it took. """ @@ -121,11 +126,15 @@ def run_commands(self, commands, version=1, auto_format=False, format='json', ti else: raise exceptions.UnknownError((code, error)) - return result + if 'Invalid' not in result[1]['messages'][0]: + return result + else: + raise exceptions.CommandError(result[1]['messages'][0]) def close(self): """ - Dummy, method. Today it does not do anything but it would be interesting to use it to fake closing a connection. + Dummy, method. Today it does not do anything but it would be interesting to use it to fake closing a + connection. """ pass @@ -150,9 +159,10 @@ def load_running_config(self): def load_candidate_config(self, filename=None, config=None): """ Populates the attribute candidate_config with the desired configuration. You can populate it from a file or - from a string. If you send both a filename and a string containing the configuration, the file takes precedence. + from a string. If you send both a filename and a string containing the configuration, the file takes + precedence. - :param filename: Path to the file containing the desired configuration. By default is None. + :param filename: Path to the file containing the desired configuration. By default it is None. :param config: String containing the desired configuration. """ @@ -164,11 +174,9 @@ def load_candidate_config(self, filename=None, config=None): def compare_replace_config(self): """ - :return: A string showing the difference between the running_config - and the candidate_config, assuming the entire running conf will be - replaced by the candidate. The running_config is loaded - automatically just before doing the comparison so there is no - neeed for you to do it. + :return: A string showing the difference between the running_config and the candidate_config, assuming the + entire running conf will be replaced by the candidate. The running_config is loaded automatically just + before doing the comparison so there is no neeed for you to do it. """ # We get the config in text format because you get better printability by parsing and using an OrderedDict @@ -207,12 +215,7 @@ def replace_config(self, config=None, force=False): 'input': config } self.original_config = self.get_config(format='text') - result = self.run_commands([body]) - - if 'Invalid' not in result[1]['messages'][0]: - return result - else: - raise exceptions.CommandError(result[1]['messages'][0]) + return self.run_commands([body]) def merge_config(self, config=None): """ @@ -230,12 +233,7 @@ def merge_config(self, config=None): if 'configure' is not commands[0]: commands.insert(0, 'configure') - result = self.run_commands([commands]) - - if 'Invalid' not in result[1]['messages'][0]: - return result - else: - raise exceptions.CommandError(result[1]['messages'][0]) + return self.run_commands([commands]) def rollback(self): """ From 99dbcf473b643b873dac89486569067d60f7bb0a Mon Sep 17 00:00:00 2001 From: Elisa Jasinska Date: Mon, 23 Mar 2015 18:18:26 +0000 Subject: [PATCH 14/17] david wins --- ansible/eos_install_config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ansible/eos_install_config b/ansible/eos_install_config index cc48614..7d12ea5 100644 --- a/ansible/eos_install_config +++ b/ansible/eos_install_config @@ -124,7 +124,7 @@ def main(): password=dict(required=True), use_ssl=dict(required=False, default=True), config_file=dict(required=True), - commit_changes=dict(required=False, default=False), + commit_changes=dict(required=True), replace_config=dict(required=False, default=False), diff_file=dict(required=False, default=None), ), From 445bb471e818ce32fc4a173bf515d88a57b0251d Mon Sep 17 00:00:00 2001 From: Elisa Jasinska Date: Mon, 23 Mar 2015 18:24:41 +0000 Subject: [PATCH 15/17] now where we agreed on 120 char width... --- ansible/eos_install_config | 37 ++++++++++++------------------------- 1 file changed, 12 insertions(+), 25 deletions(-) diff --git a/ansible/eos_install_config b/ansible/eos_install_config index 7d12ea5..d4ed0dc 100644 --- a/ansible/eos_install_config +++ b/ansible/eos_install_config @@ -30,14 +30,10 @@ DOCUMENTATION = ''' module: eos_install_config author: David Barroso version_added: "1.0.0" -short_description: - Takes configuration from a file and loads it onto a device running EOS. -description: - This library will take the configuration from a file and load it into a - device running EOS. The old configuration will be either replaced by - using the feature 'config replace terminal: force', or merged with the - running configuration. To use this module you need to enable access - to the device via the eAPI. +short_description: Takes configuration from a file and loads it onto a device running EOS. +description: This library will take the configuration from a file and load it into a device running EOS. The old + configuration will be either replaced by using the feature 'config replace terminal: force', or merged with the + running configuration. To use this module you need to enable access to the device via the eAPI. requirements: - pyEOS @@ -53,31 +49,22 @@ options: description: Password required: true use_ssl: - description: - If set to true we will connect via https, if false we will use - http instead. Default is true. + description: If set to true we will connect via https, if false we will use http instead. Default is true. required: false config_file: - description: - File to load the configuration from. + description: File to load the configuration from. required: true commit_changes: - description: - If set to true the commit will be performed. If set to false, - we will not apply the changes, only check the differences. - Default: false. + description: If set to true the commit will be performed. If set to false, we will not apply the changes, + only check the differences. Default: false. required: false replace_config: - description: - If set to true the entire configuration on the device will be - replaced during the commit. If set to false, we will merge the - new config with the existing one. Default: false. + description: If set to true the entire configuration on the device will be replaced during the commit. If + set to false, we will merge the new config with the existing one. Default: false. required: false diff_file: - description: - A file where to store the "diff" between the running - configuration and the new configuration. If it's not set the - diff between configurations is not saved. Default: none. + description: A file where to store the "diff" between the running configuration and the new configuration. + If it's not set the diff between configurations is not saved. Default: none. required: false ''' From 5c3d2ae6cc50a621f402544996dfa71bd4484e50 Mon Sep 17 00:00:00 2001 From: Elisa Jasinska Date: Tue, 24 Mar 2015 17:27:28 +0000 Subject: [PATCH 16/17] until arista supports commit and we see how to implement that... bye --- pyEOS/eos.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/pyEOS/eos.py b/pyEOS/eos.py index fd49963..a95b7c5 100644 --- a/pyEOS/eos.py +++ b/pyEOS/eos.py @@ -125,11 +125,9 @@ def run_commands(self, commands, version=1, auto_format=False, format='json', ti raise exceptions.ConfigReplaceError(e) else: raise exceptions.UnknownError((code, error)) + + return result - if 'Invalid' not in result[1]['messages'][0]: - return result - else: - raise exceptions.CommandError(result[1]['messages'][0]) def close(self): """ @@ -215,7 +213,12 @@ def replace_config(self, config=None, force=False): 'input': config } self.original_config = self.get_config(format='text') - return self.run_commands([body]) + result = self.run_commands([body]) + + if 'Invalid' not in result[1]['messages'][0]: + return result + else: + raise exceptions.CommandError(result[1]['messages'][0]) def merge_config(self, config=None): """ From d90044d8f2314561ab81a5f2e4cf1cb638cb6b45 Mon Sep 17 00:00:00 2001 From: Elisa Jasinska Date: Tue, 24 Mar 2015 17:38:04 +0000 Subject: [PATCH 17/17] until arista supports commit and we see how to implement that... bye --- ansible/eos_install_config | 9 +-------- pyEOS/eos.py | 2 +- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/ansible/eos_install_config b/ansible/eos_install_config index 089037c..c62a61f 100644 --- a/ansible/eos_install_config +++ b/ansible/eos_install_config @@ -107,7 +107,6 @@ def main(): use_ssl=dict(required=False, default=True), config_file=dict(required=True), commit_changes=dict(required=True), - replace_config=dict(required=False, default=False), diff_file=dict(required=False, default=None), ), supports_check_mode=True @@ -120,13 +119,10 @@ def main(): config_file = module.params['config_file'] commit_changes = module.params['commit_changes'] - replace_config = module.params['replace_config'] diff_file = module.params['diff_file'] if commit_changes.__class__ is str: commit_changes = ast.literal_eval(commit_changes) - if replace_config.__class__ is str: - replace_config = ast.literal_eval(replace_config) if use_ssl.__class__ is str: use_ssl = ast.literal_eval(use_ssl) @@ -144,10 +140,7 @@ def main(): module.exit_json(changed=False, msg=diff) else: if len(diff) > 0: - if replace_config: - device.replace_config() - else: - device.merge_config() + device.replace_config() module.exit_json(changed=changed, msg=diff) logger.info('DEVICE=%s CHANGED=%s STATUS=%s' % (hostname, len(changed.splitlines())), 'OK') diff --git a/pyEOS/eos.py b/pyEOS/eos.py index 2590279..a22426c 100644 --- a/pyEOS/eos.py +++ b/pyEOS/eos.py @@ -125,7 +125,7 @@ def run_commands(self, commands, version=1, auto_format=False, format='json', ti raise exceptions.ConfigReplaceError(e) else: raise exceptions.UnknownError((code, error)) - + return result def close(self):