1#!/usr/bin/python 2# -*- coding: utf-8 -*- 3 4# Copyright: (c) 2015, Peter Sprygada <psprygada@ansible.com> 5# Copyright: (c) 2017, Dell Inc. 6# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) 7 8from __future__ import absolute_import, division, print_function 9__metaclass__ = type 10 11 12ANSIBLE_METADATA = {'metadata_version': '1.1', 13 'status': ['preview'], 14 'supported_by': 'community'} 15 16 17DOCUMENTATION = """ 18--- 19module: dellos10_command 20version_added: "2.2" 21author: "Senthil Kumar Ganesan (@skg-net)" 22short_description: Run commands on remote devices running Dell OS10 23description: 24 - Sends arbitrary commands to a Dell EMC OS10 node and returns the results 25 read from the device. This module includes an 26 argument that will cause the module to wait for a specific condition 27 before returning or timing out if the condition is not met. 28 - This module does not support running commands in configuration mode. 29 Please use M(dellos10_config) to configure Dell EMC OS10 devices. 30extends_documentation_fragment: dellos10 31options: 32 commands: 33 description: 34 - List of commands to send to the remote dellos10 device over the 35 configured provider. The resulting output from the command 36 is returned. If the I(wait_for) argument is provided, the 37 module is not returned until the condition is satisfied or 38 the number of retries has expired. 39 type: list 40 required: true 41 wait_for: 42 description: 43 - List of conditions to evaluate against the output of the 44 command. The task will wait for each condition to be true 45 before moving forward. If the conditional is not true 46 within the configured number of I(retries), the task fails. 47 See examples. 48 type: list 49 version_added: "2.2" 50 match: 51 description: 52 - The I(match) argument is used in conjunction with the 53 I(wait_for) argument to specify the match policy. Valid 54 values are C(all) or C(any). If the value is set to C(all) 55 then all conditionals in the wait_for must be satisfied. If 56 the value is set to C(any) then only one of the values must be 57 satisfied. 58 type: str 59 default: all 60 choices: [ all, any ] 61 version_added: "2.5" 62 retries: 63 description: 64 - Specifies the number of retries a command should be tried 65 before it is considered failed. The command is run on the 66 target device every retry and evaluated against the 67 I(wait_for) conditions. 68 type: int 69 default: 10 70 interval: 71 description: 72 - Configures the interval in seconds to wait between retries 73 of the command. If the command does not pass the specified 74 conditions, the interval indicates how long to wait before 75 trying the command again. 76 type: int 77 default: 1 78""" 79 80EXAMPLES = """ 81tasks: 82 - name: run show version on remote devices 83 dellos10_command: 84 commands: show version 85 86 - name: run show version and check to see if output contains OS10 87 dellos10_command: 88 commands: show version 89 wait_for: result[0] contains OS10 90 91 - name: run multiple commands on remote nodes 92 dellos10_command: 93 commands: 94 - show version 95 - show interface 96 97 - name: run multiple commands and evaluate the output 98 dellos10_command: 99 commands: 100 - show version 101 - show interface 102 wait_for: 103 - result[0] contains OS10 104 - result[1] contains Ethernet 105""" 106 107RETURN = """ 108stdout: 109 description: The set of responses from the commands 110 returned: always apart from low level errors (such as action plugin) 111 type: list 112 sample: ['...', '...'] 113stdout_lines: 114 description: The value of stdout split into a list 115 returned: always apart from low level errors (such as action plugin) 116 type: list 117 sample: [['...', '...'], ['...'], ['...']] 118failed_conditions: 119 description: The list of conditionals that have failed 120 returned: failed 121 type: list 122 sample: ['...', '...'] 123warnings: 124 description: The list of warnings (if any) generated by module based on arguments 125 returned: always 126 type: list 127 sample: ['...', '...'] 128""" 129import time 130 131from ansible.module_utils.basic import AnsibleModule 132from ansible.module_utils.network.dellos10.dellos10 import run_commands 133from ansible.module_utils.network.dellos10.dellos10 import dellos10_argument_spec, check_args 134from ansible.module_utils.network.common.utils import ComplexList 135from ansible.module_utils.network.common.parsing import Conditional 136from ansible.module_utils.six import string_types 137 138 139def to_lines(stdout): 140 for item in stdout: 141 if isinstance(item, string_types): 142 item = str(item).split('\n') 143 yield item 144 145 146def parse_commands(module, warnings): 147 command = ComplexList(dict( 148 command=dict(key=True), 149 prompt=dict(), 150 answer=dict() 151 ), module) 152 commands = command(module.params['commands']) 153 for index, item in enumerate(commands): 154 if module.check_mode and not item['command'].startswith('show'): 155 warnings.append( 156 'only show commands are supported when using check mode, not ' 157 'executing `%s`' % item['command'] 158 ) 159 elif item['command'].startswith('conf'): 160 module.fail_json( 161 msg='dellos10_command does not support running config mode ' 162 'commands. Please use dellos10_config instead' 163 ) 164 return commands 165 166 167def main(): 168 """main entry point for module execution 169 """ 170 argument_spec = dict( 171 # { command: <str>, prompt: <str>, response: <str> } 172 commands=dict(type='list', required=True), 173 174 wait_for=dict(type='list'), 175 match=dict(default='all', choices=['all', 'any']), 176 177 retries=dict(default=10, type='int'), 178 interval=dict(default=1, type='int') 179 ) 180 181 argument_spec.update(dellos10_argument_spec) 182 183 module = AnsibleModule(argument_spec=argument_spec, 184 supports_check_mode=True) 185 186 result = {'changed': False} 187 188 warnings = list() 189 check_args(module, warnings) 190 commands = parse_commands(module, warnings) 191 result['warnings'] = warnings 192 193 wait_for = module.params['wait_for'] or list() 194 conditionals = [Conditional(c) for c in wait_for] 195 196 retries = module.params['retries'] 197 interval = module.params['interval'] 198 match = module.params['match'] 199 200 while retries > 0: 201 responses = run_commands(module, commands) 202 203 for item in list(conditionals): 204 if item(responses): 205 if match == 'any': 206 conditionals = list() 207 break 208 conditionals.remove(item) 209 210 if not conditionals: 211 break 212 213 time.sleep(interval) 214 retries -= 1 215 216 if conditionals: 217 failed_conditions = [item.raw for item in conditionals] 218 msg = 'One or more conditional statements have not been satisfied' 219 module.fail_json(msg=msg, failed_conditions=failed_conditions) 220 221 result.update({ 222 'changed': False, 223 'stdout': responses, 224 'stdout_lines': list(to_lines(responses)) 225 }) 226 227 module.exit_json(**result) 228 229 230if __name__ == '__main__': 231 main() 232