From 9c1f06268e8473946d60f42c770b825762b72876 Mon Sep 17 00:00:00 2001 From: Anil Kumar Muraleedharan Date: Fri, 17 Aug 2018 21:31:42 +0530 Subject: [PATCH] Making cnos_conditional_template to use persistent connection instead of paramiko (#43868) * Making cnos_template to use persistent connection instead of paramiko --- .../network/cnos/cnos_conditional_template.py | 137 +++++++----------- 1 file changed, 56 insertions(+), 81 deletions(-) diff --git a/lib/ansible/modules/network/cnos/cnos_conditional_template.py b/lib/ansible/modules/network/cnos/cnos_conditional_template.py index 781ce8810a8..8a70a7a80d3 100644 --- a/lib/ansible/modules/network/cnos/cnos_conditional_template.py +++ b/lib/ansible/modules/network/cnos/cnos_conditional_template.py @@ -33,51 +33,63 @@ DOCUMENTATION = ''' --- module: cnos_conditional_template author: "Anil Kumar Muraleedharan (@amuraleedhar)" -short_description: Manage switch configuration using templates based on condition on devices running Lenovo CNOS +short_description: Manage switch configuration using templates based on + condition on devices running Lenovo CNOS description: - - This module allows you to work with the running configuration of a switch. It provides a way to - execute a set of CNOS commands on a switch by evaluating the current running configuration and - executing the commands only if the specific settings have not been already configured. - The configuration source can be a set of commands or a template written in the Jinja2 templating language. - This module functions the same as the cnos_template module. - The only exception is that the following inventory variable can be specified + - This module allows you to work with the running configuration of a + switch. It provides a way to execute a set of CNOS commands on a switch by + evaluating the current running configuration and executing the commands + only if the specific settings have not been already configured. + The configuration source can be a set of commands or a template written in + the Jinja2 templating language. This module functions the same as the + cnos_template module. The only exception is that the following inventory + variable can be specified. ["condition = "] - When this inventory variable is specified as the variable of a task, the template is executed for - the network element that matches the flag string. Usually, templates are used when commands are the - same across a group of network devices. When there is a requirement to skip the execution of the + When this inventory variable is specified as the variable of a task, the + template is executed for the network element that matches the flag string. + Usually, templates are used when commands are the same across a group of + network devices. When there is a requirement to skip the execution of the template on one or more devices, it is recommended to use this module. - This module uses SSH to manage network device configuration. - For more information about this module from Lenovo and customizing it usage for your - use cases, please visit U(http://systemx.lenovofiles.com/help/index.jsp?topic=%2Fcom.lenovo.switchmgt.ansible.doc%2Fcnos_conditional_template.html) + This module uses SSH to manage network device configuration. For more + information about this module and customizing it usage for your use cases, + please visit U(http://systemx.lenovofiles.com/help/index.jsp?topic= + %2Fcom.lenovo.switchmgt.ansible.doc%2Fcnos_conditional_template.html) version_added: "2.3" extends_documentation_fragment: cnos options: commandfile: description: - - This specifies the path to the CNOS command file which needs to be applied. This usually - comes from the commands folder. Generally this file is the output of the variables applied - on a template file. So this command is preceded by a template module. - The command file must contain the Ansible keyword {{ inventory_hostname }} and the condition - flag in its filename to ensure that the command file is unique for each switch and condition. - If this is omitted, the command file will be overwritten during iteration. For example, - commandfile=./commands/clos_leaf_bgp_{{ inventory_hostname }}_LP21_commands.txt + - This specifies the path to the CNOS command file which needs to + be applied. This usually comes from the commands folder. Generally + this file is the output of the variables applied on a template + file. So this command is preceded by a template module. The + command file must contain the Ansible keyword + {{ inventory_hostname }} and the condition flag in its filename to + ensure that the command file is unique for each switch and + condition. If this is omitted, the command file will be + overwritten during iteration. For example, + commandfile=./commands/clos_leaf_bgp_ + {{ inventory_hostname }}_LP21_commands.txt required: true default: Null condition: description: - - If you specify condition= in the inventory file against any device, the template - execution is done for that device in case it matches the flag setting for that task. + - If you specify condition= in the inventory file + against any device, the template execution is done for that device + in case it matches the flag setting for that task. required: true default: Null flag: description: - - If a task needs to be executed, you have to set the flag the same as it is specified in - the inventory for that device. + - If a task needs to be executed, you have to set the flag the same + as it is specified in the inventory for that device. required: true default: Null ''' EXAMPLES = ''' -Tasks : The following are examples of using the module cnos_conditional_template. These are written in the main.yml file of the tasks directory. +Tasks : The following are examples of using the module + cnos_conditional_template. These are written in the main.yml file of the + tasks directory. --- - name: Applying CLI template on VLAG Tier1 Leaf Switch1 cnos_conditional_template: @@ -85,10 +97,12 @@ Tasks : The following are examples of using the module cnos_conditional_template username: "{{ hostvars[inventory_hostname]['ansible_ssh_user'] }}" password: "{{ hostvars[inventory_hostname]['ansible_ssh_pass'] }}" deviceType: "{{ hostvars[inventory_hostname]['deviceType'] }}" - outputfile: "./results/vlag_1tier_leaf_switch1_{{ inventory_hostname }}_output.txt" + outputfile: "./results/vlag_1tier_leaf_switch1_ + {{ inventory_hostname }}_output.txt" condition: "{{ hostvars[inventory_hostname]['condition']}}" flag: "leaf_switch1" - commandfile: "./commands/vlag_1tier_leaf_switch1_{{ inventory_hostname }}_commands.txt" + commandfile: "./commands/vlag_1tier_leaf_switch1_ + {{ inventory_hostname }}_commands.txt" enablePassword: "anil" stp_mode1: "disable" port_range1: "17,18,29,30" @@ -106,17 +120,13 @@ msg: ''' import sys -try: - import paramiko - HAS_PARAMIKO = True -except ImportError: - HAS_PARAMIKO = False import time import socket import array import json import time import re +import os try: from ansible.module_utils.network.cnos import cnos HAS_LIB = True @@ -140,69 +150,34 @@ def main(): enablePassword=dict(required=False, no_log=True),), supports_check_mode=False) - username = module.params['username'] - password = module.params['password'] - enablePassword = module.params['enablePassword'] condition = module.params['condition'] flag = module.params['flag'] commandfile = module.params['commandfile'] - deviceType = module.params['deviceType'] outputfile = module.params['outputfile'] - hostIP = module.params['host'] - - output = "" - if not HAS_PARAMIKO: - module.fail_json(msg='paramiko is required for this module') - # Here comes the logic against which a template is - # conditionally executed for right Network element. - if (condition != flag): - module.exit_json(changed=True, msg="Template Skipped for this value") + output = '' + if (condition is None or condition != flag): + module.exit_json(changed=True, msg="Template Skipped for this switch") return " " - - # Create instance of SSHClient object - remote_conn_pre = paramiko.SSHClient() - - # Automatically add untrusted hosts (make sure okay for security policy in your environment) - remote_conn_pre.set_missing_host_key_policy(paramiko.AutoAddPolicy()) - - # initiate SSH connection with the switch - remote_conn_pre.connect(hostIP, username=username, password=password) - time.sleep(2) - - # Use invoke_shell to establish an 'interactive session' - remote_conn = remote_conn_pre.invoke_shell() - time.sleep(2) - # Enable and enter configure terminal then send command - output = output + cnos.waitForDeviceResponse("\n", ">", 2, remote_conn) - - output = output + cnos.enterEnableModeForDevice(enablePassword, 3, remote_conn) - - # Make terminal length = 0 - output = output + cnos.waitForDeviceResponse("terminal length 0\n", "#", 2, remote_conn) - - # Go to config mode - output = output + cnos.waitForDeviceResponse("configure device\n", "(config)#", 2, remote_conn) # Send commands one by one - # with open(commandfile, "r") as f: f = open(commandfile, "r") + cmd = [] for line in f: # Omit the comment lines in template file if not line.startswith("#"): # cnos.debugOutput(line) - command = line - if not line.endswith("\n"): - command = command + "\n" - response = cnos.waitForDeviceResponse(command, "#", 2, remote_conn) - errorMsg = cnos.checkOutputForError(response) - output = output + response - if(errorMsg is not None): - break - # To cater to Mufti case + command = line.strip() + inner_cmd = [{'command': command, 'prompt': None, 'answer': None}] + cmd.extend(inner_cmd) # Write to memory - output = output + cnos.waitForDeviceResponse("save\n", "#", 3, remote_conn) - + save_cmd = [{'command': 'save', 'prompt': None, 'answer': None}] + cmd.extend(save_cmd) + output = output + str(cnos.run_cnos_commands(module, cmd)) # Write output to file + path = outputfile.rsplit('/', 1) + # cnos.debugOutput(path[0]) + if not os.path.exists(path[0]): + os.makedirs(path[0]) file = open(outputfile, "a") file.write(output) file.close()