Initial commit

This commit is contained in:
Ansible Core Team 2020-03-09 09:11:07 +00:00
commit aebc1b03fd
4861 changed files with 812621 additions and 0 deletions

View file

View file

View 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

View 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)

View 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

View 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)

View 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

View 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
View file

View 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
View 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)

View file

View 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:.

View 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

View 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
!

View 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

View 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

View 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
!

View 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
!

View 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

View 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
)

View 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
)

View 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')

View 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)

View file

View 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

View file

View 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

View file

View 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"
}
]
}
}

View 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)

View 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')

View 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')

View 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))

View 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'])
)

View file

View 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)

View 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()