From ec3dcefd393de9a4a92993ee2e0aaf0182ecf6ca Mon Sep 17 00:00:00 2001 From: Peter Sprygada Date: Tue, 30 Aug 2016 23:04:41 -0400 Subject: [PATCH] minor bug fixes in openswitch shared module * fix setting cookie after successful login * raise NotImplementedError if run_commands is called in Rest * return header msg key if status is not 2xx * add action plugin ops_config --- lib/ansible/module_utils/openswitch.py | 70 +++++++++++++----------- lib/ansible/plugins/action/ops_config.py | 28 ++++++++++ 2 files changed, 67 insertions(+), 31 deletions(-) create mode 100644 lib/ansible/plugins/action/ops_config.py diff --git a/lib/ansible/module_utils/openswitch.py b/lib/ansible/module_utils/openswitch.py index c296efe2ed2..adc2fec57af 100644 --- a/lib/ansible/module_utils/openswitch.py +++ b/lib/ansible/module_utils/openswitch.py @@ -29,8 +29,9 @@ except ImportError: HAS_OPS = False from ansible.module_utils.basic import json, json_dict_bytes_to_unicode -from ansible.module_utils.network import ModuleStub, NetCli, NetworkError +from ansible.module_utils.network import NetworkModule, ModuleStub, NetworkError from ansible.module_utils.network import add_argument, register_transport, to_list +from ansible.module_utils.shell import CliBase from ansible.module_utils.urls import fetch_url, url_argument_spec # temporary fix until modules are update. to be removed before 2.2 final @@ -79,6 +80,7 @@ class Rest(object): self.url = None self.url_args = ModuleStub(url_argument_spec(), self._error) self.headers = dict({'Content-Type': 'application/json', 'Accept': 'application/json'}) + self.default_output = 'json' self._connected = False def _error(self, msg): @@ -111,7 +113,7 @@ class Rest(object): # Update the base url for the rest of the operations. self.url = '%s/rest/v1' % (baseurl) - self.headers['Cookie'] = resp.headers.get('Set-Cookie') + self.headers['Cookie'] = hdrs['set-cookie'] def disconnect(self, **kwargs): self.url = None @@ -149,23 +151,20 @@ class Rest(object): def delete(self, path, data=None, headers=None): return self.request('DELETE', path, data, headers) + def run_commands(self, commands): + raise NotImplementedError + def configure(self, commands): path = '/system/full-configuration' return self.put(path, data=commands) def load_config(self, commands, **kwargs): - raise NotImplementedError + return self.configure(commands) def get_config(self, **kwargs): resp = self.get('/system/full-configuration') return resp.json - def commit_config(self, **kwargs): - raise NotImplementedError - - def abort_config(self, **kwargs): - raise NotImplementedError - def save_config(self): raise NotImplementedError @@ -183,42 +182,51 @@ class Rest(object): except UnicodeDecodeError: continue self._error(msg='Invalid unicode encoding encountered') -Rest = register_transport('rest')(Rest) +Rest = register_transport('rest')(Rest) -class Cli(NetCli): - CLI_PROMPTS_RE = None - CLI_ERRORS_RE = None +class Cli(CliBase): NET_PASSWD_RE = re.compile(r"[\r\n]?password: $", re.I) + + CLI_PROMPTS_RE = [ + re.compile(r"[\r\n]?[\w+\-\.:\/\[\]]+(?:\([^\)]+\)){,3}(?:>|#) ?$"), + re.compile(r"\[\w+\@[\w\-\.]+(?: [^\]])\] ?[>#\$] ?$") + ] + + CLI_ERRORS_RE = [ + re.compile(r"% ?Error"), + re.compile(r"% ?Bad secret"), + re.compile(r"invalid input", re.I), + re.compile(r"(?:incomplete|ambiguous) command", re.I), + re.compile(r"connection timed out", re.I), + re.compile(r"[^\r\n]+ not found", re.I), + re.compile(r"'[^']' +returned error code: ?\d+"), + ] + + ### implementation of netcli.Cli + + def run_commands(self, commands): + return self.execute(to_list(commands)) + + ### implementation of netcfg.Config + def configure(self, commands, **kwargs): cmds = ['configure terminal'] cmds.extend(to_list(commands)) - + if cmds[-1] != 'end': + cmds.append('end') responses = self.execute(cmds) return responses[1:] - def get_config(self, params, **kwargs): + def get_config(self): return self.execute('show running-config')[0] - def load_config(self, commands, commit=False, **kwargs): - raise NotImplementedError - - def replace_config(self, commands, **kwargs): - raise NotImplementedError - - def commit_config(self, **kwargs): - raise NotImplementedError - - def abort_config(self, **kwargs): - raise NotImplementedError + def load_config(self, commands): + return self.configure(commands) def save_config(self): - raise NotImplementedError + self.execute(['copy running-config startup-config']) - def run_commands(self, commands): - cmds = to_list(commands) - responses = self.execute(cmds) - return responses Cli = register_transport('cli', default=True)(Cli) diff --git a/lib/ansible/plugins/action/ops_config.py b/lib/ansible/plugins/action/ops_config.py new file mode 100644 index 00000000000..ffcb0f057f8 --- /dev/null +++ b/lib/ansible/plugins/action/ops_config.py @@ -0,0 +1,28 @@ +# +# Copyright 2015 Peter Sprygada +# +# This file is part of Ansible +# +# Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see . +# +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +from ansible.plugins.action import ActionBase +from ansible.plugins.action.net_config import ActionModule as NetActionModule + +class ActionModule(NetActionModule, ActionBase): + pass + +