mirror of
https://github.com/ansible-collections/community.general.git
synced 2025-10-02 14:33:21 -07:00
Initial commit
This commit is contained in:
commit
aebc1b03fd
4861 changed files with 812621 additions and 0 deletions
0
tests/unit/plugins/__init__.py
Normal file
0
tests/unit/plugins/__init__.py
Normal file
0
tests/unit/plugins/become/__init__.py
Normal file
0
tests/unit/plugins/become/__init__.py
Normal file
37
tests/unit/plugins/become/conftest.py
Normal file
37
tests/unit/plugins/become/conftest.py
Normal file
|
@ -0,0 +1,37 @@
|
|||
# (c) 2012-2014, Michael DeHaan <michael.dehaan@gmail.com>
|
||||
# (c) 2017 Ansible Project
|
||||
#
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
# Make coding more python3-ish
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
import pytest
|
||||
|
||||
from ansible.cli.arguments import option_helpers as opt_help
|
||||
from ansible.utils import context_objects as co
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def parser():
|
||||
parser = opt_help.create_base_parser('testparser')
|
||||
|
||||
opt_help.add_runas_options(parser)
|
||||
opt_help.add_meta_options(parser)
|
||||
opt_help.add_runtask_options(parser)
|
||||
opt_help.add_vault_options(parser)
|
||||
opt_help.add_async_options(parser)
|
||||
opt_help.add_connect_options(parser)
|
||||
opt_help.add_subset_options(parser)
|
||||
opt_help.add_check_options(parser)
|
||||
opt_help.add_inventory_options(parser)
|
||||
|
||||
return parser
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def reset_cli_args():
|
||||
co.GlobalCLIArgs._Singleton__instance = None
|
||||
yield
|
||||
co.GlobalCLIArgs._Singleton__instance = None
|
39
tests/unit/plugins/become/test_doas.py
Normal file
39
tests/unit/plugins/become/test_doas.py
Normal file
|
@ -0,0 +1,39 @@
|
|||
# (c) 2012-2014, Michael DeHaan <michael.dehaan@gmail.com>
|
||||
# (c) 2020 Ansible Project
|
||||
#
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
# Make coding more python3-ish
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
import re
|
||||
|
||||
from ansible import context
|
||||
from ansible.playbook.play_context import PlayContext
|
||||
from ansible.plugins.loader import become_loader
|
||||
|
||||
|
||||
def test_doas(mocker, parser, reset_cli_args):
|
||||
options = parser.parse_args([])
|
||||
context._init_global_context(options)
|
||||
play_context = PlayContext()
|
||||
|
||||
default_cmd = "/bin/foo"
|
||||
default_exe = "/bin/bash"
|
||||
doas_exe = 'doas'
|
||||
doas_flags = '-n'
|
||||
|
||||
cmd = play_context.make_become_cmd(cmd=default_cmd, executable=default_exe)
|
||||
assert cmd == default_cmd
|
||||
|
||||
success = 'BECOME-SUCCESS-.+?'
|
||||
|
||||
play_context.become = True
|
||||
play_context.become_user = 'foo'
|
||||
play_context.set_become_plugin(become_loader.get('doas'))
|
||||
play_context.become_method = 'doas'
|
||||
play_context.become_flags = doas_flags
|
||||
cmd = play_context.make_become_cmd(cmd=default_cmd, executable=default_exe)
|
||||
assert (re.match("""%s %s -u %s %s -c 'echo %s; %s'""" % (doas_exe, doas_flags, play_context.become_user, default_exe, success,
|
||||
default_cmd), cmd) is not None)
|
44
tests/unit/plugins/become/test_dzdo.py
Normal file
44
tests/unit/plugins/become/test_dzdo.py
Normal file
|
@ -0,0 +1,44 @@
|
|||
# (c) 2012-2014, Michael DeHaan <michael.dehaan@gmail.com>
|
||||
# (c) 2020 Ansible Project
|
||||
#
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
# Make coding more python3-ish
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
import re
|
||||
|
||||
from ansible import context
|
||||
from ansible.playbook.play_context import PlayContext
|
||||
from ansible.plugins.loader import become_loader
|
||||
|
||||
|
||||
def test_dzdo(mocker, parser, reset_cli_args):
|
||||
options = parser.parse_args([])
|
||||
context._init_global_context(options)
|
||||
play_context = PlayContext()
|
||||
|
||||
default_cmd = "/bin/foo"
|
||||
default_exe = "/bin/bash"
|
||||
dzdo_exe = 'dzdo'
|
||||
dzdo_flags = ''
|
||||
|
||||
cmd = play_context.make_become_cmd(cmd=default_cmd, executable=default_exe)
|
||||
assert cmd == default_cmd
|
||||
|
||||
success = 'BECOME-SUCCESS-.+?'
|
||||
|
||||
play_context.become = True
|
||||
play_context.become_user = 'foo'
|
||||
play_context.set_become_plugin(become_loader.get('dzdo'))
|
||||
play_context.become_method = 'dzdo'
|
||||
play_context.become_flags = dzdo_flags
|
||||
cmd = play_context.make_become_cmd(cmd=default_cmd, executable=default_exe)
|
||||
assert re.match("""%s %s -u %s %s -c 'echo %s; %s'""" % (dzdo_exe, dzdo_flags, play_context.become_user, default_exe,
|
||||
success, default_cmd), cmd) is not None
|
||||
play_context.become_pass = 'testpass'
|
||||
play_context.set_become_plugin(become_loader.get('dzdo'))
|
||||
cmd = play_context.make_become_cmd(cmd=default_cmd, executable=default_exe)
|
||||
assert re.match("""%s %s -p %s -u %s %s -c 'echo %s; %s'""" % (dzdo_exe, dzdo_flags, r'\"\[dzdo via ansible, key=.+?\] password:\"',
|
||||
play_context.become_user, default_exe, success, default_cmd), cmd) is not None
|
39
tests/unit/plugins/become/test_ksu.py
Normal file
39
tests/unit/plugins/become/test_ksu.py
Normal file
|
@ -0,0 +1,39 @@
|
|||
# (c) 2012-2014, Michael DeHaan <michael.dehaan@gmail.com>
|
||||
# (c) 2020 Ansible Project
|
||||
#
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
# Make coding more python3-ish
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
import re
|
||||
|
||||
from ansible import context
|
||||
from ansible.playbook.play_context import PlayContext
|
||||
from ansible.plugins.loader import become_loader
|
||||
|
||||
|
||||
def test_ksu(mocker, parser, reset_cli_args):
|
||||
options = parser.parse_args([])
|
||||
context._init_global_context(options)
|
||||
play_context = PlayContext()
|
||||
|
||||
default_cmd = "/bin/foo"
|
||||
default_exe = "/bin/bash"
|
||||
ksu_exe = 'ksu'
|
||||
ksu_flags = ''
|
||||
|
||||
cmd = play_context.make_become_cmd(cmd=default_cmd, executable=default_exe)
|
||||
assert cmd == default_cmd
|
||||
|
||||
success = 'BECOME-SUCCESS-.+?'
|
||||
|
||||
play_context.become = True
|
||||
play_context.become_user = 'foo'
|
||||
play_context.set_become_plugin(become_loader.get('ksu'))
|
||||
play_context.become_method = 'ksu'
|
||||
play_context.become_flags = ksu_flags
|
||||
cmd = play_context.make_become_cmd(cmd=default_cmd, executable=default_exe)
|
||||
assert (re.match("""%s %s %s -e %s -c 'echo %s; %s'""" % (ksu_exe, play_context.become_user, ksu_flags,
|
||||
default_exe, success, default_cmd), cmd) is not None)
|
39
tests/unit/plugins/become/test_pbrun.py
Normal file
39
tests/unit/plugins/become/test_pbrun.py
Normal file
|
@ -0,0 +1,39 @@
|
|||
# (c) 2012-2014, Michael DeHaan <michael.dehaan@gmail.com>
|
||||
# (c) 2020 Ansible Project
|
||||
#
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
# Make coding more python3-ish
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
import re
|
||||
|
||||
from ansible import context
|
||||
from ansible.playbook.play_context import PlayContext
|
||||
from ansible.plugins.loader import become_loader
|
||||
|
||||
|
||||
def test_pbrun(mocker, parser, reset_cli_args):
|
||||
options = parser.parse_args([])
|
||||
context._init_global_context(options)
|
||||
play_context = PlayContext()
|
||||
|
||||
default_cmd = "/bin/foo"
|
||||
default_exe = "/bin/bash"
|
||||
pbrun_exe = 'pbrun'
|
||||
pbrun_flags = ''
|
||||
|
||||
cmd = play_context.make_become_cmd(cmd=default_cmd, executable=default_exe)
|
||||
assert cmd == default_cmd
|
||||
|
||||
success = 'BECOME-SUCCESS-.+?'
|
||||
|
||||
play_context.become = True
|
||||
play_context.become_user = 'foo'
|
||||
play_context.set_become_plugin(become_loader.get('pbrun'))
|
||||
play_context.become_method = 'pbrun'
|
||||
play_context.become_flags = pbrun_flags
|
||||
cmd = play_context.make_become_cmd(cmd=default_cmd, executable=default_exe)
|
||||
assert re.match("""%s %s -u %s 'echo %s; %s'""" % (pbrun_exe, pbrun_flags, play_context.become_user,
|
||||
success, default_cmd), cmd) is not None
|
38
tests/unit/plugins/become/test_pfexec.py
Normal file
38
tests/unit/plugins/become/test_pfexec.py
Normal file
|
@ -0,0 +1,38 @@
|
|||
# (c) 2012-2014, Michael DeHaan <michael.dehaan@gmail.com>
|
||||
# (c) 2020 Ansible Project
|
||||
#
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
# Make coding more python3-ish
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
import re
|
||||
|
||||
from ansible import context
|
||||
from ansible.playbook.play_context import PlayContext
|
||||
from ansible.plugins.loader import become_loader
|
||||
|
||||
|
||||
def test_pfexec(mocker, parser, reset_cli_args):
|
||||
options = parser.parse_args([])
|
||||
context._init_global_context(options)
|
||||
play_context = PlayContext()
|
||||
|
||||
default_cmd = "/bin/foo"
|
||||
default_exe = "/bin/bash"
|
||||
pfexec_exe = 'pfexec'
|
||||
pfexec_flags = ''
|
||||
|
||||
cmd = play_context.make_become_cmd(cmd=default_cmd, executable=default_exe)
|
||||
assert cmd == default_cmd
|
||||
|
||||
success = 'BECOME-SUCCESS-.+?'
|
||||
|
||||
play_context.become = True
|
||||
play_context.become_user = 'foo'
|
||||
play_context.set_become_plugin(become_loader.get('pfexec'))
|
||||
play_context.become_method = 'pfexec'
|
||||
play_context.become_flags = pfexec_flags
|
||||
cmd = play_context.make_become_cmd(cmd=default_cmd, executable=default_exe)
|
||||
assert re.match('''%s %s "'echo %s; %s'"''' % (pfexec_exe, pfexec_flags, success, default_cmd), cmd) is not None
|
0
tests/unit/plugins/cache/__init__.py
vendored
Normal file
0
tests/unit/plugins/cache/__init__.py
vendored
Normal file
35
tests/unit/plugins/cache/test_memcached.py
vendored
Normal file
35
tests/unit/plugins/cache/test_memcached.py
vendored
Normal file
|
@ -0,0 +1,35 @@
|
|||
# (c) 2012-2015, Michael DeHaan <michael.dehaan@gmail.com>
|
||||
#
|
||||
# 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 pytest
|
||||
|
||||
pytest.importorskip('memcache')
|
||||
|
||||
from ansible.plugins.loader import cache_loader
|
||||
from ansible_collections.community.general.plugins.cache.memcached import CacheModule as MemcachedCache
|
||||
|
||||
|
||||
def test_memcached_cachemodule():
|
||||
assert isinstance(MemcachedCache(), MemcachedCache)
|
||||
|
||||
|
||||
def test_memcached_cachemodule_with_loader():
|
||||
assert isinstance(cache_loader.get('memcached'), MemcachedCache)
|
36
tests/unit/plugins/cache/test_redis.py
vendored
Normal file
36
tests/unit/plugins/cache/test_redis.py
vendored
Normal file
|
@ -0,0 +1,36 @@
|
|||
# (c) 2012-2015, Michael DeHaan <michael.dehaan@gmail.com>
|
||||
#
|
||||
# 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 pytest
|
||||
|
||||
pytest.importorskip('redis')
|
||||
|
||||
from ansible.plugins.loader import cache_loader
|
||||
from ansible_collections.community.general.plugins.cache.redis import CacheModule as RedisCache
|
||||
|
||||
|
||||
def test_redis_cachemodule():
|
||||
assert isinstance(RedisCache(), RedisCache)
|
||||
|
||||
|
||||
def test_redis_cachemodule_with_loader():
|
||||
# The _uri option is required for the redis plugin
|
||||
assert isinstance(cache_loader.get('redis', **{'_uri': '127.0.0.1:6379:1'}), RedisCache)
|
0
tests/unit/plugins/cliconf/__init__.py
Normal file
0
tests/unit/plugins/cliconf/__init__.py
Normal file
0
tests/unit/plugins/cliconf/fixtures/__init__.py
Normal file
0
tests/unit/plugins/cliconf/fixtures/__init__.py
Normal file
54
tests/unit/plugins/cliconf/fixtures/ios/show_version
Normal file
54
tests/unit/plugins/cliconf/fixtures/ios/show_version
Normal file
|
@ -0,0 +1,54 @@
|
|||
Cisco IOS XE Software, Version 16.06.01
|
||||
Cisco IOS Software [Everest], Virtual XE Software (X86_64_LINUX_IOSD-UNIVERSALK9-M), Version 16.6.1, RELEASE SOFTWARE (fc2)
|
||||
Technical Support: http://www.cisco.com/techsupport
|
||||
Copyright (c) 1986-2017 by Cisco Systems, Inc.
|
||||
Compiled Sat 22-Jul-17 05:51 by mcpre
|
||||
|
||||
|
||||
Cisco IOS-XE software, Copyright (c) 2005-2017 by cisco Systems, Inc.
|
||||
All rights reserved. Certain components of Cisco IOS-XE software are
|
||||
licensed under the GNU General Public License ("GPL") Version 2.0. The
|
||||
software code licensed under GPL Version 2.0 is free software that comes
|
||||
with ABSOLUTELY NO WARRANTY. You can redistribute and/or modify such
|
||||
GPL code under the terms of GPL Version 2.0. For more details, see the
|
||||
documentation or "License Notice" file accompanying the IOS-XE software,
|
||||
or the applicable URL provided on the flyer accompanying the IOS-XE
|
||||
software.
|
||||
|
||||
|
||||
ROM: IOS-XE ROMMON
|
||||
|
||||
an-csr-01 uptime is 1 day, 16 hours, 15 minutes
|
||||
Uptime for this control processor is 1 day, 16 hours, 16 minutes
|
||||
System returned to ROM by reload
|
||||
System image file is "bootflash:packages.conf"
|
||||
Last reload reason: Reload Command
|
||||
|
||||
|
||||
|
||||
This product contains cryptographic features and is subject to United
|
||||
States and local country laws governing import, export, transfer and
|
||||
use. Delivery of Cisco cryptographic products does not imply
|
||||
third-party authority to import, export, distribute or use encryption.
|
||||
Importers, exporters, distributors and users are responsible for
|
||||
compliance with U.S. and local country laws. By using this product you
|
||||
agree to comply with applicable laws and regulations. If you are unable
|
||||
to comply with U.S. and local laws, return this product immediately.
|
||||
|
||||
A summary of U.S. laws governing Cisco cryptographic products may be found at:
|
||||
http://www.cisco.com/wwl/export/crypto/tool/stqrg.html
|
||||
|
||||
If you require further assistance please contact us by sending email to
|
||||
export@cisco.com.
|
||||
|
||||
License Level: ax
|
||||
License Type: Default. No valid license found.
|
||||
Next reload license Level: ax
|
||||
|
||||
cisco CSR1000V (VXE) processor (revision VXE) with 1225511K/3075K bytes of memory.
|
||||
Processor board ID 9I5BX4UHSO4
|
||||
3 Gigabit Ethernet interfaces
|
||||
32768K bytes of non-volatile configuration memory.
|
||||
3018776K bytes of physical memory.
|
||||
16162815K bytes of virtual hard disk at bootflash:.
|
||||
0K bytes of WebUI ODM Files at webui:.
|
30
tests/unit/plugins/cliconf/fixtures/nos/show_chassis
Normal file
30
tests/unit/plugins/cliconf/fixtures/nos/show_chassis
Normal file
|
@ -0,0 +1,30 @@
|
|||
|
||||
Chassis Name: BR-VDX6740
|
||||
switchType: 131
|
||||
|
||||
FAN Unit: 1
|
||||
Time Awake: 0 days
|
||||
|
||||
FAN Unit: 2
|
||||
Time Awake: 0 days
|
||||
|
||||
POWER SUPPLY Unit: 1
|
||||
Factory Part Num: 23-1000043-01
|
||||
Factory Serial Num:
|
||||
Time Awake: 0 days
|
||||
|
||||
POWER SUPPLY Unit: 2
|
||||
Factory Part Num: 23-1000043-01
|
||||
Factory Serial Num:
|
||||
Time Awake: 0 days
|
||||
|
||||
CHASSIS/WWN Unit: 1
|
||||
Power Consume Factor: 0
|
||||
Factory Part Num: 40-1000927-06
|
||||
Factory Serial Num: CPL2541K01E
|
||||
Manufacture: Day: 11 Month: 8 Year: 14
|
||||
Update: Day: 18 Month: 7 Year: 2018
|
||||
Time Alive: 1116 days
|
||||
Time Awake: 0 days
|
||||
|
||||
Airflow direction : Port side INTAKE
|
549
tests/unit/plugins/cliconf/fixtures/nos/show_running-config
Normal file
549
tests/unit/plugins/cliconf/fixtures/nos/show_running-config
Normal file
|
@ -0,0 +1,549 @@
|
|||
diag post rbridge-id 104 enable
|
||||
ntp server 10.10.10.1 use-vrf mgmt-vrf
|
||||
logging raslog console INFO
|
||||
logging auditlog class SECURITY
|
||||
logging auditlog class CONFIGURATION
|
||||
logging auditlog class FIRMWARE
|
||||
logging syslog-facility local LOG_LOCAL7
|
||||
logging syslog-client localip CHASSIS_IP
|
||||
switch-attributes 104
|
||||
chassis-name VDX6740
|
||||
host-name LEAF4
|
||||
!
|
||||
no support autoupload enable
|
||||
line vty
|
||||
exec-timeout 10
|
||||
!
|
||||
zoning enabled-configuration cfg-name ""
|
||||
zoning enabled-configuration default-zone-access allaccess
|
||||
zoning enabled-configuration cfg-action cfg-save
|
||||
dpod 104/0/1
|
||||
reserve
|
||||
!
|
||||
dpod 104/0/2
|
||||
!
|
||||
dpod 104/0/3
|
||||
!
|
||||
dpod 104/0/4
|
||||
!
|
||||
dpod 104/0/5
|
||||
!
|
||||
dpod 104/0/6
|
||||
!
|
||||
dpod 104/0/7
|
||||
!
|
||||
dpod 104/0/8
|
||||
!
|
||||
dpod 104/0/9
|
||||
!
|
||||
dpod 104/0/10
|
||||
!
|
||||
dpod 104/0/11
|
||||
!
|
||||
dpod 104/0/12
|
||||
!
|
||||
dpod 104/0/13
|
||||
!
|
||||
dpod 104/0/14
|
||||
!
|
||||
dpod 104/0/15
|
||||
!
|
||||
dpod 104/0/16
|
||||
!
|
||||
dpod 104/0/17
|
||||
!
|
||||
dpod 104/0/18
|
||||
!
|
||||
dpod 104/0/19
|
||||
!
|
||||
dpod 104/0/20
|
||||
!
|
||||
dpod 104/0/21
|
||||
!
|
||||
dpod 104/0/22
|
||||
!
|
||||
dpod 104/0/23
|
||||
!
|
||||
dpod 104/0/24
|
||||
!
|
||||
dpod 104/0/25
|
||||
!
|
||||
dpod 104/0/26
|
||||
!
|
||||
dpod 104/0/27
|
||||
!
|
||||
dpod 104/0/28
|
||||
!
|
||||
dpod 104/0/29
|
||||
!
|
||||
dpod 104/0/30
|
||||
!
|
||||
dpod 104/0/31
|
||||
!
|
||||
dpod 104/0/32
|
||||
!
|
||||
dpod 104/0/33
|
||||
!
|
||||
dpod 104/0/34
|
||||
!
|
||||
dpod 104/0/35
|
||||
!
|
||||
dpod 104/0/36
|
||||
!
|
||||
dpod 104/0/37
|
||||
!
|
||||
dpod 104/0/38
|
||||
!
|
||||
dpod 104/0/39
|
||||
!
|
||||
dpod 104/0/40
|
||||
!
|
||||
dpod 104/0/41
|
||||
!
|
||||
dpod 104/0/42
|
||||
!
|
||||
dpod 104/0/43
|
||||
!
|
||||
dpod 104/0/44
|
||||
!
|
||||
dpod 104/0/45
|
||||
!
|
||||
dpod 104/0/46
|
||||
!
|
||||
dpod 104/0/47
|
||||
!
|
||||
dpod 104/0/48
|
||||
!
|
||||
dpod 104/0/49
|
||||
!
|
||||
dpod 104/0/50
|
||||
!
|
||||
dpod 104/0/51
|
||||
!
|
||||
dpod 104/0/52
|
||||
!
|
||||
role name admin desc Administrator
|
||||
role name user desc User
|
||||
aaa authentication login local
|
||||
aaa accounting exec default start-stop none
|
||||
aaa accounting commands default start-stop none
|
||||
service password-encryption
|
||||
username admin password "BwrsDbB+tABWGWpINOVKoQ==\n" encryption-level 7 role admin desc Administrator
|
||||
username user password "BwrsDbB+tABWGWpINOVKoQ==\n" encryption-level 7 role user desc User
|
||||
ip access-list extended test
|
||||
seq 10 permit ip host 1.1.1.1 any log
|
||||
!
|
||||
snmp-server contact "Field Support."
|
||||
snmp-server location "End User Premise."
|
||||
snmp-server sys-descr "Extreme VDX Switch."
|
||||
snmp-server enable trap
|
||||
snmp-server community private groupname admin
|
||||
snmp-server community public groupname user
|
||||
snmp-server view All 1 included
|
||||
snmp-server group admin v1 read All write All notify All
|
||||
snmp-server group public v1 read All
|
||||
snmp-server group public v2c read All
|
||||
snmp-server group user v1 read All
|
||||
snmp-server group user v2c read All
|
||||
hardware
|
||||
connector-group 104/0/1
|
||||
speed LowMixed
|
||||
!
|
||||
connector-group 104/0/3
|
||||
speed LowMixed
|
||||
!
|
||||
connector-group 104/0/5
|
||||
speed LowMixed
|
||||
!
|
||||
connector-group 104/0/6
|
||||
speed LowMixed
|
||||
!
|
||||
!
|
||||
cee-map default
|
||||
precedence 1
|
||||
priority-group-table 1 weight 40 pfc on
|
||||
priority-group-table 15.0 pfc off
|
||||
priority-group-table 15.1 pfc off
|
||||
priority-group-table 15.2 pfc off
|
||||
priority-group-table 15.3 pfc off
|
||||
priority-group-table 15.4 pfc off
|
||||
priority-group-table 15.5 pfc off
|
||||
priority-group-table 15.6 pfc off
|
||||
priority-group-table 15.7 pfc off
|
||||
priority-group-table 2 weight 60 pfc off
|
||||
priority-table 2 2 2 1 2 2 2 15.0
|
||||
remap fabric-priority priority 0
|
||||
remap lossless-priority priority 0
|
||||
!
|
||||
fcoe
|
||||
fabric-map default
|
||||
vlan 1002
|
||||
san-mode local
|
||||
priority 3
|
||||
virtual-fabric 128
|
||||
fcmap 0E:FC:00
|
||||
advertisement interval 8000
|
||||
keep-alive timeout
|
||||
!
|
||||
!
|
||||
interface Vlan 1
|
||||
!
|
||||
fabric route mcast rbridge-id 104
|
||||
!
|
||||
protocol lldp
|
||||
advertise dcbx-fcoe-app-tlv
|
||||
advertise dcbx-fcoe-logical-link-tlv
|
||||
advertise dcbx-tlv
|
||||
advertise bgp-auto-nbr-tlv
|
||||
advertise optional-tlv management-address
|
||||
advertise optional-tlv system-name
|
||||
system-description Extreme-VDX-VCS 120
|
||||
!
|
||||
vlan dot1q tag native
|
||||
port-profile UpgradedVlanProfile
|
||||
vlan-profile
|
||||
switchport
|
||||
switchport mode trunk
|
||||
switchport trunk allowed vlan all
|
||||
!
|
||||
!
|
||||
port-profile default
|
||||
vlan-profile
|
||||
switchport
|
||||
switchport mode trunk
|
||||
switchport trunk native-vlan 1
|
||||
!
|
||||
!
|
||||
port-profile-domain default
|
||||
port-profile UpgradedVlanProfile
|
||||
!
|
||||
class-map cee
|
||||
!
|
||||
class-map default
|
||||
!
|
||||
rbridge-id 104
|
||||
switch-attributes chassis-name VDX6740
|
||||
switch-attributes host-name LEAF4
|
||||
vrf mgmt-vrf
|
||||
address-family ipv4 unicast
|
||||
ip route 0.0.0.0/0 10.26.0.1
|
||||
!
|
||||
address-family ipv6 unicast
|
||||
!
|
||||
!
|
||||
system-monitor fan threshold marginal-threshold 1 down-threshold 2
|
||||
system-monitor fan alert state removed action raslog
|
||||
system-monitor power threshold marginal-threshold 1 down-threshold 2
|
||||
system-monitor power alert state removed action raslog
|
||||
system-monitor temp threshold marginal-threshold 1 down-threshold 2
|
||||
system-monitor cid-card threshold marginal-threshold 1 down-threshold 2
|
||||
system-monitor cid-card alert state none action none
|
||||
system-monitor sfp alert state none action none
|
||||
system-monitor compact-flash threshold marginal-threshold 1 down-threshold 0
|
||||
system-monitor MM threshold marginal-threshold 1 down-threshold 0
|
||||
system-monitor LineCard threshold marginal-threshold 1 down-threshold 2
|
||||
system-monitor LineCard alert state none action none
|
||||
system-monitor SFM threshold marginal-threshold 1 down-threshold 2
|
||||
resource-monitor cpu enable
|
||||
resource-monitor memory enable threshold 100 action raslog
|
||||
resource-monitor process memory enable alarm 500 critical 600
|
||||
no protocol vrrp
|
||||
no protocol vrrp-extended
|
||||
hardware-profile tcam default
|
||||
hardware-profile route-table default maximum_paths 8 openflow off
|
||||
hardware-profile kap default
|
||||
fabric neighbor-discovery
|
||||
clock timezone America/Los_Angeles
|
||||
ag
|
||||
enable
|
||||
counter reliability 25
|
||||
timeout fnm 120
|
||||
pg 0
|
||||
modes lb
|
||||
rename pg0
|
||||
!
|
||||
!
|
||||
telnet server use-vrf default-vrf
|
||||
telnet server use-vrf mgmt-vrf
|
||||
ssh server key rsa 2048
|
||||
ssh server key ecdsa 256
|
||||
ssh server key dsa
|
||||
ssh server use-vrf default-vrf
|
||||
ssh server use-vrf mgmt-vrf
|
||||
http server use-vrf default-vrf
|
||||
http server use-vrf mgmt-vrf
|
||||
fcoe
|
||||
fcoe-enodes 0
|
||||
!
|
||||
!
|
||||
interface Management 104/0
|
||||
no tcp burstrate
|
||||
ip icmp echo-reply
|
||||
no ip address dhcp
|
||||
ip address 10.26.7.226/17
|
||||
ipv6 icmpv6 echo-reply
|
||||
no ipv6 address autoconfig
|
||||
no ipv6 address dhcp
|
||||
vrf forwarding mgmt-vrf
|
||||
no shutdown
|
||||
!
|
||||
interface TenGigabitEthernet 104/0/1
|
||||
fabric isl enable
|
||||
fabric trunk enable
|
||||
no shutdown
|
||||
!
|
||||
interface TenGigabitEthernet 104/0/2
|
||||
fabric isl enable
|
||||
fabric trunk enable
|
||||
no shutdown
|
||||
!
|
||||
interface TenGigabitEthernet 104/0/3
|
||||
fabric isl enable
|
||||
fabric trunk enable
|
||||
no shutdown
|
||||
!
|
||||
interface TenGigabitEthernet 104/0/4
|
||||
fabric isl enable
|
||||
fabric trunk enable
|
||||
no shutdown
|
||||
!
|
||||
interface TenGigabitEthernet 104/0/5
|
||||
fabric isl enable
|
||||
fabric trunk enable
|
||||
no shutdown
|
||||
!
|
||||
interface TenGigabitEthernet 104/0/6
|
||||
fabric isl enable
|
||||
fabric trunk enable
|
||||
no shutdown
|
||||
!
|
||||
interface TenGigabitEthernet 104/0/7
|
||||
fabric isl enable
|
||||
fabric trunk enable
|
||||
no shutdown
|
||||
!
|
||||
interface TenGigabitEthernet 104/0/8
|
||||
fabric isl enable
|
||||
fabric trunk enable
|
||||
no shutdown
|
||||
!
|
||||
interface TenGigabitEthernet 104/0/9
|
||||
fabric isl enable
|
||||
fabric trunk enable
|
||||
no shutdown
|
||||
!
|
||||
interface TenGigabitEthernet 104/0/10
|
||||
fabric isl enable
|
||||
fabric trunk enable
|
||||
no shutdown
|
||||
!
|
||||
interface TenGigabitEthernet 104/0/11
|
||||
fabric isl enable
|
||||
fabric trunk enable
|
||||
no shutdown
|
||||
!
|
||||
interface TenGigabitEthernet 104/0/12
|
||||
fabric isl enable
|
||||
fabric trunk enable
|
||||
no shutdown
|
||||
!
|
||||
interface TenGigabitEthernet 104/0/13
|
||||
fabric isl enable
|
||||
fabric trunk enable
|
||||
no shutdown
|
||||
!
|
||||
interface TenGigabitEthernet 104/0/14
|
||||
fabric isl enable
|
||||
fabric trunk enable
|
||||
no shutdown
|
||||
!
|
||||
interface TenGigabitEthernet 104/0/15
|
||||
fabric isl enable
|
||||
fabric trunk enable
|
||||
no shutdown
|
||||
!
|
||||
interface TenGigabitEthernet 104/0/16
|
||||
fabric isl enable
|
||||
fabric trunk enable
|
||||
no shutdown
|
||||
!
|
||||
interface TenGigabitEthernet 104/0/17
|
||||
fabric isl enable
|
||||
fabric trunk enable
|
||||
no shutdown
|
||||
!
|
||||
interface TenGigabitEthernet 104/0/18
|
||||
fabric isl enable
|
||||
fabric trunk enable
|
||||
no shutdown
|
||||
!
|
||||
interface TenGigabitEthernet 104/0/19
|
||||
fabric isl enable
|
||||
fabric trunk enable
|
||||
no shutdown
|
||||
!
|
||||
interface TenGigabitEthernet 104/0/20
|
||||
fabric isl enable
|
||||
fabric trunk enable
|
||||
no shutdown
|
||||
!
|
||||
interface TenGigabitEthernet 104/0/21
|
||||
fabric isl enable
|
||||
fabric trunk enable
|
||||
no shutdown
|
||||
!
|
||||
interface TenGigabitEthernet 104/0/22
|
||||
fabric isl enable
|
||||
fabric trunk enable
|
||||
no shutdown
|
||||
!
|
||||
interface TenGigabitEthernet 104/0/23
|
||||
fabric isl enable
|
||||
fabric trunk enable
|
||||
no shutdown
|
||||
!
|
||||
interface TenGigabitEthernet 104/0/24
|
||||
fabric isl enable
|
||||
fabric trunk enable
|
||||
no shutdown
|
||||
!
|
||||
interface TenGigabitEthernet 104/0/25
|
||||
fabric isl enable
|
||||
fabric trunk enable
|
||||
no shutdown
|
||||
!
|
||||
interface TenGigabitEthernet 104/0/26
|
||||
fabric isl enable
|
||||
fabric trunk enable
|
||||
no shutdown
|
||||
!
|
||||
interface TenGigabitEthernet 104/0/27
|
||||
fabric isl enable
|
||||
fabric trunk enable
|
||||
no shutdown
|
||||
!
|
||||
interface TenGigabitEthernet 104/0/28
|
||||
fabric isl enable
|
||||
fabric trunk enable
|
||||
no shutdown
|
||||
!
|
||||
interface TenGigabitEthernet 104/0/29
|
||||
fabric isl enable
|
||||
fabric trunk enable
|
||||
no shutdown
|
||||
!
|
||||
interface TenGigabitEthernet 104/0/30
|
||||
fabric isl enable
|
||||
fabric trunk enable
|
||||
no shutdown
|
||||
!
|
||||
interface TenGigabitEthernet 104/0/31
|
||||
fabric isl enable
|
||||
fabric trunk enable
|
||||
no shutdown
|
||||
!
|
||||
interface TenGigabitEthernet 104/0/32
|
||||
fabric isl enable
|
||||
fabric trunk enable
|
||||
no shutdown
|
||||
!
|
||||
interface TenGigabitEthernet 104/0/33
|
||||
fabric isl enable
|
||||
fabric trunk enable
|
||||
no shutdown
|
||||
!
|
||||
interface TenGigabitEthernet 104/0/34
|
||||
fabric isl enable
|
||||
fabric trunk enable
|
||||
no shutdown
|
||||
!
|
||||
interface TenGigabitEthernet 104/0/35
|
||||
fabric isl enable
|
||||
fabric trunk enable
|
||||
no shutdown
|
||||
!
|
||||
interface TenGigabitEthernet 104/0/36
|
||||
fabric isl enable
|
||||
fabric trunk enable
|
||||
no shutdown
|
||||
!
|
||||
interface TenGigabitEthernet 104/0/37
|
||||
fabric isl enable
|
||||
fabric trunk enable
|
||||
no shutdown
|
||||
!
|
||||
interface TenGigabitEthernet 104/0/38
|
||||
fabric isl enable
|
||||
fabric trunk enable
|
||||
no shutdown
|
||||
!
|
||||
interface TenGigabitEthernet 104/0/39
|
||||
fabric isl enable
|
||||
fabric trunk enable
|
||||
no shutdown
|
||||
!
|
||||
interface TenGigabitEthernet 104/0/40
|
||||
fabric isl enable
|
||||
fabric trunk enable
|
||||
no shutdown
|
||||
!
|
||||
interface TenGigabitEthernet 104/0/41
|
||||
fabric isl enable
|
||||
fabric trunk enable
|
||||
no shutdown
|
||||
!
|
||||
interface TenGigabitEthernet 104/0/42
|
||||
fabric isl enable
|
||||
fabric trunk enable
|
||||
no shutdown
|
||||
!
|
||||
interface TenGigabitEthernet 104/0/43
|
||||
fabric isl enable
|
||||
fabric trunk enable
|
||||
no shutdown
|
||||
!
|
||||
interface TenGigabitEthernet 104/0/44
|
||||
fabric isl enable
|
||||
fabric trunk enable
|
||||
no shutdown
|
||||
!
|
||||
interface TenGigabitEthernet 104/0/45
|
||||
fabric isl enable
|
||||
fabric trunk enable
|
||||
no shutdown
|
||||
!
|
||||
interface TenGigabitEthernet 104/0/46
|
||||
fabric isl enable
|
||||
fabric trunk enable
|
||||
no shutdown
|
||||
!
|
||||
interface TenGigabitEthernet 104/0/47
|
||||
fabric isl enable
|
||||
fabric trunk enable
|
||||
no shutdown
|
||||
!
|
||||
interface TenGigabitEthernet 104/0/48
|
||||
fabric isl enable
|
||||
fabric trunk enable
|
||||
no shutdown
|
||||
!
|
||||
interface FortyGigabitEthernet 104/0/49
|
||||
fabric isl enable
|
||||
fabric trunk enable
|
||||
no shutdown
|
||||
!
|
||||
interface FortyGigabitEthernet 104/0/50
|
||||
fabric isl enable
|
||||
fabric trunk enable
|
||||
no shutdown
|
||||
!
|
||||
interface FortyGigabitEthernet 104/0/51
|
||||
fabric isl enable
|
||||
fabric trunk enable
|
||||
no shutdown
|
||||
!
|
||||
interface FortyGigabitEthernet 104/0/52
|
||||
fabric isl enable
|
||||
fabric trunk enable
|
||||
no shutdown
|
||||
!
|
17
tests/unit/plugins/cliconf/fixtures/nos/show_version
Normal file
17
tests/unit/plugins/cliconf/fixtures/nos/show_version
Normal file
|
@ -0,0 +1,17 @@
|
|||
Network Operating System Software
|
||||
Network Operating System Version: 7.2.0
|
||||
Copyright (c) 1995-2017 Brocade Communications Systems, Inc.
|
||||
Firmware name: 7.2.0
|
||||
Build Time: 10:52:47 Jul 10, 2017
|
||||
Install Time: 01:32:03 Jan 5, 2018
|
||||
Kernel: 2.6.34.6
|
||||
|
||||
BootProm: 1.0.1
|
||||
Control Processor: e500mc with 4096 MB of memory
|
||||
|
||||
Slot Name Primary/Secondary Versions Status
|
||||
---------------------------------------------------------------------------
|
||||
SW/0 NOS 7.2.0 ACTIVE*
|
||||
7.2.0
|
||||
SW/1 NOS 7.2.0 STANDBY
|
||||
7.2.0
|
40
tests/unit/plugins/cliconf/fixtures/slxos/show_chassis
Normal file
40
tests/unit/plugins/cliconf/fixtures/slxos/show_chassis
Normal file
|
@ -0,0 +1,40 @@
|
|||
|
||||
Chassis Name: BR-SLX9140
|
||||
switchType: 3001
|
||||
|
||||
FAN Unit: 1
|
||||
Time Awake: 36 days
|
||||
|
||||
FAN Unit: 2
|
||||
Time Awake: 36 days
|
||||
|
||||
FAN Unit: 3
|
||||
Time Awake: 36 days
|
||||
|
||||
FAN Unit: 5
|
||||
Time Awake: 36 days
|
||||
|
||||
FAN Unit: 6
|
||||
Time Awake: 36 days
|
||||
|
||||
POWER SUPPLY Unit: 1
|
||||
Factory Part Num: 11-1111111-11
|
||||
Factory Serial Num: ASERIALNUMB
|
||||
Time Awake: 36 days
|
||||
|
||||
POWER SUPPLY Unit: 2
|
||||
Factory Part Num: 11-1111111-11
|
||||
Factory Serial Num: ASERIALNUMB
|
||||
Time Awake: 36 days
|
||||
|
||||
CHASSIS/WWN Unit: 1
|
||||
Power Consume Factor: 0
|
||||
Factory Part Num: 11-1111111-11
|
||||
Factory Serial Num: ASERIALNUMB
|
||||
Manufacture: Day: 12 Month: 1 Year: 2017
|
||||
Update: Day: 5 Month: 4 Year: 2018
|
||||
Time Alive: 277 days
|
||||
Time Awake: 36 days
|
||||
|
||||
Airflow direction : Port side INTAKE
|
||||
|
624
tests/unit/plugins/cliconf/fixtures/slxos/show_running-config
Normal file
624
tests/unit/plugins/cliconf/fixtures/slxos/show_running-config
Normal file
|
@ -0,0 +1,624 @@
|
|||
root enable
|
||||
host-table aging-mode conversational
|
||||
clock timezone Europe/Warsaw
|
||||
hardware
|
||||
profile tcam default
|
||||
profile overlay-visibility default
|
||||
profile route-table default maximum_paths 8
|
||||
system-mode default
|
||||
!
|
||||
http server use-vrf default-vrf
|
||||
http server use-vrf mgmt-vrf
|
||||
node-id 1
|
||||
!
|
||||
ntp server 172.16.10.2 use-vrf mgmt-vrf
|
||||
!
|
||||
logging raslog console INFO
|
||||
logging syslog-server 10.1.5.11 use-vrf mgmt-vrf
|
||||
!
|
||||
logging auditlog class SECURITY
|
||||
logging auditlog class CONFIGURATION
|
||||
logging auditlog class FIRMWARE
|
||||
logging syslog-facility local LOG_LOCAL0
|
||||
logging syslog-client localip CHASSIS_IP
|
||||
switch-attributes chassis-name SLX9140-LEAF2
|
||||
switch-attributes host-name DC2LEAF2
|
||||
no support autoupload enable
|
||||
support ffdc
|
||||
resource-monitor cpu enable threshold 90 action raslog
|
||||
resource-monitor memory enable threshold 100 action raslog
|
||||
resource-monitor process memory enable alarm 1000 critical 1200
|
||||
system-monitor fan threshold marginal-threshold 1 down-threshold 2
|
||||
system-monitor fan alert state removed action raslog
|
||||
system-monitor power threshold marginal-threshold 1 down-threshold 2
|
||||
system-monitor power alert state removed action raslog
|
||||
system-monitor temp threshold marginal-threshold 1 down-threshold 2
|
||||
system-monitor cid-card threshold marginal-threshold 1 down-threshold 2
|
||||
system-monitor cid-card alert state none action none
|
||||
system-monitor compact-flash threshold marginal-threshold 1 down-threshold 0
|
||||
system-monitor MM threshold marginal-threshold 1 down-threshold 0
|
||||
system-monitor LineCard threshold marginal-threshold 1 down-threshold 2
|
||||
system-monitor LineCard alert state none action none
|
||||
system-monitor SFM threshold marginal-threshold 1 down-threshold 2
|
||||
telemetry server use-vrf mgmt-vrf
|
||||
transport tcp
|
||||
port 50051
|
||||
activate
|
||||
!
|
||||
telemetry profile system-utilization default_system_utilization_statistics
|
||||
interval 60
|
||||
add total-system-memory
|
||||
add total-used-memory
|
||||
add total-free-memory
|
||||
add cached-memory
|
||||
add buffers
|
||||
add user-free-memory
|
||||
add kernel-free-memory
|
||||
add total-swap-memory
|
||||
add total-free-swap-memory
|
||||
add total-used-swap-memory
|
||||
add user-process
|
||||
add system-process
|
||||
add niced-process
|
||||
add iowait
|
||||
add hw-interrupt
|
||||
add sw-interrupt
|
||||
add idle-state
|
||||
add steal-time
|
||||
add uptime
|
||||
!
|
||||
telemetry profile interface default_interface_statistics
|
||||
interval 30
|
||||
add out-pkts
|
||||
add in-pkts
|
||||
add out-unicast-pkts
|
||||
add in-unicast-pkts
|
||||
add out-broadcast-pkts
|
||||
add in-broadcast-pkts
|
||||
add out-multicast-pkts
|
||||
add in-multicast-pkts
|
||||
add out-pkts-per-second
|
||||
add in-pkts-per-second
|
||||
add out-bandwidth
|
||||
add in-bandwidth
|
||||
add out-octets
|
||||
add in-octets
|
||||
add out-errors
|
||||
add in-errors
|
||||
add out-crc-errors
|
||||
add in-crc-errors
|
||||
add out-discards
|
||||
add in-discards
|
||||
!
|
||||
line vty
|
||||
exec-timeout 10
|
||||
!
|
||||
threshold-monitor Buffer limit 70
|
||||
vrf mgmt-vrf
|
||||
address-family ipv4 unicast
|
||||
ip route 0.0.0.0/0 172.168.192.1
|
||||
!
|
||||
address-family ipv6 unicast
|
||||
!
|
||||
!
|
||||
ssh server key rsa 2048
|
||||
ssh server key ecdsa 256
|
||||
ssh server key dsa
|
||||
ssh server use-vrf default-vrf
|
||||
ssh server use-vrf mgmt-vrf
|
||||
telnet server use-vrf default-vrf
|
||||
telnet server use-vrf mgmt-vrf
|
||||
role name admin desc Administrator
|
||||
role name user desc User
|
||||
aaa authentication login local
|
||||
aaa accounting exec default start-stop none
|
||||
aaa accounting commands default start-stop none
|
||||
service password-encryption
|
||||
username admin password "AINTNOPARTYLIKEAHOTELPARTYCAUSEAHOTELPARTYDONTSLEEPNOONEWOULDEVERACTUALLYTYPETHISWHYAREYOUHERE\n" encryption-level 7 role admin desc Administrator
|
||||
cee-map default
|
||||
precedence 1
|
||||
priority-group-table 1 weight 40 pfc on
|
||||
priority-group-table 15.0 pfc off
|
||||
priority-group-table 15.1 pfc off
|
||||
priority-group-table 15.2 pfc off
|
||||
priority-group-table 15.3 pfc off
|
||||
priority-group-table 15.4 pfc off
|
||||
priority-group-table 15.5 pfc off
|
||||
priority-group-table 15.6 pfc off
|
||||
priority-group-table 15.7 pfc off
|
||||
priority-group-table 2 weight 60 pfc off
|
||||
priority-table 2 2 2 1 2 2 2 15.0
|
||||
remap lossless-priority priority 0
|
||||
!
|
||||
mac access-list extended M1
|
||||
seq 10 permit any any
|
||||
!
|
||||
vlan 1
|
||||
ip igmp snooping startup-query-interval 100
|
||||
ipv6 mld snooping startup-query-interval 100
|
||||
!
|
||||
vlan 100
|
||||
!
|
||||
vlan 200
|
||||
!
|
||||
vlan 1001
|
||||
router-interface Ve 1001
|
||||
description Thomas-Test-Cluster
|
||||
!
|
||||
qos map cos-mutation all-zero-map
|
||||
map cos 0 to cos 0
|
||||
map cos 1 to cos 0
|
||||
map cos 2 to cos 0
|
||||
map cos 3 to cos 0
|
||||
map cos 4 to cos 0
|
||||
map cos 5 to cos 0
|
||||
map cos 6 to cos 0
|
||||
map cos 7 to cos 0
|
||||
!
|
||||
qos map cos-mutation default
|
||||
map cos 0 to cos 0
|
||||
map cos 1 to cos 1
|
||||
map cos 2 to cos 2
|
||||
map cos 3 to cos 3
|
||||
map cos 4 to cos 4
|
||||
map cos 5 to cos 5
|
||||
map cos 6 to cos 6
|
||||
map cos 7 to cos 7
|
||||
!
|
||||
qos map cos-traffic-class all-zero-map
|
||||
map cos 0 to traffic-class 0
|
||||
map cos 1 to traffic-class 0
|
||||
map cos 2 to traffic-class 0
|
||||
map cos 3 to traffic-class 0
|
||||
map cos 4 to traffic-class 0
|
||||
map cos 5 to traffic-class 0
|
||||
map cos 6 to traffic-class 0
|
||||
map cos 7 to traffic-class 0
|
||||
!
|
||||
qos map cos-traffic-class default
|
||||
map cos 0 to traffic-class 1
|
||||
map cos 1 to traffic-class 0
|
||||
map cos 2 to traffic-class 2
|
||||
map cos 3 to traffic-class 3
|
||||
map cos 4 to traffic-class 4
|
||||
map cos 5 to traffic-class 5
|
||||
map cos 6 to traffic-class 6
|
||||
map cos 7 to traffic-class 7
|
||||
!
|
||||
qos map cos-dscp all-zero-map
|
||||
map cos 0 to dscp 0
|
||||
map cos 1 to dscp 0
|
||||
map cos 2 to dscp 0
|
||||
map cos 3 to dscp 0
|
||||
map cos 4 to dscp 0
|
||||
map cos 5 to dscp 0
|
||||
map cos 6 to dscp 0
|
||||
map cos 7 to dscp 0
|
||||
!
|
||||
qos map cos-dscp default
|
||||
map cos 0 to dscp 0
|
||||
map cos 1 to dscp 8
|
||||
map cos 2 to dscp 16
|
||||
map cos 3 to dscp 24
|
||||
map cos 4 to dscp 32
|
||||
map cos 5 to dscp 40
|
||||
map cos 6 to dscp 48
|
||||
map cos 7 to dscp 56
|
||||
!
|
||||
qos map traffic-class-cos all-zero-map
|
||||
map traffic-class 0 to cos 0
|
||||
map traffic-class 1 to cos 0
|
||||
map traffic-class 2 to cos 0
|
||||
map traffic-class 3 to cos 0
|
||||
map traffic-class 4 to cos 0
|
||||
map traffic-class 5 to cos 0
|
||||
map traffic-class 6 to cos 0
|
||||
map traffic-class 7 to cos 0
|
||||
!
|
||||
qos map traffic-class-cos default
|
||||
map traffic-class 0 to cos 0
|
||||
map traffic-class 1 to cos 1
|
||||
map traffic-class 2 to cos 2
|
||||
map traffic-class 3 to cos 3
|
||||
map traffic-class 4 to cos 4
|
||||
map traffic-class 5 to cos 5
|
||||
map traffic-class 6 to cos 6
|
||||
map traffic-class 7 to cos 7
|
||||
!
|
||||
qos map traffic-class-mutation all-zero-map
|
||||
map traffic-class 0 to traffic-class 0
|
||||
map traffic-class 1 to traffic-class 0
|
||||
map traffic-class 2 to traffic-class 0
|
||||
map traffic-class 3 to traffic-class 0
|
||||
map traffic-class 4 to traffic-class 0
|
||||
map traffic-class 5 to traffic-class 0
|
||||
map traffic-class 6 to traffic-class 0
|
||||
map traffic-class 7 to traffic-class 0
|
||||
!
|
||||
qos map traffic-class-mutation default
|
||||
map traffic-class 0 to traffic-class 0
|
||||
map traffic-class 1 to traffic-class 1
|
||||
map traffic-class 2 to traffic-class 2
|
||||
map traffic-class 3 to traffic-class 3
|
||||
map traffic-class 4 to traffic-class 4
|
||||
map traffic-class 5 to traffic-class 5
|
||||
map traffic-class 6 to traffic-class 6
|
||||
map traffic-class 7 to traffic-class 7
|
||||
!
|
||||
qos map traffic-class-dscp all-zero-map
|
||||
map traffic-class 0 to dscp 0
|
||||
map traffic-class 1 to dscp 0
|
||||
map traffic-class 2 to dscp 0
|
||||
map traffic-class 3 to dscp 0
|
||||
map traffic-class 4 to dscp 0
|
||||
map traffic-class 5 to dscp 0
|
||||
map traffic-class 6 to dscp 0
|
||||
map traffic-class 7 to dscp 0
|
||||
!
|
||||
qos map traffic-class-dscp default
|
||||
map traffic-class 0 to dscp 0
|
||||
map traffic-class 1 to dscp 8
|
||||
map traffic-class 2 to dscp 16
|
||||
map traffic-class 3 to dscp 24
|
||||
map traffic-class 4 to dscp 32
|
||||
map traffic-class 5 to dscp 40
|
||||
map traffic-class 6 to dscp 48
|
||||
map traffic-class 7 to dscp 56
|
||||
!
|
||||
qos map dscp-mutation all-zero-map
|
||||
map dscp 0-63 to dscp 0
|
||||
!
|
||||
qos map dscp-mutation default
|
||||
map dscp 0 to dscp 0
|
||||
map dscp 1 to dscp 1
|
||||
map dscp 10 to dscp 10
|
||||
map dscp 11 to dscp 11
|
||||
map dscp 12 to dscp 12
|
||||
map dscp 13 to dscp 13
|
||||
map dscp 14 to dscp 14
|
||||
map dscp 15 to dscp 15
|
||||
map dscp 16 to dscp 16
|
||||
map dscp 17 to dscp 17
|
||||
map dscp 18 to dscp 18
|
||||
map dscp 19 to dscp 19
|
||||
map dscp 2 to dscp 2
|
||||
map dscp 20 to dscp 20
|
||||
map dscp 21 to dscp 21
|
||||
map dscp 22 to dscp 22
|
||||
map dscp 23 to dscp 23
|
||||
map dscp 24 to dscp 24
|
||||
map dscp 25 to dscp 25
|
||||
map dscp 26 to dscp 26
|
||||
map dscp 27 to dscp 27
|
||||
map dscp 28 to dscp 28
|
||||
map dscp 29 to dscp 29
|
||||
map dscp 3 to dscp 3
|
||||
map dscp 30 to dscp 30
|
||||
map dscp 31 to dscp 31
|
||||
map dscp 32 to dscp 32
|
||||
map dscp 33 to dscp 33
|
||||
map dscp 34 to dscp 34
|
||||
map dscp 35 to dscp 35
|
||||
map dscp 36 to dscp 36
|
||||
map dscp 37 to dscp 37
|
||||
map dscp 38 to dscp 38
|
||||
map dscp 39 to dscp 39
|
||||
map dscp 4 to dscp 4
|
||||
map dscp 40 to dscp 40
|
||||
map dscp 41 to dscp 41
|
||||
map dscp 42 to dscp 42
|
||||
map dscp 43 to dscp 43
|
||||
map dscp 44 to dscp 44
|
||||
map dscp 45 to dscp 45
|
||||
map dscp 46 to dscp 46
|
||||
map dscp 47 to dscp 47
|
||||
map dscp 48 to dscp 48
|
||||
map dscp 49 to dscp 49
|
||||
map dscp 5 to dscp 5
|
||||
map dscp 50 to dscp 50
|
||||
map dscp 51 to dscp 51
|
||||
map dscp 52 to dscp 52
|
||||
map dscp 53 to dscp 53
|
||||
map dscp 54 to dscp 54
|
||||
map dscp 55 to dscp 55
|
||||
map dscp 56 to dscp 56
|
||||
map dscp 57 to dscp 57
|
||||
map dscp 58 to dscp 58
|
||||
map dscp 59 to dscp 59
|
||||
map dscp 6 to dscp 6
|
||||
map dscp 60 to dscp 60
|
||||
map dscp 61 to dscp 61
|
||||
map dscp 62 to dscp 62
|
||||
map dscp 63 to dscp 63
|
||||
map dscp 7 to dscp 7
|
||||
map dscp 8 to dscp 8
|
||||
map dscp 9 to dscp 9
|
||||
!
|
||||
qos map dscp-traffic-class all-zero-map
|
||||
map dscp 0-63 to traffic-class 0
|
||||
!
|
||||
qos map dscp-traffic-class default
|
||||
map dscp 0-7 to traffic-class 0
|
||||
map dscp 16-23 to traffic-class 2
|
||||
map dscp 24-31 to traffic-class 3
|
||||
map dscp 32-39 to traffic-class 4
|
||||
map dscp 40-47 to traffic-class 5
|
||||
map dscp 48-55 to traffic-class 6
|
||||
map dscp 56-63 to traffic-class 7
|
||||
map dscp 8-15 to traffic-class 1
|
||||
!
|
||||
qos map dscp-cos all-zero-map
|
||||
map dscp 0-63 to cos 0
|
||||
!
|
||||
qos map dscp-cos default
|
||||
map dscp 0-7 to cos 0
|
||||
map dscp 16-23 to cos 2
|
||||
map dscp 24-31 to cos 3
|
||||
map dscp 32-39 to cos 4
|
||||
map dscp 40-47 to cos 5
|
||||
map dscp 48-55 to cos 6
|
||||
map dscp 56-63 to cos 7
|
||||
map dscp 8-15 to cos 1
|
||||
!
|
||||
protocol lldp
|
||||
advertise optional-tlv management-address
|
||||
system-description Brocade BR-SLX9140 Router
|
||||
!
|
||||
vlan dot1q tag native
|
||||
police-remark-profile default
|
||||
!
|
||||
class-map BD-100
|
||||
!
|
||||
class-map C1
|
||||
match access-group M1
|
||||
!
|
||||
class-map cee
|
||||
!
|
||||
class-map default
|
||||
!
|
||||
policy-map P1
|
||||
class C1
|
||||
police cir 1000000
|
||||
!
|
||||
!
|
||||
policy-map P2
|
||||
class default
|
||||
police cir 12121212
|
||||
!
|
||||
!
|
||||
no protocol vrrp
|
||||
no protocol vrrp-extended
|
||||
router bgp
|
||||
local-as 65301
|
||||
capability as4-enable
|
||||
bfd interval 300 min-rx 300 multiplier 3
|
||||
neighbor leaf_group peer-group
|
||||
neighbor leaf_group remote-as 65500
|
||||
neighbor leaf_group bfd
|
||||
neighbor 10.220.4.3 remote-as 65500
|
||||
neighbor 10.220.4.3 peer-group leaf_group
|
||||
address-family ipv4 unicast
|
||||
network 172.32.252.5/32
|
||||
maximum-paths 8
|
||||
!
|
||||
address-family ipv6 unicast
|
||||
!
|
||||
address-family l2vpn evpn
|
||||
!
|
||||
!
|
||||
interface Loopback 1
|
||||
ip address 172.16.128.6/32
|
||||
no shutdown
|
||||
!
|
||||
interface Loopback 2
|
||||
ip address 172.16.129.5/32
|
||||
no shutdown
|
||||
!
|
||||
interface Management 0
|
||||
no tcp burstrate
|
||||
no shutdown
|
||||
vrf forwarding mgmt-vrf
|
||||
ip address dhcp
|
||||
!
|
||||
interface Ethernet 0/1
|
||||
speed 25000
|
||||
fec mode disabled
|
||||
switchport
|
||||
switchport mode access
|
||||
switchport access vlan 1
|
||||
no shutdown
|
||||
!
|
||||
interface Ethernet 0/2
|
||||
no shutdown
|
||||
!
|
||||
interface Ethernet 0/3
|
||||
speed 25000
|
||||
fec mode RS-FEC
|
||||
no shutdown
|
||||
!
|
||||
interface Ethernet 0/4
|
||||
shutdown
|
||||
!
|
||||
interface Ethernet 0/5
|
||||
service-policy in P1
|
||||
no shutdown
|
||||
!
|
||||
interface Ethernet 0/6
|
||||
mtu 1548
|
||||
description L2 Interface
|
||||
no shutdown
|
||||
!
|
||||
interface Ethernet 0/7
|
||||
mtu 1548
|
||||
description L2 Interface
|
||||
no shutdown
|
||||
!
|
||||
interface Ethernet 0/8
|
||||
switchport
|
||||
switchport mode trunk
|
||||
switchport trunk allowed vlan add 100,200
|
||||
switchport trunk tag native-vlan
|
||||
shutdown
|
||||
!
|
||||
interface Ethernet 0/9
|
||||
shutdown
|
||||
!
|
||||
interface Ethernet 0/10
|
||||
no shutdown
|
||||
!
|
||||
interface Ethernet 0/11
|
||||
no shutdown
|
||||
!
|
||||
interface Ethernet 0/12
|
||||
no shutdown
|
||||
!
|
||||
interface Ethernet 0/13
|
||||
no shutdown
|
||||
!
|
||||
interface Ethernet 0/14
|
||||
no shutdown
|
||||
!
|
||||
interface Ethernet 0/15
|
||||
shutdown
|
||||
!
|
||||
interface Ethernet 0/16
|
||||
shutdown
|
||||
!
|
||||
interface Ethernet 0/17
|
||||
shutdown
|
||||
!
|
||||
interface Ethernet 0/18
|
||||
shutdown
|
||||
!
|
||||
interface Ethernet 0/19
|
||||
shutdown
|
||||
!
|
||||
interface Ethernet 0/20
|
||||
shutdown
|
||||
!
|
||||
interface Ethernet 0/21
|
||||
shutdown
|
||||
!
|
||||
interface Ethernet 0/22
|
||||
shutdown
|
||||
!
|
||||
interface Ethernet 0/23
|
||||
shutdown
|
||||
!
|
||||
interface Ethernet 0/24
|
||||
shutdown
|
||||
!
|
||||
interface Ethernet 0/25
|
||||
shutdown
|
||||
!
|
||||
interface Ethernet 0/26
|
||||
shutdown
|
||||
!
|
||||
interface Ethernet 0/27
|
||||
shutdown
|
||||
!
|
||||
interface Ethernet 0/28
|
||||
shutdown
|
||||
!
|
||||
interface Ethernet 0/29
|
||||
shutdown
|
||||
!
|
||||
interface Ethernet 0/30
|
||||
shutdown
|
||||
!
|
||||
interface Ethernet 0/31
|
||||
shutdown
|
||||
!
|
||||
interface Ethernet 0/32
|
||||
shutdown
|
||||
!
|
||||
interface Ethernet 0/33
|
||||
shutdown
|
||||
!
|
||||
interface Ethernet 0/34
|
||||
shutdown
|
||||
!
|
||||
interface Ethernet 0/35
|
||||
shutdown
|
||||
!
|
||||
interface Ethernet 0/36
|
||||
shutdown
|
||||
!
|
||||
interface Ethernet 0/37
|
||||
shutdown
|
||||
!
|
||||
interface Ethernet 0/38
|
||||
shutdown
|
||||
!
|
||||
interface Ethernet 0/39
|
||||
shutdown
|
||||
!
|
||||
interface Ethernet 0/40
|
||||
shutdown
|
||||
!
|
||||
interface Ethernet 0/41
|
||||
shutdown
|
||||
!
|
||||
interface Ethernet 0/42
|
||||
shutdown
|
||||
!
|
||||
interface Ethernet 0/43
|
||||
shutdown
|
||||
!
|
||||
interface Ethernet 0/44
|
||||
shutdown
|
||||
!
|
||||
interface Ethernet 0/45
|
||||
shutdown
|
||||
!
|
||||
interface Ethernet 0/46
|
||||
shutdown
|
||||
!
|
||||
interface Ethernet 0/47
|
||||
shutdown
|
||||
!
|
||||
interface Ethernet 0/48
|
||||
shutdown
|
||||
!
|
||||
interface Ethernet 0/49
|
||||
shutdown
|
||||
!
|
||||
interface Ethernet 0/50
|
||||
fec mode RS-FEC
|
||||
no shutdown
|
||||
!
|
||||
interface Ethernet 0/51
|
||||
fec mode RS-FEC
|
||||
no shutdown
|
||||
!
|
||||
interface Ethernet 0/52
|
||||
fec mode RS-FEC
|
||||
no shutdown
|
||||
!
|
||||
interface Ethernet 0/53
|
||||
fec mode RS-FEC
|
||||
no shutdown
|
||||
!
|
||||
interface Ethernet 0/54
|
||||
fec mode disabled
|
||||
no shutdown
|
||||
!
|
||||
interface Port-channel 200
|
||||
switchport
|
||||
switchport mode access
|
||||
switchport access vlan 200
|
||||
shutdown
|
||||
!
|
||||
interface Port-channel 1024
|
||||
insight enable
|
||||
no shutdown
|
||||
!
|
||||
monitor session 1
|
||||
source ethernet 0/1 destination port-channel 1024 direction both
|
||||
!
|
||||
monitor session 2
|
||||
!
|
||||
bridge-domain 100 p2mp
|
||||
!
|
||||
cluster MCT1 1
|
||||
!
|
624
tests/unit/plugins/cliconf/fixtures/slxos/show_startup-config
Normal file
624
tests/unit/plugins/cliconf/fixtures/slxos/show_startup-config
Normal file
|
@ -0,0 +1,624 @@
|
|||
root enable
|
||||
host-table aging-mode conversational
|
||||
clock timezone Europe/Warsaw
|
||||
hardware
|
||||
profile tcam default
|
||||
profile overlay-visibility default
|
||||
profile route-table default maximum_paths 8
|
||||
system-mode default
|
||||
!
|
||||
http server use-vrf default-vrf
|
||||
http server use-vrf mgmt-vrf
|
||||
node-id 1
|
||||
!
|
||||
ntp server 172.16.10.2 use-vrf mgmt-vrf
|
||||
!
|
||||
logging raslog console INFO
|
||||
logging syslog-server 10.1.5.11 use-vrf mgmt-vrf
|
||||
!
|
||||
logging auditlog class SECURITY
|
||||
logging auditlog class CONFIGURATION
|
||||
logging auditlog class FIRMWARE
|
||||
logging syslog-facility local LOG_LOCAL0
|
||||
logging syslog-client localip CHASSIS_IP
|
||||
switch-attributes chassis-name SLX9140-LEAF2
|
||||
switch-attributes host-name DC2LEAF2
|
||||
no support autoupload enable
|
||||
support ffdc
|
||||
resource-monitor cpu enable threshold 90 action raslog
|
||||
resource-monitor memory enable threshold 100 action raslog
|
||||
resource-monitor process memory enable alarm 1000 critical 1200
|
||||
system-monitor fan threshold marginal-threshold 1 down-threshold 2
|
||||
system-monitor fan alert state removed action raslog
|
||||
system-monitor power threshold marginal-threshold 1 down-threshold 2
|
||||
system-monitor power alert state removed action raslog
|
||||
system-monitor temp threshold marginal-threshold 1 down-threshold 2
|
||||
system-monitor cid-card threshold marginal-threshold 1 down-threshold 2
|
||||
system-monitor cid-card alert state none action none
|
||||
system-monitor compact-flash threshold marginal-threshold 1 down-threshold 0
|
||||
system-monitor MM threshold marginal-threshold 1 down-threshold 0
|
||||
system-monitor LineCard threshold marginal-threshold 1 down-threshold 2
|
||||
system-monitor LineCard alert state none action none
|
||||
system-monitor SFM threshold marginal-threshold 1 down-threshold 2
|
||||
telemetry server use-vrf mgmt-vrf
|
||||
transport tcp
|
||||
port 50051
|
||||
activate
|
||||
!
|
||||
telemetry profile system-utilization default_system_utilization_statistics
|
||||
interval 60
|
||||
add total-system-memory
|
||||
add total-used-memory
|
||||
add total-free-memory
|
||||
add cached-memory
|
||||
add buffers
|
||||
add user-free-memory
|
||||
add kernel-free-memory
|
||||
add total-swap-memory
|
||||
add total-free-swap-memory
|
||||
add total-used-swap-memory
|
||||
add user-process
|
||||
add system-process
|
||||
add niced-process
|
||||
add iowait
|
||||
add hw-interrupt
|
||||
add sw-interrupt
|
||||
add idle-state
|
||||
add steal-time
|
||||
add uptime
|
||||
!
|
||||
telemetry profile interface default_interface_statistics
|
||||
interval 30
|
||||
add out-pkts
|
||||
add in-pkts
|
||||
add out-unicast-pkts
|
||||
add in-unicast-pkts
|
||||
add out-broadcast-pkts
|
||||
add in-broadcast-pkts
|
||||
add out-multicast-pkts
|
||||
add in-multicast-pkts
|
||||
add out-pkts-per-second
|
||||
add in-pkts-per-second
|
||||
add out-bandwidth
|
||||
add in-bandwidth
|
||||
add out-octets
|
||||
add in-octets
|
||||
add out-errors
|
||||
add in-errors
|
||||
add out-crc-errors
|
||||
add in-crc-errors
|
||||
add out-discards
|
||||
add in-discards
|
||||
!
|
||||
line vty
|
||||
exec-timeout 10
|
||||
!
|
||||
threshold-monitor Buffer limit 70
|
||||
vrf mgmt-vrf
|
||||
address-family ipv4 unicast
|
||||
ip route 0.0.0.0/0 172.168.192.1
|
||||
!
|
||||
address-family ipv6 unicast
|
||||
!
|
||||
!
|
||||
ssh server key rsa 2048
|
||||
ssh server key ecdsa 256
|
||||
ssh server key dsa
|
||||
ssh server use-vrf default-vrf
|
||||
ssh server use-vrf mgmt-vrf
|
||||
telnet server use-vrf default-vrf
|
||||
telnet server use-vrf mgmt-vrf
|
||||
role name admin desc Administrator
|
||||
role name user desc User
|
||||
aaa authentication login local
|
||||
aaa accounting exec default start-stop none
|
||||
aaa accounting commands default start-stop none
|
||||
service password-encryption
|
||||
username admin password "AINTNOPARTYLIKEAHOTELPARTYCAUSEAHOTELPARTYDONTSLEEPNOONEWOULDEVERACTUALLYTYPETHISWHYAREYOUHERE\n" encryption-level 7 role admin desc Administrator
|
||||
cee-map default
|
||||
precedence 1
|
||||
priority-group-table 1 weight 40 pfc on
|
||||
priority-group-table 15.0 pfc off
|
||||
priority-group-table 15.1 pfc off
|
||||
priority-group-table 15.2 pfc off
|
||||
priority-group-table 15.3 pfc off
|
||||
priority-group-table 15.4 pfc off
|
||||
priority-group-table 15.5 pfc off
|
||||
priority-group-table 15.6 pfc off
|
||||
priority-group-table 15.7 pfc off
|
||||
priority-group-table 2 weight 60 pfc off
|
||||
priority-table 2 2 2 1 2 2 2 15.0
|
||||
remap lossless-priority priority 0
|
||||
!
|
||||
mac access-list extended M1
|
||||
seq 10 permit any any
|
||||
!
|
||||
vlan 1
|
||||
ip igmp snooping startup-query-interval 100
|
||||
ipv6 mld snooping startup-query-interval 100
|
||||
!
|
||||
vlan 100
|
||||
!
|
||||
vlan 200
|
||||
!
|
||||
vlan 1001
|
||||
router-interface Ve 1001
|
||||
description Thomas-Test-Cluster
|
||||
!
|
||||
qos map cos-mutation all-zero-map
|
||||
map cos 0 to cos 0
|
||||
map cos 1 to cos 0
|
||||
map cos 2 to cos 0
|
||||
map cos 3 to cos 0
|
||||
map cos 4 to cos 0
|
||||
map cos 5 to cos 0
|
||||
map cos 6 to cos 0
|
||||
map cos 7 to cos 0
|
||||
!
|
||||
qos map cos-mutation default
|
||||
map cos 0 to cos 0
|
||||
map cos 1 to cos 1
|
||||
map cos 2 to cos 2
|
||||
map cos 3 to cos 3
|
||||
map cos 4 to cos 4
|
||||
map cos 5 to cos 5
|
||||
map cos 6 to cos 6
|
||||
map cos 7 to cos 7
|
||||
!
|
||||
qos map cos-traffic-class all-zero-map
|
||||
map cos 0 to traffic-class 0
|
||||
map cos 1 to traffic-class 0
|
||||
map cos 2 to traffic-class 0
|
||||
map cos 3 to traffic-class 0
|
||||
map cos 4 to traffic-class 0
|
||||
map cos 5 to traffic-class 0
|
||||
map cos 6 to traffic-class 0
|
||||
map cos 7 to traffic-class 0
|
||||
!
|
||||
qos map cos-traffic-class default
|
||||
map cos 0 to traffic-class 1
|
||||
map cos 1 to traffic-class 0
|
||||
map cos 2 to traffic-class 2
|
||||
map cos 3 to traffic-class 3
|
||||
map cos 4 to traffic-class 4
|
||||
map cos 5 to traffic-class 5
|
||||
map cos 6 to traffic-class 6
|
||||
map cos 7 to traffic-class 7
|
||||
!
|
||||
qos map cos-dscp all-zero-map
|
||||
map cos 0 to dscp 0
|
||||
map cos 1 to dscp 0
|
||||
map cos 2 to dscp 0
|
||||
map cos 3 to dscp 0
|
||||
map cos 4 to dscp 0
|
||||
map cos 5 to dscp 0
|
||||
map cos 6 to dscp 0
|
||||
map cos 7 to dscp 0
|
||||
!
|
||||
qos map cos-dscp default
|
||||
map cos 0 to dscp 0
|
||||
map cos 1 to dscp 8
|
||||
map cos 2 to dscp 16
|
||||
map cos 3 to dscp 24
|
||||
map cos 4 to dscp 32
|
||||
map cos 5 to dscp 40
|
||||
map cos 6 to dscp 48
|
||||
map cos 7 to dscp 56
|
||||
!
|
||||
qos map traffic-class-cos all-zero-map
|
||||
map traffic-class 0 to cos 0
|
||||
map traffic-class 1 to cos 0
|
||||
map traffic-class 2 to cos 0
|
||||
map traffic-class 3 to cos 0
|
||||
map traffic-class 4 to cos 0
|
||||
map traffic-class 5 to cos 0
|
||||
map traffic-class 6 to cos 0
|
||||
map traffic-class 7 to cos 0
|
||||
!
|
||||
qos map traffic-class-cos default
|
||||
map traffic-class 0 to cos 0
|
||||
map traffic-class 1 to cos 1
|
||||
map traffic-class 2 to cos 2
|
||||
map traffic-class 3 to cos 3
|
||||
map traffic-class 4 to cos 4
|
||||
map traffic-class 5 to cos 5
|
||||
map traffic-class 6 to cos 6
|
||||
map traffic-class 7 to cos 7
|
||||
!
|
||||
qos map traffic-class-mutation all-zero-map
|
||||
map traffic-class 0 to traffic-class 0
|
||||
map traffic-class 1 to traffic-class 0
|
||||
map traffic-class 2 to traffic-class 0
|
||||
map traffic-class 3 to traffic-class 0
|
||||
map traffic-class 4 to traffic-class 0
|
||||
map traffic-class 5 to traffic-class 0
|
||||
map traffic-class 6 to traffic-class 0
|
||||
map traffic-class 7 to traffic-class 0
|
||||
!
|
||||
qos map traffic-class-mutation default
|
||||
map traffic-class 0 to traffic-class 0
|
||||
map traffic-class 1 to traffic-class 1
|
||||
map traffic-class 2 to traffic-class 2
|
||||
map traffic-class 3 to traffic-class 3
|
||||
map traffic-class 4 to traffic-class 4
|
||||
map traffic-class 5 to traffic-class 5
|
||||
map traffic-class 6 to traffic-class 6
|
||||
map traffic-class 7 to traffic-class 7
|
||||
!
|
||||
qos map traffic-class-dscp all-zero-map
|
||||
map traffic-class 0 to dscp 0
|
||||
map traffic-class 1 to dscp 0
|
||||
map traffic-class 2 to dscp 0
|
||||
map traffic-class 3 to dscp 0
|
||||
map traffic-class 4 to dscp 0
|
||||
map traffic-class 5 to dscp 0
|
||||
map traffic-class 6 to dscp 0
|
||||
map traffic-class 7 to dscp 0
|
||||
!
|
||||
qos map traffic-class-dscp default
|
||||
map traffic-class 0 to dscp 0
|
||||
map traffic-class 1 to dscp 8
|
||||
map traffic-class 2 to dscp 16
|
||||
map traffic-class 3 to dscp 24
|
||||
map traffic-class 4 to dscp 32
|
||||
map traffic-class 5 to dscp 40
|
||||
map traffic-class 6 to dscp 48
|
||||
map traffic-class 7 to dscp 56
|
||||
!
|
||||
qos map dscp-mutation all-zero-map
|
||||
map dscp 0-63 to dscp 0
|
||||
!
|
||||
qos map dscp-mutation default
|
||||
map dscp 0 to dscp 0
|
||||
map dscp 1 to dscp 1
|
||||
map dscp 10 to dscp 10
|
||||
map dscp 11 to dscp 11
|
||||
map dscp 12 to dscp 12
|
||||
map dscp 13 to dscp 13
|
||||
map dscp 14 to dscp 14
|
||||
map dscp 15 to dscp 15
|
||||
map dscp 16 to dscp 16
|
||||
map dscp 17 to dscp 17
|
||||
map dscp 18 to dscp 18
|
||||
map dscp 19 to dscp 19
|
||||
map dscp 2 to dscp 2
|
||||
map dscp 20 to dscp 20
|
||||
map dscp 21 to dscp 21
|
||||
map dscp 22 to dscp 22
|
||||
map dscp 23 to dscp 23
|
||||
map dscp 24 to dscp 24
|
||||
map dscp 25 to dscp 25
|
||||
map dscp 26 to dscp 26
|
||||
map dscp 27 to dscp 27
|
||||
map dscp 28 to dscp 28
|
||||
map dscp 29 to dscp 29
|
||||
map dscp 3 to dscp 3
|
||||
map dscp 30 to dscp 30
|
||||
map dscp 31 to dscp 31
|
||||
map dscp 32 to dscp 32
|
||||
map dscp 33 to dscp 33
|
||||
map dscp 34 to dscp 34
|
||||
map dscp 35 to dscp 35
|
||||
map dscp 36 to dscp 36
|
||||
map dscp 37 to dscp 37
|
||||
map dscp 38 to dscp 38
|
||||
map dscp 39 to dscp 39
|
||||
map dscp 4 to dscp 4
|
||||
map dscp 40 to dscp 40
|
||||
map dscp 41 to dscp 41
|
||||
map dscp 42 to dscp 42
|
||||
map dscp 43 to dscp 43
|
||||
map dscp 44 to dscp 44
|
||||
map dscp 45 to dscp 45
|
||||
map dscp 46 to dscp 46
|
||||
map dscp 47 to dscp 47
|
||||
map dscp 48 to dscp 48
|
||||
map dscp 49 to dscp 49
|
||||
map dscp 5 to dscp 5
|
||||
map dscp 50 to dscp 50
|
||||
map dscp 51 to dscp 51
|
||||
map dscp 52 to dscp 52
|
||||
map dscp 53 to dscp 53
|
||||
map dscp 54 to dscp 54
|
||||
map dscp 55 to dscp 55
|
||||
map dscp 56 to dscp 56
|
||||
map dscp 57 to dscp 57
|
||||
map dscp 58 to dscp 58
|
||||
map dscp 59 to dscp 59
|
||||
map dscp 6 to dscp 6
|
||||
map dscp 60 to dscp 60
|
||||
map dscp 61 to dscp 61
|
||||
map dscp 62 to dscp 62
|
||||
map dscp 63 to dscp 63
|
||||
map dscp 7 to dscp 7
|
||||
map dscp 8 to dscp 8
|
||||
map dscp 9 to dscp 9
|
||||
!
|
||||
qos map dscp-traffic-class all-zero-map
|
||||
map dscp 0-63 to traffic-class 0
|
||||
!
|
||||
qos map dscp-traffic-class default
|
||||
map dscp 0-7 to traffic-class 0
|
||||
map dscp 16-23 to traffic-class 2
|
||||
map dscp 24-31 to traffic-class 3
|
||||
map dscp 32-39 to traffic-class 4
|
||||
map dscp 40-47 to traffic-class 5
|
||||
map dscp 48-55 to traffic-class 6
|
||||
map dscp 56-63 to traffic-class 7
|
||||
map dscp 8-15 to traffic-class 1
|
||||
!
|
||||
qos map dscp-cos all-zero-map
|
||||
map dscp 0-63 to cos 0
|
||||
!
|
||||
qos map dscp-cos default
|
||||
map dscp 0-7 to cos 0
|
||||
map dscp 16-23 to cos 2
|
||||
map dscp 24-31 to cos 3
|
||||
map dscp 32-39 to cos 4
|
||||
map dscp 40-47 to cos 5
|
||||
map dscp 48-55 to cos 6
|
||||
map dscp 56-63 to cos 7
|
||||
map dscp 8-15 to cos 1
|
||||
!
|
||||
protocol lldp
|
||||
advertise optional-tlv management-address
|
||||
system-description Brocade BR-SLX9140 Router
|
||||
!
|
||||
vlan dot1q tag native
|
||||
police-remark-profile default
|
||||
!
|
||||
class-map BD-100
|
||||
!
|
||||
class-map C1
|
||||
match access-group M1
|
||||
!
|
||||
class-map cee
|
||||
!
|
||||
class-map default
|
||||
!
|
||||
policy-map P1
|
||||
class C1
|
||||
police cir 1000000
|
||||
!
|
||||
!
|
||||
policy-map P2
|
||||
class default
|
||||
police cir 12121212
|
||||
!
|
||||
!
|
||||
no protocol vrrp
|
||||
no protocol vrrp-extended
|
||||
router bgp
|
||||
local-as 65301
|
||||
capability as4-enable
|
||||
bfd interval 300 min-rx 300 multiplier 3
|
||||
neighbor leaf_group peer-group
|
||||
neighbor leaf_group remote-as 65500
|
||||
neighbor leaf_group bfd
|
||||
neighbor 10.220.4.3 remote-as 65500
|
||||
neighbor 10.220.4.3 peer-group leaf_group
|
||||
address-family ipv4 unicast
|
||||
network 172.32.252.5/32
|
||||
maximum-paths 8
|
||||
!
|
||||
address-family ipv6 unicast
|
||||
!
|
||||
address-family l2vpn evpn
|
||||
!
|
||||
!
|
||||
interface Loopback 1
|
||||
ip address 172.16.128.6/32
|
||||
no shutdown
|
||||
!
|
||||
interface Loopback 2
|
||||
ip address 172.16.129.5/32
|
||||
no shutdown
|
||||
!
|
||||
interface Management 0
|
||||
no tcp burstrate
|
||||
no shutdown
|
||||
vrf forwarding mgmt-vrf
|
||||
ip address dhcp
|
||||
!
|
||||
interface Ethernet 0/1
|
||||
speed 25000
|
||||
fec mode disabled
|
||||
switchport
|
||||
switchport mode access
|
||||
switchport access vlan 1
|
||||
no shutdown
|
||||
!
|
||||
interface Ethernet 0/2
|
||||
no shutdown
|
||||
!
|
||||
interface Ethernet 0/3
|
||||
speed 25000
|
||||
fec mode RS-FEC
|
||||
no shutdown
|
||||
!
|
||||
interface Ethernet 0/4
|
||||
shutdown
|
||||
!
|
||||
interface Ethernet 0/5
|
||||
service-policy in P1
|
||||
no shutdown
|
||||
!
|
||||
interface Ethernet 0/6
|
||||
mtu 1548
|
||||
description L2 Interface
|
||||
no shutdown
|
||||
!
|
||||
interface Ethernet 0/7
|
||||
mtu 1548
|
||||
description L2 Interface
|
||||
no shutdown
|
||||
!
|
||||
interface Ethernet 0/8
|
||||
switchport
|
||||
switchport mode trunk
|
||||
switchport trunk allowed vlan add 100,200
|
||||
switchport trunk tag native-vlan
|
||||
shutdown
|
||||
!
|
||||
interface Ethernet 0/9
|
||||
shutdown
|
||||
!
|
||||
interface Ethernet 0/10
|
||||
no shutdown
|
||||
!
|
||||
interface Ethernet 0/11
|
||||
no shutdown
|
||||
!
|
||||
interface Ethernet 0/12
|
||||
no shutdown
|
||||
!
|
||||
interface Ethernet 0/13
|
||||
no shutdown
|
||||
!
|
||||
interface Ethernet 0/14
|
||||
no shutdown
|
||||
!
|
||||
interface Ethernet 0/15
|
||||
shutdown
|
||||
!
|
||||
interface Ethernet 0/16
|
||||
shutdown
|
||||
!
|
||||
interface Ethernet 0/17
|
||||
shutdown
|
||||
!
|
||||
interface Ethernet 0/18
|
||||
shutdown
|
||||
!
|
||||
interface Ethernet 0/19
|
||||
shutdown
|
||||
!
|
||||
interface Ethernet 0/20
|
||||
shutdown
|
||||
!
|
||||
interface Ethernet 0/21
|
||||
shutdown
|
||||
!
|
||||
interface Ethernet 0/22
|
||||
shutdown
|
||||
!
|
||||
interface Ethernet 0/23
|
||||
shutdown
|
||||
!
|
||||
interface Ethernet 0/24
|
||||
shutdown
|
||||
!
|
||||
interface Ethernet 0/25
|
||||
shutdown
|
||||
!
|
||||
interface Ethernet 0/26
|
||||
shutdown
|
||||
!
|
||||
interface Ethernet 0/27
|
||||
shutdown
|
||||
!
|
||||
interface Ethernet 0/28
|
||||
shutdown
|
||||
!
|
||||
interface Ethernet 0/29
|
||||
shutdown
|
||||
!
|
||||
interface Ethernet 0/30
|
||||
shutdown
|
||||
!
|
||||
interface Ethernet 0/31
|
||||
shutdown
|
||||
!
|
||||
interface Ethernet 0/32
|
||||
shutdown
|
||||
!
|
||||
interface Ethernet 0/33
|
||||
shutdown
|
||||
!
|
||||
interface Ethernet 0/34
|
||||
shutdown
|
||||
!
|
||||
interface Ethernet 0/35
|
||||
shutdown
|
||||
!
|
||||
interface Ethernet 0/36
|
||||
shutdown
|
||||
!
|
||||
interface Ethernet 0/37
|
||||
shutdown
|
||||
!
|
||||
interface Ethernet 0/38
|
||||
shutdown
|
||||
!
|
||||
interface Ethernet 0/39
|
||||
shutdown
|
||||
!
|
||||
interface Ethernet 0/40
|
||||
shutdown
|
||||
!
|
||||
interface Ethernet 0/41
|
||||
shutdown
|
||||
!
|
||||
interface Ethernet 0/42
|
||||
shutdown
|
||||
!
|
||||
interface Ethernet 0/43
|
||||
shutdown
|
||||
!
|
||||
interface Ethernet 0/44
|
||||
shutdown
|
||||
!
|
||||
interface Ethernet 0/45
|
||||
shutdown
|
||||
!
|
||||
interface Ethernet 0/46
|
||||
shutdown
|
||||
!
|
||||
interface Ethernet 0/47
|
||||
shutdown
|
||||
!
|
||||
interface Ethernet 0/48
|
||||
shutdown
|
||||
!
|
||||
interface Ethernet 0/49
|
||||
shutdown
|
||||
!
|
||||
interface Ethernet 0/50
|
||||
fec mode RS-FEC
|
||||
no shutdown
|
||||
!
|
||||
interface Ethernet 0/51
|
||||
fec mode RS-FEC
|
||||
no shutdown
|
||||
!
|
||||
interface Ethernet 0/52
|
||||
fec mode RS-FEC
|
||||
no shutdown
|
||||
!
|
||||
interface Ethernet 0/53
|
||||
fec mode RS-FEC
|
||||
no shutdown
|
||||
!
|
||||
interface Ethernet 0/54
|
||||
fec mode disabled
|
||||
no shutdown
|
||||
!
|
||||
interface Port-channel 200
|
||||
switchport
|
||||
switchport mode access
|
||||
switchport access vlan 200
|
||||
shutdown
|
||||
!
|
||||
interface Port-channel 1024
|
||||
insight enable
|
||||
no shutdown
|
||||
!
|
||||
monitor session 1
|
||||
source ethernet 0/1 destination port-channel 1024 direction both
|
||||
!
|
||||
monitor session 2
|
||||
!
|
||||
bridge-domain 100 p2mp
|
||||
!
|
||||
cluster MCT1 1
|
||||
!
|
18
tests/unit/plugins/cliconf/fixtures/slxos/show_version
Normal file
18
tests/unit/plugins/cliconf/fixtures/slxos/show_version
Normal file
|
@ -0,0 +1,18 @@
|
|||
SLX-OS Operating System Software
|
||||
SLX-OS Operating System Version: 17s.1.02
|
||||
Copyright (c) 1995-2018 Brocade Communications Systems, Inc.
|
||||
Firmware name: 17s.1.02
|
||||
Build Time: 00:06:59 Sep 28, 2017
|
||||
Install Time: 15:58:29 Feb 9, 2018
|
||||
Kernel: 2.6.34.6
|
||||
Host Version: Ubuntu 14.04 LTS
|
||||
Host Kernel: Linux 3.14.17
|
||||
|
||||
Control Processor: QEMU Virtual CPU version 2.0.0
|
||||
|
||||
System Uptime: 34days 4hrs 41mins 53secs
|
||||
|
||||
Slot Name Primary/Secondary Versions Status
|
||||
---------------------------------------------------------------------------
|
||||
SW/0 SLX-OS 17s.1.02 ACTIVE*
|
||||
17s.1.02
|
137
tests/unit/plugins/cliconf/test_nos.py
Normal file
137
tests/unit/plugins/cliconf/test_nos.py
Normal file
|
@ -0,0 +1,137 @@
|
|||
#
|
||||
# (c) 2018 Extreme Networks 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
|
||||
|
||||
from os import path
|
||||
import json
|
||||
|
||||
from mock import MagicMock, call
|
||||
|
||||
from ansible_collections.community.general.tests.unit.compat import unittest
|
||||
from ansible_collections.community.general.plugins.cliconf import nos
|
||||
|
||||
FIXTURE_DIR = b'%s/fixtures/nos' % (
|
||||
path.dirname(path.abspath(__file__)).encode('utf-8')
|
||||
)
|
||||
|
||||
|
||||
def _connection_side_effect(*args, **kwargs):
|
||||
try:
|
||||
if args:
|
||||
value = args[0]
|
||||
else:
|
||||
value = kwargs.get('command')
|
||||
|
||||
fixture_path = path.abspath(
|
||||
b'%s/%s' % (FIXTURE_DIR, b'_'.join(value.split(b' ')))
|
||||
)
|
||||
with open(fixture_path, 'rb') as file_desc:
|
||||
return file_desc.read()
|
||||
except (OSError, IOError):
|
||||
if args:
|
||||
value = args[0]
|
||||
return value
|
||||
elif kwargs.get('command'):
|
||||
value = kwargs.get('command')
|
||||
return value
|
||||
|
||||
return 'Nope'
|
||||
|
||||
|
||||
class TestPluginCLIConfNOS(unittest.TestCase):
|
||||
""" Test class for NOS CLI Conf Methods
|
||||
"""
|
||||
def setUp(self):
|
||||
self._mock_connection = MagicMock()
|
||||
self._mock_connection.send.side_effect = _connection_side_effect
|
||||
self._cliconf = nos.Cliconf(self._mock_connection)
|
||||
self.maxDiff = None
|
||||
|
||||
def tearDown(self):
|
||||
pass
|
||||
|
||||
def test_get_device_info(self):
|
||||
""" Test get_device_info
|
||||
"""
|
||||
device_info = self._cliconf.get_device_info()
|
||||
|
||||
mock_device_info = {
|
||||
'network_os': 'nos',
|
||||
'network_os_model': 'BR-VDX6740',
|
||||
'network_os_version': '7.2.0',
|
||||
}
|
||||
|
||||
self.assertEqual(device_info, mock_device_info)
|
||||
|
||||
def test_get_config(self):
|
||||
""" Test get_config
|
||||
"""
|
||||
running_config = self._cliconf.get_config()
|
||||
|
||||
fixture_path = path.abspath(b'%s/show_running-config' % FIXTURE_DIR)
|
||||
with open(fixture_path, 'rb') as file_desc:
|
||||
mock_running_config = file_desc.read()
|
||||
self.assertEqual(running_config, mock_running_config)
|
||||
|
||||
def test_edit_config(self):
|
||||
""" Test edit_config
|
||||
"""
|
||||
test_config_command = b'this\nis\nthe\nsong\nthat\nnever\nends'
|
||||
|
||||
self._cliconf.edit_config(test_config_command)
|
||||
|
||||
send_calls = []
|
||||
|
||||
for command in [b'configure terminal', test_config_command, b'end']:
|
||||
send_calls.append(call(
|
||||
command=command,
|
||||
prompt_retry_check=False,
|
||||
sendonly=False,
|
||||
newline=True,
|
||||
check_all=False
|
||||
))
|
||||
|
||||
self._mock_connection.send.assert_has_calls(send_calls)
|
||||
|
||||
def test_get_capabilities(self):
|
||||
""" Test get_capabilities
|
||||
"""
|
||||
capabilities = json.loads(self._cliconf.get_capabilities())
|
||||
mock_capabilities = {
|
||||
'network_api': 'cliconf',
|
||||
'rpc': [
|
||||
'get_config',
|
||||
'edit_config',
|
||||
'get_capabilities',
|
||||
'get',
|
||||
'enable_response_logging',
|
||||
'disable_response_logging'
|
||||
],
|
||||
'device_info': {
|
||||
'network_os_model': 'BR-VDX6740',
|
||||
'network_os_version': '7.2.0',
|
||||
'network_os': 'nos'
|
||||
}
|
||||
}
|
||||
|
||||
self.assertEqual(
|
||||
mock_capabilities,
|
||||
capabilities
|
||||
)
|
144
tests/unit/plugins/cliconf/test_slxos.py
Normal file
144
tests/unit/plugins/cliconf/test_slxos.py
Normal file
|
@ -0,0 +1,144 @@
|
|||
#
|
||||
# (c) 2018 Extreme Networks 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
|
||||
|
||||
from os import path
|
||||
import json
|
||||
|
||||
from mock import MagicMock, call
|
||||
|
||||
from ansible_collections.community.general.tests.unit.compat import unittest
|
||||
from ansible_collections.community.general.plugins.cliconf import slxos
|
||||
|
||||
FIXTURE_DIR = b'%s/fixtures/slxos' % (
|
||||
path.dirname(path.abspath(__file__)).encode('utf-8')
|
||||
)
|
||||
|
||||
|
||||
def _connection_side_effect(*args, **kwargs):
|
||||
try:
|
||||
if args:
|
||||
value = args[0]
|
||||
else:
|
||||
value = kwargs.get('command')
|
||||
|
||||
fixture_path = path.abspath(
|
||||
b'%s/%s' % (FIXTURE_DIR, b'_'.join(value.split(b' ')))
|
||||
)
|
||||
with open(fixture_path, 'rb') as file_desc:
|
||||
return file_desc.read()
|
||||
except (OSError, IOError):
|
||||
if args:
|
||||
value = args[0]
|
||||
return value
|
||||
elif kwargs.get('command'):
|
||||
value = kwargs.get('command')
|
||||
return value
|
||||
|
||||
return 'Nope'
|
||||
|
||||
|
||||
class TestPluginCLIConfSLXOS(unittest.TestCase):
|
||||
""" Test class for SLX-OS CLI Conf Methods
|
||||
"""
|
||||
def setUp(self):
|
||||
self._mock_connection = MagicMock()
|
||||
self._mock_connection.send.side_effect = _connection_side_effect
|
||||
self._cliconf = slxos.Cliconf(self._mock_connection)
|
||||
self.maxDiff = None
|
||||
|
||||
def tearDown(self):
|
||||
pass
|
||||
|
||||
def test_get_device_info(self):
|
||||
""" Test get_device_info
|
||||
"""
|
||||
device_info = self._cliconf.get_device_info()
|
||||
|
||||
mock_device_info = {
|
||||
'network_os': 'slxos',
|
||||
'network_os_model': 'BR-SLX9140',
|
||||
'network_os_version': '17s.1.02',
|
||||
}
|
||||
|
||||
self.assertEqual(device_info, mock_device_info)
|
||||
|
||||
def test_get_config(self):
|
||||
""" Test get_config
|
||||
"""
|
||||
running_config = self._cliconf.get_config()
|
||||
|
||||
fixture_path = path.abspath(b'%s/show_running-config' % FIXTURE_DIR)
|
||||
with open(fixture_path, 'rb') as file_desc:
|
||||
mock_running_config = file_desc.read()
|
||||
self.assertEqual(running_config, mock_running_config)
|
||||
|
||||
startup_config = self._cliconf.get_config()
|
||||
|
||||
fixture_path = path.abspath(b'%s/show_running-config' % FIXTURE_DIR)
|
||||
with open(fixture_path, 'rb') as file_desc:
|
||||
mock_startup_config = file_desc.read()
|
||||
self.assertEqual(startup_config, mock_startup_config)
|
||||
|
||||
def test_edit_config(self):
|
||||
""" Test edit_config
|
||||
"""
|
||||
test_config_command = b'this\nis\nthe\nsong\nthat\nnever\nends'
|
||||
|
||||
self._cliconf.edit_config(test_config_command)
|
||||
|
||||
send_calls = []
|
||||
|
||||
for command in [b'configure terminal', test_config_command, b'end']:
|
||||
send_calls.append(call(
|
||||
command=command,
|
||||
prompt_retry_check=False,
|
||||
sendonly=False,
|
||||
newline=True,
|
||||
check_all=False
|
||||
))
|
||||
|
||||
self._mock_connection.send.assert_has_calls(send_calls)
|
||||
|
||||
def test_get_capabilities(self):
|
||||
""" Test get_capabilities
|
||||
"""
|
||||
capabilities = json.loads(self._cliconf.get_capabilities())
|
||||
mock_capabilities = {
|
||||
'network_api': 'cliconf',
|
||||
'rpc': [
|
||||
'get_config',
|
||||
'edit_config',
|
||||
'get_capabilities',
|
||||
'get',
|
||||
'enable_response_logging',
|
||||
'disable_response_logging'
|
||||
],
|
||||
'device_info': {
|
||||
'network_os_model': 'BR-SLX9140',
|
||||
'network_os_version': '17s.1.02',
|
||||
'network_os': 'slxos'
|
||||
}
|
||||
}
|
||||
|
||||
self.assertEqual(
|
||||
mock_capabilities,
|
||||
capabilities
|
||||
)
|
0
tests/unit/plugins/connection/__init__.py
Normal file
0
tests/unit/plugins/connection/__init__.py
Normal file
61
tests/unit/plugins/connection/test_docker.py
Normal file
61
tests/unit/plugins/connection/test_docker.py
Normal file
|
@ -0,0 +1,61 @@
|
|||
# (c) 2020 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
|
||||
|
||||
from io import StringIO
|
||||
import pytest
|
||||
|
||||
from ansible_collections.community.general.tests.unit.compat import mock
|
||||
from ansible_collections.community.general.tests.unit.compat import unittest
|
||||
from ansible.errors import AnsibleError
|
||||
from ansible.playbook.play_context import PlayContext
|
||||
from ansible_collections.community.general.plugins.connection.docker import Connection as DockerConnection
|
||||
|
||||
|
||||
class TestDockerConnectionClass(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.play_context = PlayContext()
|
||||
self.play_context.prompt = (
|
||||
'[sudo via ansible, key=ouzmdnewuhucvuaabtjmweasarviygqq] password: '
|
||||
)
|
||||
self.in_stream = StringIO()
|
||||
|
||||
def tearDown(self):
|
||||
pass
|
||||
|
||||
@mock.patch('ansible_collections.community.general.plugins.connection.docker.Connection._old_docker_version', return_value=('false', 'garbage', '', 1))
|
||||
@mock.patch('ansible_collections.community.general.plugins.connection.docker.Connection._new_docker_version', return_value=('docker version', '1.2.3', '', 0))
|
||||
def test_docker_connection_module_too_old(self, mock_new_docker_verison, mock_old_docker_version):
|
||||
self.assertRaisesRegexp(AnsibleError, '^docker connection type requires docker 1.3 or higher$',
|
||||
DockerConnection, self.play_context, self.in_stream, docker_command='/fake/docker')
|
||||
|
||||
@mock.patch('ansible_collections.community.general.plugins.connection.docker.Connection._old_docker_version', return_value=('false', 'garbage', '', 1))
|
||||
@mock.patch('ansible_collections.community.general.plugins.connection.docker.Connection._new_docker_version', return_value=('docker version', '1.3.4', '', 0))
|
||||
def test_docker_connection_module(self, mock_new_docker_verison, mock_old_docker_version):
|
||||
self.assertIsInstance(DockerConnection(self.play_context, self.in_stream, docker_command='/fake/docker'),
|
||||
DockerConnection)
|
||||
|
||||
# old version and new version fail
|
||||
@mock.patch('ansible_collections.community.general.plugins.connection.docker.Connection._old_docker_version', return_value=('false', 'garbage', '', 1))
|
||||
@mock.patch('ansible_collections.community.general.plugins.connection.docker.Connection._new_docker_version', return_value=('false', 'garbage', '', 1))
|
||||
def test_docker_connection_module_wrong_cmd(self, mock_new_docker_version, mock_old_docker_version):
|
||||
self.assertRaisesRegexp(AnsibleError, '^Docker version check (.*?) failed: ',
|
||||
DockerConnection, self.play_context, self.in_stream, docker_command='/fake/docker')
|
40
tests/unit/plugins/connection/test_lxc.py
Normal file
40
tests/unit/plugins/connection/test_lxc.py
Normal file
|
@ -0,0 +1,40 @@
|
|||
#
|
||||
# (c) 2020 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
|
||||
|
||||
from io import StringIO
|
||||
import pytest
|
||||
|
||||
from ansible_collections.community.general.tests.unit.compat import unittest
|
||||
from ansible_collections.community.general.plugins.connection import lxc
|
||||
from ansible.playbook.play_context import PlayContext
|
||||
|
||||
|
||||
class TestLXCConnectionClass(unittest.TestCase):
|
||||
|
||||
def test_lxc_connection_module(self):
|
||||
play_context = PlayContext()
|
||||
play_context.prompt = (
|
||||
'[sudo via ansible, key=ouzmdnewuhucvuaabtjmweasarviygqq] password: '
|
||||
)
|
||||
in_stream = StringIO()
|
||||
|
||||
self.assertIsInstance(lxc.Connection(play_context, in_stream), lxc.Connection)
|
0
tests/unit/plugins/httpapi/__init__.py
Normal file
0
tests/unit/plugins/httpapi/__init__.py
Normal file
413
tests/unit/plugins/httpapi/test_ftd.py
Normal file
413
tests/unit/plugins/httpapi/test_ftd.py
Normal file
|
@ -0,0 +1,413 @@
|
|||
# Copyright (c) 2018 Cisco and/or its affiliates.
|
||||
#
|
||||
# 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/>.
|
||||
#
|
||||
|
||||
import json
|
||||
|
||||
from ansible.module_utils.six.moves.urllib.error import HTTPError
|
||||
from ansible_collections.community.general.tests.unit.compat import mock
|
||||
from ansible_collections.community.general.tests.unit.compat import unittest
|
||||
from ansible_collections.community.general.tests.unit.compat.mock import mock_open, patch
|
||||
|
||||
from ansible.errors import AnsibleConnectionFailure
|
||||
from ansible.module_utils.connection import ConnectionError
|
||||
from ansible_collections.community.general.plugins.module_utils.network.ftd.common import HTTPMethod, ResponseParams
|
||||
from ansible_collections.community.general.plugins.module_utils.network.ftd.fdm_swagger_client import SpecProp, FdmSwaggerParser
|
||||
from ansible.module_utils.six import BytesIO, PY3, StringIO
|
||||
from ansible_collections.community.general.plugins.httpapi.ftd import HttpApi, BASE_HEADERS, TOKEN_PATH_TEMPLATE, DEFAULT_API_VERSIONS
|
||||
|
||||
|
||||
if PY3:
|
||||
BUILTINS_NAME = 'builtins'
|
||||
else:
|
||||
BUILTINS_NAME = '__builtin__'
|
||||
|
||||
|
||||
class FakeFtdHttpApiPlugin(HttpApi):
|
||||
def __init__(self, conn):
|
||||
super(FakeFtdHttpApiPlugin, self).__init__(conn)
|
||||
self.hostvars = {
|
||||
'token_path': '/testLoginUrl',
|
||||
'spec_path': '/testSpecUrl'
|
||||
}
|
||||
|
||||
def get_option(self, var):
|
||||
return self.hostvars[var]
|
||||
|
||||
def set_option(self, var, val):
|
||||
self.hostvars[var] = val
|
||||
|
||||
|
||||
class TestFtdHttpApi(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.connection_mock = mock.Mock()
|
||||
self.ftd_plugin = FakeFtdHttpApiPlugin(self.connection_mock)
|
||||
self.ftd_plugin.access_token = 'ACCESS_TOKEN'
|
||||
self.ftd_plugin._load_name = 'httpapi'
|
||||
|
||||
def test_login_should_request_tokens_when_no_refresh_token(self):
|
||||
self.connection_mock.send.return_value = self._connection_response(
|
||||
{'access_token': 'ACCESS_TOKEN', 'refresh_token': 'REFRESH_TOKEN'}
|
||||
)
|
||||
|
||||
self.ftd_plugin.login('foo', 'bar')
|
||||
|
||||
assert 'ACCESS_TOKEN' == self.ftd_plugin.access_token
|
||||
assert 'REFRESH_TOKEN' == self.ftd_plugin.refresh_token
|
||||
assert {'Authorization': 'Bearer ACCESS_TOKEN'} == self.ftd_plugin.connection._auth
|
||||
expected_body = json.dumps({'grant_type': 'password', 'username': 'foo', 'password': 'bar'})
|
||||
self.connection_mock.send.assert_called_once_with(mock.ANY, expected_body, headers=mock.ANY, method=mock.ANY)
|
||||
|
||||
def test_login_should_update_tokens_when_refresh_token_exists(self):
|
||||
self.ftd_plugin.refresh_token = 'REFRESH_TOKEN'
|
||||
self.connection_mock.send.return_value = self._connection_response(
|
||||
{'access_token': 'NEW_ACCESS_TOKEN', 'refresh_token': 'NEW_REFRESH_TOKEN'}
|
||||
)
|
||||
|
||||
self.ftd_plugin.login('foo', 'bar')
|
||||
|
||||
assert 'NEW_ACCESS_TOKEN' == self.ftd_plugin.access_token
|
||||
assert 'NEW_REFRESH_TOKEN' == self.ftd_plugin.refresh_token
|
||||
assert {'Authorization': 'Bearer NEW_ACCESS_TOKEN'} == self.ftd_plugin.connection._auth
|
||||
expected_body = json.dumps({'grant_type': 'refresh_token', 'refresh_token': 'REFRESH_TOKEN'})
|
||||
self.connection_mock.send.assert_called_once_with(mock.ANY, expected_body, headers=mock.ANY, method=mock.ANY)
|
||||
|
||||
def test_login_should_use_env_variable_when_set(self):
|
||||
temp_token_path = self.ftd_plugin.hostvars['token_path']
|
||||
self.ftd_plugin.hostvars['token_path'] = '/testFakeLoginUrl'
|
||||
self.connection_mock.send.return_value = self._connection_response(
|
||||
{'access_token': 'ACCESS_TOKEN', 'refresh_token': 'REFRESH_TOKEN'}
|
||||
)
|
||||
|
||||
self.ftd_plugin.login('foo', 'bar')
|
||||
|
||||
self.connection_mock.send.assert_called_once_with('/testFakeLoginUrl', mock.ANY, headers=mock.ANY,
|
||||
method=mock.ANY)
|
||||
self.ftd_plugin.hostvars['token_path'] = temp_token_path
|
||||
|
||||
def test_login_raises_exception_when_no_refresh_token_and_no_credentials(self):
|
||||
with self.assertRaises(AnsibleConnectionFailure) as res:
|
||||
self.ftd_plugin.login(None, None)
|
||||
assert 'Username and password are required' in str(res.exception)
|
||||
|
||||
def test_login_raises_exception_when_invalid_response(self):
|
||||
self.connection_mock.send.return_value = self._connection_response(
|
||||
{'no_access_token': 'ACCESS_TOKEN'}
|
||||
)
|
||||
|
||||
with self.assertRaises(ConnectionError) as res:
|
||||
self.ftd_plugin.login('foo', 'bar')
|
||||
|
||||
assert 'Server returned response without token info during connection authentication' in str(res.exception)
|
||||
|
||||
def test_login_raises_exception_when_http_error(self):
|
||||
self.connection_mock.send.side_effect = HTTPError('http://testhost.com', 400, '', {},
|
||||
StringIO('{"message": "Failed to authenticate user"}'))
|
||||
|
||||
with self.assertRaises(ConnectionError) as res:
|
||||
self.ftd_plugin.login('foo', 'bar')
|
||||
|
||||
assert 'Failed to authenticate user' in str(res.exception)
|
||||
|
||||
def test_logout_should_revoke_tokens(self):
|
||||
self.ftd_plugin.access_token = 'ACCESS_TOKEN_TO_REVOKE'
|
||||
self.ftd_plugin.refresh_token = 'REFRESH_TOKEN_TO_REVOKE'
|
||||
self.connection_mock.send.return_value = self._connection_response(None)
|
||||
|
||||
self.ftd_plugin.logout()
|
||||
|
||||
assert self.ftd_plugin.access_token is None
|
||||
assert self.ftd_plugin.refresh_token is None
|
||||
expected_body = json.dumps({'grant_type': 'revoke_token', 'access_token': 'ACCESS_TOKEN_TO_REVOKE',
|
||||
'token_to_revoke': 'REFRESH_TOKEN_TO_REVOKE'})
|
||||
self.connection_mock.send.assert_called_once_with(mock.ANY, expected_body, headers=mock.ANY, method=mock.ANY)
|
||||
|
||||
def test_send_request_should_send_correct_request(self):
|
||||
exp_resp = {'id': '123', 'name': 'foo'}
|
||||
self.connection_mock.send.return_value = self._connection_response(exp_resp)
|
||||
|
||||
resp = self.ftd_plugin.send_request('/test/{objId}', HTTPMethod.PUT,
|
||||
body_params={'name': 'foo'},
|
||||
path_params={'objId': '123'},
|
||||
query_params={'at': 0})
|
||||
|
||||
assert {ResponseParams.SUCCESS: True, ResponseParams.STATUS_CODE: 200,
|
||||
ResponseParams.RESPONSE: exp_resp} == resp
|
||||
self.connection_mock.send.assert_called_once_with('/test/123?at=0', '{"name": "foo"}', method=HTTPMethod.PUT,
|
||||
headers=BASE_HEADERS)
|
||||
|
||||
def test_send_request_should_return_empty_dict_when_no_response_data(self):
|
||||
self.connection_mock.send.return_value = self._connection_response(None)
|
||||
|
||||
resp = self.ftd_plugin.send_request('/test', HTTPMethod.GET)
|
||||
|
||||
assert {ResponseParams.SUCCESS: True, ResponseParams.STATUS_CODE: 200, ResponseParams.RESPONSE: {}} == resp
|
||||
self.connection_mock.send.assert_called_once_with('/test', None, method=HTTPMethod.GET,
|
||||
headers=BASE_HEADERS)
|
||||
|
||||
def test_send_request_should_return_error_info_when_http_error_raises(self):
|
||||
self.connection_mock.send.side_effect = HTTPError('http://testhost.com', 500, '', {},
|
||||
StringIO('{"errorMessage": "ERROR"}'))
|
||||
|
||||
resp = self.ftd_plugin.send_request('/test', HTTPMethod.GET)
|
||||
|
||||
assert {ResponseParams.SUCCESS: False, ResponseParams.STATUS_CODE: 500,
|
||||
ResponseParams.RESPONSE: {'errorMessage': 'ERROR'}} == resp
|
||||
|
||||
def test_send_request_raises_exception_when_invalid_response(self):
|
||||
self.connection_mock.send.return_value = self._connection_response('nonValidJson')
|
||||
|
||||
with self.assertRaises(ConnectionError) as res:
|
||||
self.ftd_plugin.send_request('/test', HTTPMethod.GET)
|
||||
|
||||
assert 'Invalid JSON response' in str(res.exception)
|
||||
|
||||
def test_handle_httperror_should_update_tokens_and_retry_on_auth_errors(self):
|
||||
self.ftd_plugin.refresh_token = 'REFRESH_TOKEN'
|
||||
self.connection_mock.send.return_value = self._connection_response(
|
||||
{'access_token': 'NEW_ACCESS_TOKEN', 'refresh_token': 'NEW_REFRESH_TOKEN'}
|
||||
)
|
||||
|
||||
retry = self.ftd_plugin.handle_httperror(HTTPError('http://testhost.com', 401, '', {}, None))
|
||||
|
||||
assert retry
|
||||
assert 'NEW_ACCESS_TOKEN' == self.ftd_plugin.access_token
|
||||
assert 'NEW_REFRESH_TOKEN' == self.ftd_plugin.refresh_token
|
||||
|
||||
def test_handle_httperror_should_not_retry_on_non_auth_errors(self):
|
||||
assert not self.ftd_plugin.handle_httperror(HTTPError('http://testhost.com', 500, '', {}, None))
|
||||
|
||||
def test_handle_httperror_should_not_retry_when_ignoring_http_errors(self):
|
||||
self.ftd_plugin._ignore_http_errors = True
|
||||
assert not self.ftd_plugin.handle_httperror(HTTPError('http://testhost.com', 401, '', {}, None))
|
||||
|
||||
@patch('os.path.isdir', mock.Mock(return_value=False))
|
||||
def test_download_file(self):
|
||||
self.connection_mock.send.return_value = self._connection_response('File content')
|
||||
|
||||
open_mock = mock_open()
|
||||
with patch('%s.open' % BUILTINS_NAME, open_mock):
|
||||
self.ftd_plugin.download_file('/files/1', '/tmp/test.txt')
|
||||
|
||||
open_mock.assert_called_once_with('/tmp/test.txt', 'wb')
|
||||
open_mock().write.assert_called_once_with(b'File content')
|
||||
|
||||
@patch('os.path.isdir', mock.Mock(return_value=True))
|
||||
def test_download_file_should_extract_filename_from_headers(self):
|
||||
filename = 'test_file.txt'
|
||||
response = mock.Mock()
|
||||
response.info.return_value = {'Content-Disposition': 'attachment; filename="%s"' % filename}
|
||||
dummy, response_data = self._connection_response('File content')
|
||||
self.connection_mock.send.return_value = response, response_data
|
||||
|
||||
open_mock = mock_open()
|
||||
with patch('%s.open' % BUILTINS_NAME, open_mock):
|
||||
self.ftd_plugin.download_file('/files/1', '/tmp/')
|
||||
|
||||
open_mock.assert_called_once_with('/tmp/%s' % filename, 'wb')
|
||||
open_mock().write.assert_called_once_with(b'File content')
|
||||
|
||||
@patch('os.path.basename', mock.Mock(return_value='test.txt'))
|
||||
@patch('ansible_collections.community.general.plugins.httpapi.ftd.encode_multipart_formdata',
|
||||
mock.Mock(return_value=('--Encoded data--', 'multipart/form-data')))
|
||||
def test_upload_file(self):
|
||||
self.connection_mock.send.return_value = self._connection_response({'id': '123'})
|
||||
|
||||
open_mock = mock_open()
|
||||
with patch('%s.open' % BUILTINS_NAME, open_mock):
|
||||
resp = self.ftd_plugin.upload_file('/tmp/test.txt', '/files')
|
||||
|
||||
assert {'id': '123'} == resp
|
||||
exp_headers = dict(BASE_HEADERS)
|
||||
exp_headers['Content-Length'] = len('--Encoded data--')
|
||||
exp_headers['Content-Type'] = 'multipart/form-data'
|
||||
self.connection_mock.send.assert_called_once_with('/files', data='--Encoded data--',
|
||||
headers=exp_headers, method=HTTPMethod.POST)
|
||||
open_mock.assert_called_once_with('/tmp/test.txt', 'rb')
|
||||
|
||||
@patch('os.path.basename', mock.Mock(return_value='test.txt'))
|
||||
@patch('ansible_collections.community.general.plugins.httpapi.ftd.encode_multipart_formdata',
|
||||
mock.Mock(return_value=('--Encoded data--', 'multipart/form-data')))
|
||||
def test_upload_file_raises_exception_when_invalid_response(self):
|
||||
self.connection_mock.send.return_value = self._connection_response('invalidJsonResponse')
|
||||
|
||||
open_mock = mock_open()
|
||||
with patch('%s.open' % BUILTINS_NAME, open_mock):
|
||||
with self.assertRaises(ConnectionError) as res:
|
||||
self.ftd_plugin.upload_file('/tmp/test.txt', '/files')
|
||||
|
||||
assert 'Invalid JSON response' in str(res.exception)
|
||||
|
||||
@patch.object(FdmSwaggerParser, 'parse_spec')
|
||||
def test_get_operation_spec(self, parse_spec_mock):
|
||||
self.connection_mock.send.return_value = self._connection_response(None)
|
||||
parse_spec_mock.return_value = {
|
||||
SpecProp.OPERATIONS: {'testOp': 'Specification for testOp'}
|
||||
}
|
||||
|
||||
assert 'Specification for testOp' == self.ftd_plugin.get_operation_spec('testOp')
|
||||
assert self.ftd_plugin.get_operation_spec('nonExistingTestOp') is None
|
||||
|
||||
@patch.object(FdmSwaggerParser, 'parse_spec')
|
||||
def test_get_model_spec(self, parse_spec_mock):
|
||||
self.connection_mock.send.return_value = self._connection_response(None)
|
||||
parse_spec_mock.return_value = {
|
||||
SpecProp.MODELS: {'TestModel': 'Specification for TestModel'}
|
||||
}
|
||||
|
||||
assert 'Specification for TestModel' == self.ftd_plugin.get_model_spec('TestModel')
|
||||
assert self.ftd_plugin.get_model_spec('NonExistingTestModel') is None
|
||||
|
||||
@patch.object(FdmSwaggerParser, 'parse_spec')
|
||||
def test_get_operation_spec_by_model_name(self, parse_spec_mock):
|
||||
self.connection_mock.send.return_value = self._connection_response(None)
|
||||
operation1 = {'modelName': 'TestModel'}
|
||||
op_model_name_is_none = {'modelName': None}
|
||||
op_without_model_name = {'url': 'testUrl'}
|
||||
|
||||
parse_spec_mock.return_value = {
|
||||
SpecProp.MODEL_OPERATIONS: {
|
||||
'TestModel': {
|
||||
'testOp1': operation1,
|
||||
'testOp2': 'spec2'
|
||||
},
|
||||
'TestModel2': {
|
||||
'testOp10': 'spec10',
|
||||
'testOp20': 'spec20'
|
||||
}
|
||||
},
|
||||
SpecProp.OPERATIONS: {
|
||||
'testOp1': operation1,
|
||||
'testOp10': {
|
||||
'modelName': 'TestModel2'
|
||||
},
|
||||
'testOpWithoutModelName': op_without_model_name,
|
||||
'testOpModelNameIsNone': op_model_name_is_none
|
||||
}
|
||||
}
|
||||
|
||||
assert {'testOp1': operation1, 'testOp2': 'spec2'} == self.ftd_plugin.get_operation_specs_by_model_name(
|
||||
'TestModel')
|
||||
assert None is self.ftd_plugin.get_operation_specs_by_model_name(
|
||||
'testOpModelNameIsNone')
|
||||
|
||||
assert None is self.ftd_plugin.get_operation_specs_by_model_name(
|
||||
'testOpWithoutModelName')
|
||||
|
||||
assert self.ftd_plugin.get_operation_specs_by_model_name('nonExistingOperation') is None
|
||||
|
||||
@staticmethod
|
||||
def _connection_response(response, status=200):
|
||||
response_mock = mock.Mock()
|
||||
response_mock.getcode.return_value = status
|
||||
response_text = json.dumps(response) if type(response) is dict else response
|
||||
response_data = BytesIO(response_text.encode() if response_text else ''.encode())
|
||||
return response_mock, response_data
|
||||
|
||||
def test_get_list_of_supported_api_versions_with_failed_http_request(self):
|
||||
error_msg = "Invalid Credentials"
|
||||
fp = mock.MagicMock()
|
||||
fp.read.return_value = '{{"error-msg": "{0}"}}'.format(error_msg)
|
||||
send_mock = mock.MagicMock(side_effect=HTTPError('url', 400, 'msg', 'hdrs', fp))
|
||||
with mock.patch.object(self.ftd_plugin.connection, 'send', send_mock):
|
||||
with self.assertRaises(ConnectionError) as res:
|
||||
self.ftd_plugin._get_supported_api_versions()
|
||||
|
||||
assert error_msg in str(res.exception)
|
||||
|
||||
def test_get_list_of_supported_api_versions_with_buggy_response(self):
|
||||
error_msg = "Non JSON value"
|
||||
http_response_mock = mock.MagicMock()
|
||||
http_response_mock.getvalue.return_value = error_msg
|
||||
|
||||
send_mock = mock.MagicMock(return_value=(None, http_response_mock))
|
||||
|
||||
with mock.patch.object(self.ftd_plugin.connection, 'send', send_mock):
|
||||
with self.assertRaises(ConnectionError) as res:
|
||||
self.ftd_plugin._get_supported_api_versions()
|
||||
assert error_msg in str(res.exception)
|
||||
|
||||
def test_get_list_of_supported_api_versions_with_positive_response(self):
|
||||
http_response_mock = mock.MagicMock()
|
||||
http_response_mock.getvalue.return_value = '{"supportedVersions": ["v1"]}'
|
||||
|
||||
send_mock = mock.MagicMock(return_value=(None, http_response_mock))
|
||||
with mock.patch.object(self.ftd_plugin.connection, 'send', send_mock):
|
||||
supported_versions = self.ftd_plugin._get_supported_api_versions()
|
||||
assert supported_versions == ['v1']
|
||||
|
||||
@patch('ansible_collections.community.general.plugins.httpapi.ftd.HttpApi._get_api_token_path', mock.MagicMock(return_value=None))
|
||||
@patch('ansible_collections.community.general.plugins.httpapi.ftd.HttpApi._get_known_token_paths')
|
||||
def test_lookup_login_url_with_empty_response(self, get_known_token_paths_mock):
|
||||
payload = mock.MagicMock()
|
||||
get_known_token_paths_mock.return_value = []
|
||||
self.assertRaises(
|
||||
ConnectionError,
|
||||
self.ftd_plugin._lookup_login_url,
|
||||
payload
|
||||
)
|
||||
|
||||
@patch('ansible_collections.community.general.plugins.httpapi.ftd.HttpApi._get_known_token_paths')
|
||||
@patch('ansible_collections.community.general.plugins.httpapi.ftd.HttpApi._send_login_request')
|
||||
def test_lookup_login_url_with_failed_request(self, api_request_mock, get_known_token_paths_mock):
|
||||
payload = mock.MagicMock()
|
||||
url = mock.MagicMock()
|
||||
get_known_token_paths_mock.return_value = [url]
|
||||
api_request_mock.side_effect = ConnectionError('Error message')
|
||||
with mock.patch.object(self.ftd_plugin.connection, 'queue_message') as display_mock:
|
||||
self.assertRaises(
|
||||
ConnectionError,
|
||||
self.ftd_plugin._lookup_login_url,
|
||||
payload
|
||||
)
|
||||
assert display_mock.called
|
||||
|
||||
@patch('ansible_collections.community.general.plugins.httpapi.ftd.HttpApi._get_api_token_path', mock.MagicMock(return_value=None))
|
||||
@patch('ansible_collections.community.general.plugins.httpapi.ftd.HttpApi._get_known_token_paths')
|
||||
@patch('ansible_collections.community.general.plugins.httpapi.ftd.HttpApi._send_login_request')
|
||||
@patch('ansible_collections.community.general.plugins.httpapi.ftd.HttpApi._set_api_token_path')
|
||||
def test_lookup_login_url_with_positive_result(self, set_api_token_mock, api_request_mock,
|
||||
get_known_token_paths_mock):
|
||||
payload = mock.MagicMock()
|
||||
url = mock.MagicMock()
|
||||
get_known_token_paths_mock.return_value = [url]
|
||||
response_mock = mock.MagicMock()
|
||||
api_request_mock.return_value = response_mock
|
||||
|
||||
resp = self.ftd_plugin._lookup_login_url(payload)
|
||||
|
||||
set_api_token_mock.assert_called_once_with(url)
|
||||
assert resp == response_mock
|
||||
|
||||
@patch('ansible_collections.community.general.plugins.httpapi.ftd.HttpApi._get_supported_api_versions')
|
||||
def test_get_known_token_paths_with_positive_response(self, get_list_of_supported_api_versions_mock):
|
||||
test_versions = ['v1', 'v2']
|
||||
get_list_of_supported_api_versions_mock.return_value = test_versions
|
||||
result = self.ftd_plugin._get_known_token_paths()
|
||||
assert result == [TOKEN_PATH_TEMPLATE.format(version) for version in test_versions]
|
||||
|
||||
@patch('ansible_collections.community.general.plugins.httpapi.ftd.HttpApi._get_supported_api_versions')
|
||||
def test_get_known_token_paths_with_failed_api_call(self, get_list_of_supported_api_versions_mock):
|
||||
get_list_of_supported_api_versions_mock.side_effect = ConnectionError('test error message')
|
||||
result = self.ftd_plugin._get_known_token_paths()
|
||||
assert result == [TOKEN_PATH_TEMPLATE.format(version) for version in DEFAULT_API_VERSIONS]
|
||||
|
||||
def test_set_api_token_path(self):
|
||||
url = mock.MagicMock()
|
||||
self.ftd_plugin._set_api_token_path(url)
|
||||
assert self.ftd_plugin._get_api_token_path() == url
|
0
tests/unit/plugins/inventory/__init__.py
Normal file
0
tests/unit/plugins/inventory/__init__.py
Normal file
76
tests/unit/plugins/inventory/test_linode.py
Normal file
76
tests/unit/plugins/inventory/test_linode.py
Normal file
|
@ -0,0 +1,76 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright 2018 Luke Murphy <lukewm@riseup.net>
|
||||
#
|
||||
# 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 pytest
|
||||
import sys
|
||||
|
||||
linode_apiv4 = pytest.importorskip('linode_api4')
|
||||
mandatory_py_version = pytest.mark.skipif(
|
||||
sys.version_info < (2, 7),
|
||||
reason='The linode_api4 dependency requires python2.7 or higher'
|
||||
)
|
||||
|
||||
|
||||
from ansible.errors import AnsibleError, AnsibleParserError
|
||||
from ansible_collections.community.general.plugins.inventory.linode import InventoryModule
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def inventory():
|
||||
return InventoryModule()
|
||||
|
||||
|
||||
def test_access_token_lookup(inventory):
|
||||
inventory._options = {'access_token': None}
|
||||
with pytest.raises(AnsibleError) as error_message:
|
||||
inventory._build_client()
|
||||
assert 'Could not retrieve Linode access token' in error_message
|
||||
|
||||
|
||||
def test_validate_option(inventory):
|
||||
assert ['eu-west'] == inventory._validate_option('regions', list, 'eu-west')
|
||||
assert ['eu-west'] == inventory._validate_option('regions', list, ['eu-west'])
|
||||
|
||||
|
||||
def test_validation_option_bad_option(inventory):
|
||||
with pytest.raises(AnsibleParserError) as error_message:
|
||||
inventory._validate_option('regions', dict, [])
|
||||
assert "The option filters ([]) must be a <class 'dict'>" == error_message
|
||||
|
||||
|
||||
def test_empty_config_query_options(inventory):
|
||||
regions, types = inventory._get_query_options({})
|
||||
assert regions == types == []
|
||||
|
||||
|
||||
def test_conig_query_options(inventory):
|
||||
regions, types = inventory._get_query_options({
|
||||
'regions': ['eu-west', 'us-east'],
|
||||
'types': ['g5-standard-2', 'g6-standard-2'],
|
||||
})
|
||||
|
||||
assert regions == ['eu-west', 'us-east']
|
||||
assert types == ['g5-standard-2', 'g6-standard-2']
|
||||
|
||||
|
||||
def test_verify_file_bad_config(inventory):
|
||||
assert inventory.verify_file('foobar.linde.yml') is False
|
0
tests/unit/plugins/lookup/__init__.py
Normal file
0
tests/unit/plugins/lookup/__init__.py
Normal file
104
tests/unit/plugins/lookup/fixtures/avi.json
Normal file
104
tests/unit/plugins/lookup/fixtures/avi.json
Normal file
|
@ -0,0 +1,104 @@
|
|||
{
|
||||
"mock_single_obj": {
|
||||
"_last_modified": "",
|
||||
"cloud_ref": "https://192.0.2.132/api/cloud/cloud-4d063be1-99c2-44cf-8b28-977bd970524c",
|
||||
"dhcp_enabled": true,
|
||||
"exclude_discovered_subnets": false,
|
||||
"name": "PG-123",
|
||||
"synced_from_se": true,
|
||||
"tenant_ref": "https://192.0.2.132/api/tenant/admin",
|
||||
"url": "https://192.0.2.132/api/network/dvportgroup-2084-cloud-4d063be1-99c2-44cf-8b28-977bd970524c",
|
||||
"uuid": "dvportgroup-2084-cloud-4d063be1-99c2-44cf-8b28-977bd970524c",
|
||||
"vcenter_dvs": true,
|
||||
"vimgrnw_ref": "https://192.0.2.132/api/vimgrnwruntime/dvportgroup-2084-cloud-4d063be1-99c2-44cf-8b28-977bd970524c",
|
||||
"vrf_context_ref": "https://192.0.2.132/api/vrfcontext/vrfcontext-31f1b55f-319c-44eb-862f-69d79ffdf295"
|
||||
},
|
||||
"mock_multiple_obj": {
|
||||
"results": [
|
||||
{
|
||||
"_last_modified": "",
|
||||
"cloud_ref": "https://192.0.2.132/api/cloud/cloud-4d063be1-99c2-44cf-8b28-977bd970524c",
|
||||
"dhcp_enabled": true,
|
||||
"exclude_discovered_subnets": false,
|
||||
"name": "J-PG-0682",
|
||||
"synced_from_se": true,
|
||||
"tenant_ref": "https://192.0.2.132/api/tenant/admin",
|
||||
"url": "https://192.0.2.132/api/network/dvportgroup-2084-cloud-4d063be1-99c2-44cf-8b28-977bd970524c",
|
||||
"uuid": "dvportgroup-2084-cloud-4d063be1-99c2-44cf-8b28-977bd970524c",
|
||||
"vcenter_dvs": true,
|
||||
"vimgrnw_ref": "https://192.0.2.132/api/vimgrnwruntime/dvportgroup-2084-cloud-4d063be1-99c2-44cf-8b28-977bd970524c",
|
||||
"vrf_context_ref": "https://192.0.2.132/api/vrfcontext/vrfcontext-31f1b55f-319c-44eb-862f-69d79ffdf295"
|
||||
},
|
||||
{
|
||||
"_last_modified": "",
|
||||
"cloud_ref": "https://192.0.2.132/api/cloud/cloud-4d063be1-99c2-44cf-8b28-977bd970524c",
|
||||
"dhcp_enabled": true,
|
||||
"exclude_discovered_subnets": false,
|
||||
"name": "J-PG-0231",
|
||||
"synced_from_se": true,
|
||||
"tenant_ref": "https://192.0.2.132/api/tenant/admin",
|
||||
"url": "https://192.0.2.132/api/network/dvportgroup-1627-cloud-4d063be1-99c2-44cf-8b28-977bd970524c",
|
||||
"uuid": "dvportgroup-1627-cloud-4d063be1-99c2-44cf-8b28-977bd970524c",
|
||||
"vcenter_dvs": true,
|
||||
"vimgrnw_ref": "https://192.0.2.132/api/vimgrnwruntime/dvportgroup-1627-cloud-4d063be1-99c2-44cf-8b28-977bd970524c",
|
||||
"vrf_context_ref": "https://192.0.2.132/api/vrfcontext/vrfcontext-31f1b55f-319c-44eb-862f-69d79ffdf295"
|
||||
},
|
||||
{
|
||||
"_last_modified": "",
|
||||
"cloud_ref": "https://192.0.2.132/api/cloud/cloud-4d063be1-99c2-44cf-8b28-977bd970524c",
|
||||
"dhcp_enabled": true,
|
||||
"exclude_discovered_subnets": false,
|
||||
"name": "J-PG-0535",
|
||||
"synced_from_se": true,
|
||||
"tenant_ref": "https://192.0.2.132/api/tenant/admin",
|
||||
"url": "https://192.0.2.132/api/network/dvportgroup-1934-cloud-4d063be1-99c2-44cf-8b28-977bd970524c",
|
||||
"uuid": "dvportgroup-1934-cloud-4d063be1-99c2-44cf-8b28-977bd970524c",
|
||||
"vcenter_dvs": true,
|
||||
"vimgrnw_ref": "https://192.0.2.132/api/vimgrnwruntime/dvportgroup-1934-cloud-4d063be1-99c2-44cf-8b28-977bd970524c",
|
||||
"vrf_context_ref": "https://192.0.2.132/api/vrfcontext/vrfcontext-31f1b55f-319c-44eb-862f-69d79ffdf295"
|
||||
},
|
||||
{
|
||||
"_last_modified": "",
|
||||
"cloud_ref": "https://192.0.2.132/api/cloud/cloud-4d063be1-99c2-44cf-8b28-977bd970524c",
|
||||
"dhcp_enabled": true,
|
||||
"exclude_discovered_subnets": false,
|
||||
"name": "J-PG-0094",
|
||||
"synced_from_se": true,
|
||||
"tenant_ref": "https://192.0.2.132/api/tenant/admin",
|
||||
"url": "https://192.0.2.132/api/network/dvportgroup-1458-cloud-4d063be1-99c2-44cf-8b28-977bd970524c",
|
||||
"uuid": "dvportgroup-1458-cloud-4d063be1-99c2-44cf-8b28-977bd970524c",
|
||||
"vcenter_dvs": true,
|
||||
"vimgrnw_ref": "https://192.0.2.132/api/vimgrnwruntime/dvportgroup-1458-cloud-4d063be1-99c2-44cf-8b28-977bd970524c",
|
||||
"vrf_context_ref": "https://192.0.2.132/api/vrfcontext/vrfcontext-31f1b55f-319c-44eb-862f-69d79ffdf295"
|
||||
},
|
||||
{
|
||||
"_last_modified": "",
|
||||
"cloud_ref": "https://192.0.2.132/api/cloud/cloud-4d063be1-99c2-44cf-8b28-977bd970524c",
|
||||
"dhcp_enabled": true,
|
||||
"exclude_discovered_subnets": false,
|
||||
"name": "J-PG-0437",
|
||||
"synced_from_se": true,
|
||||
"tenant_ref": "https://192.0.2.132/api/tenant/admin",
|
||||
"url": "https://192.0.2.132/api/network/dvportgroup-1836-cloud-4d063be1-99c2-44cf-8b28-977bd970524c",
|
||||
"uuid": "dvportgroup-1836-cloud-4d063be1-99c2-44cf-8b28-977bd970524c",
|
||||
"vcenter_dvs": true,
|
||||
"vimgrnw_ref": "https://192.0.2.132/api/vimgrnwruntime/dvportgroup-1836-cloud-4d063be1-99c2-44cf-8b28-977bd970524c",
|
||||
"vrf_context_ref": "https://192.0.2.132/api/vrfcontext/vrfcontext-31f1b55f-319c-44eb-862f-69d79ffdf295"
|
||||
},
|
||||
{
|
||||
"_last_modified": "",
|
||||
"cloud_ref": "https://192.0.2.132/api/cloud/cloud-4d063be1-99c2-44cf-8b28-977bd970524c",
|
||||
"dhcp_enabled": true,
|
||||
"exclude_discovered_subnets": false,
|
||||
"name": "J-PG-0673",
|
||||
"synced_from_se": true,
|
||||
"tenant_ref": "https://192.0.2.132/api/tenant/admin",
|
||||
"url": "https://192.0.2.132/api/network/dvportgroup-2075-cloud-4d063be1-99c2-44cf-8b28-977bd970524c",
|
||||
"uuid": "dvportgroup-2075-cloud-4d063be1-99c2-44cf-8b28-977bd970524c",
|
||||
"vcenter_dvs": true,
|
||||
"vimgrnw_ref": "https://192.0.2.132/api/vimgrnwruntime/dvportgroup-2075-cloud-4d063be1-99c2-44cf-8b28-977bd970524c",
|
||||
"vrf_context_ref": "https://192.0.2.132/api/vrfcontext/vrfcontext-31f1b55f-319c-44eb-862f-69d79ffdf295"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
92
tests/unit/plugins/lookup/test_avi.py
Normal file
92
tests/unit/plugins/lookup/test_avi.py
Normal file
|
@ -0,0 +1,92 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# (c) 2019, Sandeep Bandi <sandeepb@avinetworks.com>
|
||||
#
|
||||
# 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 pytest
|
||||
import json
|
||||
|
||||
from ansible_collections.community.general.tests.unit.compat.mock import patch, MagicMock
|
||||
|
||||
from ansible.errors import AnsibleError
|
||||
from ansible.plugins.loader import lookup_loader
|
||||
from ansible_collections.community.general.plugins.lookup import avi
|
||||
|
||||
|
||||
try:
|
||||
import builtins as __builtin__
|
||||
except ImportError:
|
||||
import __builtin__
|
||||
|
||||
|
||||
fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
|
||||
|
||||
with open(fixture_path + '/avi.json') as json_file:
|
||||
data = json.load(json_file)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def dummy_credentials():
|
||||
dummy_credentials = {}
|
||||
dummy_credentials['controller'] = "192.0.2.13"
|
||||
dummy_credentials['username'] = "admin"
|
||||
dummy_credentials['password'] = "password"
|
||||
dummy_credentials['api_version'] = "17.2.14"
|
||||
dummy_credentials['tenant'] = 'admin'
|
||||
return dummy_credentials
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def super_switcher(scope="function", autouse=True):
|
||||
# Mocking the inbuilt super as it is used in ApiSession initialization
|
||||
original_super = __builtin__.super
|
||||
__builtin__.super = MagicMock()
|
||||
yield
|
||||
# Revert the super to default state
|
||||
__builtin__.super = original_super
|
||||
|
||||
|
||||
def test_lookup_multiple_obj(dummy_credentials):
|
||||
avi_lookup = lookup_loader.get('avi')
|
||||
avi_mock = MagicMock()
|
||||
avi_mock.return_value.get.return_value.json.return_value = data["mock_multiple_obj"]
|
||||
with patch.object(avi, 'ApiSession', avi_mock):
|
||||
retval = avi_lookup.run([], {}, avi_credentials=dummy_credentials,
|
||||
obj_type="network")
|
||||
assert retval == data["mock_multiple_obj"]["results"]
|
||||
|
||||
|
||||
def test_lookup_single_obj(dummy_credentials):
|
||||
avi_lookup = lookup_loader.get('avi')
|
||||
avi_mock = MagicMock()
|
||||
avi_mock.return_value.get_object_by_name.return_value = data["mock_single_obj"]
|
||||
with patch.object(avi, 'ApiSession', avi_mock):
|
||||
retval = avi_lookup.run([], {}, avi_credentials=dummy_credentials,
|
||||
obj_type="network", obj_name='PG-123')
|
||||
assert retval[0] == data["mock_single_obj"]
|
||||
|
||||
|
||||
def test_invalid_lookup(dummy_credentials):
|
||||
avi_lookup = lookup_loader.get('avi')
|
||||
avi_mock = MagicMock()
|
||||
with pytest.raises(AnsibleError):
|
||||
with patch.object(avi, 'ApiSession', avi_mock):
|
||||
avi_lookup.run([], {}, avi_credentials=dummy_credentials)
|
110
tests/unit/plugins/lookup/test_conjur_variable.py
Normal file
110
tests/unit/plugins/lookup/test_conjur_variable.py
Normal file
|
@ -0,0 +1,110 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# (c) 2018, Jason Vanderhoof <jason.vanderhoof@cyberark.com>
|
||||
#
|
||||
# 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 pytest
|
||||
from ansible_collections.community.general.tests.unit.compat.mock import MagicMock
|
||||
from ansible.errors import AnsibleError
|
||||
from ansible.module_utils.six.moves import http_client
|
||||
from ansible_collections.community.general.plugins.lookup import conjur_variable
|
||||
import tempfile
|
||||
|
||||
|
||||
class TestLookupModule:
|
||||
def test_valid_netrc_file(self):
|
||||
with tempfile.NamedTemporaryFile() as temp_netrc:
|
||||
temp_netrc.write(b"machine http://localhost/authn\n")
|
||||
temp_netrc.write(b" login admin\n")
|
||||
temp_netrc.write(b" password my-pass\n")
|
||||
temp_netrc.seek(0)
|
||||
|
||||
results = conjur_variable._load_identity_from_file(temp_netrc.name, 'http://localhost')
|
||||
|
||||
assert results['id'] == 'admin'
|
||||
assert results['api_key'] == 'my-pass'
|
||||
|
||||
def test_netrc_without_host_file(self):
|
||||
with tempfile.NamedTemporaryFile() as temp_netrc:
|
||||
temp_netrc.write(b"machine http://localhost/authn\n")
|
||||
temp_netrc.write(b" login admin\n")
|
||||
temp_netrc.write(b" password my-pass\n")
|
||||
temp_netrc.seek(0)
|
||||
|
||||
with pytest.raises(AnsibleError):
|
||||
conjur_variable._load_identity_from_file(temp_netrc.name, 'http://foo')
|
||||
|
||||
def test_valid_configuration(self):
|
||||
with tempfile.NamedTemporaryFile() as configuration_file:
|
||||
configuration_file.write(b"---\n")
|
||||
configuration_file.write(b"account: demo-policy\n")
|
||||
configuration_file.write(b"plugins: []\n")
|
||||
configuration_file.write(b"appliance_url: http://localhost:8080\n")
|
||||
configuration_file.seek(0)
|
||||
|
||||
results = conjur_variable._load_conf_from_file(configuration_file.name)
|
||||
assert results['account'] == 'demo-policy'
|
||||
assert results['appliance_url'] == 'http://localhost:8080'
|
||||
|
||||
def test_valid_token_retrieval(self, mocker):
|
||||
mock_response = MagicMock(spec_set=http_client.HTTPResponse)
|
||||
try:
|
||||
mock_response.getcode.return_value = 200
|
||||
except Exception:
|
||||
# HTTPResponse is a Python 3 only feature. This uses a generic mock for python 2.6
|
||||
mock_response = MagicMock()
|
||||
mock_response.getcode.return_value = 200
|
||||
|
||||
mock_response.read.return_value = 'foo-bar-token'
|
||||
mocker.patch.object(conjur_variable, 'open_url', return_value=mock_response)
|
||||
|
||||
response = conjur_variable._fetch_conjur_token('http://conjur', 'account', 'username', 'api_key')
|
||||
assert response == 'foo-bar-token'
|
||||
|
||||
def test_valid_fetch_conjur_variable(self, mocker):
|
||||
mock_response = MagicMock(spec_set=http_client.HTTPResponse)
|
||||
try:
|
||||
mock_response.getcode.return_value = 200
|
||||
except Exception:
|
||||
# HTTPResponse is a Python 3 only feature. This uses a generic mock for python 2.6
|
||||
mock_response = MagicMock()
|
||||
mock_response.getcode.return_value = 200
|
||||
|
||||
mock_response.read.return_value = 'foo-bar'
|
||||
mocker.patch.object(conjur_variable, 'open_url', return_value=mock_response)
|
||||
|
||||
response = conjur_variable._fetch_conjur_token('super-secret', 'token', 'http://conjur', 'account')
|
||||
assert response == 'foo-bar'
|
||||
|
||||
def test_invalid_fetch_conjur_variable(self, mocker):
|
||||
for code in [401, 403, 404]:
|
||||
mock_response = MagicMock(spec_set=http_client.HTTPResponse)
|
||||
try:
|
||||
mock_response.getcode.return_value = code
|
||||
except Exception:
|
||||
# HTTPResponse is a Python 3 only feature. This uses a generic mock for python 2.6
|
||||
mock_response = MagicMock()
|
||||
mock_response.getcode.return_value = code
|
||||
|
||||
mocker.patch.object(conjur_variable, 'open_url', return_value=mock_response)
|
||||
|
||||
with pytest.raises(AnsibleError):
|
||||
response = conjur_variable._fetch_conjur_token('super-secret', 'token', 'http://conjur', 'account')
|
187
tests/unit/plugins/lookup/test_lastpass.py
Normal file
187
tests/unit/plugins/lookup/test_lastpass.py
Normal file
|
@ -0,0 +1,187 @@
|
|||
# (c)2016 Andrew Zenk <azenk@umn.edu>
|
||||
#
|
||||
# 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
|
||||
|
||||
from argparse import ArgumentParser
|
||||
|
||||
from ansible_collections.community.general.tests.unit.compat import unittest
|
||||
from ansible_collections.community.general.tests.unit.compat.mock import patch
|
||||
|
||||
from ansible.errors import AnsibleError
|
||||
from ansible.module_utils import six
|
||||
from ansible_collections.community.general.plugins.lookup.lastpass import LookupModule, LPass, LPassException
|
||||
|
||||
|
||||
MOCK_ENTRIES = [{'username': 'user',
|
||||
'name': 'Mock Entry',
|
||||
'password': 't0pS3cret passphrase entry!',
|
||||
'url': 'https://localhost/login',
|
||||
'notes': 'Test\nnote with multiple lines.\n',
|
||||
'id': '0123456789'}]
|
||||
|
||||
|
||||
class MockLPass(LPass):
|
||||
|
||||
_mock_logged_out = False
|
||||
_mock_disconnected = False
|
||||
|
||||
def _lookup_mock_entry(self, key):
|
||||
for entry in MOCK_ENTRIES:
|
||||
if key == entry['id'] or key == entry['name']:
|
||||
return entry
|
||||
|
||||
def _run(self, args, stdin=None, expected_rc=0):
|
||||
# Mock behavior of lpass executable
|
||||
base_options = ArgumentParser(add_help=False)
|
||||
base_options.add_argument('--color', default="auto", choices=['auto', 'always', 'never'])
|
||||
|
||||
p = ArgumentParser()
|
||||
sp = p.add_subparsers(help='command', dest='subparser_name')
|
||||
|
||||
logout_p = sp.add_parser('logout', parents=[base_options], help='logout')
|
||||
show_p = sp.add_parser('show', parents=[base_options], help='show entry details')
|
||||
|
||||
field_group = show_p.add_mutually_exclusive_group(required=True)
|
||||
for field in MOCK_ENTRIES[0].keys():
|
||||
field_group.add_argument("--{0}".format(field), default=False, action='store_true')
|
||||
field_group.add_argument('--field', default=None)
|
||||
show_p.add_argument('selector', help='Unique Name or ID')
|
||||
|
||||
args = p.parse_args(args)
|
||||
|
||||
def mock_exit(output='', error='', rc=0):
|
||||
if rc != expected_rc:
|
||||
raise LPassException(error)
|
||||
return output, error
|
||||
|
||||
if args.color != 'never':
|
||||
return mock_exit(error='Error: Mock only supports --color=never', rc=1)
|
||||
|
||||
if args.subparser_name == 'logout':
|
||||
if self._mock_logged_out:
|
||||
return mock_exit(error='Error: Not currently logged in', rc=1)
|
||||
|
||||
logged_in_error = 'Are you sure you would like to log out? [Y/n]'
|
||||
if stdin and stdin.lower() == 'n\n':
|
||||
return mock_exit(output='Log out: aborted.', error=logged_in_error, rc=1)
|
||||
elif stdin and stdin.lower() == 'y\n':
|
||||
return mock_exit(output='Log out: complete.', error=logged_in_error, rc=0)
|
||||
else:
|
||||
return mock_exit(error='Error: aborted response', rc=1)
|
||||
|
||||
if args.subparser_name == 'show':
|
||||
if self._mock_logged_out:
|
||||
return mock_exit(error='Error: Could not find decryption key.' +
|
||||
' Perhaps you need to login with `lpass login`.', rc=1)
|
||||
|
||||
if self._mock_disconnected:
|
||||
return mock_exit(error='Error: Couldn\'t resolve host name.', rc=1)
|
||||
|
||||
mock_entry = self._lookup_mock_entry(args.selector)
|
||||
|
||||
if args.field:
|
||||
return mock_exit(output=mock_entry.get(args.field, ''))
|
||||
elif args.password:
|
||||
return mock_exit(output=mock_entry.get('password', ''))
|
||||
elif args.username:
|
||||
return mock_exit(output=mock_entry.get('username', ''))
|
||||
elif args.url:
|
||||
return mock_exit(output=mock_entry.get('url', ''))
|
||||
elif args.name:
|
||||
return mock_exit(output=mock_entry.get('name', ''))
|
||||
elif args.id:
|
||||
return mock_exit(output=mock_entry.get('id', ''))
|
||||
elif args.notes:
|
||||
return mock_exit(output=mock_entry.get('notes', ''))
|
||||
|
||||
raise LPassException('We should never get here')
|
||||
|
||||
|
||||
class DisconnectedMockLPass(MockLPass):
|
||||
|
||||
_mock_disconnected = True
|
||||
|
||||
|
||||
class LoggedOutMockLPass(MockLPass):
|
||||
|
||||
_mock_logged_out = True
|
||||
|
||||
|
||||
class TestLPass(unittest.TestCase):
|
||||
|
||||
def test_lastpass_cli_path(self):
|
||||
lp = MockLPass(path='/dev/null')
|
||||
self.assertEqual('/dev/null', lp.cli_path)
|
||||
|
||||
def test_lastpass_build_args_logout(self):
|
||||
lp = MockLPass()
|
||||
self.assertEqual(['logout', '--color=never'], lp._build_args("logout"))
|
||||
|
||||
def test_lastpass_logged_in_true(self):
|
||||
lp = MockLPass()
|
||||
self.assertTrue(lp.logged_in)
|
||||
|
||||
def test_lastpass_logged_in_false(self):
|
||||
lp = LoggedOutMockLPass()
|
||||
self.assertFalse(lp.logged_in)
|
||||
|
||||
def test_lastpass_show_disconnected(self):
|
||||
lp = DisconnectedMockLPass()
|
||||
|
||||
with self.assertRaises(LPassException):
|
||||
lp.get_field('0123456789', 'username')
|
||||
|
||||
def test_lastpass_show(self):
|
||||
lp = MockLPass()
|
||||
for entry in MOCK_ENTRIES:
|
||||
entry_id = entry.get('id')
|
||||
for k, v in six.iteritems(entry):
|
||||
self.assertEqual(v.strip(), lp.get_field(entry_id, k))
|
||||
|
||||
|
||||
class TestLastpassPlugin(unittest.TestCase):
|
||||
|
||||
@patch('ansible_collections.community.general.plugins.lookup.lastpass.LPass', new=MockLPass)
|
||||
def test_lastpass_plugin_normal(self):
|
||||
lookup_plugin = LookupModule()
|
||||
|
||||
for entry in MOCK_ENTRIES:
|
||||
entry_id = entry.get('id')
|
||||
for k, v in six.iteritems(entry):
|
||||
self.assertEqual(v.strip(),
|
||||
lookup_plugin.run([entry_id], field=k)[0])
|
||||
|
||||
@patch('ansible_collections.community.general.plugins.lookup.lastpass.LPass', LoggedOutMockLPass)
|
||||
def test_lastpass_plugin_logged_out(self):
|
||||
lookup_plugin = LookupModule()
|
||||
|
||||
entry = MOCK_ENTRIES[0]
|
||||
entry_id = entry.get('id')
|
||||
with self.assertRaises(AnsibleError):
|
||||
lookup_plugin.run([entry_id], field='password')
|
||||
|
||||
@patch('ansible_collections.community.general.plugins.lookup.lastpass.LPass', DisconnectedMockLPass)
|
||||
def test_lastpass_plugin_disconnected(self):
|
||||
lookup_plugin = LookupModule()
|
||||
|
||||
entry = MOCK_ENTRIES[0]
|
||||
entry_id = entry.get('id')
|
||||
with self.assertRaises(AnsibleError):
|
||||
lookup_plugin.run([entry_id], field='password')
|
536
tests/unit/plugins/lookup/test_manifold.py
Normal file
536
tests/unit/plugins/lookup/test_manifold.py
Normal file
|
@ -0,0 +1,536 @@
|
|||
# (c) 2018, Arigato Machine Inc.
|
||||
# (c) 2018, Ansible Project
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
from ansible_collections.community.general.tests.unit.compat import unittest
|
||||
from ansible_collections.community.general.tests.unit.compat.mock import patch, call
|
||||
from ansible.errors import AnsibleError
|
||||
from ansible.module_utils.urls import ConnectionError, SSLValidationError
|
||||
from ansible.module_utils.six.moves.urllib.error import HTTPError, URLError
|
||||
from ansible.module_utils import six
|
||||
from ansible_collections.community.general.plugins.lookup.manifold import ManifoldApiClient, LookupModule, ApiError
|
||||
import json
|
||||
|
||||
|
||||
API_FIXTURES = {
|
||||
'https://api.marketplace.manifold.co/v1/resources':
|
||||
[
|
||||
{
|
||||
"body": {
|
||||
"label": "resource-1",
|
||||
"name": "Resource 1"
|
||||
},
|
||||
"id": "rid-1"
|
||||
},
|
||||
{
|
||||
"body": {
|
||||
"label": "resource-2",
|
||||
"name": "Resource 2"
|
||||
},
|
||||
"id": "rid-2"
|
||||
}
|
||||
],
|
||||
'https://api.marketplace.manifold.co/v1/resources?label=resource-1':
|
||||
[
|
||||
{
|
||||
"body": {
|
||||
"label": "resource-1",
|
||||
"name": "Resource 1"
|
||||
},
|
||||
"id": "rid-1"
|
||||
}
|
||||
],
|
||||
'https://api.marketplace.manifold.co/v1/resources?label=resource-2':
|
||||
[
|
||||
{
|
||||
"body": {
|
||||
"label": "resource-2",
|
||||
"name": "Resource 2"
|
||||
},
|
||||
"id": "rid-2"
|
||||
}
|
||||
],
|
||||
'https://api.marketplace.manifold.co/v1/resources?team_id=tid-1':
|
||||
[
|
||||
{
|
||||
"body": {
|
||||
"label": "resource-1",
|
||||
"name": "Resource 1"
|
||||
},
|
||||
"id": "rid-1"
|
||||
}
|
||||
],
|
||||
'https://api.marketplace.manifold.co/v1/resources?project_id=pid-1':
|
||||
[
|
||||
{
|
||||
"body": {
|
||||
"label": "resource-2",
|
||||
"name": "Resource 2"
|
||||
},
|
||||
"id": "rid-2"
|
||||
}
|
||||
],
|
||||
'https://api.marketplace.manifold.co/v1/resources?project_id=pid-2':
|
||||
[
|
||||
{
|
||||
"body": {
|
||||
"label": "resource-1",
|
||||
"name": "Resource 1"
|
||||
},
|
||||
"id": "rid-1"
|
||||
},
|
||||
{
|
||||
"body": {
|
||||
"label": "resource-3",
|
||||
"name": "Resource 3"
|
||||
},
|
||||
"id": "rid-3"
|
||||
}
|
||||
],
|
||||
'https://api.marketplace.manifold.co/v1/resources?team_id=tid-1&project_id=pid-1':
|
||||
[
|
||||
{
|
||||
"body": {
|
||||
"label": "resource-1",
|
||||
"name": "Resource 1"
|
||||
},
|
||||
"id": "rid-1"
|
||||
}
|
||||
],
|
||||
'https://api.marketplace.manifold.co/v1/projects':
|
||||
[
|
||||
{
|
||||
"body": {
|
||||
"label": "project-1",
|
||||
"name": "Project 1",
|
||||
},
|
||||
"id": "pid-1",
|
||||
},
|
||||
{
|
||||
"body": {
|
||||
"label": "project-2",
|
||||
"name": "Project 2",
|
||||
},
|
||||
"id": "pid-2",
|
||||
}
|
||||
],
|
||||
'https://api.marketplace.manifold.co/v1/projects?label=project-2':
|
||||
[
|
||||
{
|
||||
"body": {
|
||||
"label": "project-2",
|
||||
"name": "Project 2",
|
||||
},
|
||||
"id": "pid-2",
|
||||
}
|
||||
],
|
||||
'https://api.marketplace.manifold.co/v1/credentials?resource_id=rid-1':
|
||||
[
|
||||
{
|
||||
"body": {
|
||||
"resource_id": "rid-1",
|
||||
"values": {
|
||||
"RESOURCE_TOKEN_1": "token-1",
|
||||
"RESOURCE_TOKEN_2": "token-2"
|
||||
}
|
||||
},
|
||||
"id": "cid-1",
|
||||
}
|
||||
],
|
||||
'https://api.marketplace.manifold.co/v1/credentials?resource_id=rid-2':
|
||||
[
|
||||
{
|
||||
"body": {
|
||||
"resource_id": "rid-2",
|
||||
"values": {
|
||||
"RESOURCE_TOKEN_3": "token-3",
|
||||
"RESOURCE_TOKEN_4": "token-4"
|
||||
}
|
||||
},
|
||||
"id": "cid-2",
|
||||
}
|
||||
],
|
||||
'https://api.marketplace.manifold.co/v1/credentials?resource_id=rid-3':
|
||||
[
|
||||
{
|
||||
"body": {
|
||||
"resource_id": "rid-3",
|
||||
"values": {
|
||||
"RESOURCE_TOKEN_1": "token-5",
|
||||
"RESOURCE_TOKEN_2": "token-6"
|
||||
}
|
||||
},
|
||||
"id": "cid-3",
|
||||
}
|
||||
],
|
||||
'https://api.identity.manifold.co/v1/teams':
|
||||
[
|
||||
{
|
||||
"id": "tid-1",
|
||||
"body": {
|
||||
"name": "Team 1",
|
||||
"label": "team-1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "tid-2",
|
||||
"body": {
|
||||
"name": "Team 2",
|
||||
"label": "team-2"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
def mock_fixture(open_url_mock, fixture=None, data=None, headers=None):
|
||||
if not headers:
|
||||
headers = {}
|
||||
if fixture:
|
||||
data = json.dumps(API_FIXTURES[fixture])
|
||||
if 'content-type' not in headers:
|
||||
headers['content-type'] = 'application/json'
|
||||
|
||||
open_url_mock.return_value.read.return_value = data
|
||||
open_url_mock.return_value.headers = headers
|
||||
|
||||
|
||||
class TestManifoldApiClient(unittest.TestCase):
|
||||
@patch('ansible_collections.community.general.plugins.lookup.manifold.open_url')
|
||||
def test_request_sends_default_headers(self, open_url_mock):
|
||||
mock_fixture(open_url_mock, data='hello')
|
||||
client = ManifoldApiClient('token-123')
|
||||
client.request('test', 'endpoint')
|
||||
open_url_mock.assert_called_with('https://api.test.manifold.co/v1/endpoint',
|
||||
headers={'Accept': '*/*', 'Authorization': 'Bearer token-123'},
|
||||
http_agent='python-manifold-ansible-1.0.0')
|
||||
|
||||
@patch('ansible_collections.community.general.plugins.lookup.manifold.open_url')
|
||||
def test_request_decodes_json(self, open_url_mock):
|
||||
mock_fixture(open_url_mock, fixture='https://api.marketplace.manifold.co/v1/resources')
|
||||
client = ManifoldApiClient('token-123')
|
||||
self.assertIsInstance(client.request('marketplace', 'resources'), list)
|
||||
|
||||
@patch('ansible_collections.community.general.plugins.lookup.manifold.open_url')
|
||||
def test_request_streams_text(self, open_url_mock):
|
||||
mock_fixture(open_url_mock, data='hello', headers={'content-type': "text/plain"})
|
||||
client = ManifoldApiClient('token-123')
|
||||
self.assertEqual('hello', client.request('test', 'endpoint'))
|
||||
|
||||
@patch('ansible_collections.community.general.plugins.lookup.manifold.open_url')
|
||||
def test_request_processes_parameterized_headers(self, open_url_mock):
|
||||
mock_fixture(open_url_mock, data='hello')
|
||||
client = ManifoldApiClient('token-123')
|
||||
client.request('test', 'endpoint', headers={'X-HEADER': 'MANIFOLD'})
|
||||
open_url_mock.assert_called_with('https://api.test.manifold.co/v1/endpoint',
|
||||
headers={'Accept': '*/*', 'Authorization': 'Bearer token-123',
|
||||
'X-HEADER': 'MANIFOLD'},
|
||||
http_agent='python-manifold-ansible-1.0.0')
|
||||
|
||||
@patch('ansible_collections.community.general.plugins.lookup.manifold.open_url')
|
||||
def test_request_passes_arbitrary_parameters(self, open_url_mock):
|
||||
mock_fixture(open_url_mock, data='hello')
|
||||
client = ManifoldApiClient('token-123')
|
||||
client.request('test', 'endpoint', use_proxy=False, timeout=5)
|
||||
open_url_mock.assert_called_with('https://api.test.manifold.co/v1/endpoint',
|
||||
headers={'Accept': '*/*', 'Authorization': 'Bearer token-123'},
|
||||
http_agent='python-manifold-ansible-1.0.0',
|
||||
use_proxy=False, timeout=5)
|
||||
|
||||
@patch('ansible_collections.community.general.plugins.lookup.manifold.open_url')
|
||||
def test_request_raises_on_incorrect_json(self, open_url_mock):
|
||||
mock_fixture(open_url_mock, data='noJson', headers={'content-type': "application/json"})
|
||||
client = ManifoldApiClient('token-123')
|
||||
with self.assertRaises(ApiError) as context:
|
||||
client.request('test', 'endpoint')
|
||||
self.assertEqual('JSON response can\'t be parsed while requesting https://api.test.manifold.co/v1/endpoint:\n'
|
||||
'noJson',
|
||||
str(context.exception))
|
||||
|
||||
@patch('ansible_collections.community.general.plugins.lookup.manifold.open_url')
|
||||
def test_request_raises_on_status_500(self, open_url_mock):
|
||||
open_url_mock.side_effect = HTTPError('https://api.test.manifold.co/v1/endpoint',
|
||||
500, 'Server error', {}, six.StringIO('ERROR'))
|
||||
client = ManifoldApiClient('token-123')
|
||||
with self.assertRaises(ApiError) as context:
|
||||
client.request('test', 'endpoint')
|
||||
self.assertEqual('Server returned: HTTP Error 500: Server error while requesting '
|
||||
'https://api.test.manifold.co/v1/endpoint:\nERROR',
|
||||
str(context.exception))
|
||||
|
||||
@patch('ansible_collections.community.general.plugins.lookup.manifold.open_url')
|
||||
def test_request_raises_on_bad_url(self, open_url_mock):
|
||||
open_url_mock.side_effect = URLError('URL is invalid')
|
||||
client = ManifoldApiClient('token-123')
|
||||
with self.assertRaises(ApiError) as context:
|
||||
client.request('test', 'endpoint')
|
||||
self.assertEqual('Failed lookup url for https://api.test.manifold.co/v1/endpoint : <url'
|
||||
'open error URL is invalid>',
|
||||
str(context.exception))
|
||||
|
||||
@patch('ansible_collections.community.general.plugins.lookup.manifold.open_url')
|
||||
def test_request_raises_on_ssl_error(self, open_url_mock):
|
||||
open_url_mock.side_effect = SSLValidationError('SSL Error')
|
||||
client = ManifoldApiClient('token-123')
|
||||
with self.assertRaises(ApiError) as context:
|
||||
client.request('test', 'endpoint')
|
||||
self.assertEqual('Error validating the server\'s certificate for https://api.test.manifold.co/v1/endpoint: '
|
||||
'SSL Error',
|
||||
str(context.exception))
|
||||
|
||||
@patch('ansible_collections.community.general.plugins.lookup.manifold.open_url')
|
||||
def test_request_raises_on_connection_error(self, open_url_mock):
|
||||
open_url_mock.side_effect = ConnectionError('Unknown connection error')
|
||||
client = ManifoldApiClient('token-123')
|
||||
with self.assertRaises(ApiError) as context:
|
||||
client.request('test', 'endpoint')
|
||||
self.assertEqual('Error connecting to https://api.test.manifold.co/v1/endpoint: Unknown connection error',
|
||||
str(context.exception))
|
||||
|
||||
@patch('ansible_collections.community.general.plugins.lookup.manifold.open_url')
|
||||
def test_get_resources_get_all(self, open_url_mock):
|
||||
url = 'https://api.marketplace.manifold.co/v1/resources'
|
||||
mock_fixture(open_url_mock, fixture=url)
|
||||
client = ManifoldApiClient('token-123')
|
||||
self.assertListEqual(API_FIXTURES[url], client.get_resources())
|
||||
open_url_mock.assert_called_with(url,
|
||||
headers={'Accept': '*/*', 'Authorization': 'Bearer token-123'},
|
||||
http_agent='python-manifold-ansible-1.0.0')
|
||||
|
||||
@patch('ansible_collections.community.general.plugins.lookup.manifold.open_url')
|
||||
def test_get_resources_filter_label(self, open_url_mock):
|
||||
url = 'https://api.marketplace.manifold.co/v1/resources?label=resource-1'
|
||||
mock_fixture(open_url_mock, fixture=url)
|
||||
client = ManifoldApiClient('token-123')
|
||||
self.assertListEqual(API_FIXTURES[url], client.get_resources(label='resource-1'))
|
||||
open_url_mock.assert_called_with(url,
|
||||
headers={'Accept': '*/*', 'Authorization': 'Bearer token-123'},
|
||||
http_agent='python-manifold-ansible-1.0.0')
|
||||
|
||||
@patch('ansible_collections.community.general.plugins.lookup.manifold.open_url')
|
||||
def test_get_resources_filter_team_and_project(self, open_url_mock):
|
||||
url = 'https://api.marketplace.manifold.co/v1/resources?team_id=tid-1&project_id=pid-1'
|
||||
mock_fixture(open_url_mock, fixture=url)
|
||||
client = ManifoldApiClient('token-123')
|
||||
self.assertListEqual(API_FIXTURES[url], client.get_resources(team_id='tid-1', project_id='pid-1'))
|
||||
args, kwargs = open_url_mock.call_args
|
||||
url_called = args[0]
|
||||
# Dict order is not guaranteed, so an url may have querystring parameters order randomized
|
||||
self.assertIn('team_id=tid-1', url_called)
|
||||
self.assertIn('project_id=pid-1', url_called)
|
||||
|
||||
@patch('ansible_collections.community.general.plugins.lookup.manifold.open_url')
|
||||
def test_get_teams_get_all(self, open_url_mock):
|
||||
url = 'https://api.identity.manifold.co/v1/teams'
|
||||
mock_fixture(open_url_mock, fixture=url)
|
||||
client = ManifoldApiClient('token-123')
|
||||
self.assertListEqual(API_FIXTURES[url], client.get_teams())
|
||||
open_url_mock.assert_called_with(url,
|
||||
headers={'Accept': '*/*', 'Authorization': 'Bearer token-123'},
|
||||
http_agent='python-manifold-ansible-1.0.0')
|
||||
|
||||
@patch('ansible_collections.community.general.plugins.lookup.manifold.open_url')
|
||||
def test_get_teams_filter_label(self, open_url_mock):
|
||||
url = 'https://api.identity.manifold.co/v1/teams'
|
||||
mock_fixture(open_url_mock, fixture=url)
|
||||
client = ManifoldApiClient('token-123')
|
||||
self.assertListEqual(API_FIXTURES[url][1:2], client.get_teams(label='team-2'))
|
||||
open_url_mock.assert_called_with(url,
|
||||
headers={'Accept': '*/*', 'Authorization': 'Bearer token-123'},
|
||||
http_agent='python-manifold-ansible-1.0.0')
|
||||
|
||||
@patch('ansible_collections.community.general.plugins.lookup.manifold.open_url')
|
||||
def test_get_projects_get_all(self, open_url_mock):
|
||||
url = 'https://api.marketplace.manifold.co/v1/projects'
|
||||
mock_fixture(open_url_mock, fixture=url)
|
||||
client = ManifoldApiClient('token-123')
|
||||
self.assertListEqual(API_FIXTURES[url], client.get_projects())
|
||||
open_url_mock.assert_called_with(url,
|
||||
headers={'Accept': '*/*', 'Authorization': 'Bearer token-123'},
|
||||
http_agent='python-manifold-ansible-1.0.0')
|
||||
|
||||
@patch('ansible_collections.community.general.plugins.lookup.manifold.open_url')
|
||||
def test_get_projects_filter_label(self, open_url_mock):
|
||||
url = 'https://api.marketplace.manifold.co/v1/projects?label=project-2'
|
||||
mock_fixture(open_url_mock, fixture=url)
|
||||
client = ManifoldApiClient('token-123')
|
||||
self.assertListEqual(API_FIXTURES[url], client.get_projects(label='project-2'))
|
||||
open_url_mock.assert_called_with(url,
|
||||
headers={'Accept': '*/*', 'Authorization': 'Bearer token-123'},
|
||||
http_agent='python-manifold-ansible-1.0.0')
|
||||
|
||||
@patch('ansible_collections.community.general.plugins.lookup.manifold.open_url')
|
||||
def test_get_credentials(self, open_url_mock):
|
||||
url = 'https://api.marketplace.manifold.co/v1/credentials?resource_id=rid-1'
|
||||
mock_fixture(open_url_mock, fixture=url)
|
||||
client = ManifoldApiClient('token-123')
|
||||
self.assertListEqual(API_FIXTURES[url], client.get_credentials(resource_id='rid-1'))
|
||||
open_url_mock.assert_called_with(url,
|
||||
headers={'Accept': '*/*', 'Authorization': 'Bearer token-123'},
|
||||
http_agent='python-manifold-ansible-1.0.0')
|
||||
|
||||
|
||||
class TestLookupModule(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.lookup = LookupModule()
|
||||
self.lookup._load_name = "manifold"
|
||||
|
||||
@patch('ansible_collections.community.general.plugins.lookup.manifold.ManifoldApiClient')
|
||||
def test_get_all(self, client_mock):
|
||||
expected_result = [{'RESOURCE_TOKEN_1': 'token-1',
|
||||
'RESOURCE_TOKEN_2': 'token-2',
|
||||
'RESOURCE_TOKEN_3': 'token-3',
|
||||
'RESOURCE_TOKEN_4': 'token-4'
|
||||
}]
|
||||
client_mock.return_value.get_resources.return_value = API_FIXTURES['https://api.marketplace.manifold.co/v1/resources']
|
||||
client_mock.return_value.get_credentials.side_effect = lambda x: API_FIXTURES['https://api.marketplace.manifold.co/v1/'
|
||||
'credentials?resource_id={0}'.format(x)]
|
||||
self.assertListEqual(expected_result, self.lookup.run([], api_token='token-123'))
|
||||
client_mock.assert_called_with('token-123')
|
||||
client_mock.return_value.get_resources.assert_called_with(team_id=None, project_id=None)
|
||||
|
||||
@patch('ansible_collections.community.general.plugins.lookup.manifold.ManifoldApiClient')
|
||||
def test_get_one_resource(self, client_mock):
|
||||
expected_result = [{'RESOURCE_TOKEN_3': 'token-3',
|
||||
'RESOURCE_TOKEN_4': 'token-4'
|
||||
}]
|
||||
client_mock.return_value.get_resources.return_value = API_FIXTURES['https://api.marketplace.manifold.co/v1/resources?label=resource-2']
|
||||
client_mock.return_value.get_credentials.side_effect = lambda x: API_FIXTURES['https://api.marketplace.manifold.co/v1/'
|
||||
'credentials?resource_id={0}'.format(x)]
|
||||
self.assertListEqual(expected_result, self.lookup.run(['resource-2'], api_token='token-123'))
|
||||
client_mock.return_value.get_resources.assert_called_with(team_id=None, project_id=None, label='resource-2')
|
||||
|
||||
@patch('ansible_collections.community.general.plugins.lookup.manifold.ManifoldApiClient')
|
||||
def test_get_two_resources(self, client_mock):
|
||||
expected_result = [{'RESOURCE_TOKEN_1': 'token-1',
|
||||
'RESOURCE_TOKEN_2': 'token-2',
|
||||
'RESOURCE_TOKEN_3': 'token-3',
|
||||
'RESOURCE_TOKEN_4': 'token-4'
|
||||
}]
|
||||
client_mock.return_value.get_resources.return_value = API_FIXTURES['https://api.marketplace.manifold.co/v1/resources']
|
||||
client_mock.return_value.get_credentials.side_effect = lambda x: API_FIXTURES['https://api.marketplace.manifold.co/v1/'
|
||||
'credentials?resource_id={0}'.format(x)]
|
||||
self.assertListEqual(expected_result, self.lookup.run(['resource-1', 'resource-2'], api_token='token-123'))
|
||||
client_mock.assert_called_with('token-123')
|
||||
client_mock.return_value.get_resources.assert_called_with(team_id=None, project_id=None)
|
||||
|
||||
@patch('ansible_collections.community.general.plugins.lookup.manifold.display')
|
||||
@patch('ansible_collections.community.general.plugins.lookup.manifold.ManifoldApiClient')
|
||||
def test_get_resources_with_same_credential_names(self, client_mock, display_mock):
|
||||
expected_result = [{'RESOURCE_TOKEN_1': 'token-5',
|
||||
'RESOURCE_TOKEN_2': 'token-6'
|
||||
}]
|
||||
client_mock.return_value.get_resources.return_value = API_FIXTURES['https://api.marketplace.manifold.co/v1/resources?project_id=pid-2']
|
||||
client_mock.return_value.get_projects.return_value = API_FIXTURES['https://api.marketplace.manifold.co/v1/projects?label=project-2']
|
||||
client_mock.return_value.get_credentials.side_effect = lambda x: API_FIXTURES['https://api.marketplace.manifold.co/v1/'
|
||||
'credentials?resource_id={0}'.format(x)]
|
||||
self.assertListEqual(expected_result, self.lookup.run([], api_token='token-123', project='project-2'))
|
||||
client_mock.assert_called_with('token-123')
|
||||
display_mock.warning.assert_has_calls([
|
||||
call("'RESOURCE_TOKEN_1' with label 'resource-1' was replaced by resource data with label 'resource-3'"),
|
||||
call("'RESOURCE_TOKEN_2' with label 'resource-1' was replaced by resource data with label 'resource-3'")],
|
||||
any_order=True
|
||||
)
|
||||
client_mock.return_value.get_resources.assert_called_with(team_id=None, project_id='pid-2')
|
||||
|
||||
@patch('ansible_collections.community.general.plugins.lookup.manifold.ManifoldApiClient')
|
||||
def test_filter_by_team(self, client_mock):
|
||||
expected_result = [{'RESOURCE_TOKEN_1': 'token-1',
|
||||
'RESOURCE_TOKEN_2': 'token-2'
|
||||
}]
|
||||
client_mock.return_value.get_resources.return_value = API_FIXTURES['https://api.marketplace.manifold.co/v1/resources?team_id=tid-1']
|
||||
client_mock.return_value.get_teams.return_value = API_FIXTURES['https://api.identity.manifold.co/v1/teams'][0:1]
|
||||
client_mock.return_value.get_credentials.side_effect = lambda x: API_FIXTURES['https://api.marketplace.manifold.co/v1/'
|
||||
'credentials?resource_id={0}'.format(x)]
|
||||
self.assertListEqual(expected_result, self.lookup.run([], api_token='token-123', team='team-1'))
|
||||
client_mock.assert_called_with('token-123')
|
||||
client_mock.return_value.get_resources.assert_called_with(team_id='tid-1', project_id=None)
|
||||
|
||||
@patch('ansible_collections.community.general.plugins.lookup.manifold.ManifoldApiClient')
|
||||
def test_filter_by_project(self, client_mock):
|
||||
expected_result = [{'RESOURCE_TOKEN_3': 'token-3',
|
||||
'RESOURCE_TOKEN_4': 'token-4'
|
||||
}]
|
||||
client_mock.return_value.get_resources.return_value = API_FIXTURES['https://api.marketplace.manifold.co/v1/resources?project_id=pid-1']
|
||||
client_mock.return_value.get_projects.return_value = API_FIXTURES['https://api.marketplace.manifold.co/v1/projects'][0:1]
|
||||
client_mock.return_value.get_credentials.side_effect = lambda x: API_FIXTURES['https://api.marketplace.manifold.co/v1/'
|
||||
'credentials?resource_id={0}'.format(x)]
|
||||
self.assertListEqual(expected_result, self.lookup.run([], api_token='token-123', project='project-1'))
|
||||
client_mock.assert_called_with('token-123')
|
||||
client_mock.return_value.get_resources.assert_called_with(team_id=None, project_id='pid-1')
|
||||
|
||||
@patch('ansible_collections.community.general.plugins.lookup.manifold.ManifoldApiClient')
|
||||
def test_filter_by_team_and_project(self, client_mock):
|
||||
expected_result = [{'RESOURCE_TOKEN_1': 'token-1',
|
||||
'RESOURCE_TOKEN_2': 'token-2'
|
||||
}]
|
||||
client_mock.return_value.get_resources.return_value = API_FIXTURES['https://api.marketplace.manifold.co/v1/resources?team_id=tid-1&project_id=pid-1']
|
||||
client_mock.return_value.get_teams.return_value = API_FIXTURES['https://api.identity.manifold.co/v1/teams'][0:1]
|
||||
client_mock.return_value.get_projects.return_value = API_FIXTURES['https://api.marketplace.manifold.co/v1/projects'][0:1]
|
||||
client_mock.return_value.get_credentials.side_effect = lambda x: API_FIXTURES['https://api.marketplace.manifold.co/v1/'
|
||||
'credentials?resource_id={0}'.format(x)]
|
||||
self.assertListEqual(expected_result, self.lookup.run([], api_token='token-123', project='project-1'))
|
||||
client_mock.assert_called_with('token-123')
|
||||
client_mock.return_value.get_resources.assert_called_with(team_id=None, project_id='pid-1')
|
||||
|
||||
@patch('ansible_collections.community.general.plugins.lookup.manifold.ManifoldApiClient')
|
||||
def test_raise_team_doesnt_exist(self, client_mock):
|
||||
client_mock.return_value.get_teams.return_value = []
|
||||
with self.assertRaises(AnsibleError) as context:
|
||||
self.lookup.run([], api_token='token-123', team='no-team')
|
||||
self.assertEqual("Team 'no-team' does not exist",
|
||||
str(context.exception))
|
||||
|
||||
@patch('ansible_collections.community.general.plugins.lookup.manifold.ManifoldApiClient')
|
||||
def test_raise_project_doesnt_exist(self, client_mock):
|
||||
client_mock.return_value.get_projects.return_value = []
|
||||
with self.assertRaises(AnsibleError) as context:
|
||||
self.lookup.run([], api_token='token-123', project='no-project')
|
||||
self.assertEqual("Project 'no-project' does not exist",
|
||||
str(context.exception))
|
||||
|
||||
@patch('ansible_collections.community.general.plugins.lookup.manifold.ManifoldApiClient')
|
||||
def test_raise_resource_doesnt_exist(self, client_mock):
|
||||
client_mock.return_value.get_resources.return_value = API_FIXTURES['https://api.marketplace.manifold.co/v1/resources']
|
||||
with self.assertRaises(AnsibleError) as context:
|
||||
self.lookup.run(['resource-1', 'no-resource-1', 'no-resource-2'], api_token='token-123')
|
||||
self.assertEqual("Resource(s) no-resource-1, no-resource-2 do not exist",
|
||||
str(context.exception))
|
||||
|
||||
@patch('ansible_collections.community.general.plugins.lookup.manifold.ManifoldApiClient')
|
||||
def test_catch_api_error(self, client_mock):
|
||||
client_mock.side_effect = ApiError('Generic error')
|
||||
with self.assertRaises(AnsibleError) as context:
|
||||
self.lookup.run([], api_token='token-123')
|
||||
self.assertEqual("API Error: Generic error",
|
||||
str(context.exception))
|
||||
|
||||
@patch('ansible_collections.community.general.plugins.lookup.manifold.ManifoldApiClient')
|
||||
def test_catch_unhandled_exception(self, client_mock):
|
||||
client_mock.side_effect = Exception('Unknown error')
|
||||
with self.assertRaises(AnsibleError) as context:
|
||||
self.lookup.run([], api_token='token-123')
|
||||
self.assertTrue('Exception: Unknown error' in str(context.exception))
|
||||
|
||||
@patch('ansible_collections.community.general.plugins.lookup.manifold.os.getenv')
|
||||
@patch('ansible_collections.community.general.plugins.lookup.manifold.ManifoldApiClient')
|
||||
def test_falls_back_to_env_var(self, client_mock, getenv_mock):
|
||||
getenv_mock.return_value = 'token-321'
|
||||
client_mock.return_value.get_resources.return_value = []
|
||||
client_mock.return_value.get_credentials.return_value = []
|
||||
self.lookup.run([])
|
||||
getenv_mock.assert_called_with('MANIFOLD_API_TOKEN')
|
||||
client_mock.assert_called_with('token-321')
|
||||
|
||||
@patch('ansible_collections.community.general.plugins.lookup.manifold.os.getenv')
|
||||
@patch('ansible_collections.community.general.plugins.lookup.manifold.ManifoldApiClient')
|
||||
def test_falls_raises_on_no_token(self, client_mock, getenv_mock):
|
||||
getenv_mock.return_value = None
|
||||
client_mock.return_value.get_resources.return_value = []
|
||||
client_mock.return_value.get_credentials.return_value = []
|
||||
with self.assertRaises(AnsibleError) as context:
|
||||
self.lookup.run([])
|
||||
self.assertEqual('API token is required. Please set api_token parameter or MANIFOLD_API_TOKEN env var',
|
||||
str(context.exception))
|
321
tests/unit/plugins/lookup/test_onepassword.py
Normal file
321
tests/unit/plugins/lookup/test_onepassword.py
Normal file
|
@ -0,0 +1,321 @@
|
|||
# (c) 2018, Scott Buchanan <sbuchanan@ri.pn>
|
||||
# (c) 2016, Andrew Zenk <azenk@umn.edu> (test_lastpass.py used as starting point)
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
import json
|
||||
import datetime
|
||||
|
||||
try:
|
||||
from urllib.parse import urlparse
|
||||
except ImportError:
|
||||
from urlparse import urlparse
|
||||
|
||||
from argparse import ArgumentParser
|
||||
|
||||
|
||||
from ansible_collections.community.general.tests.unit.compat import unittest
|
||||
from ansible_collections.community.general.tests.unit.compat.mock import patch
|
||||
from ansible.errors import AnsibleError
|
||||
from ansible_collections.community.general.plugins.lookup.onepassword import OnePass, LookupModule
|
||||
from ansible_collections.community.general.plugins.lookup.onepassword_raw import LookupModule as OnePasswordRawLookup
|
||||
|
||||
|
||||
# Intentionally excludes metadata leaf nodes that would exist in real output if not relevant.
|
||||
MOCK_ENTRIES = [
|
||||
{
|
||||
'vault_name': 'Acme "Quot\'d" Servers',
|
||||
'queries': [
|
||||
'0123456789',
|
||||
'Mock "Quot\'d" Server'
|
||||
],
|
||||
'output': {
|
||||
'uuid': '0123456789',
|
||||
'vaultUuid': '2468',
|
||||
'overview': {
|
||||
'title': 'Mock "Quot\'d" Server'
|
||||
},
|
||||
'details': {
|
||||
'sections': [{
|
||||
'title': '',
|
||||
'fields': [
|
||||
{'t': 'username', 'v': 'jamesbond'},
|
||||
{'t': 'password', 'v': 't0pS3cret'},
|
||||
{'t': 'notes', 'v': 'Test note with\nmultiple lines and trailing space.\n\n'},
|
||||
{'t': 'tricksy "quot\'d" field\\', 'v': '"quot\'d" value'}
|
||||
]
|
||||
}]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
'vault_name': 'Acme Logins',
|
||||
'queries': [
|
||||
'9876543210',
|
||||
'Mock Website',
|
||||
'acme.com'
|
||||
],
|
||||
'output': {
|
||||
'uuid': '9876543210',
|
||||
'vaultUuid': '1357',
|
||||
'overview': {
|
||||
'title': 'Mock Website',
|
||||
'URLs': [
|
||||
{'l': 'website', 'u': 'https://acme.com/login'}
|
||||
]
|
||||
},
|
||||
'details': {
|
||||
'sections': [{
|
||||
'title': '',
|
||||
'fields': [
|
||||
{'t': 'password', 'v': 't0pS3cret'}
|
||||
]
|
||||
}]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
'vault_name': 'Acme Logins',
|
||||
'queries': [
|
||||
'864201357'
|
||||
],
|
||||
'output': {
|
||||
'uuid': '864201357',
|
||||
'vaultUuid': '1357',
|
||||
'overview': {
|
||||
'title': 'Mock Something'
|
||||
},
|
||||
'details': {
|
||||
'fields': [
|
||||
{
|
||||
'value': 'jbond@mi6.gov.uk',
|
||||
'name': 'emailAddress'
|
||||
},
|
||||
{
|
||||
'name': 'password',
|
||||
'value': 'vauxhall'
|
||||
},
|
||||
{},
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
def get_mock_query_generator(require_field=None):
|
||||
def _process_field(field, section_title=None):
|
||||
field_name = field.get('name', field.get('t', ''))
|
||||
field_value = field.get('value', field.get('v', ''))
|
||||
|
||||
if require_field is None or field_name == require_field:
|
||||
return entry, query, section_title, field_name, field_value
|
||||
|
||||
for entry in MOCK_ENTRIES:
|
||||
for query in entry['queries']:
|
||||
for field in entry['output']['details'].get('fields', []):
|
||||
fixture = _process_field(field)
|
||||
if fixture:
|
||||
yield fixture
|
||||
for section in entry['output']['details'].get('sections', []):
|
||||
for field in section['fields']:
|
||||
fixture = _process_field(field, section['title'])
|
||||
if fixture:
|
||||
yield fixture
|
||||
|
||||
|
||||
def get_one_mock_query(require_field=None):
|
||||
generator = get_mock_query_generator(require_field)
|
||||
return next(generator)
|
||||
|
||||
|
||||
class MockOnePass(OnePass):
|
||||
|
||||
_mock_logged_out = False
|
||||
_mock_timed_out = False
|
||||
|
||||
def _lookup_mock_entry(self, key, vault=None):
|
||||
for entry in MOCK_ENTRIES:
|
||||
if vault is not None and vault.lower() != entry['vault_name'].lower() and vault.lower() != entry['output']['vaultUuid'].lower():
|
||||
continue
|
||||
|
||||
match_fields = [
|
||||
entry['output']['uuid'],
|
||||
entry['output']['overview']['title']
|
||||
]
|
||||
|
||||
# Note that exactly how 1Password matches on domains in non-trivial cases is neither documented
|
||||
# nor obvious, so this may not precisely match the real behavior.
|
||||
urls = entry['output']['overview'].get('URLs')
|
||||
if urls is not None:
|
||||
match_fields += [urlparse(url['u']).netloc for url in urls]
|
||||
|
||||
if key in match_fields:
|
||||
return entry['output']
|
||||
|
||||
def _run(self, args, expected_rc=0, command_input=None, ignore_errors=False):
|
||||
parser = ArgumentParser()
|
||||
|
||||
command_parser = parser.add_subparsers(dest='command')
|
||||
|
||||
get_parser = command_parser.add_parser('get')
|
||||
get_options = ArgumentParser(add_help=False)
|
||||
get_options.add_argument('--vault')
|
||||
get_type_parser = get_parser.add_subparsers(dest='object_type')
|
||||
get_type_parser.add_parser('account', parents=[get_options])
|
||||
get_item_parser = get_type_parser.add_parser('item', parents=[get_options])
|
||||
get_item_parser.add_argument('item_id')
|
||||
|
||||
args = parser.parse_args(args)
|
||||
|
||||
def mock_exit(output='', error='', rc=0):
|
||||
if rc != expected_rc:
|
||||
raise AnsibleError(error)
|
||||
if error != '':
|
||||
now = datetime.date.today()
|
||||
error = '[LOG] {0} (ERROR) {1}'.format(now.strftime('%Y/%m/%d %H:$M:$S'), error)
|
||||
return rc, output, error
|
||||
|
||||
if args.command == 'get':
|
||||
if self._mock_logged_out:
|
||||
return mock_exit(error='You are not currently signed in. Please run `op signin --help` for instructions', rc=1)
|
||||
|
||||
if self._mock_timed_out:
|
||||
return mock_exit(error='401: Authentication required.', rc=1)
|
||||
|
||||
if args.object_type == 'item':
|
||||
mock_entry = self._lookup_mock_entry(args.item_id, args.vault)
|
||||
|
||||
if mock_entry is None:
|
||||
return mock_exit(error='Item {0} not found'.format(args.item_id))
|
||||
|
||||
return mock_exit(output=json.dumps(mock_entry))
|
||||
|
||||
if args.object_type == 'account':
|
||||
# Since we don't actually ever use this output, don't bother mocking output.
|
||||
return mock_exit()
|
||||
|
||||
raise AnsibleError('Unsupported command string passed to OnePass mock: {0}'.format(args))
|
||||
|
||||
|
||||
class LoggedOutMockOnePass(MockOnePass):
|
||||
|
||||
_mock_logged_out = True
|
||||
|
||||
|
||||
class TimedOutMockOnePass(MockOnePass):
|
||||
|
||||
_mock_timed_out = True
|
||||
|
||||
|
||||
class TestOnePass(unittest.TestCase):
|
||||
|
||||
def test_onepassword_cli_path(self):
|
||||
op = MockOnePass(path='/dev/null')
|
||||
self.assertEqual('/dev/null', op.cli_path)
|
||||
|
||||
def test_onepassword_logged_in(self):
|
||||
op = MockOnePass()
|
||||
try:
|
||||
op.assert_logged_in()
|
||||
except Exception:
|
||||
self.fail()
|
||||
|
||||
def test_onepassword_logged_out(self):
|
||||
op = LoggedOutMockOnePass()
|
||||
with self.assertRaises(AnsibleError):
|
||||
op.assert_logged_in()
|
||||
|
||||
def test_onepassword_timed_out(self):
|
||||
op = TimedOutMockOnePass()
|
||||
with self.assertRaises(AnsibleError):
|
||||
op.assert_logged_in()
|
||||
|
||||
def test_onepassword_get(self):
|
||||
op = MockOnePass()
|
||||
op.logged_in = True
|
||||
query_generator = get_mock_query_generator()
|
||||
for dummy, query, dummy, field_name, field_value in query_generator:
|
||||
self.assertEqual(field_value, op.get_field(query, field_name))
|
||||
|
||||
def test_onepassword_get_raw(self):
|
||||
op = MockOnePass()
|
||||
op.logged_in = True
|
||||
for entry in MOCK_ENTRIES:
|
||||
for query in entry['queries']:
|
||||
self.assertEqual(json.dumps(entry['output']), op.get_raw(query))
|
||||
|
||||
def test_onepassword_get_not_found(self):
|
||||
op = MockOnePass()
|
||||
op.logged_in = True
|
||||
self.assertEqual('', op.get_field('a fake query', 'a fake field'))
|
||||
|
||||
def test_onepassword_get_with_section(self):
|
||||
op = MockOnePass()
|
||||
op.logged_in = True
|
||||
dummy, query, section_title, field_name, field_value = get_one_mock_query()
|
||||
self.assertEqual(field_value, op.get_field(query, field_name, section=section_title))
|
||||
|
||||
def test_onepassword_get_with_vault(self):
|
||||
op = MockOnePass()
|
||||
op.logged_in = True
|
||||
entry, query, dummy, field_name, field_value = get_one_mock_query()
|
||||
for vault_query in [entry['vault_name'], entry['output']['vaultUuid']]:
|
||||
self.assertEqual(field_value, op.get_field(query, field_name, vault=vault_query))
|
||||
|
||||
def test_onepassword_get_with_wrong_vault(self):
|
||||
op = MockOnePass()
|
||||
op.logged_in = True
|
||||
dummy, query, dummy, field_name, dummy = get_one_mock_query()
|
||||
self.assertEqual('', op.get_field(query, field_name, vault='a fake vault'))
|
||||
|
||||
def test_onepassword_get_diff_case(self):
|
||||
op = MockOnePass()
|
||||
op.logged_in = True
|
||||
entry, query, section_title, field_name, field_value = get_one_mock_query()
|
||||
self.assertEqual(
|
||||
field_value,
|
||||
op.get_field(
|
||||
query,
|
||||
field_name.upper(),
|
||||
vault=entry['vault_name'].upper(),
|
||||
section=section_title.upper()
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@patch('ansible_collections.community.general.plugins.lookup.onepassword.OnePass', MockOnePass)
|
||||
class TestLookupModule(unittest.TestCase):
|
||||
|
||||
def test_onepassword_plugin_multiple(self):
|
||||
lookup_plugin = LookupModule()
|
||||
|
||||
entry = MOCK_ENTRIES[0]
|
||||
field = entry['output']['details']['sections'][0]['fields'][0]
|
||||
|
||||
self.assertEqual(
|
||||
[field['v']] * len(entry['queries']),
|
||||
lookup_plugin.run(entry['queries'], field=field['t'])
|
||||
)
|
||||
|
||||
def test_onepassword_plugin_default_field(self):
|
||||
lookup_plugin = LookupModule()
|
||||
|
||||
dummy, query, dummy, dummy, field_value = get_one_mock_query('password')
|
||||
self.assertEqual([field_value], lookup_plugin.run([query]))
|
||||
|
||||
|
||||
@patch('ansible_collections.community.general.plugins.lookup.onepassword_raw.OnePass', MockOnePass)
|
||||
class TestOnePasswordRawLookup(unittest.TestCase):
|
||||
|
||||
def test_onepassword_raw_plugin_multiple(self):
|
||||
raw_lookup_plugin = OnePasswordRawLookup()
|
||||
|
||||
entry = MOCK_ENTRIES[0]
|
||||
raw_value = entry['output']
|
||||
|
||||
self.assertEqual(
|
||||
[raw_value] * len(entry['queries']),
|
||||
raw_lookup_plugin.run(entry['queries'])
|
||||
)
|
0
tests/unit/plugins/terminal/__init__.py
Normal file
0
tests/unit/plugins/terminal/__init__.py
Normal file
55
tests/unit/plugins/terminal/test_junos.py
Normal file
55
tests/unit/plugins/terminal/test_junos.py
Normal file
|
@ -0,0 +1,55 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Copyright: (c) 2018, Fran Fitzpatrick <francis.x.fitzpatrick@gmail.com> fxfitz
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
from mock import call, MagicMock
|
||||
import pytest
|
||||
|
||||
from ansible.errors import AnsibleConnectionFailure
|
||||
from ansible_collections.junipernetworks.junos.plugins.terminal import junos
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def junos_terminal():
|
||||
mock_connection = MagicMock()
|
||||
return junos.TerminalModule(mock_connection)
|
||||
|
||||
|
||||
def test_on_open_shell_sets_terminal_parameters(junos_terminal):
|
||||
expected_calls = [
|
||||
call(b'set cli timestamp disable'),
|
||||
call(b'set cli screen-length 0'),
|
||||
call(b'set cli screen-width 1024'),
|
||||
]
|
||||
junos_terminal._exec_cli_command = MagicMock()
|
||||
junos_terminal._get_prompt = MagicMock()
|
||||
|
||||
junos_terminal._get_prompt.return_value = b'user@localhost >'
|
||||
junos_terminal.on_open_shell()
|
||||
junos_terminal._exec_cli_command.assert_has_calls(expected_calls)
|
||||
|
||||
|
||||
def test_on_open_shell_enters_cli_if_root_prompt(junos_terminal):
|
||||
expected_calls = [
|
||||
call(b'cli'),
|
||||
call(b'set cli timestamp disable'),
|
||||
call(b'set cli screen-length 0'),
|
||||
call(b'set cli screen-width 1024'),
|
||||
]
|
||||
junos_terminal._exec_cli_command = MagicMock()
|
||||
junos_terminal._get_prompt = MagicMock()
|
||||
|
||||
junos_terminal._connection.get_prompt.return_value = b'root@localhost%'
|
||||
junos_terminal.on_open_shell()
|
||||
junos_terminal._exec_cli_command.assert_has_calls(expected_calls)
|
||||
|
||||
|
||||
def test_on_open_shell_raises_problem_setting_terminal_config(junos_terminal):
|
||||
junos_terminal._connection.exec_command.side_effect = AnsibleConnectionFailure
|
||||
with pytest.raises(AnsibleConnectionFailure) as exc:
|
||||
junos_terminal.on_open_shell()
|
||||
|
||||
assert 'unable to set terminal parameters' in str(exc.value)
|
53
tests/unit/plugins/terminal/test_slxos.py
Normal file
53
tests/unit/plugins/terminal/test_slxos.py
Normal file
|
@ -0,0 +1,53 @@
|
|||
#
|
||||
# (c) 2018 Extreme Networks 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
|
||||
|
||||
from mock import MagicMock
|
||||
|
||||
from ansible_collections.community.general.tests.unit.compat import unittest
|
||||
from ansible_collections.community.general.plugins.terminal import slxos
|
||||
from ansible.errors import AnsibleConnectionFailure
|
||||
|
||||
|
||||
class TestPluginTerminalSLXOS(unittest.TestCase):
|
||||
""" Test class for SLX-OS Terminal Module
|
||||
"""
|
||||
def setUp(self):
|
||||
self._mock_connection = MagicMock()
|
||||
self._terminal = slxos.TerminalModule(self._mock_connection)
|
||||
|
||||
def test_on_open_shell(self):
|
||||
""" Test on_open_shell
|
||||
"""
|
||||
self._mock_connection.exec_command.side_effect = [
|
||||
b'Looking out my window I see a brick building, and people. Cool.',
|
||||
]
|
||||
self._terminal.on_open_shell()
|
||||
self._mock_connection.exec_command.assert_called_with(u'terminal length 0')
|
||||
|
||||
def test_on_open_shell_error(self):
|
||||
""" Test on_open_shell with error
|
||||
"""
|
||||
self._mock_connection.exec_command.side_effect = [
|
||||
AnsibleConnectionFailure
|
||||
]
|
||||
|
||||
with self.assertRaises(AnsibleConnectionFailure):
|
||||
self._terminal.on_open_shell()
|
Loading…
Add table
Add a link
Reference in a new issue