summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorXu Yuandong <yuandongdeyouxiang@gmail.com>2019-11-13 03:57:48 +0800
committerMatt Davis <nitzmahone@users.noreply.github.com>2019-11-12 11:57:48 -0800
commit2dbe024fcbafdf22e200cb44060a14e36c7534f7 (patch)
tree8cf33975a8eda9170da0659d5f03aafb62d45027
parent20a8bf592e16556ac6c97144e3b3df6a1cde79cc (diff)
downloadansible-2dbe024fcbafdf22e200cb44060a14e36c7534f7.tar.gz
ce_config/bug/jingdong: a bug from jingdong. (#62872) (#63978)
* update to fix "`quit` may make seesion closed." * update to fix "`quit` may make seesion closed." * 274:49: E272: multiple spaces before keyword * add a changelog fragment. * Update ce_config.py using run_command for prompts. * Update ce_config.py * Update ce_config.py typo error * update to use get_prompt * Update ce_config.py * Update ce_config.py * Update ce_config.py * Update ce_config.py * Update ce_config.py * Update ce_config.py * Update ce_config.py (cherry picked from commit e4b6dd186231c95aba732794d5f82e68fbaf5425)
-rw-r--r--changelogs/fragments/62872-ce_config_too_many_quit_close_connection.yml2
-rw-r--r--lib/ansible/modules/network/cloudengine/ce_config.py120
2 files changed, 77 insertions, 45 deletions
diff --git a/changelogs/fragments/62872-ce_config_too_many_quit_close_connection.yml b/changelogs/fragments/62872-ce_config_too_many_quit_close_connection.yml
new file mode 100644
index 0000000000..cb5dd6a00e
--- /dev/null
+++ b/changelogs/fragments/62872-ce_config_too_many_quit_close_connection.yml
@@ -0,0 +1,2 @@
+bugfixes:
+ - ce_config - fixed issue - Re-building commands(config src) by replacing '#' with 'quit','quit' commands may close connection (https://github.com/ansible/ansible/issues/62872)
diff --git a/lib/ansible/modules/network/cloudengine/ce_config.py b/lib/ansible/modules/network/cloudengine/ce_config.py
index 9a07642e0a..d55f54f573 100644
--- a/lib/ansible/modules/network/cloudengine/ce_config.py
+++ b/lib/ansible/modules/network/cloudengine/ce_config.py
@@ -220,6 +220,7 @@ backup_path:
sample: /playbooks/ansible/backup/ce_config.2016-07-16@22:28:34
"""
from ansible.module_utils.basic import AnsibleModule
+from ansible.module_utils.connection import ConnectionError, Connection
from ansible.module_utils.network.common.config import NetworkConfig as _NetworkConfig
from ansible.module_utils.network.common.config import dumps, ConfigLine, ignore_line
from ansible.module_utils.network.cloudengine.ce import get_config, run_commands, exec_command, cli_err_msg
@@ -232,71 +233,70 @@ def check_args(module, warnings):
ce_check_args(module, warnings)
+def not_user_view(prompt):
+ return prompt is not None and prompt.strip().startswith("[")
+
+
+def command_level(command):
+ regex_level = re.search(r"^(\s*)\S+", command)
+ if regex_level is not None:
+ level = str(regex_level.group(1))
+ return len(level)
+ return 0
+
+
def _load_config(module, config):
"""Sends configuration commands to the remote device
"""
+ connection = Connection(module._socket_path)
rc, out, err = exec_command(module, 'mmi-mode enable')
if rc != 0:
module.fail_json(msg='unable to set mmi-mode enable', output=err)
rc, out, err = exec_command(module, 'system-view immediately')
if rc != 0:
module.fail_json(msg='unable to enter system-view', output=err)
+ current_view_prompt = system_view_prompt = connection.get_prompt()
for index, cmd in enumerate(config):
+ level = command_level(cmd)
+ current_view_prompt = connection.get_prompt()
rc, out, err = exec_command(module, cmd)
if rc != 0:
print_msg = cli_err_msg(cmd.strip(), err)
- exec_command(module, "quit")
- rc, out, err = exec_command(module, cmd)
- if rc != 0:
- print_msg1 = cli_err_msg(cmd.strip(), err)
- if not re.findall(r"unrecognized command found", print_msg1):
- print_msg = print_msg1
- exec_command(module, "return")
- exec_command(module, "system-view immediately")
+ # re-try command max 3 times
+ for i in (1, 2, 3):
+ current_view_prompt = connection.get_prompt()
+ if current_view_prompt != system_view_prompt and not_user_view(current_view_prompt):
+ exec_command(module, "quit")
+ current_view_prompt = connection.get_prompt()
+ # if current view is system-view, break.
+ if current_view_prompt == system_view_prompt and level > 0:
+ break
+ elif current_view_prompt == system_view_prompt or not not_user_view(current_view_prompt):
+ break
rc, out, err = exec_command(module, cmd)
- if rc != 0:
- print_msg2 = cli_err_msg(cmd.strip(), err)
- if not re.findall(r"unrecognized command found", print_msg2):
- print_msg = print_msg2
- module.fail_json(msg=print_msg)
-
- rc, out, err = exec_command(module, 'return')
- if rc != 0:
- module.fail_json(msg='unable to return', output=err)
- rc, out, err = exec_command(module, 'undo mmi-mode enable')
- if rc != 0:
- module.fail_json(msg='unable to undo mmi-mode enable', output=err)
-
-
-def conversion_src(module):
- src_list = module.params['src'].split('\n')
- src_list_organize = []
- if src_list[0].strip() == '#':
- src_list.pop(0)
- for per_config in src_list:
- if per_config.strip() == '#':
- src_list_organize.append('quit')
- else:
- src_list_organize.append(per_config)
- src_str = '\n'.join(src_list_organize)
- return src_str
+ if rc == 0:
+ print_msg = None
+ break
+ if print_msg is not None:
+ module.fail_json(msg=print_msg)
def get_running_config(module):
contents = module.params['config']
if not contents:
- flags = []
+ command = "display current-configuration "
if module.params['defaults']:
- flags.append('include-default')
- contents = get_config(module, flags=flags)
+ command += 'include-default'
+ resp = run_commands(module, command)
+ contents = resp[0]
return NetworkConfig(indent=1, contents=contents)
def get_candidate(module):
candidate = NetworkConfig(indent=1)
if module.params['src']:
- config = conversion_src(module)
+ config = module.params['src']
candidate.load(config)
elif module.params['lines']:
parents = module.params['parents'] or list()
@@ -311,14 +311,17 @@ def run(module, result):
candidate = get_candidate(module)
if match != 'none':
- config = get_running_config(module)
+ before = get_running_config(module)
path = module.params['parents']
- configobjs = candidate.difference(config, match=match, replace=replace, path=path)
+ configobjs = candidate.difference(before, match=match, replace=replace, path=path)
else:
configobjs = candidate.items
if configobjs:
- commands = dumps(configobjs, 'commands').split('\n')
+ out_type = "commands"
+ if module.params["src"] is not None:
+ out_type = "raw"
+ commands = dumps(configobjs, out_type).split('\n')
if module.params['lines']:
if module.params['before']:
@@ -340,8 +343,34 @@ def run(module, result):
load_config(module, commands)
else:
_load_config(module, commands)
-
- result['changed'] = True
+ if match != "none":
+ after = get_running_config(module)
+ path = module.params["parents"]
+ if path is not None and match != 'line':
+ before_objs = before.get_block(path)
+ after_objs = after.get_block(path)
+ update = []
+ if len(before_objs) == len(after_objs):
+ for b_item, a_item in zip(before_objs, after_objs):
+ if b_item != a_item:
+ update.append(a_item.text)
+ else:
+ update = [item.text for item in after_objs]
+ if len(update) == 0:
+ result["changed"] = False
+ result['updates'] = []
+ else:
+ result["changed"] = True
+ result['updates'] = update
+ else:
+ configobjs = after.difference(before, match=match, replace=replace, path=path)
+ if len(configobjs) > 0:
+ result["changed"] = True
+ else:
+ result["changed"] = False
+ result['updates'] = []
+ else:
+ result['changed'] = True
class NetworkConfig(_NetworkConfig):
@@ -452,8 +481,9 @@ def main():
if module.params['save']:
if not module.check_mode:
- run_commands(module, ['save'])
- result['changed'] = True
+ run_commands(module, ['return', 'mmi-mode enable', 'save'])
+ result["changed"] = True
+ run_commands(module, ['return', 'undo mmi-mode enable'])
module.exit_json(**result)