1
0
Fork 0
mirror of https://github.com/ansible-collections/community.general.git synced 2024-09-14 20:13:21 +02:00

code clean of old code from network modules updates (#21469)

* removes unused code
* removes module_utils/local.py
* removes plugins/action/network.py
* removes action_handler from connection plugins
* removes code to use action_handler in task_executor
* updates action plugins to subclass from normal
This commit is contained in:
Peter Sprygada 2017-02-15 12:46:30 -05:00 committed by GitHub
parent 2d14cdc5ac
commit 48b02336ab
9 changed files with 4 additions and 413 deletions

View file

@ -768,8 +768,7 @@ class TaskExecutor:
elif all((module_prefix in network_group_modules, module_prefix in self._shared_loader_obj.action_loader)):
handler_name = module_prefix
else:
pc_conn = self._shared_loader_obj.connection_loader.get(self._play_context.connection, class_only=True)
handler_name = getattr(pc_conn, 'action_handler', 'normal')
handler_name = 'normal'
handler = self._shared_loader_obj.action_loader.get(
handler_name,

View file

@ -1,80 +0,0 @@
#
# This code is part of Ansible, but is an independent component.
# This particular file snippet, and this file snippet only, is BSD licensed.
# Modules you write using this snippet, which is embedded dynamically by Ansible
# still belong to the author of the module, and may assign their own license
# to the complete work.
#
# (c) 2016 Red Hat Inc.
#
# Redistribution and use in source and binary forms, with or without modification,
# are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# 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.
#
import json
import ansible.module_utils.basic
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.basic import remove_values
from ansible.module_utils._text import to_bytes
from ansible.errors import AnsibleModuleExit
_ANSIBLE_CONNECTION = None
def _modify_module(task_args, connection):
params = {'ANSIBLE_MODULE_ARGS': task_args}
params = json.dumps(params)
ansible.module_utils.basic._ANSIBLE_ARGS = to_bytes(params)
global _ANSIBLE_CONNECTION
_ANSIBLE_CONNECTION = connection
class LocalAnsibleModule(AnsibleModule):
@property
def connection(self):
return _ANSIBLE_CONNECTION
def exec_command(self, args, check_rc=False):
'''
Execute a command, returns rc, stdout, and stderr.
'''
rc, out, err = self.connection.exec_command(args)
if check_rc and rc != 0:
self.fail_json(msg='command %s failed' % args, rc=rc, stderr=err, stdout=out)
return rc, out, err
def exit_json(self, **kwargs):
''' return from the module, without error '''
if not 'changed' in kwargs:
kwargs['changed'] = False
if 'invocation' not in kwargs:
kwargs['invocation'] = {'module_args': self.params}
kwargs = remove_values(kwargs, self.no_log_values)
raise AnsibleModuleExit(kwargs)
def fail_json(self, **kwargs):
''' return from the module, with an error message '''
assert 'msg' in kwargs, "implementation error -- msg to explain the error is required"
kwargs['failed'] = True
if 'invocation' not in kwargs:
kwargs['invocation'] = {'module_args': self.params}
kwargs = remove_values(kwargs, self.no_log_values)
raise AnsibleModuleExit(kwargs)

View file

@ -1,133 +0,0 @@
#!/usr/bin/python
#
# 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 <http://www.gnu.org/licenses/>.
#
ANSIBLE_METADATA = {
'status': ['preview'],
'supported_by': 'core',
'version': '1.0'
}
DOCUMENTATION = """
---
module: net_command
version_added: "2.3"
author: "Peter Sprygada (@privateip)"
short_description: Executes a command on a remote network device
description:
- This module will take the command and execute it on the remote
device in a CLI shell. The command will output will be returned
via the stdout return key. If an error is detected, the command
will return the error via the stderr key.
options:
free_form:
description:
- A free form command to run on the remote host. There is no
parameter actually named 'free_form'. See the examples.
required: true
notes:
- This module requires setting the Ansible C(connection) type to C(network_cli).
- This module will always set the changed return key to C(True)
"""
EXAMPLES = """
# Note: These examples assume 'connection' has been set to 'network_cli'.
- name: execute show version
net_command: show version
- name: run a series of commands
net_command: "{{ item }}"
with_items:
- show interfaces
- show ip route
- show version
"""
RETURN = """
rc:
description: The command return code (0 means success)
returned: always
type: int
sample: 0
stdout:
description: The command standard output
returned: always
type: string
sample: "Hostname: ios01\nFQDN: ios01.example.net"
stderr:
description: The command standard error
returned: always
type: string
sample: "shw hostname\r\n% Invalid input\r\nios01>"
stdout_lines:
description: The command standard output split in lines
returned: always
type: list
sample: ["Hostname: ios01", "FQDN: ios01.example.net"]
start:
description: The time the job started
returned: always
type: str
sample: "2016-11-16 10:38:15.126146"
end:
description: The time the job ended
returned: always
type: str
sample: "2016-11-16 10:38:25.595612"
delta:
description: The time elapsed to perform all operations
returned: always
type: str
sample: "0:00:10.469466"
"""
from ansible.module_utils.local import LocalAnsibleModule
def main():
""" main entry point for module execution
"""
argument_spec = dict(
_raw_params=dict()
)
module = LocalAnsibleModule(argument_spec=argument_spec,
supports_check_mode=False)
if str(module.params['_raw_params']).strip() == '':
module.fail_json(rc=256, msg='no command given')
result = {'changed': True}
rc, out, err = module.exec_command(module.params['_raw_params'])
try:
out = module.from_json(out)
except ValueError:
if out:
out = str(out).strip()
result['stdout_lines'] = out.split('\n')
result.update({
'rc': rc,
'stdout': out,
'stderr': str(err).strip()
})
module.exit_json(**result)
if __name__ == '__main__':
main()

View file

@ -24,7 +24,7 @@ import re
import time
import glob
from ansible.plugins.action.network import ActionModule as _ActionModule
from ansible.plugins.action.normal import ActionModule as _ActionModule
from ansible.module_utils._text import to_text
from ansible.module_utils.six.moves.urllib.parse import urlsplit
from ansible.utils.vars import merge_hash
@ -43,10 +43,7 @@ class ActionModule(_ActionModule):
except ValueError as exc:
return dict(failed=True, msg=exc.message)
if self._play_context.connection == 'local':
result = self.normal(tmp, task_vars)
else:
result = super(ActionModule, self).run(tmp, task_vars)
result = super(ActionModule, self).run(tmp, task_vars)
if self._task.args.get('backup') and result.get('__backup__'):
# User requested backup and no error occurred in module.
@ -64,22 +61,6 @@ class ActionModule(_ActionModule):
return result
def normal(self, tmp=None, task_vars=None):
if task_vars is None:
task_vars = dict()
#results = super(ActionModule, self).run(tmp, task_vars)
# remove as modules might hide due to nolog
#del results['invocation']['module_args']
results = {}
results = merge_hash(results, self._execute_module(tmp=tmp, task_vars=task_vars))
# hack to keep --verbose from showing all the setup module results
if self._task.action == 'setup':
results['_ansible_verbose_override'] = True
return results
def _get_working_path(self):
cwd = self._loader.get_basedir()
if self._task._role is not None:

View file

@ -25,7 +25,7 @@ import glob
import urlparse
from ansible.module_utils._text import to_text
from ansible.plugins.action.network import ActionModule as _ActionModule
from ansible.plugins.action.normal import ActionModule as _ActionModule
class ActionModule(_ActionModule):

View file

@ -1,66 +0,0 @@
#
# (c) 2016 Red Hat Inc.
#
# 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 <http://www.gnu.org/licenses/>.
#
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
import datetime
from ansible.plugins.action import ActionBase, display
from ansible.module_utils.local import _modify_module
from ansible.errors import AnsibleModuleExit
class ActionModule(ActionBase):
def run(self, tmp=None, task_vars=None):
result = super(ActionModule, self).run(tmp, task_vars)
if result.get('invocation', {}).get('module_args'):
del result['invocation']['module_args']
self._update_module_args(self._task.action, self._task.args, task_vars)
try:
_modify_module(self._task.args, self._connection)
path = self._shared_loader_obj.module_loader.find_plugin(self._task.action)
pkg = '.'.join(['ansible', 'modules', self._task.action])
module = self._shared_loader_obj.module_loader._load_module_source(pkg, path)
start_time = datetime.datetime.now()
module.main()
except AnsibleModuleExit as exc:
result.update(exc.result)
for field in ('_ansible_notify',):
if field in result:
result.pop(field)
except Exception as exc:
if display.verbosity > 2:
raise
result.update(dict(failed=True, msg=str(exc)))
end_time = datetime.datetime.now()
delta = end_time - start_time
result.update({
'start': str(start_time),
'end': str(end_time),
'delta': str(delta)
})
return result

View file

@ -67,7 +67,6 @@ class ConnectionBase(with_metaclass(ABCMeta, object)):
# language means any language.
module_implementation_preferences = ('',)
allow_executable = True
action_handler = 'normal'
def __init__(self, play_context, new_stdin, *args, **kwargs):
# All these hasattrs allow subclasses to override these parameters

View file

@ -42,7 +42,6 @@ class Connection(_Connection):
transport = 'network_cli'
has_pipelining = False
action_handler = 'network'
def __init__(self, play_context, new_stdin, *args, **kwargs):
super(Connection, self).__init__(play_context, new_stdin, *args, **kwargs)

View file

@ -1,108 +0,0 @@
#!/usr/bin/env python
#
# (c) 2016 Red Hat Inc.
#
# 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 <http://www.gnu.org/licenses/>.
# Make coding more python3-ish
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
import os
import json
from ansible.compat.tests import unittest
from ansible.compat.tests.mock import patch, MagicMock
from ansible.errors import AnsibleModuleExit
from ansible.modules.network.basics import net_command
from ansible.module_utils import basic
from ansible.module_utils.local import LocalAnsibleModule
from ansible.module_utils._text import to_bytes
def set_module_args(args):
args = json.dumps({'ANSIBLE_MODULE_ARGS': args})
basic._ANSIBLE_ARGS = to_bytes(args)
fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
fixture_data = {}
def load_fixture(name):
path = os.path.join(fixture_path, name)
if path in fixture_data:
return fixture_data[path]
with open(path) as f:
data = f.read()
try:
data = json.loads(data)
except:
pass
fixture_data[path] = data
return data
class TestNetCommandModule(unittest.TestCase):
def execute_module(self, command_response=None, failed=False, changed=True):
if not command_response:
command_response = (256, '', 'no command response provided in test case')
with patch.object(LocalAnsibleModule, 'exec_command') as mock_exec_command:
mock_exec_command.return_value = command_response
with self.assertRaises(AnsibleModuleExit) as exc:
net_command.main()
result = exc.exception.result
if failed:
self.assertTrue(result.get('failed'), result)
else:
self.assertEqual(result.get('changed'), changed, result)
return result
def test_net_command_string(self):
"""
Test for all keys in the response
"""
set_module_args({'_raw_params': 'show version'})
result = self.execute_module((0, 'ok', ''))
for key in ['rc', 'stdout', 'stderr', 'stdout_lines']:
self.assertIn(key, result)
def test_net_command_json(self):
"""
The stdout_lines key should not be present when the return
string is a json data structure
"""
set_module_args({'_raw_params': 'show version'})
result = self.execute_module((0, '{"key": "value"}', ''))
for key in ['rc', 'stdout', 'stderr']:
self.assertIn(key, result)
self.assertNotIn('stdout_lines', result)
def test_net_command_missing_command(self):
"""
Test failure on missing command
"""
set_module_args({'_raw_params': ''})
self.execute_module(failed=True)