Bug fixes- Dellos modules (#63272)
This commit is contained in:
parent
4745d45711
commit
2e65c1ebb7
10 changed files with 295 additions and 165 deletions
|
@ -29,12 +29,12 @@
|
||||||
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
||||||
# USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
# USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
#
|
#
|
||||||
import re
|
import json
|
||||||
|
|
||||||
from ansible.module_utils._text import to_text
|
from ansible.module_utils._text import to_text
|
||||||
from ansible.module_utils.basic import env_fallback
|
from ansible.module_utils.basic import env_fallback
|
||||||
from ansible.module_utils.network.common.utils import to_list, ComplexList
|
from ansible.module_utils.network.common.utils import to_list, ComplexList
|
||||||
from ansible.module_utils.connection import exec_command
|
from ansible.module_utils.connection import Connection, ConnectionError, exec_command
|
||||||
from ansible.module_utils.network.common.config import NetworkConfig, ConfigLine
|
from ansible.module_utils.network.common.config import NetworkConfig, ConfigLine
|
||||||
|
|
||||||
_DEVICE_CONFIGS = {}
|
_DEVICE_CONFIGS = {}
|
||||||
|
@ -71,6 +71,35 @@ dellos10_top_spec = {
|
||||||
dellos10_argument_spec.update(dellos10_top_spec)
|
dellos10_argument_spec.update(dellos10_top_spec)
|
||||||
|
|
||||||
|
|
||||||
|
def get_provider_argspec():
|
||||||
|
return dellos10_provider_spec
|
||||||
|
|
||||||
|
|
||||||
|
def get_connection(module):
|
||||||
|
if hasattr(module, '_dellos10_connection'):
|
||||||
|
return module._dellos10_connection
|
||||||
|
|
||||||
|
capabilities = get_capabilities(module)
|
||||||
|
network_api = capabilities.get('network_api')
|
||||||
|
if network_api == 'cliconf':
|
||||||
|
module._dellos10_connection = Connection(module._socket_path)
|
||||||
|
else:
|
||||||
|
module.fail_json(msg='Invalid connection type %s' % network_api)
|
||||||
|
|
||||||
|
return module._dellos10_connection
|
||||||
|
|
||||||
|
|
||||||
|
def get_capabilities(module):
|
||||||
|
if hasattr(module, '_dellos10_capabilities'):
|
||||||
|
return module._dellos10_capabilities
|
||||||
|
try:
|
||||||
|
capabilities = Connection(module._socket_path).get_capabilities()
|
||||||
|
except ConnectionError as exc:
|
||||||
|
module.fail_json(msg=to_text(exc, errors='surrogate_then_replace'))
|
||||||
|
module._dellos10_capabilities = json.loads(capabilities)
|
||||||
|
return module._dellos10_capabilities
|
||||||
|
|
||||||
|
|
||||||
def check_args(module, warnings):
|
def check_args(module, warnings):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@ -78,7 +107,7 @@ def check_args(module, warnings):
|
||||||
def get_config(module, flags=None):
|
def get_config(module, flags=None):
|
||||||
flags = [] if flags is None else flags
|
flags = [] if flags is None else flags
|
||||||
|
|
||||||
cmd = 'show running-config '
|
cmd = 'show running-configuration '
|
||||||
cmd += ' '.join(flags)
|
cmd += ' '.join(flags)
|
||||||
cmd = cmd.strip()
|
cmd = cmd.strip()
|
||||||
|
|
||||||
|
@ -93,26 +122,12 @@ def get_config(module, flags=None):
|
||||||
return cfg
|
return cfg
|
||||||
|
|
||||||
|
|
||||||
def to_commands(module, commands):
|
|
||||||
spec = {
|
|
||||||
'command': dict(key=True),
|
|
||||||
'prompt': dict(),
|
|
||||||
'answer': dict()
|
|
||||||
}
|
|
||||||
transform = ComplexList(spec, module)
|
|
||||||
return transform(commands)
|
|
||||||
|
|
||||||
|
|
||||||
def run_commands(module, commands, check_rc=True):
|
def run_commands(module, commands, check_rc=True):
|
||||||
responses = list()
|
connection = get_connection(module)
|
||||||
commands = to_commands(module, to_list(commands))
|
try:
|
||||||
for cmd in commands:
|
return connection.run_commands(commands=commands, check_rc=check_rc)
|
||||||
cmd = module.jsonify(cmd)
|
except ConnectionError as exc:
|
||||||
rc, out, err = exec_command(module, cmd)
|
module.fail_json(msg=to_text(exc))
|
||||||
if check_rc and rc != 0:
|
|
||||||
module.fail_json(msg=to_text(err, errors='surrogate_or_strict'), rc=rc)
|
|
||||||
responses.append(to_text(out, errors='surrogate_or_strict'))
|
|
||||||
return responses
|
|
||||||
|
|
||||||
|
|
||||||
def load_config(module, commands):
|
def load_config(module, commands):
|
||||||
|
|
|
@ -30,11 +30,12 @@
|
||||||
# USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
# USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
#
|
#
|
||||||
import re
|
import re
|
||||||
|
import json
|
||||||
|
|
||||||
from ansible.module_utils._text import to_text
|
from ansible.module_utils._text import to_text
|
||||||
from ansible.module_utils.basic import env_fallback
|
from ansible.module_utils.basic import env_fallback
|
||||||
from ansible.module_utils.network.common.utils import to_list, ComplexList
|
from ansible.module_utils.network.common.utils import to_list, ComplexList
|
||||||
from ansible.module_utils.connection import exec_command
|
from ansible.module_utils.connection import Connection, ConnectionError, exec_command
|
||||||
from ansible.module_utils.network.common.config import NetworkConfig, ConfigLine, ignore_line
|
from ansible.module_utils.network.common.config import NetworkConfig, ConfigLine, ignore_line
|
||||||
|
|
||||||
_DEVICE_CONFIGS = {}
|
_DEVICE_CONFIGS = {}
|
||||||
|
@ -71,6 +72,35 @@ dellos6_top_spec = {
|
||||||
dellos6_argument_spec.update(dellos6_top_spec)
|
dellos6_argument_spec.update(dellos6_top_spec)
|
||||||
|
|
||||||
|
|
||||||
|
def get_provider_argspec():
|
||||||
|
return dellos6_provider_spec
|
||||||
|
|
||||||
|
|
||||||
|
def get_connection(module):
|
||||||
|
if hasattr(module, '_dellos6_connection'):
|
||||||
|
return module._dellos6_connection
|
||||||
|
|
||||||
|
capabilities = get_capabilities(module)
|
||||||
|
network_api = capabilities.get('network_api')
|
||||||
|
if network_api == 'cliconf':
|
||||||
|
module._dellos6_connection = Connection(module._socket_path)
|
||||||
|
else:
|
||||||
|
module.fail_json(msg='Invalid connection type %s' % network_api)
|
||||||
|
|
||||||
|
return module._dellos6_connection
|
||||||
|
|
||||||
|
|
||||||
|
def get_capabilities(module):
|
||||||
|
if hasattr(module, '_dellos6_capabilities'):
|
||||||
|
return module._dellos6_capabilities
|
||||||
|
try:
|
||||||
|
capabilities = Connection(module._socket_path).get_capabilities()
|
||||||
|
except ConnectionError as exc:
|
||||||
|
module.fail_json(msg=to_text(exc, errors='surrogate_then_replace'))
|
||||||
|
module._dellos6_capabilities = json.loads(capabilities)
|
||||||
|
return module._dellos6_capabilities
|
||||||
|
|
||||||
|
|
||||||
def check_args(module, warnings):
|
def check_args(module, warnings):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@ -93,26 +123,12 @@ def get_config(module, flags=None):
|
||||||
return cfg
|
return cfg
|
||||||
|
|
||||||
|
|
||||||
def to_commands(module, commands):
|
|
||||||
spec = {
|
|
||||||
'command': dict(key=True),
|
|
||||||
'prompt': dict(),
|
|
||||||
'answer': dict()
|
|
||||||
}
|
|
||||||
transform = ComplexList(spec, module)
|
|
||||||
return transform(commands)
|
|
||||||
|
|
||||||
|
|
||||||
def run_commands(module, commands, check_rc=True):
|
def run_commands(module, commands, check_rc=True):
|
||||||
responses = list()
|
connection = get_connection(module)
|
||||||
commands = to_commands(module, to_list(commands))
|
try:
|
||||||
for cmd in commands:
|
return connection.run_commands(commands=commands, check_rc=check_rc)
|
||||||
cmd = module.jsonify(cmd)
|
except ConnectionError as exc:
|
||||||
rc, out, err = exec_command(module, cmd)
|
module.fail_json(msg=to_text(exc))
|
||||||
if check_rc and rc != 0:
|
|
||||||
module.fail_json(msg=to_text(err, errors='surrogate_or_strict'), rc=rc)
|
|
||||||
responses.append(to_text(out, errors='surrogate_or_strict'))
|
|
||||||
return responses
|
|
||||||
|
|
||||||
|
|
||||||
def load_config(module, commands):
|
def load_config(module, commands):
|
||||||
|
@ -152,16 +168,16 @@ def os6_parse(lines, indent=None, comment_tokens=None):
|
||||||
re.compile(r'datacenter-bridging.*$'),
|
re.compile(r'datacenter-bridging.*$'),
|
||||||
re.compile(r'line (console|telnet|ssh).*$'),
|
re.compile(r'line (console|telnet|ssh).*$'),
|
||||||
re.compile(r'ip ssh !(server).*$'),
|
re.compile(r'ip ssh !(server).*$'),
|
||||||
|
re.compile(r'(ip|mac|management|arp) access-list.*$'),
|
||||||
re.compile(r'ip dhcp pool.*$'),
|
re.compile(r'ip dhcp pool.*$'),
|
||||||
re.compile(r'ip vrf !(forwarding).*$'),
|
re.compile(r'ip vrf !(forwarding).*$'),
|
||||||
re.compile(r'(ip|mac|management|arp) access-list.*$'),
|
|
||||||
re.compile(r'ipv6 (dhcp pool|router).*$'),
|
re.compile(r'ipv6 (dhcp pool|router).*$'),
|
||||||
re.compile(r'mail-server.*$'),
|
re.compile(r'mail-server.*$'),
|
||||||
re.compile(r'vpc domain.*$'),
|
re.compile(r'vpc domain.*$'),
|
||||||
re.compile(r'router.*$'),
|
re.compile(r'router.*$'),
|
||||||
re.compile(r'route-map.*$'),
|
re.compile(r'route-map.*$'),
|
||||||
re.compile(r'policy-map.*$'),
|
re.compile(r'policy-map.*$'),
|
||||||
re.compile(r'class-map match-all.*$'),
|
re.compile(r'((class-map match-(all|any))|(class\s)).*$'),
|
||||||
re.compile(r'captive-portal.*$'),
|
re.compile(r'captive-portal.*$'),
|
||||||
re.compile(r'admin-profile.*$'),
|
re.compile(r'admin-profile.*$'),
|
||||||
re.compile(r'link-dependency group.*$'),
|
re.compile(r'link-dependency group.*$'),
|
||||||
|
@ -172,7 +188,9 @@ def os6_parse(lines, indent=None, comment_tokens=None):
|
||||||
re.compile(r'address-family.*$'),
|
re.compile(r'address-family.*$'),
|
||||||
re.compile(r'spanning-tree mst configuration.*$'),
|
re.compile(r'spanning-tree mst configuration.*$'),
|
||||||
re.compile(r'logging (?!.*(cli-command|buffered|console|email|facility|file|monitor|protocol|snmp|source-interface|traps|web-session)).*$'),
|
re.compile(r'logging (?!.*(cli-command|buffered|console|email|facility|file|monitor|protocol|snmp|source-interface|traps|web-session)).*$'),
|
||||||
re.compile(r'(radius-server|tacacs-server) host.*$')]
|
re.compile(r'(radius-server|tacacs-server) host.*$'),
|
||||||
|
re.compile(r'radius server (auth|acct).*$'),
|
||||||
|
re.compile(r'aaa server radius dynamic-author.*$')]
|
||||||
|
|
||||||
childline = re.compile(r'^exit$')
|
childline = re.compile(r'^exit$')
|
||||||
config = list()
|
config = list()
|
||||||
|
@ -184,8 +202,6 @@ def os6_parse(lines, indent=None, comment_tokens=None):
|
||||||
cfg = ConfigLine(text)
|
cfg = ConfigLine(text)
|
||||||
cfg.raw = line
|
cfg.raw = line
|
||||||
if not text or ignore_line(text, comment_tokens):
|
if not text or ignore_line(text, comment_tokens):
|
||||||
parent = list()
|
|
||||||
children = []
|
|
||||||
continue
|
continue
|
||||||
|
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -29,12 +29,12 @@
|
||||||
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
||||||
# USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
# USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
#
|
#
|
||||||
import re
|
import json
|
||||||
|
|
||||||
from ansible.module_utils._text import to_text
|
from ansible.module_utils._text import to_text
|
||||||
from ansible.module_utils.basic import env_fallback
|
from ansible.module_utils.basic import env_fallback
|
||||||
from ansible.module_utils.network.common.utils import to_list, ComplexList
|
from ansible.module_utils.network.common.utils import to_list, ComplexList
|
||||||
from ansible.module_utils.connection import exec_command
|
from ansible.module_utils.connection import Connection, ConnectionError, exec_command
|
||||||
from ansible.module_utils.network.common.config import NetworkConfig, ConfigLine
|
from ansible.module_utils.network.common.config import NetworkConfig, ConfigLine
|
||||||
|
|
||||||
_DEVICE_CONFIGS = {}
|
_DEVICE_CONFIGS = {}
|
||||||
|
@ -71,6 +71,35 @@ dellos9_top_spec = {
|
||||||
dellos9_argument_spec.update(dellos9_top_spec)
|
dellos9_argument_spec.update(dellos9_top_spec)
|
||||||
|
|
||||||
|
|
||||||
|
def get_provider_argspec():
|
||||||
|
return dellos9_provider_spec
|
||||||
|
|
||||||
|
|
||||||
|
def get_connection(module):
|
||||||
|
if hasattr(module, '_dellos9_connection'):
|
||||||
|
return module._dellos9_connection
|
||||||
|
|
||||||
|
capabilities = get_capabilities(module)
|
||||||
|
network_api = capabilities.get('network_api')
|
||||||
|
if network_api == 'cliconf':
|
||||||
|
module._dellos9_connection = Connection(module._socket_path)
|
||||||
|
else:
|
||||||
|
module.fail_json(msg='Invalid connection type %s' % network_api)
|
||||||
|
|
||||||
|
return module._dellos9_connection
|
||||||
|
|
||||||
|
|
||||||
|
def get_capabilities(module):
|
||||||
|
if hasattr(module, '_dellos9_capabilities'):
|
||||||
|
return module._dellos9_capabilities
|
||||||
|
try:
|
||||||
|
capabilities = Connection(module._socket_path).get_capabilities()
|
||||||
|
except ConnectionError as exc:
|
||||||
|
module.fail_json(msg=to_text(exc, errors='surrogate_then_replace'))
|
||||||
|
module._dellos9_capabilities = json.loads(capabilities)
|
||||||
|
return module._dellos9_capabilities
|
||||||
|
|
||||||
|
|
||||||
def check_args(module, warnings):
|
def check_args(module, warnings):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@ -93,26 +122,12 @@ def get_config(module, flags=None):
|
||||||
return cfg
|
return cfg
|
||||||
|
|
||||||
|
|
||||||
def to_commands(module, commands):
|
|
||||||
spec = {
|
|
||||||
'command': dict(key=True),
|
|
||||||
'prompt': dict(),
|
|
||||||
'answer': dict()
|
|
||||||
}
|
|
||||||
transform = ComplexList(spec, module)
|
|
||||||
return transform(commands)
|
|
||||||
|
|
||||||
|
|
||||||
def run_commands(module, commands, check_rc=True):
|
def run_commands(module, commands, check_rc=True):
|
||||||
responses = list()
|
connection = get_connection(module)
|
||||||
commands = to_commands(module, to_list(commands))
|
try:
|
||||||
for cmd in commands:
|
return connection.run_commands(commands=commands, check_rc=check_rc)
|
||||||
cmd = module.jsonify(cmd)
|
except ConnectionError as exc:
|
||||||
rc, out, err = exec_command(module, cmd)
|
module.fail_json(msg=to_text(exc))
|
||||||
if check_rc and rc != 0:
|
|
||||||
module.fail_json(msg=to_text(err, errors='surrogate_or_strict'), rc=rc)
|
|
||||||
responses.append(to_text(out, errors='surrogate_or_strict'))
|
|
||||||
return responses
|
|
||||||
|
|
||||||
|
|
||||||
def load_config(module, commands):
|
def load_config(module, commands):
|
||||||
|
|
|
@ -35,7 +35,11 @@ options:
|
||||||
configured provider. The resulting output from the command
|
configured provider. The resulting output from the command
|
||||||
is returned. If the I(wait_for) argument is provided, the
|
is returned. If the I(wait_for) argument is provided, the
|
||||||
module is not returned until the condition is satisfied or
|
module is not returned until the condition is satisfied or
|
||||||
the number of retries has expired.
|
the number of retries has expired. If a command sent to the
|
||||||
|
device requires answering a prompt, it is possible to pass
|
||||||
|
a dict containing I(command), I(answer) and I(prompt).
|
||||||
|
Common answers are 'yes' or "\\r" (carriage return, must be
|
||||||
|
double quotes). See examples.
|
||||||
type: list
|
type: list
|
||||||
required: true
|
required: true
|
||||||
wait_for:
|
wait_for:
|
||||||
|
@ -43,7 +47,7 @@ options:
|
||||||
- List of conditions to evaluate against the output of the
|
- List of conditions to evaluate against the output of the
|
||||||
command. The task will wait for each condition to be true
|
command. The task will wait for each condition to be true
|
||||||
before moving forward. If the conditional is not true
|
before moving forward. If the conditional is not true
|
||||||
within the configured number of I(retries), the task fails.
|
within the configured number of retries, the task fails.
|
||||||
See examples.
|
See examples.
|
||||||
type: list
|
type: list
|
||||||
version_added: "2.2"
|
version_added: "2.2"
|
||||||
|
@ -57,7 +61,7 @@ options:
|
||||||
satisfied.
|
satisfied.
|
||||||
type: str
|
type: str
|
||||||
default: all
|
default: all
|
||||||
choices: [ all, any ]
|
choices: [ 'all', 'any' ]
|
||||||
version_added: "2.5"
|
version_added: "2.5"
|
||||||
retries:
|
retries:
|
||||||
description:
|
description:
|
||||||
|
@ -102,6 +106,13 @@ tasks:
|
||||||
wait_for:
|
wait_for:
|
||||||
- result[0] contains OS10
|
- result[0] contains OS10
|
||||||
- result[1] contains Ethernet
|
- result[1] contains Ethernet
|
||||||
|
|
||||||
|
- name: run commands that require answering a prompt
|
||||||
|
dellos10_command:
|
||||||
|
commands:
|
||||||
|
- command: 'reload'
|
||||||
|
prompt: '[confirm yes/no]: ?$'
|
||||||
|
answer: 'no'
|
||||||
"""
|
"""
|
||||||
|
|
||||||
RETURN = """
|
RETURN = """
|
||||||
|
@ -128,39 +139,26 @@ warnings:
|
||||||
"""
|
"""
|
||||||
import time
|
import time
|
||||||
|
|
||||||
|
from ansible.module_utils._text import to_text
|
||||||
from ansible.module_utils.basic import AnsibleModule
|
from ansible.module_utils.basic import AnsibleModule
|
||||||
|
from ansible.module_utils.network.common.parsing import Conditional
|
||||||
|
from ansible.module_utils.network.common.utils import transform_commands, to_lines
|
||||||
from ansible.module_utils.network.dellos10.dellos10 import run_commands
|
from ansible.module_utils.network.dellos10.dellos10 import run_commands
|
||||||
from ansible.module_utils.network.dellos10.dellos10 import dellos10_argument_spec, check_args
|
from ansible.module_utils.network.dellos10.dellos10 import dellos10_argument_spec, check_args
|
||||||
from ansible.module_utils.network.common.utils import ComplexList
|
|
||||||
from ansible.module_utils.network.common.parsing import Conditional
|
|
||||||
from ansible.module_utils.six import string_types
|
|
||||||
|
|
||||||
|
|
||||||
def to_lines(stdout):
|
|
||||||
for item in stdout:
|
|
||||||
if isinstance(item, string_types):
|
|
||||||
item = str(item).split('\n')
|
|
||||||
yield item
|
|
||||||
|
|
||||||
|
|
||||||
def parse_commands(module, warnings):
|
def parse_commands(module, warnings):
|
||||||
command = ComplexList(dict(
|
commands = transform_commands(module)
|
||||||
command=dict(key=True),
|
|
||||||
prompt=dict(),
|
if module.check_mode:
|
||||||
answer=dict()
|
for item in list(commands):
|
||||||
), module)
|
if not item['command'].startswith('show'):
|
||||||
commands = command(module.params['commands'])
|
warnings.append(
|
||||||
for index, item in enumerate(commands):
|
'Only show commands are supported when using check mode, not '
|
||||||
if module.check_mode and not item['command'].startswith('show'):
|
'executing %s' % item['command']
|
||||||
warnings.append(
|
)
|
||||||
'only show commands are supported when using check mode, not '
|
commands.remove(item)
|
||||||
'executing `%s`' % item['command']
|
|
||||||
)
|
|
||||||
elif item['command'].startswith('conf'):
|
|
||||||
module.fail_json(
|
|
||||||
msg='dellos10_command does not support running config mode '
|
|
||||||
'commands. Please use dellos10_config instead'
|
|
||||||
)
|
|
||||||
return commands
|
return commands
|
||||||
|
|
||||||
|
|
||||||
|
@ -191,8 +189,11 @@ def main():
|
||||||
result['warnings'] = warnings
|
result['warnings'] = warnings
|
||||||
|
|
||||||
wait_for = module.params['wait_for'] or list()
|
wait_for = module.params['wait_for'] or list()
|
||||||
conditionals = [Conditional(c) for c in wait_for]
|
|
||||||
|
|
||||||
|
try:
|
||||||
|
conditionals = [Conditional(c) for c in wait_for]
|
||||||
|
except AttributeError as exc:
|
||||||
|
module.fail_json(msg=to_text(exc))
|
||||||
retries = module.params['retries']
|
retries = module.params['retries']
|
||||||
interval = module.params['interval']
|
interval = module.params['interval']
|
||||||
match = module.params['match']
|
match = module.params['match']
|
||||||
|
@ -219,7 +220,6 @@ def main():
|
||||||
module.fail_json(msg=msg, failed_conditions=failed_conditions)
|
module.fail_json(msg=msg, failed_conditions=failed_conditions)
|
||||||
|
|
||||||
result.update({
|
result.update({
|
||||||
'changed': False,
|
|
||||||
'stdout': responses,
|
'stdout': responses,
|
||||||
'stdout_lines': list(to_lines(responses))
|
'stdout_lines': list(to_lines(responses))
|
||||||
})
|
})
|
||||||
|
|
|
@ -34,7 +34,11 @@ options:
|
||||||
configured provider. The resulting output from the command
|
configured provider. The resulting output from the command
|
||||||
is returned. If the I(wait_for) argument is provided, the
|
is returned. If the I(wait_for) argument is provided, the
|
||||||
module is not returned until the condition is satisfied or
|
module is not returned until the condition is satisfied or
|
||||||
the number of retries has expired.
|
the number of retries has expired. If a command sent to the
|
||||||
|
device requires answering a prompt, it is possible to pass
|
||||||
|
a dict containing I(command), I(answer) and I(prompt).
|
||||||
|
Common answers are 'yes' or "\\r" (carriage return, must be
|
||||||
|
double quotes). See examples.
|
||||||
type: list
|
type: list
|
||||||
required: true
|
required: true
|
||||||
wait_for:
|
wait_for:
|
||||||
|
@ -42,7 +46,7 @@ options:
|
||||||
- List of conditions to evaluate against the output of the
|
- List of conditions to evaluate against the output of the
|
||||||
command. The task will wait for each condition to be true
|
command. The task will wait for each condition to be true
|
||||||
before moving forward. If the conditional is not true
|
before moving forward. If the conditional is not true
|
||||||
within the configured number of I(retries), the task fails.
|
within the configured number of retries, the task fails.
|
||||||
See examples.
|
See examples.
|
||||||
type: list
|
type: list
|
||||||
version_added: "2.2"
|
version_added: "2.2"
|
||||||
|
@ -56,7 +60,7 @@ options:
|
||||||
satisfied.
|
satisfied.
|
||||||
type: str
|
type: str
|
||||||
default: all
|
default: all
|
||||||
choices: [ all, any ]
|
choices: [ 'all', 'any' ]
|
||||||
version_added: "2.5"
|
version_added: "2.5"
|
||||||
retries:
|
retries:
|
||||||
description:
|
description:
|
||||||
|
@ -101,6 +105,13 @@ tasks:
|
||||||
wait_for:
|
wait_for:
|
||||||
- result[0] contains Dell
|
- result[0] contains Dell
|
||||||
- result[1] contains Access
|
- result[1] contains Access
|
||||||
|
|
||||||
|
- name: run commands that require answering a prompt
|
||||||
|
dellos6_command:
|
||||||
|
commands:
|
||||||
|
- command: 'copy running-config startup-config'
|
||||||
|
prompt: '[confirm yes/no]: ?$'
|
||||||
|
answer: 'yes'
|
||||||
"""
|
"""
|
||||||
|
|
||||||
RETURN = """
|
RETURN = """
|
||||||
|
@ -128,39 +139,26 @@ warnings:
|
||||||
|
|
||||||
import time
|
import time
|
||||||
|
|
||||||
|
from ansible.module_utils._text import to_text
|
||||||
from ansible.module_utils.basic import AnsibleModule
|
from ansible.module_utils.basic import AnsibleModule
|
||||||
|
from ansible.module_utils.network.common.parsing import Conditional
|
||||||
|
from ansible.module_utils.network.common.utils import transform_commands, to_lines
|
||||||
from ansible.module_utils.network.dellos6.dellos6 import run_commands
|
from ansible.module_utils.network.dellos6.dellos6 import run_commands
|
||||||
from ansible.module_utils.network.dellos6.dellos6 import dellos6_argument_spec, check_args
|
from ansible.module_utils.network.dellos6.dellos6 import dellos6_argument_spec, check_args
|
||||||
from ansible.module_utils.network.common.utils import ComplexList
|
|
||||||
from ansible.module_utils.network.common.parsing import Conditional
|
|
||||||
from ansible.module_utils.six import string_types
|
|
||||||
|
|
||||||
|
|
||||||
def to_lines(stdout):
|
|
||||||
for item in stdout:
|
|
||||||
if isinstance(item, string_types):
|
|
||||||
item = str(item).split('\n')
|
|
||||||
yield item
|
|
||||||
|
|
||||||
|
|
||||||
def parse_commands(module, warnings):
|
def parse_commands(module, warnings):
|
||||||
command = ComplexList(dict(
|
commands = transform_commands(module)
|
||||||
command=dict(key=True),
|
|
||||||
prompt=dict(),
|
if module.check_mode:
|
||||||
answer=dict()
|
for item in list(commands):
|
||||||
), module)
|
if not item['command'].startswith('show'):
|
||||||
commands = command(module.params['commands'])
|
warnings.append(
|
||||||
for index, item in enumerate(commands):
|
'Only show commands are supported when using check mode, not '
|
||||||
if module.check_mode and not item['command'].startswith('show'):
|
'executing %s' % item['command']
|
||||||
warnings.append(
|
)
|
||||||
'only show commands are supported when using check mode, not '
|
commands.remove(item)
|
||||||
'executing `%s`' % item['command']
|
|
||||||
)
|
|
||||||
elif item['command'].startswith('conf'):
|
|
||||||
module.fail_json(
|
|
||||||
msg='dellos6_command does not support running config mode '
|
|
||||||
'commands. Please use dellos6_config instead'
|
|
||||||
)
|
|
||||||
return commands
|
return commands
|
||||||
|
|
||||||
|
|
||||||
|
@ -190,8 +188,11 @@ def main():
|
||||||
result['warnings'] = warnings
|
result['warnings'] = warnings
|
||||||
|
|
||||||
wait_for = module.params['wait_for'] or list()
|
wait_for = module.params['wait_for'] or list()
|
||||||
conditionals = [Conditional(c) for c in wait_for]
|
|
||||||
|
|
||||||
|
try:
|
||||||
|
conditionals = [Conditional(c) for c in wait_for]
|
||||||
|
except AttributeError as exc:
|
||||||
|
module.fail_json(msg=to_text(exc))
|
||||||
retries = module.params['retries']
|
retries = module.params['retries']
|
||||||
interval = module.params['interval']
|
interval = module.params['interval']
|
||||||
match = module.params['match']
|
match = module.params['match']
|
||||||
|
@ -218,7 +219,6 @@ def main():
|
||||||
module.fail_json(msg=msg, failed_conditions=failed_conditions)
|
module.fail_json(msg=msg, failed_conditions=failed_conditions)
|
||||||
|
|
||||||
result.update({
|
result.update({
|
||||||
'changed': False,
|
|
||||||
'stdout': responses,
|
'stdout': responses,
|
||||||
'stdout_lines': list(to_lines(responses))
|
'stdout_lines': list(to_lines(responses))
|
||||||
})
|
})
|
||||||
|
|
|
@ -35,7 +35,11 @@ options:
|
||||||
configured provider. The resulting output from the command
|
configured provider. The resulting output from the command
|
||||||
is returned. If the I(wait_for) argument is provided, the
|
is returned. If the I(wait_for) argument is provided, the
|
||||||
module is not returned until the condition is satisfied or
|
module is not returned until the condition is satisfied or
|
||||||
the number of retries has expired.
|
the number of retries has expired. If a command sent to the
|
||||||
|
device requires answering a prompt, it is possible to pass
|
||||||
|
a dict containing I(command), I(answer) and I(prompt).
|
||||||
|
Common answers are 'yes' or "\\r" (carriage return, must be
|
||||||
|
double quotes). See examples.
|
||||||
type: list
|
type: list
|
||||||
required: true
|
required: true
|
||||||
wait_for:
|
wait_for:
|
||||||
|
@ -43,7 +47,7 @@ options:
|
||||||
- List of conditions to evaluate against the output of the
|
- List of conditions to evaluate against the output of the
|
||||||
command. The task will wait for each condition to be true
|
command. The task will wait for each condition to be true
|
||||||
before moving forward. If the conditional is not true
|
before moving forward. If the conditional is not true
|
||||||
within the configured number of I(retries), the task fails.
|
within the configured number of retries, the task fails.
|
||||||
See examples.
|
See examples.
|
||||||
type: list
|
type: list
|
||||||
version_added: "2.2"
|
version_added: "2.2"
|
||||||
|
@ -57,7 +61,7 @@ options:
|
||||||
satisfied.
|
satisfied.
|
||||||
type: str
|
type: str
|
||||||
default: all
|
default: all
|
||||||
choices: [ all, any ]
|
choices: [ 'all', 'any' ]
|
||||||
version_added: "2.5"
|
version_added: "2.5"
|
||||||
retries:
|
retries:
|
||||||
description:
|
description:
|
||||||
|
@ -111,6 +115,13 @@ tasks:
|
||||||
wait_for:
|
wait_for:
|
||||||
- result[0] contains OS9
|
- result[0] contains OS9
|
||||||
- result[1] contains Loopback
|
- result[1] contains Loopback
|
||||||
|
|
||||||
|
- name: run commands that require answering a prompt
|
||||||
|
dellos9_command:
|
||||||
|
commands:
|
||||||
|
- command: 'copy running-config startup-config'
|
||||||
|
prompt: '[confirm yes/no]: ?$'
|
||||||
|
answer: 'yes'
|
||||||
"""
|
"""
|
||||||
|
|
||||||
RETURN = """
|
RETURN = """
|
||||||
|
@ -137,39 +148,26 @@ warnings:
|
||||||
"""
|
"""
|
||||||
import time
|
import time
|
||||||
|
|
||||||
|
from ansible.module_utils._text import to_text
|
||||||
from ansible.module_utils.basic import AnsibleModule
|
from ansible.module_utils.basic import AnsibleModule
|
||||||
|
from ansible.module_utils.network.common.parsing import Conditional
|
||||||
|
from ansible.module_utils.network.common.utils import transform_commands, to_lines
|
||||||
from ansible.module_utils.network.dellos9.dellos9 import run_commands
|
from ansible.module_utils.network.dellos9.dellos9 import run_commands
|
||||||
from ansible.module_utils.network.dellos9.dellos9 import dellos9_argument_spec, check_args
|
from ansible.module_utils.network.dellos9.dellos9 import dellos9_argument_spec, check_args
|
||||||
from ansible.module_utils.network.common.utils import ComplexList
|
|
||||||
from ansible.module_utils.network.common.parsing import Conditional
|
|
||||||
from ansible.module_utils.six import string_types
|
|
||||||
|
|
||||||
|
|
||||||
def to_lines(stdout):
|
|
||||||
for item in stdout:
|
|
||||||
if isinstance(item, string_types):
|
|
||||||
item = str(item).split('\n')
|
|
||||||
yield item
|
|
||||||
|
|
||||||
|
|
||||||
def parse_commands(module, warnings):
|
def parse_commands(module, warnings):
|
||||||
command = ComplexList(dict(
|
commands = transform_commands(module)
|
||||||
command=dict(key=True),
|
|
||||||
prompt=dict(),
|
if module.check_mode:
|
||||||
answer=dict()
|
for item in list(commands):
|
||||||
), module)
|
if not item['command'].startswith('show'):
|
||||||
commands = command(module.params['commands'])
|
warnings.append(
|
||||||
for index, item in enumerate(commands):
|
'Only show commands are supported when using check mode, not '
|
||||||
if module.check_mode and not item['command'].startswith('show'):
|
'executing %s' % item['command']
|
||||||
warnings.append(
|
)
|
||||||
'only show commands are supported when using check mode, not '
|
commands.remove(item)
|
||||||
'executing `%s`' % item['command']
|
|
||||||
)
|
|
||||||
elif item['command'].startswith('conf'):
|
|
||||||
module.fail_json(
|
|
||||||
msg='dellos9_command does not support running config mode '
|
|
||||||
'commands. Please use dellos9_config instead'
|
|
||||||
)
|
|
||||||
return commands
|
return commands
|
||||||
|
|
||||||
|
|
||||||
|
@ -200,8 +198,11 @@ def main():
|
||||||
result['warnings'] = warnings
|
result['warnings'] = warnings
|
||||||
|
|
||||||
wait_for = module.params['wait_for'] or list()
|
wait_for = module.params['wait_for'] or list()
|
||||||
conditionals = [Conditional(c) for c in wait_for]
|
|
||||||
|
|
||||||
|
try:
|
||||||
|
conditionals = [Conditional(c) for c in wait_for]
|
||||||
|
except AttributeError as exc:
|
||||||
|
module.fail_json(msg=to_text(exc))
|
||||||
retries = module.params['retries']
|
retries = module.params['retries']
|
||||||
interval = module.params['interval']
|
interval = module.params['interval']
|
||||||
match = module.params['match']
|
match = module.params['match']
|
||||||
|
@ -228,7 +229,6 @@ def main():
|
||||||
module.fail_json(msg=msg, failed_conditions=failed_conditions)
|
module.fail_json(msg=msg, failed_conditions=failed_conditions)
|
||||||
|
|
||||||
result.update({
|
result.update({
|
||||||
'changed': False,
|
|
||||||
'stdout': responses,
|
'stdout': responses,
|
||||||
'stdout_lines': list(to_lines(responses))
|
'stdout_lines': list(to_lines(responses))
|
||||||
})
|
})
|
||||||
|
|
|
@ -36,7 +36,9 @@ import json
|
||||||
|
|
||||||
from itertools import chain
|
from itertools import chain
|
||||||
|
|
||||||
|
from ansible.errors import AnsibleConnectionFailure
|
||||||
from ansible.module_utils._text import to_bytes, to_text
|
from ansible.module_utils._text import to_bytes, to_text
|
||||||
|
from ansible.module_utils.common._collections_compat import Mapping
|
||||||
from ansible.module_utils.network.common.utils import to_list
|
from ansible.module_utils.network.common.utils import to_list
|
||||||
from ansible.plugins.cliconf import CliconfBase, enable_mode
|
from ansible.plugins.cliconf import CliconfBase, enable_mode
|
||||||
|
|
||||||
|
@ -87,3 +89,27 @@ class Cliconf(CliconfBase):
|
||||||
def get_capabilities(self):
|
def get_capabilities(self):
|
||||||
result = super(Cliconf, self).get_capabilities()
|
result = super(Cliconf, self).get_capabilities()
|
||||||
return json.dumps(result)
|
return json.dumps(result)
|
||||||
|
|
||||||
|
def run_commands(self, commands=None, check_rc=True):
|
||||||
|
if commands is None:
|
||||||
|
raise ValueError("'commands' value is required")
|
||||||
|
|
||||||
|
responses = list()
|
||||||
|
for cmd in to_list(commands):
|
||||||
|
if not isinstance(cmd, Mapping):
|
||||||
|
cmd = {'command': cmd}
|
||||||
|
|
||||||
|
output = cmd.pop('output', None)
|
||||||
|
if output:
|
||||||
|
raise ValueError("'output' value %s is not supported for run_commands" % output)
|
||||||
|
|
||||||
|
try:
|
||||||
|
out = self.send_command(**cmd)
|
||||||
|
except AnsibleConnectionFailure as e:
|
||||||
|
if check_rc:
|
||||||
|
raise
|
||||||
|
out = getattr(e, 'err', to_text(e))
|
||||||
|
|
||||||
|
responses.append(out)
|
||||||
|
|
||||||
|
return responses
|
||||||
|
|
|
@ -36,7 +36,9 @@ import json
|
||||||
|
|
||||||
from itertools import chain
|
from itertools import chain
|
||||||
|
|
||||||
|
from ansible.errors import AnsibleConnectionFailure
|
||||||
from ansible.module_utils._text import to_bytes, to_text
|
from ansible.module_utils._text import to_bytes, to_text
|
||||||
|
from ansible.module_utils.common._collections_compat import Mapping
|
||||||
from ansible.module_utils.network.common.utils import to_list
|
from ansible.module_utils.network.common.utils import to_list
|
||||||
from ansible.plugins.cliconf import CliconfBase, enable_mode
|
from ansible.plugins.cliconf import CliconfBase, enable_mode
|
||||||
|
|
||||||
|
@ -58,7 +60,7 @@ class Cliconf(CliconfBase):
|
||||||
if match:
|
if match:
|
||||||
device_info['network_os_model'] = match.group(1)
|
device_info['network_os_model'] = match.group(1)
|
||||||
|
|
||||||
reply = self.get('show running-config | grep hostname')
|
reply = self.get('show running-config | include hostname')
|
||||||
data = to_text(reply, errors='surrogate_or_strict').strip()
|
data = to_text(reply, errors='surrogate_or_strict').strip()
|
||||||
match = re.search(r'^hostname (.+)', data, re.M)
|
match = re.search(r'^hostname (.+)', data, re.M)
|
||||||
if match:
|
if match:
|
||||||
|
@ -87,3 +89,27 @@ class Cliconf(CliconfBase):
|
||||||
def get_capabilities(self):
|
def get_capabilities(self):
|
||||||
result = super(Cliconf, self).get_capabilities()
|
result = super(Cliconf, self).get_capabilities()
|
||||||
return json.dumps(result)
|
return json.dumps(result)
|
||||||
|
|
||||||
|
def run_commands(self, commands=None, check_rc=True):
|
||||||
|
if commands is None:
|
||||||
|
raise ValueError("'commands' value is required")
|
||||||
|
|
||||||
|
responses = list()
|
||||||
|
for cmd in to_list(commands):
|
||||||
|
if not isinstance(cmd, Mapping):
|
||||||
|
cmd = {'command': cmd}
|
||||||
|
|
||||||
|
output = cmd.pop('output', None)
|
||||||
|
if output:
|
||||||
|
raise ValueError("'output' value %s is not supported for run_commands" % output)
|
||||||
|
|
||||||
|
try:
|
||||||
|
out = self.send_command(**cmd)
|
||||||
|
except AnsibleConnectionFailure as e:
|
||||||
|
if check_rc:
|
||||||
|
raise
|
||||||
|
out = getattr(e, 'err', to_text(e))
|
||||||
|
|
||||||
|
responses.append(out)
|
||||||
|
|
||||||
|
return responses
|
||||||
|
|
|
@ -36,7 +36,9 @@ import json
|
||||||
|
|
||||||
from itertools import chain
|
from itertools import chain
|
||||||
|
|
||||||
|
from ansible.errors import AnsibleConnectionFailure
|
||||||
from ansible.module_utils._text import to_bytes, to_text
|
from ansible.module_utils._text import to_bytes, to_text
|
||||||
|
from ansible.module_utils.common._collections_compat import Mapping
|
||||||
from ansible.module_utils.network.common.utils import to_list
|
from ansible.module_utils.network.common.utils import to_list
|
||||||
from ansible.plugins.cliconf import CliconfBase, enable_mode
|
from ansible.plugins.cliconf import CliconfBase, enable_mode
|
||||||
|
|
||||||
|
@ -87,3 +89,27 @@ class Cliconf(CliconfBase):
|
||||||
def get_capabilities(self):
|
def get_capabilities(self):
|
||||||
result = super(Cliconf, self).get_capabilities()
|
result = super(Cliconf, self).get_capabilities()
|
||||||
return json.dumps(result)
|
return json.dumps(result)
|
||||||
|
|
||||||
|
def run_commands(self, commands=None, check_rc=True):
|
||||||
|
if commands is None:
|
||||||
|
raise ValueError("'commands' value is required")
|
||||||
|
|
||||||
|
responses = list()
|
||||||
|
for cmd in to_list(commands):
|
||||||
|
if not isinstance(cmd, Mapping):
|
||||||
|
cmd = {'command': cmd}
|
||||||
|
|
||||||
|
output = cmd.pop('output', None)
|
||||||
|
if output:
|
||||||
|
raise ValueError("'output' value %s is not supported for run_commands" % output)
|
||||||
|
|
||||||
|
try:
|
||||||
|
out = self.send_command(**cmd)
|
||||||
|
except AnsibleConnectionFailure as e:
|
||||||
|
if check_rc:
|
||||||
|
raise
|
||||||
|
out = getattr(e, 'err', to_text(e))
|
||||||
|
|
||||||
|
responses.append(out)
|
||||||
|
|
||||||
|
return responses
|
||||||
|
|
|
@ -55,6 +55,12 @@ class TerminalModule(TerminalBase):
|
||||||
|
|
||||||
terminal_inital_prompt_newline = False
|
terminal_inital_prompt_newline = False
|
||||||
|
|
||||||
|
def on_open_shell(self):
|
||||||
|
try:
|
||||||
|
self._exec_cli_command(b'terminal length 0')
|
||||||
|
except AnsibleConnectionFailure:
|
||||||
|
raise AnsibleConnectionFailure('unable to set terminal parameters')
|
||||||
|
|
||||||
def on_become(self, passwd=None):
|
def on_become(self, passwd=None):
|
||||||
if self._get_prompt().endswith(b'#'):
|
if self._get_prompt().endswith(b'#'):
|
||||||
return
|
return
|
||||||
|
|
Loading…
Reference in a new issue