summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnsible Core Team <info@ansible.com>2020-03-09 09:40:35 +0000
committerAnsible Core Team <info@ansible.com>2020-03-09 09:40:35 +0000
commit37e8b907bcfdd5bfd3e4c8c5af8de23641874e32 (patch)
treeb8e7bddf8bcd439cdc2f5cadf0dc14fcc0411038
parentc8db741307ca7ba1342a403a92ab1c82ae563eaa (diff)
downloadansible-37e8b907bcfdd5bfd3e4c8c5af8de23641874e32.tar.gz
Migrated to f5networks.f5_modules
-rw-r--r--lib/ansible/module_utils/network/f5/bigip.py98
-rw-r--r--lib/ansible/module_utils/network/f5/bigiq.py139
-rw-r--r--lib/ansible/module_utils/network/f5/common.py573
-rw-r--r--lib/ansible/module_utils/network/f5/compare.py84
-rw-r--r--lib/ansible/module_utils/network/f5/icontrol.py612
-rw-r--r--lib/ansible/module_utils/network/f5/ipaddress.py105
-rw-r--r--lib/ansible/modules/network/f5/bigip_apm_acl.py996
-rw-r--r--lib/ansible/modules/network/f5/bigip_apm_network_access.py1032
-rw-r--r--lib/ansible/modules/network/f5/bigip_apm_policy_fetch.py499
-rw-r--r--lib/ansible/modules/network/f5/bigip_apm_policy_import.py406
-rw-r--r--lib/ansible/modules/network/f5/bigip_appsvcs_extension.py549
-rw-r--r--lib/ansible/modules/network/f5/bigip_asm_dos_application.py1308
-rw-r--r--lib/ansible/modules/network/f5/bigip_asm_policy_fetch.py688
-rw-r--r--lib/ansible/modules/network/f5/bigip_asm_policy_import.py475
-rw-r--r--lib/ansible/modules/network/f5/bigip_asm_policy_manage.py892
-rw-r--r--lib/ansible/modules/network/f5/bigip_asm_policy_server_technology.py482
-rw-r--r--lib/ansible/modules/network/f5/bigip_asm_policy_signature_set.py721
-rw-r--r--lib/ansible/modules/network/f5/bigip_cli_alias.py418
-rw-r--r--lib/ansible/modules/network/f5/bigip_cli_script.py460
-rw-r--r--lib/ansible/modules/network/f5/bigip_command.py726
-rw-r--r--lib/ansible/modules/network/f5/bigip_config.py427
-rw-r--r--lib/ansible/modules/network/f5/bigip_configsync_action.py432
-rw-r--r--lib/ansible/modules/network/f5/bigip_data_group.py1372
-rw-r--r--lib/ansible/modules/network/f5/bigip_device_auth.py803
-rw-r--r--lib/ansible/modules/network/f5/bigip_device_auth_ldap.py844
-rw-r--r--lib/ansible/modules/network/f5/bigip_device_certificate.py627
-rw-r--r--lib/ansible/modules/network/f5/bigip_device_connectivity.py718
-rw-r--r--lib/ansible/modules/network/f5/bigip_device_dns.py553
-rw-r--r--lib/ansible/modules/network/f5/bigip_device_group.py626
-rw-r--r--lib/ansible/modules/network/f5/bigip_device_group_member.py293
-rw-r--r--lib/ansible/modules/network/f5/bigip_device_ha_group.py814
-rw-r--r--lib/ansible/modules/network/f5/bigip_device_httpd.py723
-rw-r--r--lib/ansible/modules/network/f5/bigip_device_info.py16266
-rw-r--r--lib/ansible/modules/network/f5/bigip_device_license.py889
-rw-r--r--lib/ansible/modules/network/f5/bigip_device_ntp.py417
-rw-r--r--lib/ansible/modules/network/f5/bigip_device_sshd.py449
-rw-r--r--lib/ansible/modules/network/f5/bigip_device_syslog.py735
-rw-r--r--lib/ansible/modules/network/f5/bigip_device_traffic_group.py672
-rw-r--r--lib/ansible/modules/network/f5/bigip_device_trust.py380
-rw-r--r--lib/ansible/modules/network/f5/bigip_dns_cache_resolver.py547
-rw-r--r--lib/ansible/modules/network/f5/bigip_dns_nameserver.py468
-rw-r--r--lib/ansible/modules/network/f5/bigip_dns_resolver.py536
-rw-r--r--lib/ansible/modules/network/f5/bigip_dns_zone.py698
-rw-r--r--lib/ansible/modules/network/f5/bigip_file_copy.py684
-rw-r--r--lib/ansible/modules/network/f5/bigip_firewall_address_list.py978
-rw-r--r--lib/ansible/modules/network/f5/bigip_firewall_dos_profile.py426
-rw-r--r--lib/ansible/modules/network/f5/bigip_firewall_dos_vector.py1307
-rw-r--r--lib/ansible/modules/network/f5/bigip_firewall_global_rules.py381
-rw-r--r--lib/ansible/modules/network/f5/bigip_firewall_log_profile.py880
-rw-r--r--lib/ansible/modules/network/f5/bigip_firewall_log_profile_network.py1269
-rw-r--r--lib/ansible/modules/network/f5/bigip_firewall_policy.py532
-rw-r--r--lib/ansible/modules/network/f5/bigip_firewall_port_list.py645
-rw-r--r--lib/ansible/modules/network/f5/bigip_firewall_rule.py1319
-rw-r--r--lib/ansible/modules/network/f5/bigip_firewall_rule_list.py532
-rw-r--r--lib/ansible/modules/network/f5/bigip_firewall_schedule.py670
-rw-r--r--lib/ansible/modules/network/f5/bigip_gtm_datacenter.py490
-rw-r--r--lib/ansible/modules/network/f5/bigip_gtm_global.py349
-rw-r--r--lib/ansible/modules/network/f5/bigip_gtm_monitor_bigip.py663
-rw-r--r--lib/ansible/modules/network/f5/bigip_gtm_monitor_external.py706
-rw-r--r--lib/ansible/modules/network/f5/bigip_gtm_monitor_firepass.py793
-rw-r--r--lib/ansible/modules/network/f5/bigip_gtm_monitor_http.py837
-rw-r--r--lib/ansible/modules/network/f5/bigip_gtm_monitor_https.py960
-rw-r--r--lib/ansible/modules/network/f5/bigip_gtm_monitor_tcp.py796
-rw-r--r--lib/ansible/modules/network/f5/bigip_gtm_monitor_tcp_half_open.py704
-rw-r--r--lib/ansible/modules/network/f5/bigip_gtm_pool.py1283
-rw-r--r--lib/ansible/modules/network/f5/bigip_gtm_pool_member.py1089
-rw-r--r--lib/ansible/modules/network/f5/bigip_gtm_server.py1793
-rw-r--r--lib/ansible/modules/network/f5/bigip_gtm_topology_record.py1080
-rw-r--r--lib/ansible/modules/network/f5/bigip_gtm_topology_region.py892
-rw-r--r--lib/ansible/modules/network/f5/bigip_gtm_virtual_server.py1196
-rw-r--r--lib/ansible/modules/network/f5/bigip_gtm_wide_ip.py948
-rw-r--r--lib/ansible/modules/network/f5/bigip_hostname.py308
-rw-r--r--lib/ansible/modules/network/f5/bigip_iapp_service.py994
-rw-r--r--lib/ansible/modules/network/f5/bigip_iapp_template.py571
-rw-r--r--lib/ansible/modules/network/f5/bigip_ike_peer.py804
-rw-r--r--lib/ansible/modules/network/f5/bigip_imish_config.py831
-rw-r--r--lib/ansible/modules/network/f5/bigip_ipsec_policy.py778
-rw-r--r--lib/ansible/modules/network/f5/bigip_irule.py577
-rw-r--r--lib/ansible/modules/network/f5/bigip_log_destination.py1765
-rw-r--r--lib/ansible/modules/network/f5/bigip_log_publisher.py425
-rw-r--r--lib/ansible/modules/network/f5/bigip_lx_package.py480
-rw-r--r--lib/ansible/modules/network/f5/bigip_management_route.py453
-rw-r--r--lib/ansible/modules/network/f5/bigip_message_routing_peer.py659
-rw-r--r--lib/ansible/modules/network/f5/bigip_message_routing_protocol.py566
-rw-r--r--lib/ansible/modules/network/f5/bigip_message_routing_route.py555
-rw-r--r--lib/ansible/modules/network/f5/bigip_message_routing_router.py751
-rw-r--r--lib/ansible/modules/network/f5/bigip_message_routing_transport_config.py667
-rw-r--r--lib/ansible/modules/network/f5/bigip_monitor_dns.py1028
-rw-r--r--lib/ansible/modules/network/f5/bigip_monitor_external.py744
-rw-r--r--lib/ansible/modules/network/f5/bigip_monitor_gateway_icmp.py801
-rw-r--r--lib/ansible/modules/network/f5/bigip_monitor_http.py759
-rw-r--r--lib/ansible/modules/network/f5/bigip_monitor_https.py746
-rw-r--r--lib/ansible/modules/network/f5/bigip_monitor_ldap.py823
-rw-r--r--lib/ansible/modules/network/f5/bigip_monitor_snmp_dca.py764
-rw-r--r--lib/ansible/modules/network/f5/bigip_monitor_tcp.py667
-rw-r--r--lib/ansible/modules/network/f5/bigip_monitor_tcp_echo.py600
-rw-r--r--lib/ansible/modules/network/f5/bigip_monitor_tcp_half_open.py651
-rw-r--r--lib/ansible/modules/network/f5/bigip_monitor_udp.py663
-rw-r--r--lib/ansible/modules/network/f5/bigip_node.py1195
-rw-r--r--lib/ansible/modules/network/f5/bigip_partition.py496
-rw-r--r--lib/ansible/modules/network/f5/bigip_password_policy.py439
-rw-r--r--lib/ansible/modules/network/f5/bigip_policy.py1128
-rw-r--r--lib/ansible/modules/network/f5/bigip_policy_rule.py1068
-rw-r--r--lib/ansible/modules/network/f5/bigip_pool.py1276
-rw-r--r--lib/ansible/modules/network/f5/bigip_pool_member.py1658
-rw-r--r--lib/ansible/modules/network/f5/bigip_profile_analytics.py761
-rw-r--r--lib/ansible/modules/network/f5/bigip_profile_client_ssl.py1117
-rw-r--r--lib/ansible/modules/network/f5/bigip_profile_dns.py751
-rw-r--r--lib/ansible/modules/network/f5/bigip_profile_fastl4.py1399
-rw-r--r--lib/ansible/modules/network/f5/bigip_profile_http.py1757
-rw-r--r--lib/ansible/modules/network/f5/bigip_profile_http2.py679
-rw-r--r--lib/ansible/modules/network/f5/bigip_profile_http_compression.py542
-rw-r--r--lib/ansible/modules/network/f5/bigip_profile_oneconnect.py617
-rw-r--r--lib/ansible/modules/network/f5/bigip_profile_persistence_cookie.py972
-rw-r--r--lib/ansible/modules/network/f5/bigip_profile_persistence_src_addr.py556
-rw-r--r--lib/ansible/modules/network/f5/bigip_profile_server_ssl.py665
-rw-r--r--lib/ansible/modules/network/f5/bigip_profile_tcp.py651
-rw-r--r--lib/ansible/modules/network/f5/bigip_profile_udp.py459
-rw-r--r--lib/ansible/modules/network/f5/bigip_provision.py1099
-rw-r--r--lib/ansible/modules/network/f5/bigip_qkview.py605
-rw-r--r--lib/ansible/modules/network/f5/bigip_remote_role.py553
-rw-r--r--lib/ansible/modules/network/f5/bigip_remote_syslog.py467
-rw-r--r--lib/ansible/modules/network/f5/bigip_remote_user.py391
-rw-r--r--lib/ansible/modules/network/f5/bigip_routedomain.py731
-rw-r--r--lib/ansible/modules/network/f5/bigip_selfip.py853
-rw-r--r--lib/ansible/modules/network/f5/bigip_service_policy.py440
-rw-r--r--lib/ansible/modules/network/f5/bigip_smtp.py568
-rw-r--r--lib/ansible/modules/network/f5/bigip_snat_pool.py530
-rw-r--r--lib/ansible/modules/network/f5/bigip_snat_translation.py779
-rw-r--r--lib/ansible/modules/network/f5/bigip_snmp.py425
-rw-r--r--lib/ansible/modules/network/f5/bigip_snmp_community.py919
-rw-r--r--lib/ansible/modules/network/f5/bigip_snmp_trap.py681
-rw-r--r--lib/ansible/modules/network/f5/bigip_software_image.py479
-rw-r--r--lib/ansible/modules/network/f5/bigip_software_install.py523
-rw-r--r--lib/ansible/modules/network/f5/bigip_software_update.py335
-rw-r--r--lib/ansible/modules/network/f5/bigip_ssl_certificate.py579
-rw-r--r--lib/ansible/modules/network/f5/bigip_ssl_key.py520
-rw-r--r--lib/ansible/modules/network/f5/bigip_ssl_ocsp.py775
-rw-r--r--lib/ansible/modules/network/f5/bigip_static_route.py703
-rw-r--r--lib/ansible/modules/network/f5/bigip_sys_daemon_log_tmm.py493
-rw-r--r--lib/ansible/modules/network/f5/bigip_sys_db.py403
-rw-r--r--lib/ansible/modules/network/f5/bigip_sys_global.py506
-rw-r--r--lib/ansible/modules/network/f5/bigip_timer_policy.py636
-rw-r--r--lib/ansible/modules/network/f5/bigip_traffic_selector.py509
-rw-r--r--lib/ansible/modules/network/f5/bigip_trunk.py605
-rw-r--r--lib/ansible/modules/network/f5/bigip_tunnel.py619
-rw-r--r--lib/ansible/modules/network/f5/bigip_ucs.py718
-rw-r--r--lib/ansible/modules/network/f5/bigip_ucs_fetch.py612
-rw-r--r--lib/ansible/modules/network/f5/bigip_user.py1116
-rw-r--r--lib/ansible/modules/network/f5/bigip_vcmp_guest.py1017
-rw-r--r--lib/ansible/modules/network/f5/bigip_virtual_address.py945
-rw-r--r--lib/ansible/modules/network/f5/bigip_virtual_server.py3665
-rw-r--r--lib/ansible/modules/network/f5/bigip_vlan.py967
-rw-r--r--lib/ansible/modules/network/f5/bigip_wait.py346
-rw-r--r--lib/ansible/modules/network/f5/bigiq_application_fasthttp.py756
-rw-r--r--lib/ansible/modules/network/f5/bigiq_application_fastl4_tcp.py702
-rw-r--r--lib/ansible/modules/network/f5/bigiq_application_fastl4_udp.py702
-rw-r--r--lib/ansible/modules/network/f5/bigiq_application_http.py755
-rw-r--r--lib/ansible/modules/network/f5/bigiq_application_https_offload.py1011
-rw-r--r--lib/ansible/modules/network/f5/bigiq_application_https_waf.py1038
-rw-r--r--lib/ansible/modules/network/f5/bigiq_device_discovery.py1240
-rw-r--r--lib/ansible/modules/network/f5/bigiq_device_info.py2313
-rw-r--r--lib/ansible/modules/network/f5/bigiq_regkey_license.py482
-rw-r--r--lib/ansible/modules/network/f5/bigiq_regkey_license_assignment.py635
-rw-r--r--lib/ansible/modules/network/f5/bigiq_regkey_pool.py417
-rw-r--r--lib/ansible/modules/network/f5/bigiq_utility_license.py462
-rw-r--r--lib/ansible/modules/network/f5/bigiq_utility_license_assignment.py645
-rw-r--r--lib/ansible/plugins/action/bigip.py101
-rw-r--r--lib/ansible/plugins/action/bigiq.py95
-rw-r--r--lib/ansible/plugins/doc_fragments/f5.py80
-rw-r--r--lib/ansible/plugins/terminal/bigip.py62
-rw-r--r--test/sanity/ignore.txt267
-rw-r--r--test/units/modules/network/f5/fixtures/MyApp-0.1.0-0001.noarch.rpmbin57508 -> 0 bytes
-rw-r--r--test/units/modules/network/f5/fixtures/basic-iapp.tmpl25
-rw-r--r--test/units/modules/network/f5/fixtures/cert1.crt101
-rw-r--r--test/units/modules/network/f5/fixtures/cert1.key27
-rw-r--r--test/units/modules/network/f5/fixtures/cert2.crt101
-rw-r--r--test/units/modules/network/f5/fixtures/cert2.key30
-rw-r--r--test/units/modules/network/f5/fixtures/chain1.crt68
-rw-r--r--test/units/modules/network/f5/fixtures/create_gtm_irule.tcl8
-rw-r--r--test/units/modules/network/f5/fixtures/create_iapp_service_parameters_f5_http.json199
-rw-r--r--test/units/modules/network/f5/fixtures/create_iapp_template.iapp56
-rw-r--r--test/units/modules/network/f5/fixtures/create_insecure_cert1.crt101
-rw-r--r--test/units/modules/network/f5/fixtures/create_insecure_key1.key27
-rw-r--r--test/units/modules/network/f5/fixtures/create_ltm_irule.tcl18
-rw-r--r--test/units/modules/network/f5/fixtures/data-group-address.txt5
-rw-r--r--test/units/modules/network/f5/fixtures/data-group-integer.txt6
-rw-r--r--test/units/modules/network/f5/fixtures/data-group-string.txt6
-rw-r--r--test/units/modules/network/f5/fixtures/fake_policy.tar.gzbin1450 -> 0 bytes
-rw-r--r--test/units/modules/network/f5/fixtures/fake_policy.xml12174
-rw-r--r--test/units/modules/network/f5/fixtures/load_afm_global_network_log_network.json31
-rw-r--r--test/units/modules/network/f5/fixtures/load_afm_log_global_network_profile.json50
-rw-r--r--test/units/modules/network/f5/fixtures/load_afm_schedule.json19
-rw-r--r--test/units/modules/network/f5/fixtures/load_apm_acl.json27
-rw-r--r--test/units/modules/network/f5/fixtures/load_apm_network_access.json98
-rw-r--r--test/units/modules/network/f5/fixtures/load_asm_dos.json276
-rw-r--r--test/units/modules/network/f5/fixtures/load_asm_policy_active.json197
-rw-r--r--test/units/modules/network/f5/fixtures/load_asm_policy_inactive.json197
-rw-r--r--test/units/modules/network/f5/fixtures/load_auth_remote_role_role_info_1.json16
-rw-r--r--test/units/modules/network/f5/fixtures/load_auth_user_no_pass.json18
-rw-r--r--test/units/modules/network/f5/fixtures/load_auth_user_with_pass.json19
-rw-r--r--test/units/modules/network/f5/fixtures/load_generic_parser.json16
-rw-r--r--test/units/modules/network/f5/fixtures/load_generic_peer.json22
-rw-r--r--test/units/modules/network/f5/fixtures/load_generic_route.json19
-rw-r--r--test/units/modules/network/f5/fixtures/load_generic_router.json22
-rw-r--r--test/units/modules/network/f5/fixtures/load_generic_transport_config.json53
-rw-r--r--test/units/modules/network/f5/fixtures/load_gtm_datacenter_default.json9
-rw-r--r--test/units/modules/network/f5/fixtures/load_gtm_datacenter_disabled.json12
-rw-r--r--test/units/modules/network/f5/fixtures/load_gtm_global_settings_general_1.json25
-rw-r--r--test/units/modules/network/f5/fixtures/load_gtm_irules.json20
-rw-r--r--test/units/modules/network/f5/fixtures/load_gtm_monitor_firepass_1.json19
-rw-r--r--test/units/modules/network/f5/fixtures/load_gtm_monitor_http_1.json21
-rw-r--r--test/units/modules/network/f5/fixtures/load_gtm_monitor_tcp_1.json18
-rw-r--r--test/units/modules/network/f5/fixtures/load_gtm_pool_a_collection.json44
-rw-r--r--test/units/modules/network/f5/fixtures/load_gtm_pool_a_default.json38
-rw-r--r--test/units/modules/network/f5/fixtures/load_gtm_pool_a_example_stats.json48
-rw-r--r--test/units/modules/network/f5/fixtures/load_gtm_pool_a_member_1.json18
-rw-r--r--test/units/modules/network/f5/fixtures/load_gtm_pool_a_with_members_1.json94
-rw-r--r--test/units/modules/network/f5/fixtures/load_gtm_pool_untyped_default.json39
-rw-r--r--test/units/modules/network/f5/fixtures/load_gtm_server_1.json68
-rw-r--r--test/units/modules/network/f5/fixtures/load_gtm_server_virtual_2.json18
-rw-r--r--test/units/modules/network/f5/fixtures/load_gtm_wide_ip_with_pools.json30
-rw-r--r--test/units/modules/network/f5/fixtures/load_imish_output_1.json6
-rw-r--r--test/units/modules/network/f5/fixtures/load_ltm_dns_cache_resolver_1.json43
-rw-r--r--test/units/modules/network/f5/fixtures/load_ltm_dns_nameserver_1.json18
-rw-r--r--test/units/modules/network/f5/fixtures/load_ltm_dns_zone_1.json31
-rw-r--r--test/units/modules/network/f5/fixtures/load_ltm_fastl4_profile_1.json56
-rw-r--r--test/units/modules/network/f5/fixtures/load_ltm_http2_profile.json27
-rw-r--r--test/units/modules/network/f5/fixtures/load_ltm_http_profile_1.json81
-rw-r--r--test/units/modules/network/f5/fixtures/load_ltm_irules.json179
-rw-r--r--test/units/modules/network/f5/fixtures/load_ltm_monitor_http.json28
-rw-r--r--test/units/modules/network/f5/fixtures/load_ltm_monitor_https.json30
-rw-r--r--test/units/modules/network/f5/fixtures/load_ltm_monitor_tcp.json25
-rw-r--r--test/units/modules/network/f5/fixtures/load_ltm_monitor_tcp_echo.json21
-rw-r--r--test/units/modules/network/f5/fixtures/load_ltm_monitor_tcp_half_open.json16
-rw-r--r--test/units/modules/network/f5/fixtures/load_ltm_monitor_udp.json25
-rw-r--r--test/units/modules/network/f5/fixtures/load_ltm_node_1.json25
-rw-r--r--test/units/modules/network/f5/fixtures/load_ltm_node_2.json26
-rw-r--r--test/units/modules/network/f5/fixtures/load_ltm_node_3.json24
-rw-r--r--test/units/modules/network/f5/fixtures/load_ltm_policy_draft_rule_http-uri_forward.json60
-rw-r--r--test/units/modules/network/f5/fixtures/load_ltm_pool.json32
-rw-r--r--test/units/modules/network/f5/fixtures/load_ltm_profile_analytics_1.json52
-rw-r--r--test/units/modules/network/f5/fixtures/load_ltm_profile_clientssl.json103
-rw-r--r--test/units/modules/network/f5/fixtures/load_ltm_profile_dns_1.json35
-rw-r--r--test/units/modules/network/f5/fixtures/load_ltm_profile_http_compression_1.json37
-rw-r--r--test/units/modules/network/f5/fixtures/load_ltm_profile_oneconnect_1.json18
-rw-r--r--test/units/modules/network/f5/fixtures/load_ltm_profile_persistence_cookie_1.json27
-rw-r--r--test/units/modules/network/f5/fixtures/load_ltm_profile_persistence_src_addr_1.json22
-rw-r--r--test/units/modules/network/f5/fixtures/load_ltm_profile_serverssl_1.json73
-rw-r--r--test/units/modules/network/f5/fixtures/load_ltm_profile_tcp_1.json92
-rw-r--r--test/units/modules/network/f5/fixtures/load_ltm_profile_udp_1.json27
-rw-r--r--test/units/modules/network/f5/fixtures/load_ltm_snat_translation_default.json15
-rw-r--r--test/units/modules/network/f5/fixtures/load_ltm_snatpool.json20
-rw-r--r--test/units/modules/network/f5/fixtures/load_ltm_virtual_1.json43
-rw-r--r--test/units/modules/network/f5/fixtures/load_ltm_virtual_1_address.json25
-rw-r--r--test/units/modules/network/f5/fixtures/load_ltm_virtual_2.json65
-rw-r--r--test/units/modules/network/f5/fixtures/load_ltm_virtual_3.json115
-rw-r--r--test/units/modules/network/f5/fixtures/load_ltm_virtual_address_collection_1.json31
-rw-r--r--test/units/modules/network/f5/fixtures/load_ltm_virtual_address_default.json25
-rw-r--r--test/units/modules/network/f5/fixtures/load_machine_resolver.json187
-rw-r--r--test/units/modules/network/f5/fixtures/load_net_dns_resolver_1.json19
-rw-r--r--test/units/modules/network/f5/fixtures/load_net_interfaces.json424
-rw-r--r--test/units/modules/network/f5/fixtures/load_net_node_with_fqdn.json25
-rw-r--r--test/units/modules/network/f5/fixtures/load_net_node_with_ipv4_address.json24
-rw-r--r--test/units/modules/network/f5/fixtures/load_net_route_description.json15
-rw-r--r--test/units/modules/network/f5/fixtures/load_net_route_domain_1.json36
-rw-r--r--test/units/modules/network/f5/fixtures/load_net_service_policy_1.json17
-rw-r--r--test/units/modules/network/f5/fixtures/load_net_timer_policy_1.json9
-rw-r--r--test/units/modules/network/f5/fixtures/load_net_tunnel_1.json25
-rw-r--r--test/units/modules/network/f5/fixtures/load_ntp.json13
-rw-r--r--test/units/modules/network/f5/fixtures/load_regkey_license_key.json96
-rw-r--r--test/units/modules/network/f5/fixtures/load_regkey_license_pool.json10
-rw-r--r--test/units/modules/network/f5/fixtures/load_remote_user_settings.json10
-rw-r--r--test/units/modules/network/f5/fixtures/load_security_address_list_1.json53
-rw-r--r--test/units/modules/network/f5/fixtures/load_security_firewall_global_rules_1.json16
-rw-r--r--test/units/modules/network/f5/fixtures/load_security_firewall_policy_1.json51
-rw-r--r--test/units/modules/network/f5/fixtures/load_security_port_list_1.json41
-rw-r--r--test/units/modules/network/f5/fixtures/load_shared_system_setup_1.json9
-rw-r--r--test/units/modules/network/f5/fixtures/load_sys_application_template_w_new_checksum.json21
-rw-r--r--test/units/modules/network/f5/fixtures/load_sys_application_template_w_old_checksum.json21
-rw-r--r--test/units/modules/network/f5/fixtures/load_sys_crypto_cert_validator_1.json33
-rw-r--r--test/units/modules/network/f5/fixtures/load_sys_file_external-monitor_1.json17
-rw-r--r--test/units/modules/network/f5/fixtures/load_sys_file_ssl_cert_with_issuer_cert.json42
-rw-r--r--test/units/modules/network/f5/fixtures/load_sys_global_settings.json24
-rw-r--r--test/units/modules/network/f5/fixtures/load_sys_httpd.json36
-rw-r--r--test/units/modules/network/f5/fixtures/load_sys_httpd_non_default.json36
-rw-r--r--test/units/modules/network/f5/fixtures/load_sys_log_config_destination_1.json15
-rw-r--r--test/units/modules/network/f5/fixtures/load_sys_log_config_publisher_1.json32
-rw-r--r--test/units/modules/network/f5/fixtures/load_sys_management_route_1.json12
-rw-r--r--test/units/modules/network/f5/fixtures/load_sys_provision_default.json5
-rw-r--r--test/units/modules/network/f5/fixtures/load_sys_smtp_server.json16
-rw-r--r--test/units/modules/network/f5/fixtures/load_sys_snmp_communities_1.json10
-rw-r--r--test/units/modules/network/f5/fixtures/load_sys_snmp_communities_2.json12
-rw-r--r--test/units/modules/network/f5/fixtures/load_sys_snmp_communities_3.json12
-rw-r--r--test/units/modules/network/f5/fixtures/load_sys_snmp_communities_4.json10
-rw-r--r--test/units/modules/network/f5/fixtures/load_sys_snmp_users_1.json15
-rw-r--r--test/units/modules/network/f5/fixtures/load_sys_software_image_1.json15
-rw-r--r--test/units/modules/network/f5/fixtures/load_sys_software_update.json9
-rw-r--r--test/units/modules/network/f5/fixtures/load_sys_syslog_1.json24
-rw-r--r--test/units/modules/network/f5/fixtures/load_tg_ha_order.json22
-rw-r--r--test/units/modules/network/f5/fixtures/load_tm_auth_partition.json9
-rw-r--r--test/units/modules/network/f5/fixtures/load_tm_auth_password_policy_1.json15
-rw-r--r--test/units/modules/network/f5/fixtures/load_tm_auth_tacacs_1.json19
-rw-r--r--test/units/modules/network/f5/fixtures/load_tm_cli_alias_1.json10
-rw-r--r--test/units/modules/network/f5/fixtures/load_tm_cli_script_1.json13
-rw-r--r--test/units/modules/network/f5/fixtures/load_tm_cm_device.json76
-rw-r--r--test/units/modules/network/f5/fixtures/load_tm_cm_device_default.json61
-rw-r--r--test/units/modules/network/f5/fixtures/load_tm_cm_device_group.json19
-rw-r--r--test/units/modules/network/f5/fixtures/load_tm_cm_traffic_group_1.json16
-rw-r--r--test/units/modules/network/f5/fixtures/load_tm_cm_traffic_group_2.json16
-rw-r--r--test/units/modules/network/f5/fixtures/load_tm_net_self.json26
-rw-r--r--test/units/modules/network/f5/fixtures/load_tm_net_trunk_1.json29
-rw-r--r--test/units/modules/network/f5/fixtures/load_tm_sys_syslog_1.json38
-rw-r--r--test/units/modules/network/f5/fixtures/load_tm_sys_syslog_2.json38
-rw-r--r--test/units/modules/network/f5/fixtures/load_tmm_log.json14
-rw-r--r--test/units/modules/network/f5/fixtures/load_vlan.json30
-rw-r--r--test/units/modules/network/f5/fixtures/load_vlan_interfaces.json15
-rw-r--r--test/units/modules/network/f5/fixtures/load_vlan_tagged_ifcs.json12
-rw-r--r--test/units/modules/network/f5/fixtures/load_vlan_untag_ifcs.json11
-rw-r--r--test/units/modules/network/f5/fixtures/pool_members_subcollection.json21
-rw-r--r--test/units/modules/network/f5/fixtures/update_iapp_service_parameters_f5_http.json195
-rw-r--r--test/units/modules/network/f5/fixtures/update_vlan_description.json31
-rw-r--r--test/units/modules/network/f5/test_bigip_apm_acl.py243
-rw-r--r--test/units/modules/network/f5/test_bigip_apm_network_access.py209
-rw-r--r--test/units/modules/network/f5/test_bigip_apm_policy_fetch.py128
-rw-r--r--test/units/modules/network/f5/test_bigip_apm_policy_import.py127
-rw-r--r--test/units/modules/network/f5/test_bigip_appsvcs_extension.py104
-rw-r--r--test/units/modules/network/f5/test_bigip_asm_dos_application.py279
-rw-r--r--test/units/modules/network/f5/test_bigip_asm_policy_fetch.py130
-rw-r--r--test/units/modules/network/f5/test_bigip_asm_policy_import.py125
-rw-r--r--test/units/modules/network/f5/test_bigip_asm_policy_manage.py519
-rw-r--r--test/units/modules/network/f5/test_bigip_asm_policy_server_technology.py122
-rw-r--r--test/units/modules/network/f5/test_bigip_asm_policy_signature_set.py151
-rw-r--r--test/units/modules/network/f5/test_bigip_cli_alias.py118
-rw-r--r--test/units/modules/network/f5/test_bigip_cli_script.py114
-rw-r--r--test/units/modules/network/f5/test_bigip_command.py299
-rw-r--r--test/units/modules/network/f5/test_bigip_config.py112
-rw-r--r--test/units/modules/network/f5/test_bigip_configsync_action.py135
-rw-r--r--test/units/modules/network/f5/test_bigip_data_group.py485
-rw-r--r--test/units/modules/network/f5/test_bigip_device_auth.py131
-rw-r--r--test/units/modules/network/f5/test_bigip_device_auth_ldap.py131
-rw-r--r--test/units/modules/network/f5/test_bigip_device_certificate.py173
-rw-r--r--test/units/modules/network/f5/test_bigip_device_connectivity.py388
-rw-r--r--test/units/modules/network/f5/test_bigip_device_dns.py126
-rw-r--r--test/units/modules/network/f5/test_bigip_device_group.py186
-rw-r--r--test/units/modules/network/f5/test_bigip_device_group_member.py104
-rw-r--r--test/units/modules/network/f5/test_bigip_device_ha_group.py230
-rw-r--r--test/units/modules/network/f5/test_bigip_device_httpd.py303
-rw-r--r--test/units/modules/network/f5/test_bigip_device_info.py130
-rw-r--r--test/units/modules/network/f5/test_bigip_device_license.py120
-rw-r--r--test/units/modules/network/f5/test_bigip_device_ntp.py253
-rw-r--r--test/units/modules/network/f5/test_bigip_device_sshd.py128
-rw-r--r--test/units/modules/network/f5/test_bigip_device_syslog.py111
-rw-r--r--test/units/modules/network/f5/test_bigip_device_traffic_group.py167
-rw-r--r--test/units/modules/network/f5/test_bigip_device_trust.py183
-rw-r--r--test/units/modules/network/f5/test_bigip_dns_cache_resolver.py113
-rw-r--r--test/units/modules/network/f5/test_bigip_dns_nameserver.py126
-rw-r--r--test/units/modules/network/f5/test_bigip_dns_resolver.py124
-rw-r--r--test/units/modules/network/f5/test_bigip_dns_zone.py128
-rw-r--r--test/units/modules/network/f5/test_bigip_file_copy.py121
-rw-r--r--test/units/modules/network/f5/test_bigip_firewall_address_list.py140
-rw-r--r--test/units/modules/network/f5/test_bigip_firewall_dos_profile.py110
-rw-r--r--test/units/modules/network/f5/test_bigip_firewall_dos_vector.py110
-rw-r--r--test/units/modules/network/f5/test_bigip_firewall_global_rules.py115
-rw-r--r--test/units/modules/network/f5/test_bigip_firewall_log_profile.py146
-rw-r--r--test/units/modules/network/f5/test_bigip_firewall_log_profile_network.py171
-rw-r--r--test/units/modules/network/f5/test_bigip_firewall_policy.py119
-rw-r--r--test/units/modules/network/f5/test_bigip_firewall_port_list.py147
-rw-r--r--test/units/modules/network/f5/test_bigip_firewall_rule.py156
-rw-r--r--test/units/modules/network/f5/test_bigip_firewall_rule_list.py109
-rw-r--r--test/units/modules/network/f5/test_bigip_firewall_schedule.py128
-rw-r--r--test/units/modules/network/f5/test_bigip_gtm_datacenter.py245
-rw-r--r--test/units/modules/network/f5/test_bigip_gtm_global.py120
-rw-r--r--test/units/modules/network/f5/test_bigip_gtm_monitor_bigip.py179
-rw-r--r--test/units/modules/network/f5/test_bigip_gtm_monitor_external.py135
-rw-r--r--test/units/modules/network/f5/test_bigip_gtm_monitor_firepass.py156
-rw-r--r--test/units/modules/network/f5/test_bigip_gtm_monitor_http.py162
-rw-r--r--test/units/modules/network/f5/test_bigip_gtm_monitor_https.py170
-rw-r--r--test/units/modules/network/f5/test_bigip_gtm_monitor_tcp.py223
-rw-r--r--test/units/modules/network/f5/test_bigip_gtm_monitor_tcp_half_open.py193
-rw-r--r--test/units/modules/network/f5/test_bigip_gtm_pool.py385
-rw-r--r--test/units/modules/network/f5/test_bigip_gtm_pool_member.py219
-rw-r--r--test/units/modules/network/f5/test_bigip_gtm_server.py341
-rw-r--r--test/units/modules/network/f5/test_bigip_gtm_topology_record.py132
-rw-r--r--test/units/modules/network/f5/test_bigip_gtm_topology_region.py144
-rw-r--r--test/units/modules/network/f5/test_bigip_gtm_virtual_server.py178
-rw-r--r--test/units/modules/network/f5/test_bigip_gtm_wide_ip.py351
-rw-r--r--test/units/modules/network/f5/test_bigip_hostname.py109
-rw-r--r--test/units/modules/network/f5/test_bigip_iapp_service.py376
-rw-r--r--test/units/modules/network/f5/test_bigip_iapp_template.py202
-rw-r--r--test/units/modules/network/f5/test_bigip_ike_peer.py111
-rw-r--r--test/units/modules/network/f5/test_bigip_imish_config.py104
-rw-r--r--test/units/modules/network/f5/test_bigip_ipsec_policy.py109
-rw-r--r--test/units/modules/network/f5/test_bigip_irule.py266
-rw-r--r--test/units/modules/network/f5/test_bigip_log_destination.py131
-rw-r--r--test/units/modules/network/f5/test_bigip_log_publisher.py132
-rw-r--r--test/units/modules/network/f5/test_bigip_lx_package.py123
-rw-r--r--test/units/modules/network/f5/test_bigip_management_route.py124
-rw-r--r--test/units/modules/network/f5/test_bigip_message_routing_peer.py194
-rw-r--r--test/units/modules/network/f5/test_bigip_message_routing_protocol.py179
-rw-r--r--test/units/modules/network/f5/test_bigip_message_routing_route.py178
-rw-r--r--test/units/modules/network/f5/test_bigip_message_routing_router.py206
-rw-r--r--test/units/modules/network/f5/test_bigip_message_routing_transport_config.py183
-rw-r--r--test/units/modules/network/f5/test_bigip_monitor_dns.py157
-rw-r--r--test/units/modules/network/f5/test_bigip_monitor_external.py120
-rw-r--r--test/units/modules/network/f5/test_bigip_monitor_gateway_icmp.py155
-rw-r--r--test/units/modules/network/f5/test_bigip_monitor_http.py452
-rw-r--r--test/units/modules/network/f5/test_bigip_monitor_https.py452
-rw-r--r--test/units/modules/network/f5/test_bigip_monitor_ldap.py110
-rw-r--r--test/units/modules/network/f5/test_bigip_monitor_snmp_dca.py175
-rw-r--r--test/units/modules/network/f5/test_bigip_monitor_tcp.py454
-rw-r--r--test/units/modules/network/f5/test_bigip_monitor_tcp_echo.py331
-rw-r--r--test/units/modules/network/f5/test_bigip_monitor_tcp_half_open.py338
-rw-r--r--test/units/modules/network/f5/test_bigip_monitor_udp.py452
-rw-r--r--test/units/modules/network/f5/test_bigip_node.py250
-rw-r--r--test/units/modules/network/f5/test_bigip_partition.py214
-rw-r--r--test/units/modules/network/f5/test_bigip_password_policy.py152
-rw-r--r--test/units/modules/network/f5/test_bigip_policy.py158
-rw-r--r--test/units/modules/network/f5/test_bigip_policy_rule.py198
-rw-r--r--test/units/modules/network/f5/test_bigip_pool.py546
-rw-r--r--test/units/modules/network/f5/test_bigip_pool_member.py256
-rw-r--r--test/units/modules/network/f5/test_bigip_profile_analytics.py121
-rw-r--r--test/units/modules/network/f5/test_bigip_profile_client_ssl.py129
-rw-r--r--test/units/modules/network/f5/test_bigip_profile_dns.py147
-rw-r--r--test/units/modules/network/f5/test_bigip_profile_fastl4.py178
-rw-r--r--test/units/modules/network/f5/test_bigip_profile_http.py127
-rw-r--r--test/units/modules/network/f5/test_bigip_profile_http2.py130
-rw-r--r--test/units/modules/network/f5/test_bigip_profile_http_compression.py129
-rw-r--r--test/units/modules/network/f5/test_bigip_profile_oneconnect.py124
-rw-r--r--test/units/modules/network/f5/test_bigip_profile_persistence_cookie.py124
-rw-r--r--test/units/modules/network/f5/test_bigip_profile_persistence_src_addr.py128
-rw-r--r--test/units/modules/network/f5/test_bigip_profile_server_ssl.py115
-rw-r--r--test/units/modules/network/f5/test_bigip_profile_tcp.py116
-rw-r--r--test/units/modules/network/f5/test_bigip_profile_udp.py119
-rw-r--r--test/units/modules/network/f5/test_bigip_provision.py318
-rw-r--r--test/units/modules/network/f5/test_bigip_qkview.py178
-rw-r--r--test/units/modules/network/f5/test_bigip_remote_role.py110
-rw-r--r--test/units/modules/network/f5/test_bigip_remote_syslog.py230
-rw-r--r--test/units/modules/network/f5/test_bigip_remote_user.py126
-rw-r--r--test/units/modules/network/f5/test_bigip_routedomain.py128
-rw-r--r--test/units/modules/network/f5/test_bigip_selfip.py207
-rw-r--r--test/units/modules/network/f5/test_bigip_service_policy.py132
-rw-r--r--test/units/modules/network/f5/test_bigip_smtp.py152
-rw-r--r--test/units/modules/network/f5/test_bigip_snat_pool.py187
-rw-r--r--test/units/modules/network/f5/test_bigip_snat_translation.py337
-rw-r--r--test/units/modules/network/f5/test_bigip_snmp.py266
-rw-r--r--test/units/modules/network/f5/test_bigip_snmp_community.py305
-rw-r--r--test/units/modules/network/f5/test_bigip_snmp_trap.py203
-rw-r--r--test/units/modules/network/f5/test_bigip_software_image.py123
-rw-r--r--test/units/modules/network/f5/test_bigip_software_install.py119
-rw-r--r--test/units/modules/network/f5/test_bigip_software_update.py119
-rw-r--r--test/units/modules/network/f5/test_bigip_ssl_certificate.py152
-rw-r--r--test/units/modules/network/f5/test_bigip_ssl_key.py113
-rw-r--r--test/units/modules/network/f5/test_bigip_ssl_ocsp.py130
-rw-r--r--test/units/modules/network/f5/test_bigip_static_route.py377
-rw-r--r--test/units/modules/network/f5/test_bigip_sys_daemon_log_tmm.py138
-rw-r--r--test/units/modules/network/f5/test_bigip_sys_db.py130
-rw-r--r--test/units/modules/network/f5/test_bigip_sys_global.py133
-rw-r--r--test/units/modules/network/f5/test_bigip_timer_policy.py112
-rw-r--r--test/units/modules/network/f5/test_bigip_traffic_selector.py108
-rw-r--r--test/units/modules/network/f5/test_bigip_trunk.py141
-rw-r--r--test/units/modules/network/f5/test_bigip_tunnel.py112
-rw-r--r--test/units/modules/network/f5/test_bigip_ucs.py411
-rw-r--r--test/units/modules/network/f5/test_bigip_ucs_fetch.py131
-rw-r--r--test/units/modules/network/f5/test_bigip_user.py892
-rw-r--r--test/units/modules/network/f5/test_bigip_vcmp_guest.py262
-rw-r--r--test/units/modules/network/f5/test_bigip_virtual_address.py235
-rw-r--r--test/units/modules/network/f5/test_bigip_virtual_server.py995
-rw-r--r--test/units/modules/network/f5/test_bigip_vlan.py344
-rw-r--r--test/units/modules/network/f5/test_bigip_wait.py128
-rw-r--r--test/units/modules/network/f5/test_bigiq_application_fasthttp.py242
-rw-r--r--test/units/modules/network/f5/test_bigiq_application_fastl4_tcp.py235
-rw-r--r--test/units/modules/network/f5/test_bigiq_application_fastl4_udp.py235
-rw-r--r--test/units/modules/network/f5/test_bigiq_application_http.py242
-rw-r--r--test/units/modules/network/f5/test_bigiq_application_https_offload.py260
-rw-r--r--test/units/modules/network/f5/test_bigiq_application_https_waf.py268
-rw-r--r--test/units/modules/network/f5/test_bigiq_device_discovery.py134
-rw-r--r--test/units/modules/network/f5/test_bigiq_device_info.py106
-rw-r--r--test/units/modules/network/f5/test_bigiq_regkey_license.py125
-rw-r--r--test/units/modules/network/f5/test_bigiq_regkey_license_assignment.py141
-rw-r--r--test/units/modules/network/f5/test_bigiq_regkey_pool.py109
-rw-r--r--test/units/modules/network/f5/test_bigiq_utility_license.py113
-rw-r--r--test/units/modules/network/f5/test_bigiq_utility_license_assignment.py134
483 files changed, 0 insertions, 191281 deletions
diff --git a/lib/ansible/module_utils/network/f5/bigip.py b/lib/ansible/module_utils/network/f5/bigip.py
deleted file mode 100644
index 8c4d505277..0000000000
--- a/lib/ansible/module_utils/network/f5/bigip.py
+++ /dev/null
@@ -1,98 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright (c) 2017 F5 Networks Inc.
-# 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 time
-
-try:
- from library.module_utils.network.f5.common import F5BaseClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.icontrol import iControlRestSession
-except ImportError:
- from ansible.module_utils.network.f5.common import F5BaseClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.icontrol import iControlRestSession
-
-
-class F5RestClient(F5BaseClient):
- def __init__(self, *args, **kwargs):
- super(F5RestClient, self).__init__(*args, **kwargs)
- self.provider = self.merge_provider_params()
- self.headers = {
- 'Content-Type': 'application/json'
- }
- self.retries = 0
-
- @property
- def api(self):
- if self._client:
- return self._client
- session, err = self.connect_via_token_auth()
- if err or session is None:
- session, err = self.connect_via_basic_auth()
- if err or session is None:
- raise F5ModuleError(err)
- self._client = session
- return session
-
- def connect_via_token_auth(self):
- url = "https://{0}:{1}/mgmt/shared/authn/login".format(
- self.provider['server'], self.provider['server_port']
- )
- payload = {
- 'username': self.provider['user'],
- 'password': self.provider['password'],
- 'loginProviderName': self.provider['auth_provider'] or 'tmos'
- }
- session = iControlRestSession(
- validate_certs=self.provider['validate_certs']
- )
-
- response = session.post(
- url,
- json=payload,
- headers=self.headers
- )
-
- if response.status not in [200]:
- if b'Configuration Utility restarting...' in response.content and self.retries < 3:
- time.sleep(30)
- self.retries += 1
- return self.connect_via_token_auth()
- else:
- self.retries = 0
- return None, response.content
-
- self.retries = 0
- session.request.headers['X-F5-Auth-Token'] = response.json()['token']['token']
- return session, None
-
- def connect_via_basic_auth(self):
- url = "https://{0}:{1}/mgmt/tm/sys".format(
- self.provider['server'], self.provider['server_port']
- )
- session = iControlRestSession(
- url_username=self.provider['user'],
- url_password=self.provider['password'],
- validate_certs=self.provider['validate_certs'],
- )
-
- response = session.get(
- url,
- headers=self.headers
- )
-
- if response.status not in [200]:
- if b'Configuration Utility restarting...' in response.content and self.retries < 3:
- time.sleep(30)
- self.retries += 1
- return self.connect_via_basic_auth()
- else:
- self.retries = 0
- return None, response.content
- self.retries = 0
- return session, None
diff --git a/lib/ansible/module_utils/network/f5/bigiq.py b/lib/ansible/module_utils/network/f5/bigiq.py
deleted file mode 100644
index bc1bac413d..0000000000
--- a/lib/ansible/module_utils/network/f5/bigiq.py
+++ /dev/null
@@ -1,139 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright (c) 2017 F5 Networks Inc.
-# 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 os
-
-
-try:
- from library.module_utils.network.f5.common import F5BaseClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import is_ansible_debug
- from library.module_utils.network.f5.icontrol import iControlRestSession
-except ImportError:
- from ansible.module_utils.network.f5.common import F5BaseClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import is_ansible_debug
- from ansible.module_utils.network.f5.icontrol import iControlRestSession
-
-
-class F5RestClient(F5BaseClient):
- def __init__(self, *args, **kwargs):
- super(F5RestClient, self).__init__(*args, **kwargs)
- self.provider = self.merge_provider_params()
- self.headers = {
- 'Content-Type': 'application/json'
- }
-
- @property
- def api(self):
- if self._client:
- return self._client
- session, err = self.connect_via_token_auth()
- if err:
- raise F5ModuleError(err)
- self._client = session
- return session
-
- def connect_via_token_auth(self):
- provider = self.provider['auth_provider'] or 'local'
-
- url = "https://{0}:{1}/mgmt/shared/authn/login".format(
- self.provider['server'], self.provider['server_port']
- )
- payload = {
- 'username': self.provider['user'],
- 'password': self.provider['password'],
- }
-
- # - local is a special provider that is baked into the system and
- # has no loginReference
- if provider != 'local':
- login_ref = self.get_login_ref(provider)
- payload.update(login_ref)
-
- session = iControlRestSession(
- validate_certs=self.provider['validate_certs']
- )
-
- response = session.post(
- url,
- json=payload,
- headers=self.headers
- )
-
- if response.status not in [200]:
- return None, response.content
-
- session.request.headers['X-F5-Auth-Token'] = response.json()['token']['token']
- return session, None
-
- def get_login_ref(self, provider):
- info = self.read_provider_info_from_device()
- uuids = [os.path.basename(os.path.dirname(x['link'])) for x in info['providers'] if '-' in x['link']]
- if provider in uuids:
- name = self.get_name_of_provider_id(info, provider)
- if not name:
- raise F5ModuleError(
- "No name found for the provider '{0}'".format(provider)
- )
- return dict(
- loginReference=dict(
- link="https://localhost/mgmt/cm/system/authn/providers/{0}/{1}/login".format(name, provider)
- )
- )
- names = [os.path.basename(os.path.dirname(x['link'])) for x in info['providers'] if '-' in x['link']]
- if names.count(provider) > 1:
- raise F5ModuleError(
- "Ambiguous auth_provider provided. Please specify a specific provider ID."
- )
- uuid = self.get_id_of_provider_name(info, provider)
- if not uuid:
- raise F5ModuleError(
- "No name found for the provider '{0}'".format(provider)
- )
- return dict(
- loginReference=dict(
- link="https://localhost/mgmt/cm/system/authn/providers/{0}/{1}/login".format(provider, uuid)
- )
- )
-
- def get_name_of_provider_id(self, info, provider):
- # Add slashes to the provider name so that it specifically finds the provider
- # as part of the URL and not a part of another substring
- provider = '/' + provider + '/'
- for x in info['providers']:
- if x['link'].find(provider) > -1:
- return x['name']
- return None
-
- def get_id_of_provider_name(self, info, provider):
- for x in info['providers']:
- if x['name'] == provider:
- return os.path.basename(os.path.dirname(x['link']))
- return None
-
- def read_provider_info_from_device(self):
- uri = "https://{0}:{1}/info/system".format(
- self.provider['server'], self.provider['server_port']
- )
- session = iControlRestSession()
- session.verify = self.provider['validate_certs']
-
- resp = session.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return response
diff --git a/lib/ansible/module_utils/network/f5/common.py b/lib/ansible/module_utils/network/f5/common.py
deleted file mode 100644
index 9b3aa71092..0000000000
--- a/lib/ansible/module_utils/network/f5/common.py
+++ /dev/null
@@ -1,573 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright (c) 2017 F5 Networks Inc.
-# 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 copy
-import os
-import re
-import datetime
-
-from ansible.module_utils._text import to_text
-from ansible.module_utils.basic import env_fallback
-from ansible.module_utils.connection import exec_command
-from ansible.module_utils.network.common.utils import to_list
-from ansible.module_utils.network.common.utils import ComplexList
-from ansible.module_utils.six import iteritems
-from ansible.module_utils.parsing.convert_bool import BOOLEANS_TRUE
-from ansible.module_utils.parsing.convert_bool import BOOLEANS_FALSE
-from collections import defaultdict
-
-
-MANAGED_BY_ANNOTATION_VERSION = 'f5-ansible.version'
-MANAGED_BY_ANNOTATION_MODIFIED = 'f5-ansible.last_modified'
-
-
-f5_provider_spec = {
- 'server': dict(
- fallback=(env_fallback, ['F5_SERVER'])
- ),
- 'server_port': dict(
- type='int',
- default=443,
- fallback=(env_fallback, ['F5_SERVER_PORT'])
- ),
- 'user': dict(
- fallback=(env_fallback, ['F5_USER', 'ANSIBLE_NET_USERNAME'])
- ),
- 'password': dict(
- no_log=True,
- aliases=['pass', 'pwd'],
- fallback=(env_fallback, ['F5_PASSWORD', 'ANSIBLE_NET_PASSWORD'])
- ),
- 'ssh_keyfile': dict(
- type='path'
- ),
- 'validate_certs': dict(
- type='bool',
- default='yes',
- fallback=(env_fallback, ['F5_VALIDATE_CERTS'])
- ),
- 'transport': dict(
- choices=['cli', 'rest'],
- default='rest'
- ),
- 'timeout': dict(type='int'),
- 'auth_provider': dict(),
-}
-
-f5_argument_spec = {
- 'provider': dict(type='dict', options=f5_provider_spec),
-}
-
-
-def get_provider_argspec():
- return f5_provider_spec
-
-
-def load_params(params):
- provider = params.get('provider') or dict()
- for key, value in iteritems(provider):
- if key in f5_argument_spec:
- if params.get(key) is None and value is not None:
- params[key] = value
-
-
-def is_empty_list(seq):
- if len(seq) == 1:
- if seq[0] == '' or seq[0] == 'none':
- return True
- return False
-
-
-def fq_name(partition, value, sub_path=''):
- """Returns a 'Fully Qualified' name
-
- A BIG-IP expects most names of resources to be in a fully-qualified
- form. This means that both the simple name, and the partition need
- to be combined.
-
- The Ansible modules, however, can accept (as names for several
- resources) their name in the FQ format. This becomes an issue when
- the FQ name and the partition are both specified as separate values.
-
- Consider the following examples.
-
- # Name not FQ
- name: foo
- partition: Common
-
- # Name FQ
- name: /Common/foo
- partition: Common
-
- This method will rectify the above situation and will, in both cases,
- return the following for name.
-
- /Common/foo
-
- Args:
- partition (string): The partition that you would want attached to
- the name if the name has no partition.
- value (string): The name that you want to attach a partition to.
- This value will be returned unchanged if it has a partition
- attached to it already.
- sub_path (string): The sub path element. If defined the sub_path
- will be inserted between partition and value.
- This will also work on FQ names.
- Returns:
- string: The fully qualified name, given the input parameters.
- """
- if value is not None and sub_path == '':
- try:
- int(value)
- return '/{0}/{1}'.format(partition, value)
- except (ValueError, TypeError):
- if not value.startswith('/'):
- return '/{0}/{1}'.format(partition, value)
- if value is not None and sub_path != '':
- try:
- int(value)
- return '/{0}/{1}/{2}'.format(partition, sub_path, value)
- except (ValueError, TypeError):
- if value.startswith('/'):
- dummy, partition, name = value.split('/')
- return '/{0}/{1}/{2}'.format(partition, sub_path, name)
- if not value.startswith('/'):
- return '/{0}/{1}/{2}'.format(partition, sub_path, value)
- return value
-
-
-# Fully Qualified name (with partition) for a list
-def fq_list_names(partition, list_names):
- if list_names is None:
- return None
- return map(lambda x: fq_name(partition, x), list_names)
-
-
-def to_commands(module, commands):
- spec = {
- 'command': dict(key=True),
- 'prompt': dict(),
- 'answer': dict()
- }
- transform = ComplexList(spec, module)
- return transform(commands)
-
-
-def run_commands(module, commands, check_rc=True):
- responses = list()
- commands = to_commands(module, to_list(commands))
- for cmd in commands:
- cmd = module.jsonify(cmd)
- rc, out, err = exec_command(module, cmd)
- if check_rc and rc != 0:
- raise F5ModuleError(to_text(err, errors='surrogate_then_replace'))
- result = to_text(out, errors='surrogate_then_replace')
- responses.append(result)
- return responses
-
-
-def flatten_boolean(value):
- truthy = list(BOOLEANS_TRUE) + ['enabled', 'True', 'true']
- falsey = list(BOOLEANS_FALSE) + ['disabled', 'False', 'false']
- if value is None:
- return None
- elif value in truthy:
- return 'yes'
- elif value in falsey:
- return 'no'
-
-
-def is_cli(module):
- transport = module.params['transport']
- provider_transport = (module.params['provider'] or {}).get('transport')
- result = 'cli' in (transport, provider_transport)
- return result
-
-
-def is_valid_hostname(host):
- """Reasonable attempt at validating a hostname
-
- Compiled from various paragraphs outlined here
- https://tools.ietf.org/html/rfc3696#section-2
- https://tools.ietf.org/html/rfc1123
-
- Notably,
- * Host software MUST handle host names of up to 63 characters and
- SHOULD handle host names of up to 255 characters.
- * The "LDH rule", after the characters that it permits. (letters, digits, hyphen)
- * If the hyphen is used, it is not permitted to appear at
- either the beginning or end of a label
-
- :param host:
- :return:
- """
- if len(host) > 255:
- return False
- host = host.rstrip(".")
- allowed = re.compile(r'(?!-)[A-Z0-9-]{1,63}(?<!-)$', re.IGNORECASE)
- result = all(allowed.match(x) for x in host.split("."))
- return result
-
-
-def is_valid_fqdn(host):
- """Reasonable attempt at validating a hostname
-
- Compiled from various paragraphs outlined here
- https://tools.ietf.org/html/rfc3696#section-2
- https://tools.ietf.org/html/rfc1123
-
- Notably,
- * Host software MUST handle host names of up to 63 characters and
- SHOULD handle host names of up to 255 characters.
- * The "LDH rule", after the characters that it permits. (letters, digits, hyphen)
- * If the hyphen is used, it is not permitted to appear at
- either the beginning or end of a label
-
- :param host:
- :return:
- """
- if len(host) > 255:
- return False
- host = host.rstrip(".")
- allowed = re.compile(r'(?!-)[A-Z0-9-]{1,63}(?<!-)$', re.IGNORECASE)
- result = all(allowed.match(x) for x in host.split("."))
- if result:
- parts = host.split('.')
- if len(parts) > 1:
- return True
- return False
-
-
-def transform_name(partition='', name='', sub_path=''):
- if partition != '':
- if name.startswith(partition + '/'):
- name = name.replace(partition + '/', '')
- if name.startswith('/' + partition + '/'):
- name = name.replace('/' + partition + '/', '')
-
- if name:
- name = name.replace('/', '~')
- name = name.replace('%', '%25')
-
- if partition:
- partition = partition.replace('/', '~')
- if not partition.startswith('~'):
- partition = '~' + partition
- else:
- if sub_path:
- raise F5ModuleError(
- 'When giving the subPath component include partition as well.'
- )
-
- if sub_path and partition:
- sub_path = '~' + sub_path
-
- if name and partition:
- name = '~' + name
-
- result = partition + sub_path + name
- return result
-
-
-def is_ansible_debug(module):
- if module._debug and module._verbosity >= 4:
- return True
- return False
-
-
-def is_uuid(uuid=None):
- """Check to see if value is an F5 UUID
-
- UUIDs are used in BIG-IQ and in select areas of BIG-IP (notably ASM). This method
- will check to see if the provided value matches a UUID as known by these products.
-
- Args:
- uuid (string): The value to check for UUID-ness
-
- Returns:
- bool:
- """
- if uuid is None:
- return False
- pattern = r'[A-Za-z0-9]{8}-[A-Za-z0-9]{4}-[A-Za-z0-9]{4}-[A-Za-z0-9]{4}-[A-Za-z0-9]{12}'
- if re.match(pattern, uuid):
- return True
- return False
-
-
-def on_bigip():
- if os.path.exists('/usr/bin/tmsh'):
- return True
- return False
-
-
-def mark_managed_by(ansible_version, params):
- metadata = []
- result = copy.deepcopy(params)
- found1 = False
- found2 = False
- mark1 = dict(
- name=MANAGED_BY_ANNOTATION_VERSION,
- value=ansible_version,
- persist='true'
- )
- mark2 = dict(
- name=MANAGED_BY_ANNOTATION_MODIFIED,
- value=str(datetime.datetime.utcnow()),
- persist='true'
- )
-
- if 'metadata' not in result:
- result['metadata'] = [mark1, mark2]
- return result
-
- for x in params['metadata']:
- if x['name'] == MANAGED_BY_ANNOTATION_VERSION:
- found1 = True
- metadata.append(mark1)
- if x['name'] == MANAGED_BY_ANNOTATION_MODIFIED:
- found2 = True
- metadata.append(mark1)
- else:
- metadata.append(x)
- if not found1:
- metadata.append(mark1)
- if not found2:
- metadata.append(mark2)
-
- result['metadata'] = metadata
- return result
-
-
-def only_has_managed_metadata(metadata):
- managed = [
- MANAGED_BY_ANNOTATION_MODIFIED,
- MANAGED_BY_ANNOTATION_VERSION,
- ]
-
- for x in metadata:
- if x['name'] not in managed:
- return False
- return True
-
-
-class Noop(object):
- """Represent no-operation required
-
- This class is used in the Difference engine to specify when an attribute
- has not changed. Difference attributes may return an instance of this
- class as a means to indicate when the attribute has not changed.
-
- The Noop object allows attributes to be set to None when sending updates
- to the API. `None` is technically a valid value in some cases (it indicates
- that the attribute should be removed from the resource).
- """
- pass
-
-
-class F5BaseClient(object):
- def __init__(self, *args, **kwargs):
- self.params = kwargs
- self.module = kwargs.get('module', None)
- load_params(self.params)
- self._client = None
-
- @property
- def api(self):
- raise F5ModuleError("Management root must be used from the concrete product classes.")
-
- def reconnect(self):
- """Attempts to reconnect to a device
-
- The existing token from a ManagementRoot can become invalid if you,
- for example, upgrade the device (such as is done in the *_software
- module.
-
- This method can be used to reconnect to a remote device without
- having to re-instantiate the ArgumentSpec and AnsibleF5Client classes
- it will use the same values that were initially provided to those
- classes
-
- :return:
- :raises iControlUnexpectedHTTPError
- """
- self._client = None
-
- @staticmethod
- def validate_params(key, store):
- if key in store and store[key] is not None:
- return True
- else:
- return False
-
- def merge_provider_params(self):
- result = dict()
- provider = self.params.get('provider', None)
- if not provider:
- provider = {}
-
- self.merge_provider_server_param(result, provider)
- self.merge_provider_server_port_param(result, provider)
- self.merge_provider_validate_certs_param(result, provider)
- self.merge_provider_auth_provider_param(result, provider)
- self.merge_provider_user_param(result, provider)
- self.merge_provider_password_param(result, provider)
-
- return result
-
- def merge_provider_server_param(self, result, provider):
- if self.validate_params('server', provider):
- result['server'] = provider['server']
- elif self.validate_params('F5_SERVER', os.environ):
- result['server'] = os.environ['F5_SERVER']
- else:
- raise F5ModuleError('Server parameter cannot be None or missing, please provide a valid value')
-
- def merge_provider_server_port_param(self, result, provider):
- if self.validate_params('server_port', provider):
- result['server_port'] = provider['server_port']
- elif self.validate_params('F5_SERVER_PORT', os.environ):
- result['server_port'] = os.environ['F5_SERVER_PORT']
- else:
- result['server_port'] = 443
-
- def merge_provider_validate_certs_param(self, result, provider):
- if self.validate_params('validate_certs', provider):
- result['validate_certs'] = provider['validate_certs']
- elif self.validate_params('F5_VALIDATE_CERTS', os.environ):
- result['validate_certs'] = os.environ['F5_VALIDATE_CERTS']
- else:
- result['validate_certs'] = True
- if result['validate_certs'] in BOOLEANS_TRUE:
- result['validate_certs'] = True
- else:
- result['validate_certs'] = False
-
- def merge_provider_auth_provider_param(self, result, provider):
- if self.validate_params('auth_provider', provider):
- result['auth_provider'] = provider['auth_provider']
- elif self.validate_params('F5_AUTH_PROVIDER', os.environ):
- result['auth_provider'] = os.environ['F5_AUTH_PROVIDER']
- else:
- result['auth_provider'] = None
-
- # Handle a specific case of the user specifying ``|default(omit)``
- # as the value to the auth_provider.
- #
- # In this case, Ansible will inject the omit-placeholder value
- # and the module params incorrectly interpret this. This case
- # can occur when specifying ``|default(omit)`` for a variable
- # value defined in the ``environment`` section of a Play.
- #
- # An example of the omit placeholder is shown below.
- #
- # __omit_place_holder__11bd71a2840bff144594b9cc2149db814256f253
- #
- if result['auth_provider'] is not None and '__omit_place_holder__' in result['auth_provider']:
- result['auth_provider'] = None
-
- def merge_provider_user_param(self, result, provider):
- if self.validate_params('user', provider):
- result['user'] = provider['user']
- elif self.validate_params('F5_USER', os.environ):
- result['user'] = os.environ.get('F5_USER')
- elif self.validate_params('ANSIBLE_NET_USERNAME', os.environ):
- result['user'] = os.environ.get('ANSIBLE_NET_USERNAME')
- else:
- result['user'] = None
-
- def merge_provider_password_param(self, result, provider):
- if self.validate_params('password', provider):
- result['password'] = provider['password']
- elif self.validate_params('F5_PASSWORD', os.environ):
- result['password'] = os.environ.get('F5_PASSWORD')
- elif self.validate_params('ANSIBLE_NET_PASSWORD', os.environ):
- result['password'] = os.environ.get('ANSIBLE_NET_PASSWORD')
- else:
- result['password'] = None
-
-
-class AnsibleF5Parameters(object):
- def __init__(self, *args, **kwargs):
- self._values = defaultdict(lambda: None)
- self._values['__warnings'] = []
- self.client = kwargs.pop('client', None)
- self._module = kwargs.pop('module', None)
- self._params = {}
-
- params = kwargs.pop('params', None)
- if params:
- self.update(params=params)
- self._params.update(params)
-
- def update(self, params=None):
- if params:
- self._params.update(params)
- for k, v in iteritems(params):
- # Adding this here because ``username`` is a connection parameter
- # and in cases where it is also an API parameter, we run the risk
- # of overriding the specified parameter with the connection parameter.
- #
- # Since this is a problem, and since "username" is never a valid
- # parameter outside its usage in connection params (where we do not
- # use the ApiParameter or ModuleParameters classes) it is safe to
- # skip over it if it is provided.
- if k == 'password':
- continue
- if self.api_map is not None and k in self.api_map:
- map_key = self.api_map[k]
- else:
- map_key = k
-
- # Handle weird API parameters like `dns.proxy.__iter__` by
- # using a map provided by the module developer
- class_attr = getattr(type(self), map_key, None)
- if isinstance(class_attr, property):
- # There is a mapped value for the api_map key
- if class_attr.fset is None:
- # If the mapped value does not have
- # an associated setter
- self._values[map_key] = v
- else:
- # The mapped value has a setter
- setattr(self, map_key, v)
- else:
- # If the mapped value is not a @property
- self._values[map_key] = v
-
- def api_params(self):
- result = {}
- for api_attribute in self.api_attributes:
- if self.api_map is not None and api_attribute in self.api_map:
- result[api_attribute] = getattr(self, self.api_map[api_attribute])
- else:
- result[api_attribute] = getattr(self, api_attribute)
- result = self._filter_params(result)
- return result
-
- def __getattr__(self, item):
- # Ensures that properties that weren't defined, and therefore stashed
- # in the `_values` dict, will be retrievable.
- return self._values[item]
-
- @property
- def partition(self):
- if self._values['partition'] is None:
- return 'Common'
- return self._values['partition'].strip('/')
-
- @partition.setter
- def partition(self, value):
- self._values['partition'] = value
-
- def _filter_params(self, params):
- return dict((k, v) for k, v in iteritems(params) if v is not None)
-
-
-class F5ModuleError(Exception):
- pass
diff --git a/lib/ansible/module_utils/network/f5/compare.py b/lib/ansible/module_utils/network/f5/compare.py
deleted file mode 100644
index f45dabe940..0000000000
--- a/lib/ansible/module_utils/network/f5/compare.py
+++ /dev/null
@@ -1,84 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright (c) 2017 F5 Networks Inc.
-# 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.module_utils.six import iteritems
-
-
-def cmp_simple_list(want, have):
- if want is None:
- return None
- if have is None and want in ['', 'none']:
- return None
- if have is not None and want in ['', 'none']:
- return []
- if have is None:
- return want
- if set(want) != set(have):
- return want
- return None
-
-
-def cmp_str_with_none(want, have):
- if want is None:
- return None
- if have is None and want == '':
- return None
- if want != have:
- return want
-
-
-def compare_complex_list(want, have):
- """Performs a complex list comparison
-
- A complex list is a list of dictionaries
-
- Args:
- want (list): List of dictionaries to compare with second parameter.
- have (list): List of dictionaries compare with first parameter.
-
- Returns:
- bool:
- """
- if want == [] and have is None:
- return None
- if want is None:
- return None
- w = []
- h = []
- for x in want:
- tmp = [(str(k), str(v)) for k, v in iteritems(x)]
- w += tmp
- for x in have:
- tmp = [(str(k), str(v)) for k, v in iteritems(x)]
- h += tmp
- if set(w) == set(h):
- return None
- else:
- return want
-
-
-def compare_dictionary(want, have):
- """Performs a dictionary comparison
-
- Args:
- want (dict): Dictionary to compare with second parameter.
- have (dict): Dictionary to compare with first parameter.
-
- Returns:
- bool:
- """
- if want == {} and have is None:
- return None
- if want is None:
- return None
- w = [(str(k), str(v)) for k, v in iteritems(want)]
- h = [(str(k), str(v)) for k, v in iteritems(have)]
- if set(w) == set(h):
- return None
- else:
- return want
diff --git a/lib/ansible/module_utils/network/f5/icontrol.py b/lib/ansible/module_utils/network/f5/icontrol.py
deleted file mode 100644
index 1b596cf5f4..0000000000
--- a/lib/ansible/module_utils/network/f5/icontrol.py
+++ /dev/null
@@ -1,612 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright (c) 2017, F5 Networks Inc.
-# 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 os
-
-try:
- from StringIO import StringIO
-except ImportError:
- from io import StringIO
-
-try:
- from BytesIO import BytesIO
-except ImportError:
- from io import BytesIO
-
-from ansible.module_utils.urls import urlparse
-from ansible.module_utils.urls import generic_urlparse
-from ansible.module_utils.urls import Request
-
-try:
- import json as _json
-except ImportError:
- import simplejson as _json
-
-try:
- from library.module_utils.network.f5.common import F5ModuleError
-except ImportError:
- from ansible.module_utils.network.f5.common import F5ModuleError
-
-
-"""An F5 REST API URI handler.
-
-Use this module to make calls to an F5 REST server. It is influenced by the same
-API that the Python ``requests`` tool uses, but the two are not the same, as the
-library here is **much** more simple and targeted specifically to F5's needs.
-
-The ``requests`` design was chosen due to familiarity with the tool. Internally,
-the classes contained herein use Ansible native libraries.
-
-The means by which you should use it are similar to ``requests`` basic usage.
-
-Authentication is not handled for you automatically by this library, however it *is*
-handled automatically for you in the supporting F5 module_utils code; specifically the
-different product module_util files (bigip.py, bigiq.py, etc).
-
-Internal (non-module) usage of this library looks like this.
-
-```
-# Create a session instance
-mgmt = iControlRestSession()
-mgmt.verify = False
-
-server = '1.1.1.1'
-port = 443
-
-# Payload used for getting an initial authentication token
-payload = {
- 'username': 'admin',
- 'password': 'secret',
- 'loginProviderName': 'tmos'
-}
-
-# Create URL to call, injecting server and port
-url = f"https://{server}:{port}/mgmt/shared/authn/login"
-
-# Call the API
-resp = session.post(url, json=payload)
-
-# View the response
-print(resp.json())
-
-# Update the session with the authentication token
-session.headers['X-F5-Auth-Token'] = resp.json()['token']['token']
-
-# Create another URL to call, injecting server and port
-url = f"https://{server}:{port}/mgmt/tm/ltm/virtual/~Common~virtual1"
-
-# Call the API
-resp = session.get(url)
-
-# View the details of a virtual payload
-print(resp.json())
-```
-"""
-
-from ansible.module_utils.six.moves.urllib.error import HTTPError
-
-
-class Response(object):
- def __init__(self):
- self._content = None
- self.status = None
- self.headers = dict()
- self.url = None
- self.reason = None
- self.request = None
- self.msg = None
-
- @property
- def content(self):
- return self._content
-
- @property
- def raw_content(self):
- return self._content
-
- def json(self):
- return _json.loads(self._content or 'null')
-
- @property
- def ok(self):
- if self.status is not None and int(self.status) > 400:
- return False
- try:
- response = self.json()
- if 'code' in response and response['code'] > 400:
- return False
- except ValueError:
- pass
- return True
-
-
-class iControlRestSession(object):
- """Represents a session that communicates with a BigIP.
-
- This acts as a loose wrapper around Ansible's ``Request`` class. We're doing
- this as interim work until we move to the httpapi connector.
- """
- def __init__(self, headers=None, use_proxy=True, force=False, timeout=120,
- validate_certs=True, url_username=None, url_password=None,
- http_agent=None, force_basic_auth=False, follow_redirects='urllib2',
- client_cert=None, client_key=None, cookies=None):
- self.request = Request(
- headers=headers,
- use_proxy=use_proxy,
- force=force,
- timeout=timeout,
- validate_certs=validate_certs,
- url_username=url_username,
- url_password=url_password,
- http_agent=http_agent,
- force_basic_auth=force_basic_auth,
- follow_redirects=follow_redirects,
- client_cert=client_cert,
- client_key=client_key,
- cookies=cookies
- )
- self.last_url = None
-
- def get_headers(self, result):
- try:
- return dict(result.getheaders())
- except AttributeError:
- return result.headers
-
- def update_response(self, response, result):
- response.headers = self.get_headers(result)
- response._content = result.read()
- response.status = result.getcode()
- response.url = result.geturl()
- response.msg = "OK (%s bytes)" % response.headers.get('Content-Length', 'unknown')
-
- def send(self, method, url, **kwargs):
- response = Response()
-
- # Set the last_url called
- #
- # This is used by the object destructor to erase the token when the
- # ModuleManager exits and destroys the iControlRestSession object
- self.last_url = url
-
- body = None
- data = kwargs.pop('data', None)
- json = kwargs.pop('json', None)
-
- if not data and json is not None:
- self.request.headers['Content-Type'] = 'application/json'
- body = _json.dumps(json)
- if not isinstance(body, bytes):
- body = body.encode('utf-8')
- if data:
- body = data
- if body:
- kwargs['data'] = body
-
- try:
- result = self.request.open(method, url, **kwargs)
- except HTTPError as e:
- # Catch HTTPError delivered from Ansible
- #
- # The structure of this object, in Ansible 2.8 is
- #
- # HttpError {
- # args
- # characters_written
- # close
- # code
- # delete
- # errno
- # file
- # filename
- # filename2
- # fp
- # getcode
- # geturl
- # hdrs
- # headers
- # info
- # msg
- # name
- # reason
- # strerror
- # url
- # with_traceback
- # }
- self.update_response(response, e)
- return response
-
- self.update_response(response, result)
- return response
-
- def delete(self, url, **kwargs):
- return self.send('DELETE', url, **kwargs)
-
- def get(self, url, **kwargs):
- return self.send('GET', url, **kwargs)
-
- def patch(self, url, data=None, **kwargs):
- return self.send('PATCH', url, data=data, **kwargs)
-
- def post(self, url, data=None, **kwargs):
- return self.send('POST', url, data=data, **kwargs)
-
- def put(self, url, data=None, **kwargs):
- return self.send('PUT', url, data=data, **kwargs)
-
- def __del__(self):
- if self.last_url is None:
- return
- token = self.request.headers.get('X-F5-Auth-Token', None)
- if not token:
- return
- try:
- p = generic_urlparse(urlparse(self.last_url))
- uri = "https://{0}:{1}/mgmt/shared/authz/tokens/{2}".format(
- p['hostname'], p['port'], token
- )
- self.delete(uri)
- except ValueError:
- pass
-
-
-class TransactionContextManager(object):
- def __init__(self, client, validate_only=False):
- self.client = client
- self.validate_only = validate_only
- self.transid = None
-
- def __enter__(self):
- uri = "https://{0}:{1}/mgmt/tm/transaction/".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- resp = self.client.api.post(uri, json={})
- if resp.status not in [200]:
- raise Exception
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- self.transid = response['transId']
- self.client.api.request.headers['X-F5-REST-Coordination-Id'] = self.transid
- return self.client
-
- def __exit__(self, exc_type, exc_value, exc_tb):
- self.client.api.request.headers.pop('X-F5-REST-Coordination-Id')
- if exc_tb is None:
- uri = "https://{0}:{1}/mgmt/tm/transaction/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- self.transid
- )
- params = dict(
- state="VALIDATING",
- validateOnly=self.validate_only
- )
- resp = self.client.api.patch(uri, json=params)
- if resp.status not in [200]:
- raise Exception
-
-
-def download_asm_file(client, url, dest):
- """Download an ASM file from the remote device
-
- This method handles issues with ASM file endpoints that allow
- downloads of ASM objects on the BIG-IP.
-
- Arguments:
- client (object): The F5RestClient connection object.
- url (string): The URL to download.
- dest (string): The location on (Ansible controller) disk to store the file.
-
- Returns:
- bool: True on success. False otherwise.
- """
-
- with open(dest, 'wb') as fileobj:
- headers = {
- 'Content-Type': 'application/json'
- }
- data = {'headers': headers,
- 'verify': False
- }
-
- response = client.api.get(url, headers=headers, json=data)
- if response.status == 200:
- if 'Content-Length' not in response.headers:
- error_message = "The Content-Length header is not present."
- raise F5ModuleError(error_message)
-
- length = response.headers['Content-Length']
-
- if int(length) > 0:
- fileobj.write(response.content)
- else:
- error = "Invalid Content-Length value returned: %s ," \
- "the value should be greater than 0" % length
- raise F5ModuleError(error)
-
-
-def download_file(client, url, dest):
- """Download a file from the remote device
-
- This method handles the chunking needed to download a file from
- a given URL on the BIG-IP.
-
- Arguments:
- client (object): The F5RestClient connection object.
- url (string): The URL to download.
- dest (string): The location on (Ansible controller) disk to store the file.
-
- Returns:
- bool: True on success. False otherwise.
- """
- with open(dest, 'wb') as fileobj:
- chunk_size = 512 * 1024
- start = 0
- end = chunk_size - 1
- size = 0
- current_bytes = 0
-
- while True:
- content_range = "%s-%s/%s" % (start, end, size)
- headers = {
- 'Content-Range': content_range,
- 'Content-Type': 'application/octet-stream'
- }
- data = {
- 'headers': headers,
- 'verify': False,
- 'stream': False
- }
- response = client.api.get(url, headers=headers, json=data)
- if response.status == 200:
- # If the size is zero, then this is the first time through
- # the loop and we don't want to write data because we
- # haven't yet figured out the total size of the file.
- if size > 0:
- current_bytes += chunk_size
- fileobj.write(response.raw_content)
- # Once we've downloaded the entire file, we can break out of
- # the loop
- if end == size:
- break
- crange = response.headers['Content-Range']
- # Determine the total number of bytes to read.
- if size == 0:
- size = int(crange.split('/')[-1]) - 1
- # If the file is smaller than the chunk_size, the BigIP
- # will return an HTTP 400. Adjust the chunk_size down to
- # the total file size...
- if chunk_size > size:
- end = size
- # ...and pass on the rest of the code.
- continue
- start += chunk_size
- if (current_bytes + chunk_size) > size:
- end = size
- else:
- end = start + chunk_size - 1
- return True
-
-
-def upload_file(client, url, src, dest=None):
- """Upload a file to an arbitrary URL.
-
- This method is responsible for correctly chunking an upload request to an
- arbitrary file worker URL.
-
- Arguments:
- client (object): The F5RestClient connection object.
- url (string): The URL to upload a file to.
- src (string): The file to be uploaded.
- dest (string): The file name to create on the remote device.
-
- Examples:
- The ``dest`` may be either an absolute or relative path. The basename
- of the path is used as the remote file name upon upload. For instance,
- in the example below, ``BIGIP-13.1.0.8-0.0.3.iso`` would be the name
- of the remote file.
-
- The specified URL should be the full URL to where you want to upload a
- file. BIG-IP has many different URLs that can be used to handle different
- types of files. This is why a full URL is required.
-
- >>> from ansible.module_utils.network.f5.icontrol import upload_client
- >>> url = 'https://{0}:{1}/mgmt/cm/autodeploy/software-image-uploads'.format(
- ... self.client.provider['server'],
- ... self.client.provider['server_port']
- ... )
- >>> dest = '/path/to/BIGIP-13.1.0.8-0.0.3.iso'
- >>> upload_file(self.client, url, dest)
- True
-
- Returns:
- bool: True on success. False otherwise.
-
- Raises:
- F5ModuleError: Raised if ``retries`` limit is exceeded.
- """
- if isinstance(src, StringIO) or isinstance(src, BytesIO):
- fileobj = src
- else:
- fileobj = open(src, 'rb')
-
- try:
- size = os.stat(src).st_size
- is_file = True
- except TypeError:
- src.seek(0, os.SEEK_END)
- size = src.tell()
- src.seek(0)
- is_file = False
-
- # This appears to be the largest chunk size that iControlREST can handle.
- #
- # The trade-off you are making by choosing a chunk size is speed, over size of
- # transmission. A lower chunk size will be slower because a smaller amount of
- # data is read from disk and sent via HTTP. Lots of disk reads are slower and
- # There is overhead in sending the request to the BIG-IP.
- #
- # Larger chunk sizes are faster because more data is read from disk in one
- # go, and therefore more data is transmitted to the BIG-IP in one HTTP request.
- #
- # If you are transmitting over a slow link though, it may be more reliable to
- # transmit many small chunks that fewer large chunks. It will clearly take
- # longer, but it may be more robust.
- chunk_size = 1024 * 7168
- start = 0
- retries = 0
- if dest is None and is_file:
- basename = os.path.basename(src)
- else:
- basename = dest
- url = '{0}/{1}'.format(url.rstrip('/'), basename)
-
- while True:
- if retries == 3:
- # Retries are used here to allow the REST API to recover if you kill
- # an upload mid-transfer.
- #
- # There exists a case where retrying a new upload will result in the
- # API returning the POSTed payload (in bytes) with a non-200 response
- # code.
- #
- # Retrying (after seeking back to 0) seems to resolve this problem.
- raise F5ModuleError(
- "Failed to upload file too many times."
- )
- try:
- file_slice = fileobj.read(chunk_size)
- if not file_slice:
- break
-
- current_bytes = len(file_slice)
- if current_bytes < chunk_size:
- end = size
- else:
- end = start + current_bytes
- headers = {
- 'Content-Range': '%s-%s/%s' % (start, end - 1, size),
- 'Content-Type': 'application/octet-stream'
- }
-
- # Data should always be sent using the ``data`` keyword and not the
- # ``json`` keyword. This allows bytes to be sent (such as in the case
- # of uploading ISO files.
- response = client.api.post(url, headers=headers, data=file_slice)
-
- if response.status != 200:
- # When this fails, the output is usually the body of whatever you
- # POSTed. This is almost always unreadable because it is a series
- # of bytes.
- #
- # Therefore, including an empty exception here.
- raise F5ModuleError()
- start += current_bytes
- except F5ModuleError:
- # You must seek back to the beginning of the file upon exception.
- #
- # If this is not done, then you risk uploading a partial file.
- fileobj.seek(0)
- retries += 1
- return True
-
-
-def tmos_version(client):
- uri = "https://{0}:{1}/mgmt/tm/sys/".format(
- client.provider['server'],
- client.provider['server_port'],
- )
- resp = client.api.get(uri)
-
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- to_parse = urlparse(response['selfLink'])
- query = to_parse.query
- version = query.split('=')[1]
- return version
-
-
-def bigiq_version(client):
- uri = "https://{0}:{1}/mgmt/shared/resolver/device-groups/cm-shared-all-big-iqs/devices".format(
- client.provider['server'],
- client.provider['server_port'],
- )
- query = "?$select=version"
-
- resp = client.api.get(uri + query)
-
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- if 'items' in response:
- version = response['items'][0]['version']
- return version
-
- raise F5ModuleError(
- 'Failed to retrieve BIGIQ version information.'
- )
-
-
-def module_provisioned(client, module_name):
- provisioned = modules_provisioned(client)
- if module_name in provisioned:
- return True
- return False
-
-
-def modules_provisioned(client):
- """Returns a list of all provisioned modules
-
- Args:
- client: Client connection to the BIG-IP
-
- Returns:
- A list of provisioned modules in their short name for.
- For example, ['afm', 'asm', 'ltm']
- """
- uri = "https://{0}:{1}/mgmt/tm/sys/provision".format(
- client.provider['server'],
- client.provider['server_port']
- )
- resp = client.api.get(uri)
-
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- if 'items' not in response:
- return []
- return [x['name'] for x in response['items'] if x['level'] != 'none']
diff --git a/lib/ansible/module_utils/network/f5/ipaddress.py b/lib/ansible/module_utils/network/f5/ipaddress.py
deleted file mode 100644
index 5871530b67..0000000000
--- a/lib/ansible/module_utils/network/f5/ipaddress.py
+++ /dev/null
@@ -1,105 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright (c) 2018 F5 Networks Inc.
-# 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.module_utils.network.common.utils import validate_ip_address
-
-try:
- # Ansible 2.6 and later
- from ansible.module_utils.network.common.utils import validate_ip_v6_address
-except ImportError:
- import socket
-
- # Ansible 2.5 and earlier
- #
- # This method is simply backported from the 2.6 source code.
- def validate_ip_v6_address(address):
- try:
- socket.inet_pton(socket.AF_INET6, address)
- except socket.error:
- return False
- return True
-
-
-try:
- from library.module_utils.compat.ipaddress import ip_interface
- from library.module_utils.compat.ipaddress import ip_network
-except ImportError:
- from ansible.module_utils.compat.ipaddress import ip_interface
- from ansible.module_utils.compat.ipaddress import ip_network
-
-
-def is_valid_ip(addr, type='all'):
- if type in ['all', 'ipv4']:
- if validate_ip_address(addr):
- return True
- if type in ['all', 'ipv6']:
- if validate_ip_v6_address(addr):
- return True
- return False
-
-
-def ipv6_netmask_to_cidr(mask):
- """converts an IPv6 netmask to CIDR form
-
- According to the link below, CIDR is the only official way to specify
- a subset of IPv6. With that said, the same link provides a way to
- loosely convert an netmask to a CIDR.
-
- Arguments:
- mask (string): The IPv6 netmask to convert to CIDR
-
- Returns:
- int: The CIDR representation of the netmask
-
- References:
- https://stackoverflow.com/a/33533007
- http://v6decode.com/
- """
- bit_masks = [
- 0, 0x8000, 0xc000, 0xe000, 0xf000, 0xf800,
- 0xfc00, 0xfe00, 0xff00, 0xff80, 0xffc0,
- 0xffe0, 0xfff0, 0xfff8, 0xfffc, 0xfffe,
- 0xffff
- ]
- count = 0
- try:
- for w in mask.split(':'):
- if not w or int(w, 16) == 0:
- break
- count += bit_masks.index(int(w, 16))
- return count
- except Exception:
- return -1
-
-
-def is_valid_ip_network(address):
- try:
- ip_network(u'{0}'.format(address))
- return True
- except ValueError:
- return False
-
-
-def is_valid_ip_interface(address):
- try:
- ip_interface(u'{0}'.format(address))
- return True
- except ValueError:
- return False
-
-
-def get_netmask(address):
- addr = ip_network(u'{0}'.format(address))
- netmask = addr.netmask.compressed
- return netmask
-
-
-def compress_address(address):
- addr = ip_network(u'{0}'.format(address))
- result = addr.compressed.split('/')[0]
- return result
diff --git a/lib/ansible/modules/network/f5/bigip_apm_acl.py b/lib/ansible/modules/network/f5/bigip_apm_acl.py
deleted file mode 100644
index 9dd9aaab7e..0000000000
--- a/lib/ansible/modules/network/f5/bigip_apm_acl.py
+++ /dev/null
@@ -1,996 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2019, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_apm_acl
-short_description: Manage user-defined APM ACLs
-description:
- - Manage user-defined APM ACLs.
-version_added: 2.9
-options:
- name:
- description:
- - Specifies the name of the ACL to manage.
- type: str
- required: True
- description:
- description:
- - User created ACL description.
- type: str
- type:
- description:
- - Specifies the type of ACL to create.
- - Once the type is set it cannot be changed.
- type: str
- choices:
- - static
- - dynamic
- acl_order:
- description:
- - Specifies a number that indicates the order of this ACL relative to other ACLs.
- - When not set, the device will always place the ACL after the last one created.
- - The lower number the higher the ACL will be in the general order, with lowest number C(0) being the topmost one.
- - Valid range of values is between C(0) and C(65535) inclusive.
- type: int
- path_match_case:
- description:
- - Specifies whether alphabetic case is considered when matching paths in an access control entry.
- type: bool
- entries:
- description:
- - Access control entries that define the ACL matching and its respective behavior.
- - The order in which the rules are placed as arguments to this parameter, determines their order in the ACL,
- in other words changing the order of the same elements will cause a change on the unit.
- type: list
- suboptions:
- action:
- description:
- - Specifies the action that the access control entry takes when a match for this access control entry
- is encountered.
- type: str
- required: True
- choices:
- - allow
- - reject
- - discard
- - continue
- dst_port:
- description:
- - Specifies the destination port for the access control entry.
- - Can be set to C(*) to indicate all ports.
- - Parameter is mutually exclusive with C(dst_port_range).
- type: str
- dst_port_range:
- description:
- - Specifies the destination port range for the access control entry.
- - Parameter is mutually exclusive with C(dst_port_range).
- - To indicate all ports the C(dst_port) parameter must be used and set to C(*).
- type: str
- src_port:
- description:
- - Specifies the source port for the access control entry.
- - Can be set to C(*) to indicate all ports.
- - Parameter is mutually exclusive with C(src_port_range).
- type: str
- src_port_range:
- description:
- - Specifies the source port range for the access control entry.
- - Parameter is mutually exclusive with C(src_port_range).
- - To indicate all ports the C(src_port) parameter must be used and set to C(*).
- type: str
- dst_addr:
- description:
- - Specifies the destination IP address for the access control entry.
- - When set to C(any) the ACL will match any destination address, C(dst_mask) is ignored in this case.
- type: str
- dst_mask:
- description:
- - Optional parameter that specifies the destination network mask for the access control entry.
- - If not specified and C(dst_addr) is not C(any) the C(dst_addr) is deemed to be host address.
- type: str
- src_addr:
- description:
- - Specifies the source IP address for the access control entry.
- - When set to C(any) the ACL will match any source address, C(src_mask) is ignored in this case.
- type: str
- src_mask:
- description:
- - Optional parameter that specifies the source network mask for the access control entry.
- - If not specified and C(src_addr) is not C(any) the C(src_addr) is deemed to be host address.
- type: str
- scheme:
- description:
- - This parameter applies to Layer 7 access control entries only.
- - "Specifies the URI scheme: C(http), C(https) or C(any) on which the access control entry operates."
- type: str
- choices:
- - http
- - https
- - any
- protocol:
- description:
- - This parameter applies to Layer 4 access control entries only.
- - "Specifies the protocol: C(tcp), C(udp), C(icmp) or C(all) protocols,
- to which the access control entry applies."
- type: str
- choices:
- - tcp
- - icmp
- - udp
- - all
- host_name:
- description:
- - This parameter applies to Layer 7 access control entries only.
- - Specifies a host to which the access control entry applies.
- type: str
- paths:
- description:
- - This parameter applies to Layer 7 access control entries only.
- - Specifies the path or paths to which the access control entry applies.
- type: str
- log:
- description:
- - Specifies the log level that is logged when actions of this type occur.
- - When C(none) it will log nothing, which is a default action.
- - When C(packet) it will log the matched packet.
- type: str
- choices:
- - none
- - packet
- partition:
- description:
- - Device partition to manage resources on.
- type: str
- default: Common
- state:
- description:
- - When C(state) is C(present), ensures that the ACL exists.
- - When C(state) is C(absent), ensures that the ACL is removed.
- type: str
- choices:
- - present
- - absent
- default: present
-extends_documentation_fragment: f5
-author:
- - Wojciech Wypior (@wojtek0806)
-'''
-
-EXAMPLES = r'''
-- name: Create a static ACL with L4 entries
- bigip_apm_acl:
- name: L4foo
- acl_order: 0
- type: static
- entries:
- - action: allow
- dst_port: '80'
- dst_addr: '192.168.1.1'
- src_port: '443'
- src_addr: '10.10.10.0'
- src_mask: '255.255.255.128'
- protocol: tcp
- - action: reject
- dst_port: '*'
- dst_addr: '192.168.1.1'
- src_port: '*'
- src_addr: '10.10.10.0'
- src_mask: '255.255.255.128'
- protocol: tcp
- log: packet
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-
-- name: Create a static ACL with L7 entries
- bigip_apm_acl:
- name: L7foo
- acl_order: 1
- type: static
- path_match_case: no
- entries:
- - action: allow
- host_name: 'foobar.com'
- paths: '/shopfront'
- scheme: https
- - action: reject
- host_name: 'internal_foobar.com'
- paths: '/admin'
- scheme: any
- log: packet
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-
-- name: Create a static ACL with L7/L4 entries
- bigip_apm_acl:
- name: L7L4foo
- acl_order: 2
- type: static
- path_match_case: no
- entries:
- - action: allow
- host_name: 'foobar.com'
- paths: '/shopfront'
- scheme: https
- dst_port: '8181'
- dst_addr: '192.168.1.1'
- protocol: tcp
- - action: reject
- dst_addr: '192.168.1.1'
- host_name: 'internal_foobar.com'
- paths: '/admin'
- scheme: any
- protocol: all
- log: packet
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-
-- name: Modify a static ACL entries
- bigip_apm_acl:
- name: L4foo
- entries:
- - action: allow
- dst_port: '80'
- dst_addr: '192.168.1.1'
- src_port: '443'
- src_addr: '10.10.10.0'
- src_mask: '255.255.255.128'
- protocol: tcp
- - action: discard
- dst_port: '*'
- dst_addr: 192.168.1.1
- src_port: '*'
- src_addr: '10.10.10.0'
- src_mask: '255.2155.255.128'
- protocol: all
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-
-- name: Remove static ACL
- bigip_apm_acl:
- name: L4foo
- state: absent
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-'''
-
-RETURN = r'''
-description:
- description: The new description of the ACL.
- returned: changed
- type: str
- sample: My ACL
-type:
- description: The type of ACL to create.
- returned: changed
- type: str
- sample: static
-acl_order:
- description: The order of this ACL relative to other ACLs.
- returned: changed
- type: int
- sample: 10
-path_match_case:
- description: Specifies whether alphabetic case is considered when matching paths in an access control entry.
- returned: changed
- type: bool
- sample: yes
-entries:
- description: Access control entries that define the ACL matching and its respective behavior.
- type: complex
- returned: changed
- contains:
- action:
- description: Action that the access control entry takes when a match for this access control entry is encountered.
- returned: changed
- type: str
- sample: allow
- dst_port:
- description: The destination port for the access control entry.
- returned: changed
- type: str
- sample: '80'
- dst_port_range:
- description: The destination port range for the access control entry.
- returned: changed
- type: str
- sample: '80-81'
- src_port:
- description: The source port for the access control entry.
- returned: changed
- type: str
- sample: '80'
- src_port_range:
- description: The source port range for the access control entry.
- returned: changed
- type: str
- sample: '80-81'
- dst_addr:
- description: The destination IP address for the access control entry.
- returned: changed
- type: str
- sample: 192.168.0.1
- dst_mask:
- description: The destination network mask for the access control entry.
- returned: changed
- type: str
- sample: 255.255.255.128
- src_addr:
- description: The source IP address for the access control entry.
- returned: changed
- type: str
- sample: 192.168.0.1
- src_mask:
- description: The source network mask for the access control entry.
- returned: changed
- type: str
- sample: 255.255.255.128
- scheme:
- description: The URI scheme on which the access control entry operates.
- returned: changed
- type: str
- sample: https
- protocol:
- description: The protocol to which the access control entry applies.
- returned: changed
- type: str
- sample: tcp
- host_name:
- description: The host to which the access control entry applies.
- returned: changed
- type: str
- sample: foobar.com
- paths:
- description: The path or paths to which the access control entry applies.
- returned: changed
- type: str
- sample: /fooshop
- log:
- description: The log level that is logged when actions of this type occur.
- returned: changed
- type: str
- sample: packet
- sample: hash/dictionary of values
-'''
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.basic import env_fallback
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import fq_name
- from library.module_utils.network.f5.common import transform_name
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.common import flatten_boolean
- from library.module_utils.network.f5.compare import cmp_str_with_none
- from library.module_utils.network.f5.ipaddress import is_valid_ip
- from library.module_utils.network.f5.ipaddress import is_valid_ip_network
- from library.module_utils.network.f5.ipaddress import is_valid_ip_interface
- from library.module_utils.compat.ipaddress import ip_network
- from library.module_utils.compat.ipaddress import ip_interface
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import fq_name
- from ansible.module_utils.network.f5.common import transform_name
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.common import flatten_boolean
- from ansible.module_utils.network.f5.compare import cmp_str_with_none
- from ansible.module_utils.network.f5.ipaddress import is_valid_ip
- from ansible.module_utils.network.f5.ipaddress import is_valid_ip_network
- from ansible.module_utils.network.f5.ipaddress import is_valid_ip_interface
- from ansible.module_utils.compat.ipaddress import ip_network
- from ansible.module_utils.compat.ipaddress import ip_interface
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'aclOrder': 'acl_order',
- 'pathMatchCase': 'path_match_case'
- }
-
- api_attributes = [
- 'entries',
- 'description',
- 'aclOrder',
- 'pathMatchCase',
- 'type',
- ]
-
- returnables = [
- 'entries',
- 'acl_order',
- 'path_match_case',
- 'type',
- 'description',
- ]
-
- updatables = [
- 'entries',
- 'acl_order',
- 'path_match_case',
- 'type',
- 'description',
- ]
-
-
-class ApiParameters(Parameters):
- pass
-
-
-class ModuleParameters(Parameters):
- protocol_map = {
- 'icmp': 1,
- 'tcp': 6,
- 'udp': 17,
- 'all': 0
- }
-
- @property
- def path_match_case(self):
- result = flatten_boolean(self._values['path_match_case'])
- if result == 'yes':
- return 'true'
- if result == 'no':
- return 'false'
-
- @property
- def acl_order(self):
- if self._values['acl_order'] is None:
- return None
- if 0 < self._values['acl_order'] > 65535:
- raise F5ModuleError(
- "Specified number is out of valid range, correct range is between 0 and 65535."
- )
- return self._values['acl_order']
-
- @property
- def description(self):
- if self._values['description'] is None:
- return None
- elif self._values['description'] in ['none', '']:
- return ''
- return self._values['description']
-
- @property
- def entries(self):
- if self._values['entries'] is None:
- return None
- if self._values['entries'] == 'none':
- return []
- result = []
- element = dict()
- for x in self._values['entries']:
- element['action'] = x['action']
- if 'dst_port' in x and x['dst_port'] is not None:
- if x['dst_port'] == '*':
- element['dstEndPort'] = 0
- element['dstStartPort'] = 0
- else:
- self._validate_port(int(x['dst_port']))
- element['dstEndPort'] = int(x['dst_port'])
- element['dstStartPort'] = int(x['dst_port'])
- if 'dst_port_range' in x and x['dst_port_range'] is not None:
- start, stop = self._validate_ports(x['dst_port_range'])
- element['dstEndPort'] = stop
- element['dstStartPort'] = start
- if 'src_port' in x and x['src_port'] is not None:
- if x['src_port'] == '*':
- element['srcEndPort'] = 0
- element['srcStartPort'] = 0
- else:
- self._validate_port(int(x['src_port']))
- element['srcEndPort'] = int(x['src_port'])
- element['srcStartPort'] = int(x['src_port'])
- if 'src_port_range' in x and x['src_port_range'] is not None:
- start, stop = self._validate_ports(x['src_port_range'])
- element['srcEndPort'] = stop
- element['srcStartPort'] = start
- if 'dst_addr' in x and x['dst_addr'] is not None:
- if 'dst_mask' in x and x['dst_mask'] is not None:
- element['dstSubnet'] = self._convert_address(x['dst_addr'], x['dst_mask'])
- else:
- element['dstSubnet'] = self._convert_address(x['dst_addr'])
- if 'src_addr' in x and x['src_addr'] is not None:
- if 'src_mask' in x and x['src_mask'] is not None:
- element['srcSubnet'] = self._convert_address(x['src_addr'], x['src_mask'])
- else:
- element['srcSubnet'] = self._convert_address(x['src_addr'])
- if 'scheme' in x and x['scheme'] is not None:
- element['scheme'] = x['scheme']
- if 'protocol' in x and x['protocol'] is not None:
- element['protocol'] = self.protocol_map[x['protocol']]
- if 'host_name' in x and x['host_name'] is not None:
- element['host'] = x['host_name']
- if 'paths' in x and x['paths'] is not None:
- element['paths'] = x['paths']
- if 'log' in x and x['log'] is not None:
- element['log'] = x['log']
- result.append(element)
- return result
-
- def _validate_port(self, item):
- if 0 < item > 65535:
- raise F5ModuleError(
- "Specified port number is out of valid range, correct range is between 0 and 65535."
- )
-
- def _validate_ports(self, item):
- start, stop = item.split('-')
- start = int(start.strip())
- stop = int(stop.strip())
- if 0 < start > 65535 or 0 < stop > 65535:
- raise F5ModuleError(
- "Specified port number is out of valid range, correct range is between 0 and 65535."
- )
- return start, stop
-
- def _convert_address(self, item, mask=None):
- if item == 'any':
- return '0.0.0.0/0'
- if not is_valid_ip(item):
- raise F5ModuleError('The provided IP address is not a valid IP address.')
- if mask:
- msk = self._convert_netmask(mask)
- network = '{0}/{1}'.format(item, msk)
- if is_valid_ip_network(u'{0}'.format(network)):
- return network
- else:
- raise F5ModuleError(
- 'The provided IP and Mask are not a valid IP network.'
- )
- host = ip_interface(u'{0}'.format(item))
- return host.with_prefixlen
-
- def _convert_netmask(self, item):
- result = -1
- try:
- result = int(item)
- if 0 < result < 256:
- pass
- except ValueError:
- if is_valid_ip(item):
- ip = ip_network(u'0.0.0.0/%s' % str(item))
- result = ip.prefixlen
- if result < 0:
- raise F5ModuleError(
- 'The provided netmask {0} is neither in IP or CIDR format'.format(result)
- )
- return result
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class UsableChanges(Changes):
- pass
-
-
-class ReportableChanges(Changes):
- protocol_map = {
- 1: 'icmp',
- 6: 'tcp',
- 17: 'udp',
- 0: 'all'
- }
-
- @property
- def path_match_case(self):
- result = flatten_boolean(self._values['path_match_case'])
- return result
-
- @property
- def entries(self):
- if self._values['entries'] is None:
- return None
- if not self._values['entries']:
- return 'none'
- result = []
- to_filter = dict()
- for x in self._values['entries']:
- to_filter['action'] = x['action']
- if 'dstStartPort' and 'dstEndPort' in x:
- if x['dstStartPort'] == x['dstEndPort']:
- if x['dstStartPort'] == 0:
- to_filter['dst_port'] = '*'
- else:
- to_filter['dst_port'] = str(x['dstStartPort'])
- else:
- to_filter['dst_port_range'] = '{0}-{1}'.format(x['dstStartPort'], x['dstEndPort'])
- if 'srcStartPort' and 'srcEndPort' in x:
- if x['srcStartPort'] == x['srcEndPort']:
- if x['srcStartPort'] == 0:
- to_filter['src_port'] = '*'
- else:
- to_filter['src_port'] = str(x['srcStartPort'])
- else:
- to_filter['src_port_range'] = '{0}-{1}'.format(x['srcStartPort'], x['srcEndPort'])
- if 'dstSubnet' in x:
- to_filter['dst_addr'], to_filter['dst_mask'] = self._convert_address(x['dstSubnet'])
- if 'srcSubnet' in x:
- to_filter['src_addr'], to_filter['src_mask'] = self._convert_address(x['srcSubnet'])
- if 'scheme' in x:
- to_filter['scheme'] = x['scheme']
- if 'protocol' in x:
- to_filter['protocol'] = self.protocol_map[x['protocol']]
- if 'host' in x:
- to_filter['host_name'] = x['host']
- if 'paths' in x:
- to_filter['paths'] = x['paths']
- if 'log' in x:
- to_filter['log'] = x['log']
- element = self._filter_params(to_filter)
- result.append(element)
- return result
-
- def _convert_address(self, item):
- if item == '0.0.0.0/0':
- return 'any', None
- result = ip_network(u'{0}'.format(item))
- if result.prefixlen == 32:
- return str(result.network_address), None
- else:
- return str(result.network_address), str(result.netmask)
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
- @property
- def description(self):
- return cmp_str_with_none(self.want.description, self.have.description)
-
- @property
- def entries(self):
- if self.want.entries is None:
- return None
- if self.have.entries is None and self.want.entries == []:
- return None
-
- want = self.want.entries
- have = list()
- # First we remove extra keys in have
- for idx, item in enumerate(want):
- entry = self._filter_have(item, self.have.entries[idx])
- have.append(entry)
- # Compare each element in the list by position
- for idx, item in enumerate(want):
- if item != have[idx]:
- return self.want.entries
-
- def _filter_have(self, want, have):
- to_check = set(want.keys()).intersection(set(have.keys()))
- result = dict()
- for k in list(to_check):
- result[k] = have[k]
- return result
-
- @property
- def type(self):
- if self.want.type is None:
- return None
- if self.want.type == self.have.type:
- return None
- raise F5ModuleError(
- "ACL type cannot be changed after ACL creation."
- )
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(params=self.module.params)
- self.have = ApiParameters()
- self.changes = UsableChanges()
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = UsableChanges(params=changed)
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.client.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def exec_module(self):
- changed = False
- result = dict()
- state = self.want.state
-
- if state == "present":
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def present(self):
- if self.exists():
- return self.update()
- else:
- return self.create()
-
- def absent(self):
- if self.exists():
- return self.remove()
- return False
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def update(self):
- self.have = self.read_current_from_device()
- if not self.should_update():
- return False
- if self.module.check_mode:
- return True
- self.update_on_device()
- return True
-
- def remove(self):
- if self.module.check_mode:
- return True
- self.remove_from_device()
- if self.exists():
- raise F5ModuleError("Failed to delete the resource.")
- return True
-
- def create(self):
- self._set_changed_options()
- if self.module.check_mode:
- return True
- self.create_on_device()
- return True
-
- def exists(self):
- uri = "https://{0}:{1}/mgmt/tm/apm/acl/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def create_on_device(self):
- params = self.changes.api_params()
- params['name'] = self.want.name
- params['partition'] = self.want.partition
- uri = "https://{0}:{1}/mgmt/tm/apm/acl/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 409]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return True
-
- def update_on_device(self):
- params = self.changes.api_params()
- uri = "https://{0}:{1}/mgmt/tm/apm/acl/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def remove_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/apm/acl/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- response = self.client.api.delete(uri)
- if response.status == 200:
- return True
- raise F5ModuleError(response.content)
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/apm/acl/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return ApiParameters(params=response)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- name=dict(required=True),
- acl_order=dict(type='int'),
- description=dict(),
- path_match_case=dict(type='bool'),
- type=dict(
- choices=['static', 'dynamic'],
- ),
- entries=dict(
- type='list',
- elements='dict',
- options=dict(
- action=dict(
- choices=['allow', 'reject', 'discard', 'continue'],
- required=True
- ),
- dst_port=dict(),
- dst_port_range=dict(),
- src_port=dict(),
- src_port_range=dict(),
- dst_addr=dict(),
- dst_mask=dict(),
- src_addr=dict(),
- src_mask=dict(),
- scheme=dict(
- choices=['any', 'https', 'http']
- ),
- protocol=dict(
- choices=['tcp', 'icmp', 'udp', 'all']
- ),
- host_name=dict(),
- paths=dict(),
- log=dict(
- choices=['packet', 'none']
- ),
- ),
- mutually_exclusive=[
- ['dst_port', 'dst_port_range'],
- ['src_port', 'src_port_range'],
- ],
- ),
- partition=dict(
- default='Common',
- fallback=(env_fallback, ['F5_PARTITION'])
- ),
- state=dict(
- default='present',
- choices=['present', 'absent']
- )
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode,
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_apm_network_access.py b/lib/ansible/modules/network/f5/bigip_apm_network_access.py
deleted file mode 100644
index b19b5a0102..0000000000
--- a/lib/ansible/modules/network/f5/bigip_apm_network_access.py
+++ /dev/null
@@ -1,1032 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2019, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_apm_network_access
-short_description: Manage APM Network Access resource
-description:
- - Manage APM Network Access resource.
-version_added: 2.9
-options:
- name:
- description:
- - Specifies the name of the APM network access to manage/create.
- type: str
- required: True
- description:
- description:
- - User created network access description.
- type: str
- ip_version:
- description:
- - Supported IP version on the network access resource.
- type: str
- choices:
- - ipv4
- - ipv4-ipv6
- allow_local_subnet:
- description:
- - Enables local subnet access and local access to any host or subnet in routes specified in the client routing
- table.
- - When C(yes) the system does not support integrated IP filtering.
- type: bool
- allow_local_dns:
- description:
- - Enables local access to DNS servers configured on client prior to establishing network access connection.
- type: bool
- split_tunnel:
- description:
- - Specifies that only the traffic targeted to a specified address space is sent over the network access tunnel.
- type: bool
- snat_pool:
- description:
- - Specifies the name of a SNAT pool used for implementing selective and intelligent SNATs.
- - When C(none) the system uses no SNAT pool for this network resource.
- - When C(automap) the system uses all of the self IP addresses as the translation addresses for the pool.
- type: str
- dtls:
- description:
- - When C(yes) the network access connection uses Datagram Transport Level Security instead of TCP,
- to provide better throughput for high demand applications like VoIP or streaming video.
- type: bool
- dtls_port:
- description:
- - Specifies the port number that the network access resource uses for secure UDP traffic with DTLS.
- type: int
- ipv4_lease_pool:
- description:
- - Specifies IPV4 lease pool resource to use with network access.
- - Referencing lease pool can be done in the full path format for example, C(/Common/pool_name).
- - When lease pool is referenced in full path format, the C(partition) parameter is ignored.
- type: str
- ipv6_lease_pool:
- description:
- - Specifies IPV6 lease pool resource to use with network access.
- - Referencing lease pool can be done in the full path format for example, C(/Common/pool_name).
- - When lease pool is referenced in full path format, the C(partition) parameter is ignored.
- type: str
- excluded_ipv6_adresses:
- description:
- - Specifies IPV6 address spaces for which traffic is not forced through the tunnel.
- type: list
- suboptions:
- subnet:
- description:
- - "The address of subnet in CIDR format, e.g. C(2001:db8:abcd:8000::/52)"
- - Host addresses can be specified without the CIDR mask notation.
- type: str
- excluded_ipv4_adresses:
- description:
- - Specifies IPV4 address spaces for which traffic is not forced through the tunnel.
- type: list
- suboptions:
- subnet:
- description:
- - "The address of subnet in CIDR format, e.g. C(192.168.1.0/24)"
- - Host addresses can be specified without the CIDR mask notation.
- type: str
- excluded_dns_addresses:
- description:
- - Specifies the DNS address spaces for which traffic is not forced through the tunnel.
- type: list
- dns_address_space:
- description:
- - Specifies a list of domain names describing the target LAN DNS addresses.
- type: list
- ipv4_address_space:
- description:
- - Specifies a list of IPv4 hosts or networks describing the target LAN.
- - This option is mandatory when creating a new resource and C(split_tunnel) is set to C(yes).
- type: list
- suboptions:
- subnet:
- description:
- - "The address of subnet in CIDR format, e.g. C(192.168.1.0/24)"
- - Host addresses can be specified without the CIDR mask notation.
- type: str
- ipv6_address_space:
- description:
- - Specifies a list of IPv6 hosts or networks describing the target LAN.
- - This option is mandatory when creating a new resource and C(split_tunnel) is set to C(yes).
- type: list
- suboptions:
- subnet:
- description:
- - "The address of subnet in CIDR format, e.g. C(2001:db8:abcd:8000::/52)"
- - Host addresses can be specified without the CIDR mask notation.
- type: str
- partition:
- description:
- - Device partition to manage resources on.
- type: str
- default: Common
- state:
- description:
- - When C(state) is C(present), ensures that the ACL exists.
- - When C(state) is C(absent), ensures that the ACL is removed.
- type: str
- choices:
- - present
- - absent
- default: present
-extends_documentation_fragment: f5
-author:
- - Wojciech Wypior (@wojtek0806)
-'''
-
-EXAMPLES = r'''
-- name: Create a split tunnel IPV4 Network Access
- bigip_apm_network_access:
- name: foobar
- ip_version: ipv4
- split_tunnel: yes
- snat_pool: "none"
- ipv4_lease_pool: leasefoo
- ipv4_address_space:
- - subnet: 10.10.1.1
- - subnet: 10.10.2.0/24
- excluded_ipv4_adresses:
- - subnet: 192.168.1.0/24
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-
-- name: Modify a split tunnel IPV4 Network Access
- bigip_apm_network_access:
- name: foobar
- snat_pool: /Common/poolsnat
- ipv4_address_space:
- - subnet: 172.16.23.0/24
- excluded_ipv4_adresses:
- - subnet: 10.10.2.0/24
- allow_local_subnet: yes
- allow_local_dns: yes
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-
-- name: Remove Network Access
- bigip_apm_network_access:
- name: foobar
- state: absent
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-'''
-
-RETURN = r'''
-description:
- description: The new description of Network Access.
- returned: changed
- type: str
- sample: My Access
-ip_version:
- description: Supported IP version on the network access resource.
- returned: changed
- type: str
- sample: ipv4-ipv6
-allow_local_subnet:
- description: Enables local subnet access.
- returned: changed
- type: bool
- sample: yes
-allow_local_dns:
- description: Enables local access to DNS servers configured on client.
- returned: changed
- type: bool
- sample: yes
-split_tunnel:
- description: Enables split tunnel on network access resource.
- returned: changed
- type: bool
- sample: yes
-snat_pool:
- description: The name of a SNAT pool used by network access resource.
- returned: changed
- type: str
- sample: /Common/my-pool
-dtls:
- description: Enables use of DTLS by network access.
- returned: changed
- type: bool
- sample: no
-dtls_port:
- description: Specifies the port number that the network access resource uses for DTLS.
- returned: changed
- type: int
- sample: 4433
-ipv4_lease_pool:
- description: Specifies IPV4 lease pool resource to use with network access.
- returned: changed
- type: str
- sample: /Common/leasepoolv4
-ipv6_lease_pool:
- description: Specifies IPV6 lease pool resource to use with network access.
- returned: changed
- type: str
- sample: /Common/leasepoolv6
-excluded_ipv6_adresses:
- description: Specifies IPV6 address spaces for which traffic is not forced through the tunnel.
- type: complex
- returned: changed
- contains:
- subnet:
- description: The host or network address.
- returned: changed
- type: str
- sample: "2001:DB8:ABCD:0012::0"
- sample: hash/dictionary of values
-excluded_ipv4_adresses:
- description: Specifies IPV4 address spaces for which traffic is not forced through the tunnel.
- type: complex
- returned: changed
- contains:
- subnet:
- description: The host or network address.
- returned: changed
- type: str
- sample: 192.168.10.1
- sample: hash/dictionary of values
-excluded_dns_addresses:
- description: Specifies the DNS address spaces for which traffic is not forced through the tunnel.
- returned: changed
- type: list
- sample: ['foobar.com', 'bazbar.org']
-dns_address_space:
- description: Specifies a list of domain names describing the target LAN DNS addresses.
- returned: changed
- type: list
- sample: ['internal.net', '*.engnet.org']
-ipv6_address_space:
- description: Specifies a list of IPv6 hosts or networks describing the target LAN.
- type: complex
- returned: changed
- contains:
- subnet:
- description: The host or network address.
- returned: changed
- type: str
- sample: "2001:DB8:ABCD:0012::0"
- sample: hash/dictionary of values
-ipv4_address_space:
- description: Specifies a list of IPv4 hosts or networks describing the target LAN.
- type: complex
- returned: changed
- contains:
- subnet:
- description: The host or network address.
- returned: changed
- type: str
- sample: 192.168.10.1
- sample: hash/dictionary of values
-'''
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.basic import env_fallback
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import fq_name
- from library.module_utils.network.f5.common import transform_name
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.common import flatten_boolean
- from library.module_utils.network.f5.common import is_empty_list
- from library.module_utils.network.f5.compare import cmp_str_with_none
- from library.module_utils.network.f5.compare import cmp_simple_list
- from library.module_utils.network.f5.compare import compare_complex_list
- from library.module_utils.network.f5.ipaddress import ip_network
- from library.module_utils.network.f5.ipaddress import is_valid_ip
- from library.module_utils.network.f5.ipaddress import is_valid_ip_network
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import fq_name
- from ansible.module_utils.network.f5.common import transform_name
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.common import flatten_boolean
- from ansible.module_utils.network.f5.common import is_empty_list
- from ansible.module_utils.network.f5.compare import cmp_str_with_none
- from ansible.module_utils.network.f5.compare import cmp_simple_list
- from ansible.module_utils.network.f5.compare import compare_complex_list
- from ansible.module_utils.network.f5.ipaddress import ip_network
- from ansible.module_utils.network.f5.ipaddress import is_valid_ip
- from ansible.module_utils.network.f5.ipaddress import is_valid_ip_network
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'supportedIpVersion': 'ip_version',
- 'splitTunneling': 'split_tunnel',
- 'addressSpaceLocalSubnetsExcluded': 'allow_local_subnet',
- 'addressSpaceLocDnsServersExcluded': 'allow_local_dns',
- 'dtlsPort': 'dtls_port',
- 'leasepoolName': 'ipv4_lease_pool',
- 'ipv6LeasepoolName': 'ipv6_lease_pool',
- 'ipv6AddressSpaceExcludeSubnet': 'excluded_ipv6_adresses',
- 'addressSpaceExcludeSubnet': 'excluded_ipv4_adresses',
- 'addressSpaceExcludeDnsName': 'excluded_dns_addresses',
- 'addressSpaceIncludeDnsName': 'dns_address_space',
- 'addressSpaceIncludeSubnet': 'ipv4_address_space',
- 'ipv6AddressSpaceIncludeSubnet': 'ipv6_address_space',
- 'snatpool': 'snat_pool',
- }
-
- api_attributes = [
- 'supportedIpVersion',
- 'splitTunneling',
- 'addressSpaceLocalSubnetsExcluded',
- 'addressSpaceLocDnsServersExcluded',
- 'dtlsPort',
- 'leasepoolName',
- 'ipv6LeasepoolName',
- 'ipv6AddressSpaceExcludeSubnet',
- 'addressSpaceExcludeSubnet',
- 'addressSpaceExcludeDnsName',
- 'addressSpaceIncludeSubnet',
- 'ipv6AddressSpaceIncludeSubnet',
- 'addressSpaceIncludeDnsName',
- 'snat',
- 'snatpool',
- 'dtls',
- 'description',
- ]
-
- returnables = [
- 'description',
- 'ip_version',
- 'split_tunnel',
- 'allow_local_subnet',
- 'allow_local_dns',
- 'snat_pool',
- 'dtls',
- 'dtls_port',
- 'ipv4_lease_pool',
- 'ipv6_lease_pool',
- 'excluded_ipv6_adresses',
- 'excluded_ipv4_adresses',
- 'excluded_dns_addresses',
- 'dns_address_space',
- 'ipv4_address_space',
- 'ipv6_address_space',
- ]
-
- updatables = [
- 'description',
- 'ip_version',
- 'split_tunnel',
- 'allow_local_subnet',
- 'allow_local_dns',
- 'snat_pool',
- 'dtls',
- 'dtls_port',
- 'ipv4_lease_pool',
- 'ipv6_lease_pool',
- 'excluded_ipv6_adresses',
- 'excluded_ipv4_adresses',
- 'excluded_dns_addresses',
- 'dns_address_space',
- 'ipv4_address_space',
- 'ipv6_address_space',
- ]
-
-
-class ApiParameters(Parameters):
- @property
- def snat_pool(self):
- if self._values['snat'] is None and self._values['snat_pool'] is None:
- return None
- if self._values['snat'] in ['automap', 'none']:
- return self._values['snat']
- return self._values['snat_pool']
-
-
-class ModuleParameters(Parameters):
- def _handle_booleans(self, item):
- result = flatten_boolean(item)
- if result == 'yes':
- return 'true'
- if result == 'no':
- return 'false'
- return None
-
- def _convert_address(self, item):
- ip = ip_network(u'{0}'.format(item))
- return ip.with_prefixlen
-
- def _format_subnets(self, items):
- result = []
- for x in items:
- to_change = dict()
- to_change['subnet'] = self._convert_address(x['subnet'])
- result.append(to_change)
- return result
-
- @property
- def description(self):
- if self._values['description'] is None:
- return None
- if self._values['description'] in ['none', '']:
- return ''
- return self._values['description']
-
- @property
- def split_tunnel(self):
- return self._handle_booleans(self._values['split_tunnel'])
-
- @property
- def allow_local_subnet(self):
- return self._handle_booleans(self._values['allow_local_subnet'])
-
- @property
- def allow_local_dns(self):
- return self._handle_booleans(self._values['allow_local_dns'])
-
- @property
- def dtls(self):
- return self._handle_booleans(self._values['dtls'])
-
- @property
- def dtls_port(self):
- if self._values['dtls_port'] is None:
- return None
- if 0 < self._values['dtls_port'] > 65535:
- raise F5ModuleError(
- "Specified port number is out of valid range, correct range is between 0 and 65535."
- )
- return self._values['dtls_port']
-
- @property
- def ipv4_lease_pool(self):
- if self._values['ipv4_lease_pool'] is None:
- return None
- if self._values['ipv4_lease_pool'] in ['none', '']:
- return ''
- return fq_name(self.partition, self._values['ipv4_lease_pool'])
-
- @property
- def ipv6_lease_pool(self):
- if self._values['ipv6_lease_pool'] is None:
- return None
- if self._values['ipv6_lease_pool'] in ['none', '']:
- return ''
- return fq_name(self.partition, self._values['ipv6_lease_pool'])
-
- @property
- def excluded_ipv6_adresses(self):
- if self._values['excluded_ipv6_adresses'] is None:
- return None
- if is_empty_list(self._values['excluded_ipv6_adresses']):
- return []
- result = self._format_subnets(self._values['excluded_ipv6_adresses'])
- return result
-
- @property
- def excluded_ipv4_adresses(self):
- if self._values['excluded_ipv4_adresses'] is None:
- return None
- if is_empty_list(self._values['excluded_ipv4_adresses']):
- return []
- result = self._format_subnets(self._values['excluded_ipv4_adresses'])
- return result
-
- @property
- def ipv4_address_space(self):
- if self._values['ipv4_address_space'] is None:
- return None
- if is_empty_list(self._values['ipv4_address_space']):
- return []
- result = self._format_subnets(self._values['ipv4_address_space'])
- return result
-
- @property
- def ipv6_address_space(self):
- if self._values['ipv6_address_space'] is None:
- return None
- if is_empty_list(self._values['ipv6_address_space']):
- return []
- result = self._format_subnets(self._values['ipv6_address_space'])
- return result
-
- @property
- def dns_address_space(self):
- if self._values['dns_address_space'] is None:
- return None
- if is_empty_list(self._values['dns_address_space']):
- return []
- return self._values['dns_address_space']
-
- @property
- def excluded_dns_addresses(self):
- if self._values['excluded_dns_addresses'] is None:
- return None
- if is_empty_list(self._values['excluded_dns_addresses']):
- return []
- return self._values['excluded_dns_addresses']
-
- @property
- def snat_pool(self):
- if self._values['snat_pool'] is None:
- return None
- if self._values['snat_pool'] in ['automap', 'none']:
- return self._values['snat_pool']
- result = fq_name(self.partition, self._values['snat_pool'])
- return result
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class UsableChanges(Changes):
- @property
- def snat(self):
- if self._values['snat_pool'] is None:
- return None
- if self._values['snat_pool'] in ['automap', 'none']:
- return self._values['snat_pool']
-
- @property
- def snat_pool(self):
- if self._values['snat_pool'] in [None, 'automap', 'none']:
- return None
- return self._values['snat_pool']
-
-
-class ReportableChanges(Changes):
- def _parse_hosts(self, item):
- ip = ip_network(u'{0}'.format(item))
- if ip.prefixlen in [32, 128]:
- result = item.split('/')[0]
- return result
- return item
-
- def _format_subnets(self, items):
- result = []
- for x in items:
- to_change = dict()
- to_change['subnet'] = self._parse_hosts(x['subnet'])
- result.append(to_change)
- return result
-
- @property
- def split_tunnel(self):
- return flatten_boolean(self._values['split_tunnel'])
-
- @property
- def allow_local_subnet(self):
- return flatten_boolean(self._values['allow_local_subnet'])
-
- @property
- def allow_local_dns(self):
- return flatten_boolean(self._values['allow_local_dns'])
-
- @property
- def dtls(self):
- return flatten_boolean(self._values['dtls'])
-
- @property
- def excluded_ipv4_adresses(self):
- if self._values['excluded_ipv4_adresses'] is None:
- return None
- if not self._values['excluded_ipv4_adresses']:
- return []
- result = self._format_subnets(self._values['excluded_ipv4_adresses'])
- return result
-
- @property
- def excluded_ipv6_adresses(self):
- if self._values['excluded_ipv6_adresses'] is None:
- return None
- if not self._values['excluded_ipv6_adresses']:
- return []
- result = self._format_subnets(self._values['excluded_ipv6_adresses'])
- return result
-
- @property
- def ipv4_address_space(self):
- if self._values['ipv4_address_space'] is None:
- return None
- if not self._values['ipv4_address_space']:
- return []
- result = self._format_subnets(self._values['ipv4_address_space'])
- return result
-
- @property
- def ipv6_address_space(self):
- if self._values['ipv6_address_space'] is None:
- return None
- if not self._values['ipv6_address_space']:
- return []
- result = self._format_subnets(self._values['ipv6_address_space'])
- return result
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
- @property
- def description(self):
- result = cmp_str_with_none(self.want.description, self.have.description)
- return result
-
- @property
- def ipv4_lease_pool(self):
- result = cmp_str_with_none(self.want.ipv4_lease_pool, self.have.ipv4_lease_pool)
- return result
-
- @property
- def ipv6_lease_pool(self):
- result = cmp_str_with_none(self.want.ipv6_lease_pool, self.have.ipv6_lease_pool)
- return result
-
- @property
- def excluded_dns_addresses(self):
- result = cmp_simple_list(self.want.excluded_dns_addresses, self.have.excluded_dns_addresses)
- return result
-
- @property
- def dns_address_space(self):
- result = cmp_simple_list(self.want.dns_address_space, self.have.dns_address_space)
- return result
-
- @property
- def excluded_ipv4_adresses(self):
- result = compare_complex_list(self.want.excluded_ipv4_adresses, self.have.excluded_ipv4_adresses)
- return result
-
- @property
- def excluded_ipv6_adresses(self):
- result = compare_complex_list(self.want.excluded_ipv6_adresses, self.have.excluded_ipv6_adresses)
- return result
-
- @property
- def ipv4_address_space(self):
- result = compare_complex_list(self.want.ipv4_address_space, self.have.ipv4_address_space)
- return result
-
- @property
- def ipv6_address_space(self):
- result = compare_complex_list(self.want.ipv6_address_space, self.have.ipv6_address_space)
- return result
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(params=self.module.params)
- self.have = ApiParameters()
- self.changes = UsableChanges()
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = UsableChanges(params=changed)
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.client.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def exec_module(self):
- changed = False
- result = dict()
- state = self.want.state
-
- if state == "present":
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def present(self):
- if self.exists():
- return self.update()
- else:
- return self.create()
-
- def absent(self):
- if self.exists():
- return self.remove()
- return False
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def update(self):
- self.have = self.read_current_from_device()
- self.check_required_params()
- if not self.should_update():
- return False
- if self.module.check_mode:
- return True
- self.update_on_device()
- return True
-
- def remove(self):
- if self.module.check_mode:
- return True
- self.remove_from_device()
- if self.exists():
- raise F5ModuleError("Failed to delete the resource.")
- return True
-
- def create(self):
- self._set_changed_options()
- self.check_required_params()
- if self.module.check_mode:
- return True
- self.create_on_device()
- return True
-
- def check_required_params(self):
- if self.want.split_tunnel == 'true':
- if self.want.ip_version == 'ipv4':
- if self.want.ipv4_address_space in [None, []]:
- raise F5ModuleError(
- 'The ipv4_address_space cannot be empty, when split_tunnel is set to {0}'.format(
- self.want.split_tunnel
- )
- )
- if self.want.ip_version == 'ipv4-ipv6':
- if self.want.ipv4_address_space in [None, []]:
- raise F5ModuleError(
- 'The ipv4_address_space cannot be empty, when split_tunnel is set to {0}'.format(
- self.want.split_tunnel
- )
- )
- if self.want.ipv6_address_space in [None, []]:
- raise F5ModuleError(
- 'The ipv6_address_space cannot be empty, when split_tunnel is set to {0}'.format(
- self.want.split_tunnel
- )
- )
- if self.have.split_tunnel == 'true':
- if self.have.ip_version == 'ipv4':
- if self.want.ipv4_address_space is not None and not self.want.ipv4_address_space:
- raise F5ModuleError(
- 'Cannot remove ipv4_address_space when split_tunnel on device is: {0}'.format(
- self.have.split_tunnel
- )
- )
- if self.have.ip_version == 'ipv4-ipv6':
- if self.want.ipv4_address_space is not None and not self.want.ipv4_address_space:
- raise F5ModuleError(
- 'Cannot remove ipv4_address_space when split_tunnel on device is: {0}'.format(
- self.have.split_tunnel
- )
- )
- if self.want.ipv6_address_space is not None and not self.want.ipv6_address_space:
- raise F5ModuleError(
- 'Cannot remove ipv6_address_space when split_tunnel on device is: {0}'.format(
- self.have.split_tunnel
- )
- )
-
- def exists(self):
- uri = "https://{0}:{1}/mgmt/tm/apm/resource/network-access/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def create_on_device(self):
- params = self.changes.api_params()
- params['name'] = self.want.name
- params['partition'] = self.want.partition
- uri = "https://{0}:{1}/mgmt/tm/apm/resource/network-access/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 409]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return True
-
- def update_on_device(self):
- params = self.changes.api_params()
- uri = "https://{0}:{1}/mgmt/tm/apm/resource/network-access/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def remove_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/apm/resource/network-access/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- response = self.client.api.delete(uri)
- if response.status == 200:
- return True
- raise F5ModuleError(response.content)
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/apm/resource/network-access/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return ApiParameters(params=response)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- name=dict(required=True),
- ip_version=dict(
- choices=['ipv4', 'ipv4-ipv6']
- ),
- split_tunnel=dict(
- type='bool',
- ),
- allow_local_subnet=dict(type='bool'),
- allow_local_dns=dict(type='bool'),
- snat_pool=dict(),
- description=dict(),
- dtls=dict(type='bool'),
- dtls_port=dict(type='int'),
- ipv4_lease_pool=dict(),
- ipv6_lease_pool=dict(),
- excluded_ipv6_adresses=dict(
- type='list',
- options=dict(
- subnet=dict(),
- )
- ),
- excluded_ipv4_adresses=dict(
- type='list',
- options=dict(
- subnet=dict(),
- )
- ),
- excluded_dns_addresses=dict(
- type='list'
- ),
- dns_address_space=dict(
- type='list'
- ),
- ipv4_address_space=dict(
- type='list',
- options=dict(
- subnet=dict(),
- )
- ),
- ipv6_address_space=dict(
- type='list',
- options=dict(
- subnet=dict(),
- )
- ),
- partition=dict(
- default='Common',
- fallback=(env_fallback, ['F5_PARTITION'])
- ),
- state=dict(
- default='present',
- choices=['present', 'absent']
- )
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode,
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_apm_policy_fetch.py b/lib/ansible/modules/network/f5/bigip_apm_policy_fetch.py
deleted file mode 100644
index dc94bc275c..0000000000
--- a/lib/ansible/modules/network/f5/bigip_apm_policy_fetch.py
+++ /dev/null
@@ -1,499 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2018, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_apm_policy_fetch
-short_description: Exports the APM policy or APM access profile from remote nodes.
-description:
- - Exports the apm policy or APM access profile from remote nodes.
-version_added: 2.8
-options:
- name:
- description:
- - The name of the APM policy or APM access profile exported to create a file on the remote device for downloading.
- type: str
- required: True
- dest:
- description:
- - A directory to save the file into.
- type: path
- file:
- description:
- - The name of the file to be created on the remote device for downloading.
- type: str
- type:
- description:
- - Specifies the type of item to export from device.
- type: str
- choices:
- - profile_access
- - access_policy
- default: profile_access
- force:
- description:
- - If C(no), the file will only be transferred if it does not exist in the destination.
- type: bool
- default: yes
- partition:
- description:
- - Device partition to which contain APM policy or APM access profile to export.
- type: str
- default: Common
-notes:
- - Due to ID685681 it is not possible to execute ng_* tools via REST api on v12.x and 13.x, once this is fixed
- this restriction will be removed.
- - Requires BIG-IP >= 14.0.0
-extends_documentation_fragment: f5
-author:
- - Wojciech Wypior (@wojtek0806)
-'''
-
-EXAMPLES = r'''
-- name: Export APM access profile
- bigip_apm_policy_fetch:
- name: foobar
- file: export_foo
- dest: /root/download
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-
-- name: Export APM access policy
- bigip_apm_policy_fetch:
- name: foobar
- file: export_foo
- dest: /root/download
- type: access_policy
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-
-- name: Export APM access profile, autogenerate name
- bigip_apm_policy_fetch:
- name: foobar
- dest: /root/download
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-'''
-
-RETURN = r'''
-name:
- description: Name of the APM policy or APM access profile to be exported.
- returned: changed
- type: str
- sample: APM_policy_global
-file:
- description:
- - Name of the exported file on the remote BIG-IP to download. If not
- specified, then this will be a randomly generated filename.
- returned: changed
- type: str
- sample: foobar_file
-dest:
- description: Local path to download exported APM policy.
- returned: changed
- type: str
- sample: /root/downloads/profile-foobar_file.conf.tar.gz
-type:
- description: Set to specify type of item to export.
- returned: changed
- type: str
- sample: access_policy
-'''
-
-import os
-import tempfile
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.basic import env_fallback
-from distutils.version import LooseVersion
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.common import transform_name
- from library.module_utils.network.f5.icontrol import download_file
- from library.module_utils.network.f5.icontrol import tmos_version
- from library.module_utils.network.f5.icontrol import module_provisioned
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.common import transform_name
- from ansible.module_utils.network.f5.icontrol import download_file
- from ansible.module_utils.network.f5.icontrol import tmos_version
- from ansible.module_utils.network.f5.icontrol import module_provisioned
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {}
-
- api_attributes = []
-
- returnables = [
- 'name',
- 'file',
- 'dest',
- 'type',
- 'force',
- ]
-
- updatables = []
-
-
-class ApiParameters(Parameters):
- pass
-
-
-class ModuleParameters(Parameters):
- def _item_exists(self):
- if self.type == 'access_policy':
- uri = 'https://{0}:{1}/mgmt/tm/apm/policy/access-policy/{2}'.format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.partition, self.name)
- )
- else:
- uri = 'https://{0}:{1}/mgmt/tm/apm/profile/access/{2}'.format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.partition, self.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if 'items' in response and response['items'] != []:
- return True
- return False
-
- @property
- def file(self):
- if self._values['file'] is not None:
- return self._values['file']
- result = next(tempfile._get_candidate_names()) + '.tar.gz'
- self._values['file'] = result
- return result
-
- @property
- def fulldest(self):
- result = None
- if os.path.isdir(self.dest):
- result = os.path.join(self.dest, self.file)
- else:
- if os.path.exists(os.path.dirname(self.dest)):
- result = self.dest
- else:
- try:
- # os.path.exists() can return false in some
- # circumstances where the directory does not have
- # the execute bit for the current user set, in
- # which case the stat() call will raise an OSError
- os.stat(os.path.dirname(result))
- except OSError as e:
- if "permission denied" in str(e).lower():
- raise F5ModuleError(
- "Destination directory {0} is not accessible".format(os.path.dirname(result))
- )
- raise F5ModuleError(
- "Destination directory {0} does not exist".format(os.path.dirname(result))
- )
-
- if not os.access(os.path.dirname(result), os.W_OK):
- raise F5ModuleError(
- "Destination {0} not writable".format(os.path.dirname(result))
- )
- return result
-
- @property
- def name(self):
- if not self._item_exists():
- raise F5ModuleError('The provided {0} with the name {1} does not exist on device.'.format(
- self.type, self._values['name'])
- )
- return self._values['name']
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class UsableChanges(Changes):
- pass
-
-
-class ReportableChanges(Changes):
- pass
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(params=self.module.params)
- self.changes = UsableChanges()
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = UsableChanges(params=changed)
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.client.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def exec_module(self):
- if not module_provisioned(self.client, 'apm'):
- raise F5ModuleError(
- "APM must be provisioned to use this module."
- )
-
- if self.version_less_than_14():
- raise F5ModuleError('Due to bug ID685681 it is not possible to use this module on TMOS version below 14.x')
-
- result = dict()
-
- self.export()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=True))
- return result
-
- def version_less_than_14(self):
- version = tmos_version(self.client)
- if LooseVersion(version) < LooseVersion('14.0.0'):
- return True
- return False
-
- def export(self):
- if self.exists():
- return self.update()
- else:
- return self.create()
-
- def update(self):
- if not self.want.force:
- raise F5ModuleError(
- "File '{0}' already exists.".format(self.want.fulldest)
- )
- self.execute()
-
- def create(self):
- self._set_changed_options()
- if self.module.check_mode:
- return True
- self.create_on_device()
- self.execute()
- return True
-
- def download(self):
- self.download_from_device(self.want.fulldest)
- if os.path.exists(self.want.fulldest):
- return True
- raise F5ModuleError(
- "Failed to download the remote file."
- )
-
- def execute(self):
- self.download()
- self.remove_temp_file_from_device()
- return True
-
- def exists(self):
- if os.path.exists(self.want.fulldest):
- return True
- return False
-
- def create_on_device(self):
- cmd = 'ng_export -t {0} {1} {2} -p {3}'.format(
- self.want.type, self.want.name, self.want.name, self.want.partition
- )
- uri = "https://{0}:{1}/mgmt/tm/util/bash/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- args = dict(
- command='run',
- utilCmdArgs='-c "{0}"'.format(cmd)
- )
- resp = self.client.api.post(uri, json=args)
-
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- if 'commandResult' in response:
- raise F5ModuleError('Item export command failed.')
- return True
-
- def _move_file_to_download(self):
- if self.want.type == 'access_policy':
- item = 'policy'
- else:
- item = 'profile'
-
- name = '{0}-{1}.conf.tar.gz'.format(item, self.want.name)
- move_path = '/shared/tmp/{0} {1}/{2}'.format(
- name,
- '/ts/var/rest',
- self.want.file
- )
- params = dict(
- command='run',
- utilCmdArgs=move_path
- )
-
- uri = "https://{0}:{1}/mgmt/tm/util/unix-mv/".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
-
- resp = self.client.api.post(uri, json=params)
-
- try:
- response = resp.json()
- if 'commandResult' in response:
- if 'cannot stat' in response['commandResult']:
- raise F5ModuleError(response['commandResult'])
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- return True
-
- def download_from_device(self, dest):
- url = 'https://{0}:{1}/mgmt/tm/asm/file-transfer/downloads/{2}'.format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- self.want.file
- )
- try:
- download_file(self.client, url, dest)
- except F5ModuleError:
- raise F5ModuleError(
- "Failed to download the file."
- )
- if os.path.exists(self.want.dest):
- return True
- return False
-
- def remove_temp_file_from_device(self):
- tpath_name = '/ts/var/rest/{0}'.format(self.want.file)
- uri = "https://{0}:{1}/mgmt/tm/util/unix-rm/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- args = dict(
- command='run',
- utilCmdArgs=tpath_name
- )
- resp = self.client.api.post(uri, json=args)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- name=dict(
- required=True,
- ),
- dest=dict(
- type='path'
- ),
- type=dict(
- default='profile_access',
- choices=['profile_access', 'access_policy']
- ),
- file=dict(),
- force=dict(
- default='yes',
- type='bool'
- ),
- partition=dict(
- default='Common',
- fallback=(env_fallback, ['F5_PARTITION'])
- )
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode,
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_apm_policy_import.py b/lib/ansible/modules/network/f5/bigip_apm_policy_import.py
deleted file mode 100644
index 94ee3d3f6a..0000000000
--- a/lib/ansible/modules/network/f5/bigip_apm_policy_import.py
+++ /dev/null
@@ -1,406 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2018, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_apm_policy_import
-short_description: Manage BIG-IP APM policy or APM access profile imports
-description:
- - Manage BIG-IP APM policy or APM access profile imports.
-version_added: 2.8
-options:
- name:
- description:
- - The name of the APM policy or APM access profile to create or override.
- type: str
- required: True
- type:
- description:
- - Specifies the type of item to export from device.
- type: str
- choices:
- - profile_access
- - access_policy
- default: profile_access
- source:
- description:
- - Full path to a file to be imported into the BIG-IP APM.
- type: path
- force:
- description:
- - When set to C(yes) any existing policy with the same name will be overwritten by the new import.
- - If policy does not exist this setting is ignored.
- default: no
- type: bool
- partition:
- description:
- - Device partition to manage resources on.
- type: str
- default: Common
-notes:
- - Due to ID685681 it is not possible to execute ng_* tools via REST api on v12.x and 13.x, once this is fixed
- this restriction will be removed.
- - Requires BIG-IP >= 14.0.0
-extends_documentation_fragment: f5
-author:
- - Wojciech Wypior (@wojtek0806)
-'''
-
-EXAMPLES = r'''
-- name: Import APM profile
- bigip_apm_policy_import:
- name: new_apm_profile
- source: /root/apm_profile.tar.gz
- provider:
- server: lb.mydomain.com
- user: admin
- password: secret
- delegate_to: localhost
-
-- name: Import APM policy
- bigip_apm_policy_import:
- name: new_apm_policy
- source: /root/apm_policy.tar.gz
- type: access_policy
- provider:
- server: lb.mydomain.com
- user: admin
- password: secret
- delegate_to: localhost
-
-- name: Override existing APM policy
- bigip_asm_policy:
- name: new_apm_policy
- source: /root/apm_policy.tar.gz
- force: yes
- provider:
- server: lb.mydomain.com
- user: admin
- password: secret
- delegate_to: localhost
-'''
-
-RETURN = r'''
-source:
- description: Local path to APM policy file.
- returned: changed
- type: str
- sample: /root/some_policy.tar.gz
-name:
- description: Name of the APM policy or APM access profile to be created/overwritten.
- returned: changed
- type: str
- sample: APM_policy_global
-type:
- description: Set to specify type of item to export.
- returned: changed
- type: str
- sample: access_policy
-force:
- description: Set when overwriting an existing policy or profile.
- returned: changed
- type: bool
- sample: yes
-'''
-
-import os
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.basic import env_fallback
-from distutils.version import LooseVersion
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import fq_name
- from library.module_utils.network.f5.common import transform_name
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.icontrol import upload_file
- from library.module_utils.network.f5.icontrol import tmos_version
- from library.module_utils.network.f5.icontrol import module_provisioned
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import fq_name
- from ansible.module_utils.network.f5.common import transform_name
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.icontrol import upload_file
- from ansible.module_utils.network.f5.icontrol import tmos_version
- from ansible.module_utils.network.f5.icontrol import module_provisioned
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
-
- }
-
- api_attributes = [
-
- ]
-
- returnables = [
- 'name',
- 'source',
- 'type',
-
- ]
-
- updatables = [
-
- ]
-
-
-class ApiParameters(Parameters):
- pass
-
-
-class ModuleParameters(Parameters):
- pass
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class UsableChanges(Changes):
- pass
-
-
-class ReportableChanges(Changes):
- pass
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(params=self.module.params)
- self.changes = UsableChanges()
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = UsableChanges(params=changed)
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.client.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def exec_module(self):
- if not module_provisioned(self.client, 'apm'):
- raise F5ModuleError(
- "APM must be provisioned to use this module."
- )
-
- if self.version_less_than_14():
- raise F5ModuleError('Due to bug ID685681 it is not possible to use this module on TMOS version below 14.x')
-
- result = dict()
-
- changed = self.policy_import()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def version_less_than_14(self):
- version = tmos_version(self.client)
- if LooseVersion(version) < LooseVersion('14.0.0'):
- return True
- return False
-
- def policy_import(self):
- self._set_changed_options()
- if self.module.check_mode:
- return True
- if self.exists():
- if self.want.force is False:
- return False
-
- self.import_file_to_device()
- self.remove_temp_file_from_device()
- return True
-
- def exists(self):
- if self.want.type == 'access_policy':
- uri = "https://{0}:{1}/mgmt/tm/apm/policy/access-policy/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- else:
- uri = "https://{0}:{1}/mgmt/tm/apm/profile/access/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def upload_file_to_device(self, content, name):
- url = 'https://{0}:{1}/mgmt/shared/file-transfer/uploads'.format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- try:
- upload_file(self.client, url, content, name)
- except F5ModuleError:
- raise F5ModuleError(
- "Failed to upload the file."
- )
-
- def import_file_to_device(self):
- name = os.path.split(self.want.source)[1]
- self.upload_file_to_device(self.want.source, name)
-
- cmd = 'ng_import -s /var/config/rest/downloads/{0} {1} -p {2}'.format(name, self.want.name, self.want.partition)
-
- uri = "https://{0}:{1}/mgmt/tm/util/bash/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- args = dict(
- command='run',
- utilCmdArgs='-c "{0}"'.format(cmd)
- )
- resp = self.client.api.post(uri, json=args)
-
- try:
- response = resp.json()
- if 'commandResult' in response:
- raise F5ModuleError(response['commandResult'])
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return True
-
- def remove_temp_file_from_device(self):
- name = os.path.split(self.want.source)[1]
- tpath_name = '/var/config/rest/downloads/{0}'.format(name)
- uri = "https://{0}:{1}/mgmt/tm/util/unix-rm/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- args = dict(
- command='run',
- utilCmdArgs=tpath_name
- )
- resp = self.client.api.post(uri, json=args)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- name=dict(
- required=True,
- ),
- source=dict(type='path'),
- force=dict(
- type='bool',
- default='no'
- ),
- type=dict(
- default='profile_access',
- choices=['profile_access', 'access_policy']
- ),
- partition=dict(
- default='Common',
- fallback=(env_fallback, ['F5_PARTITION'])
- )
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode,
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_appsvcs_extension.py b/lib/ansible/modules/network/f5/bigip_appsvcs_extension.py
deleted file mode 100644
index 194954076e..0000000000
--- a/lib/ansible/modules/network/f5/bigip_appsvcs_extension.py
+++ /dev/null
@@ -1,549 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2018, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_appsvcs_extension
-short_description: Manage application service deployments
-description:
- - Manages application service deployments via the App Services Extension functionality
- in BIG-IP.
-version_added: 2.7
-options:
- content:
- description:
- - Declaration of tenants configured on the system.
- - This parameter is most often used along with the C(file) or C(template) lookup plugins.
- Refer to the examples section for correct usage.
- - For anything advanced or with formatting consider using the C(template) lookup.
- - This can additionally be used for specifying application service configurations
- directly in YAML, however that is not an encouraged practice and, if used at all,
- should only be used for the absolute smallest of configurations to prevent your
- Playbooks from becoming too large.
- - If you C(content) includes encrypted values (such as ciphertexts, passphrases, etc),
- the returned C(changed) value will always be true.
- - If you are using the C(to_nice_json) filter, it will cause this module to fail because
- the purpose of that filter is to format the JSON to be human-readable and this process
- includes inserting "extra characters that break JSON validators.
- type: raw
- required: True
- tenants:
- description:
- - A list of tenants that you want to remove.
- - This parameter is only relevant when C(state) is C(absent). It will be ignored when
- C(state) is C(present).
- - A value of C(all) will remove all tenants.
- - Tenants can be specified as a list as well to remove only specific tenants.
- type: raw
- force:
- description:
- - Force updates a declaration.
- - This parameter should be used in cases where your declaration includes items that
- are encrypted or in cases (such as WAF Policies) where you want a large reload to take place.
- type: bool
- default: no
- state:
- description:
- - When C(state) is C(present), ensures the configuration exists.
- - When C(state) is C(absent), ensures that the configuration is removed.
- type: str
- choices:
- - present
- - absent
- default: present
-extends_documentation_fragment: f5
-author:
- - Tim Rupp (@caphrim007)
-'''
-
-EXAMPLES = r'''
-- name: Deploy an app service configuration
- bigip_appsvcs_extension:
- content: "{{ lookup('file', '/path/to/appsvcs.json') }}"
- state: present
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-
-- name: Remove all app service configurations
- bigip_appsvcs_extension:
- tenants: all
- state: absent
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-
-- name: Remove tenants T1 and T2 from app service configurations
- bigip_appsvcs_extension:
- tenants:
- - T1
- - T2
- state: absent
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-'''
-
-RETURN = r'''
-action:
- description:
- - The action performed.
- returned: changed
- type: str
- sample: deploy
-'''
-
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.six import iteritems
-from ansible.module_utils.six import string_types
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import fq_name
- from library.module_utils.network.f5.common import f5_argument_spec
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import fq_name
- from ansible.module_utils.network.f5.common import f5_argument_spec
-
-
-try:
- import json
-except ImportError:
- import simplejson as json
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'class': 'class_name',
- 'patchBody': 'patch_body',
- 'resourceTimeout': 'resource_timeout',
- 'targetTimeout': 'target_timeout',
- 'targetTokens': 'target_tokens',
- 'targetPassphrase': 'target_passphrase',
- 'targetUsername': 'target_username',
- 'targetPort': 'target_port',
- 'targetHost': 'target_host',
- 'retrieveAge': 'retrieve_age',
- 'logLevel': 'log_level',
- 'historyLimit': 'history_limit',
- 'syncToGroup': 'sync_to_group',
- 'redeployUpdateMode': 'redeploy_update_mode',
- 'redeployAge': 'redeploy_age',
- }
-
- api_attributes = [
- 'class',
- 'action',
- 'persist',
- 'declaration',
- 'patchBody',
- 'resourceTimeout',
- 'targetTimeout',
- 'targetTokens',
- 'targetPassphrase',
- 'targetUsername',
- 'targetPort',
- 'targetHost',
- 'retrieveAge',
- 'trace',
- 'logLevel',
- 'historyLimit',
- 'syncToGroup',
- 'redeployUpdateMode',
- 'redeployAge',
- ]
-
- returnables = [
- 'class_name',
- 'action',
- 'persist',
- 'declaration',
- 'patch_body',
- 'resource_timeout',
- 'target_timeout',
- 'target_tokens',
- 'target_passphrase',
- 'target_username',
- 'target_port',
- 'target_host',
- 'retrieve_age',
- 'trace',
- 'log_level',
- 'history_limit',
- 'sync_to_group',
- 'redeploy_update_mode',
- 'redeploy_age',
- ]
-
- updatables = [
- 'class_name',
- 'action',
- 'persist',
- 'declaration',
- 'patch_body',
- 'resource_timeout',
- 'target_timeout',
- 'target_tokens',
- 'target_passphrase',
- 'target_username',
- 'target_port',
- 'target_host',
- 'retrieve_age',
- 'trace',
- 'log_level',
- 'history_limit',
- 'sync_to_group',
- 'redeploy_update_mode',
- 'redeploy_age',
- ]
-
-
-class ApiParameters(Parameters):
- pass
-
-
-class ModuleParameters(Parameters):
- @property
- def content(self):
- if self._values['content'] is None:
- return None
- if isinstance(self._values['content'], string_types):
- return json.loads(self._values['content'] or 'null')
- else:
- return self._values['content']
-
- @property
- def class_name(self):
- return self._values['content'].get('class', None)
-
- @property
- def action(self):
- return self._values['content'].get('action', None)
-
- @property
- def declaration(self):
- return self._values['content'].get('declaration', None)
-
- @property
- def persist(self):
- if self._values['content']:
- return self._values['content'].get('persist', None)
- elif self.param_persist:
- return self.param_persist
- return None
-
- @property
- def param_persist(self):
- if self._values['parameters'] is None:
- return None
- result = self._values['parameters'].get('persist', None)
- return result
-
- @property
- def tenants(self):
- if self._values['tenants'] in [None, 'all']:
- return ''
- if isinstance(self._values['tenants'], list):
- return ','.join(self._values['tenants'])
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class UsableChanges(Changes):
- pass
-
-
-class ReportableChanges(Changes):
- @property
- def declaration(self):
- return None
-
- @property
- def target_passphrase(self):
- return None
-
- @property
- def class_name(self):
- return None
-
- @property
- def persist(self):
- return None
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(params=self.module.params)
- self.have = ApiParameters()
- self.changes = UsableChanges()
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = UsableChanges(params=changed)
-
- def exec_module(self):
- changed = False
- result = dict()
- state = self.want.state
-
- if state == "present":
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- return result
-
- def present(self):
- if self.exists():
- return False
- return self.upsert()
-
- def remove(self):
- if self.module.check_mode:
- return True
- self.remove_from_device()
- if self.tenant_exists():
- raise F5ModuleError("Failed to delete the resource.")
- return True
-
- def upsert(self):
- self._set_changed_options()
- if self.module.check_mode:
- return True
- if self.want.content == 'all':
- raise F5ModuleError(
- "'all' keyword cannot be used when 'state' is 'present'."
- )
- self.upsert_on_device()
- return True
-
- def _get_errors_from_response(self, messages):
- results = []
- if 'results' not in messages:
- if 'message' in messages:
- results.append(messages['message'])
- if 'errors' in messages:
- results += messages['errors']
- else:
- for message in messages['results']:
- if 'message' in message and message['message'] == 'declaration failed':
- results.append(message['response'])
- if 'errors' in message:
- results += message['errors']
- return results
-
- def upsert_on_device(self):
- uri = 'https://{0}:{1}/mgmt/shared/appsvcs/declare/'.format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.post(uri, json=self.want.content)
-
- if resp.status != 200:
- result = resp.json()
- errors = self._get_errors_from_response(result)
- if errors:
- message = "{0}".format('. '.join(errors))
- raise F5ModuleError(message)
- raise F5ModuleError(resp.content)
- else:
- result = resp.json()
- errors = self._get_errors_from_response(result)
- if errors:
- message = "{0}".format('. '.join(errors))
- raise F5ModuleError(message)
-
- def ignore_changes(self, obj):
- if isinstance(obj, dict):
- if 'passphrase' in obj:
- obj['passphrase']['ignoreChanges'] = True
- if 'class' in obj and obj['class'] == 'WAF_Policy':
- obj['ignoreChanges'] = True
- return dict((k, self.ignore_changes(v)) for k, v in iteritems(obj))
- else:
- return obj
-
- def exists(self):
- declaration = {}
- if self.want.content is None:
- raise F5ModuleError(
- "Empty content cannot be specified when 'state' is 'present'."
- )
- try:
- declaration.update(self.want.content)
- except ValueError:
- raise F5ModuleError(
- "The provided 'content' could not be converted into valid json. If you "
- "are using the 'to_nice_json' filter, please remove it."
- )
- declaration['action'] = 'dry-run'
-
- # This deals with cases where you're comparing a passphrase.
- #
- # Passphrases will always cause an idempotent operation to register
- # a change. Therefore, by specifying "force", you are instructing
- # the module to **not** ignore the passphrase.
- #
- # This will cause the module to not append ignore clauses to the
- # classes that support them.
- if not self.want.force:
- self.ignore_changes(declaration)
-
- uri = "https://{0}:{1}/mgmt/shared/appsvcs/declare/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.post(uri, json=declaration)
- try:
- response = resp.json()
- except ValueError:
- return False
- try:
- if response['results'][0]['message'] == 'no change':
- return True
- except KeyError:
- return False
-
- def tenant_exists(self):
- uri = "https://{0}:{1}/mgmt/shared/appsvcs/declare/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- self.want.tenants
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'statusCode' in response and response['statusCode'] == 404:
- return False
- return True
-
- def absent(self):
- if self.tenant_exists():
- return self.remove()
- return False
-
- def remove_from_device(self):
- uri = 'https://{0}:{1}/mgmt/shared/appsvcs/declare/{2}'.format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- self.want.tenants
- )
- response = self.client.api.delete(uri)
- if response.status != 200:
- result = response.json()
- errors = self._get_errors_from_response(result)
- if errors:
- message = "{0}".format('. '.join(errors))
- raise F5ModuleError(message)
- raise F5ModuleError(response.content)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- content=dict(type='raw'),
- state=dict(
- default='present',
- choices=['present', 'absent']
- ),
- tenants=dict(type='raw'),
- force=dict(type='bool', default='no')
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
- self.required_if = [
- ['state', 'present', ['content']]
- ]
- self.mutually_exclusive = [
- ['content', 'tenants']
- ]
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode,
- required_if=spec.required_if
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_asm_dos_application.py b/lib/ansible/modules/network/f5/bigip_asm_dos_application.py
deleted file mode 100644
index a89acc82d6..0000000000
--- a/lib/ansible/modules/network/f5/bigip_asm_dos_application.py
+++ /dev/null
@@ -1,1308 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2019, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_asm_dos_application
-short_description: Manage application settings for DOS profile
-description:
- - Manages Application settings for ASM/AFM DOS profile.
-version_added: 2.9
-options:
- profile:
- description:
- - Specifies the name of the profile to manage application settings in.
- type: str
- required: True
- rtbh_duration:
- description:
- - Specifies the duration of the RTBH BGP route advertisement, in seconds.
- - The accepted range is between 0 and 4294967295 inclusive.
- type: int
- rtbh_enable:
- description:
- - Specifies whether to enable Remote Triggered Black Hole C(RTBH) of attacking IPs by advertising BGP routes.
- type: bool
- scrubbing_duration:
- description:
- - Specifies the duration of the Traffic Scrubbing BGP route advertisement, in seconds.
- - The accepted range is between 0 and 4294967295 inclusive.
- type: int
- scrubbing_enable:
- description:
- - Specifies whether to enable Traffic Scrubbing during attacks by advertising BGP routes.
- type: bool
- single_page_application:
- description:
- - Specifies, when C(yes), that the system supports a Single Page Applications.
- type: bool
- trigger_irule:
- description:
- - Specifies, when C(yes), that the system activates an Application DoS iRule event.
- type: bool
- geolocations:
- description:
- - Manages the geolocations countries whitelist, blacklist.
- type: dict
- suboptions:
- whitelist:
- description:
- - A list of countries to be put on whitelist, must not have overlapping elements with C(blacklist).
- type: list
- blacklist:
- description:
- - A list of countries to be put on blacklist, must not have overlapping elements with C(whitelist).
- type: list
- heavy_urls:
- description:
- - Manages Heavy URL protection.
- - Heavy URLs are a small number of site URLs that might consume considerable server resources per request.
- type: dict
- suboptions:
- auto_detect:
- description:
- - Enables or disables automatic heavy URL detection.
- type: bool
- latency_threshold:
- description:
- - Specifies the latency threshold for automatic heavy URL detection.
- - The accepted range is between 0 and 4294967295 milliseconds inclusive.
- type: int
- exclude:
- description:
- - Specifies a list of URLs or wildcards to exclude from the heavy URLs.
- type: list
- include:
- description:
- - Configures additional URLs to include in the heavy URLs that were auto detected.
- type: list
- suboptions:
- url:
- description:
- - Specifies the URL to be added to the list of heavy URLs, in addition to the automatically detected ones.
- type: str
- threshold:
- description:
- - Specifies the threshold of requests per second, where the URL in question is considered under attack.
- - The accepted range is between 1 and 4294967295 inclusive, or C(auto).
- type: str
- mobile_detection:
- description:
- - Configures detection of mobile applications built with the Anti-Bot Mobile SDK and defines how requests
- from these mobile application clients are handled.
- type: dict
- suboptions:
- enabled:
- description:
- - When C(yes), requests from mobile applications built with Anti-Bot Mobile SDK will be detected and handled
- according to the parameters set.
- - When C(no), these requests will be handled like any other request which may let attacks in, or cause false
- positives.
- type: bool
- allow_android_rooted_device:
- description:
- - When C(yes) device will allow traffic from rooted Android devices.
- type: bool
- allow_any_android_package:
- description:
- - When C(yes) allows any application publisher.
- - A publisher is identified by the certificate used to sign the application.
- type: bool
- allow_any_ios_package:
- description:
- - When C(yes) allows any iOS package.
- - A package name is the unique identifier of the mobile application.
- type: bool
- allow_jailbroken_devices:
- description:
- - When C(yes) allows traffic from jailbroken iOS devices.
- type: bool
- allow_emulators:
- description:
- - When C(yes) allows traffic from applications run on emulators.
- type: bool
- client_side_challenge_mode:
- description:
- - Action to take when a CAPTCHA or Client Side Integrity challenge needs to be presented.
- - The mobile application user will not see a CAPTCHA challenge and the mobile application will not be
- presented with the Client Side Integrity challenge. The such options for mobile applications are C(pass)
- or C(cshui).
- - When C(pass) the traffic is passed without incident.
- - When C(cshui) the SDK checks for human interactions with the screen in the last few seconds.
- If none are detected, the traffic is blocked.
- type: str
- choices:
- - pass
- - cshui
- ios_allowed_package_names:
- description:
- - Specifies the names of iOS packages to allow traffic on.
- - This option has no effect when C(allow_any_ios_package) is set to C(yes).
- type: list
- android_publishers:
- description:
- - This option has no effect when C(allow_any_android_package) is set to C(yes).
- - Specifies the allowed publisher certificates for android applications.
- - The publisher certificate needs to be installed on the BIG-IP beforehand.
- - "The certificate name located on a different partition than the one specified
- in C(partition) parameter needs to be provided in C(full_path) format C(/Foo/cert.crt)."
- type: list
- partition:
- description:
- - Device partition to manage resources on.
- type: str
- default: Common
- state:
- description:
- - When C(state) is C(present), ensures that the Application object exists.
- - When C(state) is C(absent), ensures that the Application object is removed.
- type: str
- choices:
- - present
- - absent
- default: present
-notes:
- - Requires BIG-IP >= 13.1.0
-extends_documentation_fragment: f5
-author:
- - Wojciech Wypior (@wojtek0806)
-'''
-
-EXAMPLES = r'''
-- name: Create an ASM dos application profile
- bigip_asm_dos_application:
- profile: dos_foo
- geolocations:
- blacklist:
- - Afghanistan
- - Andora
- whitelist:
- - Cuba
- heavy_urls:
- auto_detect: yes
- latency_threshold: 1000
- rtbh_duration: 3600
- rtbh_enable: yes
- single_page_application: yes
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-
-- name: Update an ASM dos application profile
- bigip_asm_dos_application:
- profile: dos_foo
- mobile_detection:
- enabled: yes
- allow_any_ios_package: yes
- allow_emulators: yes
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-
-- name: Remove an ASM dos application profile
- bigip_asm_dos_application:
- profile: dos_foo
- state: absent
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-'''
-
-RETURN = r'''
-rtbh_enable:
- description: Enables Remote Triggered Black Hole of attacking IPs.
- returned: changed
- type: bool
- sample: no
-rtbh_duration:
- description: The duration of the RTBH BGP route advertisement.
- returned: changed
- type: int
- sample: 3600
-scrubbing_enable:
- description: Enables Traffic Scrubbing during attacks.
- returned: changed
- type: bool
- sample: yes
-scrubbing_duration:
- description: The duration of the Traffic Scrubbing BGP route advertisement.
- returned: changed
- type: int
- sample: 3600
-single_page_application:
- description: Enables support of a Single Page Applications.
- returned: changed
- type: bool
- sample: no
-trigger_irule:
- description: Activates an Application DoS iRule event.
- returned: changed
- type: bool
- sample: yes
-geolocations:
- description: Specifies geolocations countries whitelist, blacklist.
- type: complex
- returned: changed
- contains:
- whitelist:
- description: A list of countries to be put on whitelist.
- returned: changed
- type: list
- sample: ['United States, United Kingdom']
- blacklist:
- description: A list of countries to be put on blacklist.
- returned: changed
- type: list
- sample: ['Russia', 'Germany']
- sample: hash/dictionary of values
-heavy_urls:
- description: Manages Heavy URL protection.
- type: complex
- returned: changed
- contains:
- auto_detect:
- description: Enables or disables automatic heavy URL detection.
- returned: changed
- type: bool
- sample: yes
- latency_threshold:
- description: Specifies the latency threshold for automatic heavy URL detection.
- returned: changed
- type: int
- sample: 2000
- exclude:
- description: Specifies a list of URLs or wildcards to exclude from the heavy URLs.
- returned: changed
- type: list
- sample: ['/exclude.html', '/exclude2.html']
- include:
- description: Configures additional URLs to include in the heavy URLs.
- type: complex
- returned: changed
- contains:
- url:
- description: The URL to be added to the list of heavy URLs.
- returned: changed
- type: str
- sample: /include.html
- threshold:
- description: The threshold of requests per second
- returned: changed
- type: str
- sample: auto
- sample: hash/dictionary of values
- sample: hash/dictionary of values
-mobile_detection:
- description: Configures detection of mobile applications built with the Anti-Bot Mobile SDK.
- type: complex
- returned: changed
- contains:
- enable:
- description: Enables or disables automatic mobile detection.
- returned: changed
- type: bool
- sample: yes
- allow_android_rooted_device:
- description: Allows traffic from rooted Android devices.
- returned: changed
- type: bool
- sample: no
- allow_any_android_package:
- description: Allows any application publisher.
- returned: changed
- type: bool
- sample: no
- allow_any_ios_package:
- description: Allows any iOS package.
- returned: changed
- type: bool
- sample: yes
- allow_jailbroken_devices:
- description: Allows traffic from jailbroken iOS devices.
- returned: changed
- type: bool
- sample: no
- allow_emulators:
- description: Allows traffic from applications run on emulators.
- returned: changed
- type: bool
- sample: yes
- client_side_challenge_mode:
- description: Action to take when a CAPTCHA or Client Side Integrity challenge needs to be presented.
- returned: changed
- type: str
- sample: pass
- ios_allowed_package_names:
- description: The names of iOS packages to allow traffic on.
- returned: changed
- type: list
- sample: ['package1','package2']
- android_publishers:
- description: The allowed publisher certificates for android applications.
- returned: changed
- type: list
- sample: ['/Common/cert1.crt', '/Common/cert2.crt']
- sample: hash/dictionary of values
-'''
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.basic import env_fallback
-from distutils.version import LooseVersion
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import fq_name
- from library.module_utils.network.f5.common import transform_name
- from library.module_utils.network.f5.common import flatten_boolean
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.compare import compare_complex_list
- from library.module_utils.network.f5.compare import cmp_simple_list
- from library.module_utils.network.f5.icontrol import tmos_version
- from library.module_utils.network.f5.icontrol import module_provisioned
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import fq_name
- from ansible.module_utils.network.f5.common import transform_name
- from ansible.module_utils.network.f5.common import flatten_boolean
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.compare import compare_complex_list
- from ansible.module_utils.network.f5.compare import cmp_simple_list
- from ansible.module_utils.network.f5.icontrol import tmos_version
- from ansible.module_utils.network.f5.icontrol import module_provisioned
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'rtbhDurationSec': 'rtbh_duration',
- 'rtbhEnable': 'rtbh_enable',
- 'scrubbingDurationSec': 'scrubbing_duration',
- 'scrubbingEnable': 'scrubbing_enable',
- 'singlePageApplication': 'single_page_application',
- 'triggerIrule': 'trigger_irule',
- 'heavyUrls': 'heavy_urls',
- 'mobileDetection': 'mobile_detection',
- }
-
- api_attributes = [
- 'geolocations',
- 'rtbhDurationSec',
- 'rtbhEnable',
- 'scrubbingDurationSec',
- 'scrubbingEnable',
- 'singlePageApplication',
- 'triggerIrule',
- 'heavyUrls',
- 'mobileDetection',
- ]
-
- returnables = [
- 'rtbh_duration',
- 'rtbh_enable',
- 'scrubbing_duration',
- 'scrubbing_enable',
- 'single_page_application',
- 'trigger_irule',
- 'enable_mobile_detection',
- 'allow_android_rooted_device',
- 'allow_any_android_package',
- 'allow_any_ios_package',
- 'allow_jailbroken_devices',
- 'allow_emulators',
- 'client_side_challenge_mode',
- 'ios_allowed_package_names',
- 'android_publishers',
- 'auto_detect',
- 'latency_threshold',
- 'hw_url_exclude',
- 'hw_url_include',
- 'geo_blacklist',
- 'geo_whitelist',
- ]
-
- updatables = [
- 'rtbh_duration',
- 'rtbh_enable',
- 'scrubbing_duration',
- 'scrubbing_enable',
- 'single_page_application',
- 'trigger_irule',
- 'enable_mobile_detection',
- 'allow_android_rooted_device',
- 'allow_any_android_package',
- 'allow_any_ios_package',
- 'allow_jailbroken_devices',
- 'allow_emulators',
- 'client_side_challenge_mode',
- 'ios_allowed_package_names',
- 'android_publishers',
- 'auto_detect',
- 'latency_threshold',
- 'hw_url_exclude',
- 'hw_url_include',
- 'geo_blacklist',
- 'geo_whitelist',
- ]
-
-
-class ApiParameters(Parameters):
- @property
- def enable_mobile_detection(self):
- if self._values['mobile_detection'] is None:
- return None
- return self._values['mobile_detection']['enabled']
-
- @property
- def allow_android_rooted_device(self):
- if self._values['mobile_detection'] is None:
- return None
- return self._values['mobile_detection']['allowAndroidRootedDevice']
-
- @property
- def allow_any_android_package(self):
- if self._values['mobile_detection'] is None:
- return None
- return self._values['mobile_detection']['allowAnyAndroidPackage']
-
- @property
- def allow_any_ios_package(self):
- if self._values['mobile_detection'] is None:
- return None
- return self._values['mobile_detection']['allowAnyIosPackage']
-
- @property
- def allow_jailbroken_devices(self):
- if self._values['mobile_detection'] is None:
- return None
- return self._values['mobile_detection']['allowJailbrokenDevices']
-
- @property
- def allow_emulators(self):
- if self._values['mobile_detection'] is None:
- return None
- return self._values['mobile_detection']['allowEmulators']
-
- @property
- def client_side_challenge_mode(self):
- if self._values['mobile_detection'] is None:
- return None
- return self._values['mobile_detection']['clientSideChallengeMode']
-
- @property
- def ios_allowed_package_names(self):
- if self._values['mobile_detection'] is None:
- return None
- return self._values['mobile_detection'].get('iosAllowedPackageNames', None)
-
- @property
- def android_publishers(self):
- if self._values['mobile_detection'] is None or 'androidPublishers' not in self._values['mobile_detection']:
- return None
- result = [fq_name(publisher['partition'], publisher['name'])
- for publisher in self._values['mobile_detection']['androidPublishers']]
- return result
-
- @property
- def auto_detect(self):
- if self._values['heavy_urls'] is None:
- return None
- return self._values['heavy_urls']['automaticDetection']
-
- @property
- def latency_threshold(self):
- if self._values['heavy_urls'] is None:
- return None
- return self._values['heavy_urls']['latencyThreshold']
-
- @property
- def hw_url_exclude(self):
- if self._values['heavy_urls'] is None:
- return None
- return self._values['heavy_urls'].get('exclude', None)
-
- @property
- def hw_url_include(self):
- if self._values['heavy_urls'] is None:
- return None
- return self._values['heavy_urls'].get('includeList', None)
-
- @property
- def geo_blacklist(self):
- if self._values['geolocations'] is None:
- return None
- result = list()
- for item in self._values['geolocations']:
- if 'blackListed' in item and item['blackListed'] is True:
- result.append(item['name'])
- if result:
- return result
-
- @property
- def geo_whitelist(self):
- if self._values['geolocations'] is None:
- return None
- result = list()
- for item in self._values['geolocations']:
- if 'whiteListed' in item and item['whiteListed'] is True:
- result.append(item['name'])
- if result:
- return result
-
-
-class ModuleParameters(Parameters):
- @property
- def rtbh_duration(self):
- if self._values['rtbh_duration'] is None:
- return None
- if 0 <= self._values['rtbh_duration'] <= 4294967295:
- return self._values['rtbh_duration']
- raise F5ModuleError(
- "Valid 'rtbh_duration' must be in range 0 - 4294967295 seconds."
- )
-
- @property
- def rtbh_enable(self):
- result = flatten_boolean(self._values['rtbh_enable'])
- if result == 'yes':
- return 'enabled'
- if result == 'no':
- return 'disabled'
- return result
-
- @property
- def scrubbing_duration(self):
- if self._values['scrubbing_duration'] is None:
- return None
- if 0 <= self._values['scrubbing_duration'] <= 4294967295:
- return self._values['scrubbing_duration']
- raise F5ModuleError(
- "Valid 'scrubbing_duration' must be in range 0 - 4294967295 seconds."
- )
-
- @property
- def scrubbing_enable(self):
- result = flatten_boolean(self._values['scrubbing_enable'])
- if result == 'yes':
- return 'enabled'
- if result == 'no':
- return 'disabled'
- return result
-
- @property
- def single_page_application(self):
- result = flatten_boolean(self._values['single_page_application'])
- if result == 'yes':
- return 'enabled'
- if result == 'no':
- return 'disabled'
- return result
-
- @property
- def trigger_irule(self):
- result = flatten_boolean(self._values['trigger_irule'])
- if result == 'yes':
- return 'enabled'
- if result == 'no':
- return 'disabled'
- return result
-
- @property
- def enable_mobile_detection(self):
- if self._values['mobile_detection'] is None:
- return None
- result = flatten_boolean(self._values['mobile_detection']['enabled'])
- if result == 'yes':
- return 'enabled'
- if result == 'no':
- return 'disabled'
- return result
-
- @property
- def allow_android_rooted_device(self):
- if self._values['mobile_detection'] is None:
- return None
- result = flatten_boolean(self._values['mobile_detection']['allow_android_rooted_device'])
- if result == 'yes':
- return 'true'
- if result == 'no':
- return 'false'
- return result
-
- @property
- def allow_any_android_package(self):
- if self._values['mobile_detection'] is None:
- return None
- result = flatten_boolean(self._values['mobile_detection']['allow_any_android_package'])
- if result == 'yes':
- return 'true'
- if result == 'no':
- return 'false'
- return result
-
- @property
- def allow_any_ios_package(self):
- if self._values['mobile_detection'] is None:
- return None
- result = flatten_boolean(self._values['mobile_detection']['allow_any_ios_package'])
- if result == 'yes':
- return 'true'
- if result == 'no':
- return 'false'
- return result
-
- @property
- def allow_jailbroken_devices(self):
- if self._values['mobile_detection'] is None:
- return None
- result = flatten_boolean(self._values['mobile_detection']['allow_jailbroken_devices'])
- if result == 'yes':
- return 'true'
- if result == 'no':
- return 'false'
- return result
-
- @property
- def allow_emulators(self):
- if self._values['mobile_detection'] is None:
- return None
- result = flatten_boolean(self._values['mobile_detection']['allow_emulators'])
- if result == 'yes':
- return 'true'
- if result == 'no':
- return 'false'
- return result
-
- @property
- def client_side_challenge_mode(self):
- if self._values['mobile_detection'] is None:
- return None
- return self._values['mobile_detection']['client_side_challenge_mode']
-
- @property
- def ios_allowed_package_names(self):
- if self._values['mobile_detection'] is None:
- return None
- return self._values['mobile_detection']['ios_allowed_package_names']
-
- @property
- def android_publishers(self):
- if self._values['mobile_detection'] is None or self._values['mobile_detection']['android_publishers'] is None:
- return None
- result = [fq_name(self.partition, item) for item in self._values['mobile_detection']['android_publishers']]
- return result
-
- @property
- def auto_detect(self):
- if self._values['heavy_urls'] is None:
- return None
- result = flatten_boolean(self._values['heavy_urls']['auto_detect'])
- if result == 'yes':
- return 'enabled'
- if result == 'no':
- return 'disabled'
- return result
-
- @property
- def latency_threshold(self):
- if self._values['heavy_urls'] is None or self._values['heavy_urls']['latency_threshold'] is None:
- return None
- if 0 <= self._values['heavy_urls']['latency_threshold'] <= 4294967295:
- return self._values['heavy_urls']['latency_threshold']
- raise F5ModuleError(
- "Valid 'latency_threshold' must be in range 0 - 4294967295 milliseconds."
- )
-
- @property
- def hw_url_exclude(self):
- if self._values['heavy_urls'] is None:
- return None
- return self._values['heavy_urls']['exclude']
-
- @property
- def hw_url_include(self):
- if self._values['heavy_urls'] is None or self._values['heavy_urls']['include'] is None:
- return None
- result = list()
- for item in self._values['heavy_urls']['include']:
- element = dict()
- element['url'] = self._correct_url(item['url'])
- element['name'] = 'URL{0}'.format(self._correct_url(item['url']))
- if 'threshold' in item:
- element['threshold'] = self._validate_threshold(item['threshold'])
- result.append(element)
- return result
-
- def _validate_threshold(self, item):
- if item == 'auto':
- return item
- if 1 <= int(item) <= 4294967295:
- return item
- raise F5ModuleError(
- "Valid 'url threshold' must be in range 1 - 4294967295 requests per second or 'auto'."
- )
-
- def _correct_url(self, item):
- if item.startswith('/'):
- return item
- return "/{0}".format(item)
-
- @property
- def geo_blacklist(self):
- if self._values['geolocations'] is None:
- return None
- whitelist = self.geo_whitelist
- blacklist = self._values['geolocations']['blacklist']
- if whitelist and blacklist:
- if not set(whitelist).isdisjoint(set(blacklist)):
- raise F5ModuleError('Cannot specify the same element in blacklist and whitelist.')
- return blacklist
-
- @property
- def geo_whitelist(self):
- if self._values['geolocations'] is None:
- return None
- return self._values['geolocations']['whitelist']
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class UsableChanges(Changes):
- @property
- def geolocations(self):
- if self._values['geo_blacklist'] is None and self._values['geo_whitelist'] is None:
- return None
- result = list()
- if self._values['geo_blacklist']:
- for item in self._values['geo_blacklist']:
- element = dict()
- element['name'] = item
- element['blackListed'] = True
- result.append(element)
- if self._values['geo_whitelist']:
- for item in self._values['geo_whitelist']:
- element = dict()
- element['name'] = item
- element['whiteListed'] = True
- result.append(element)
- if result:
- return result
-
- @property
- def heavy_urls(self):
- tmp = dict()
- tmp['automaticDetection'] = self._values['auto_detect']
- tmp['latencyThreshold'] = self._values['latency_threshold']
- tmp['exclude'] = self._values['hw_url_exclude']
- tmp['includeList'] = self._values['hw_url_include']
- result = self._filter_params(tmp)
- if result:
- return result
-
- @property
- def mobile_detection(self):
- tmp = dict()
- tmp['enabled'] = self._values['enable_mobile_detection']
- tmp['allowAndroidRootedDevice'] = self._values['allow_android_rooted_device']
- tmp['allowAnyAndroidPackage'] = self._values['allow_any_android_package']
- tmp['allowAnyIosPackage'] = self._values['allow_any_ios_package']
- tmp['allowJailbrokenDevices'] = self._values['allow_jailbroken_devices']
- tmp['allowEmulators'] = self._values['allow_emulators']
- tmp['clientSideChallengeMode'] = self._values['client_side_challenge_mode']
- tmp['iosAllowedPackageNames'] = self._values['ios_allowed_package_names']
- tmp['androidPublishers'] = self._values['android_publishers']
- result = self._filter_params(tmp)
- if result:
- return result
-
-
-class ReportableChanges(Changes):
- returnables = [
- 'rtbh_duration',
- 'rtbh_enable',
- 'scrubbing_duration',
- 'scrubbing_enable',
- 'single_page_application',
- 'trigger_irule',
- 'heavy_urls',
- 'mobile_detection',
- 'geolocations',
- ]
-
- def _convert_include_list(self, items):
- result = list()
- for item in items:
- element = dict()
- element['url'] = item['url']
- if 'threshold' in item:
- element['threshold'] = item['threshold']
- result.append(element)
- if result:
- return result
-
- @property
- def geolocations(self):
- tmp = dict()
- tmp['blacklist'] = self._values['geo_blacklist']
- tmp['whitelist'] = self._values['geo_whitelist']
- result = self._filter_params(tmp)
- if result:
- return result
-
- @property
- def heavy_urls(self):
- tmp = dict()
- tmp['auto_detect'] = flatten_boolean(self._values['auto_detect'])
- tmp['latency_threshold'] = self._values['latency_threshold']
- tmp['exclude'] = self._values['hw_url_exclude']
- tmp['include'] = self._convert_include_list(self._values['hw_url_include'])
- result = self._filter_params(tmp)
- if result:
- return result
-
- @property
- def mobile_detection(self):
- tmp = dict()
- tmp['enabled'] = flatten_boolean(self._values['enable_mobile_detection'])
- tmp['allow_android_rooted_device'] = flatten_boolean(self._values['allow_android_rooted_device'])
- tmp['allow_any_android_package'] = flatten_boolean(self._values['allow_any_android_package'])
- tmp['allow_any_ios_package'] = flatten_boolean(self._values['allow_any_ios_package'])
- tmp['allow_jailbroken_devices'] = flatten_boolean(self._values['allow_jailbroken_devices'])
- tmp['allow_emulators'] = flatten_boolean(self._values['allow_emulators'])
- tmp['client_side_challenge_mode'] = self._values['client_side_challenge_mode']
- tmp['ios_allowed_package_names'] = self._values['ios_allowed_package_names']
- tmp['android_publishers'] = self._values['android_publishers']
- result = self._filter_params(tmp)
- if result:
- return result
-
- @property
- def rtbh_enable(self):
- result = flatten_boolean(self._values['rtbh_enable'])
- return result
-
- @property
- def scrubbing_enable(self):
- result = flatten_boolean(self._values['scrubbing_enable'])
- return result
-
- @property
- def single_page_application(self):
- result = flatten_boolean(self._values['single_page_application'])
- return result
-
- @property
- def trigger_irule(self):
- result = flatten_boolean(self._values['trigger_irule'])
- return result
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
- @property
- def hw_url_include(self):
- if self.want.hw_url_include is None:
- return None
- if self.have.hw_url_include is None and self.want.hw_url_include == []:
- return None
- if self.have.hw_url_include is None:
- return self.want.hw_url_include
-
- wants = self.want.hw_url_include
- haves = list()
- # First we remove extra keys in have for the same elements
- for want in wants:
- for have in self.have.hw_url_include:
- if want['url'] == have['url']:
- entry = self._filter_have(want, have)
- haves.append(entry)
- # Next we do compare the lists as normal
- result = compare_complex_list(wants, haves)
- return result
-
- def _filter_have(self, want, have):
- to_check = set(want.keys()).intersection(set(have.keys()))
- result = dict()
- for k in list(to_check):
- result[k] = have[k]
- return result
-
- @property
- def hw_url_exclude(self):
- result = cmp_simple_list(self.want.hw_url_exclude, self.have.hw_url_exclude)
- return result
-
- @property
- def geo_blacklist(self):
- result = cmp_simple_list(self.want.geo_blacklist, self.have.geo_blacklist)
- return result
-
- @property
- def geo_whitelist(self):
- result = cmp_simple_list(self.want.geo_whitelist, self.have.geo_whitelist)
- return result
-
- @property
- def android_publishers(self):
- result = cmp_simple_list(self.want.android_publishers, self.have.android_publishers)
- return result
-
- @property
- def ios_allowed_package_names(self):
- result = cmp_simple_list(self.want.ios_allowed_package_names, self.have.ios_allowed_package_names)
- return result
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(params=self.module.params)
- self.have = ApiParameters()
- self.changes = UsableChanges()
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = UsableChanges(params=changed)
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.client.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def exec_module(self):
- if not module_provisioned(self.client, 'asm'):
- raise F5ModuleError(
- "ASM must be provisioned to use this module."
- )
-
- if self.version_less_than_13_1():
- raise F5ModuleError('Module supported on TMOS versions 13.1.x and above')
-
- changed = False
- result = dict()
- state = self.want.state
-
- if state == "present":
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def version_less_than_13_1(self):
- version = tmos_version(self.client)
- if LooseVersion(version) < LooseVersion('13.1.0'):
- return True
- return False
-
- def present(self):
- if self.exists():
- return self.update()
- else:
- return self.create()
-
- def absent(self):
- if self.exists():
- return self.remove()
- return False
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def update(self):
- self.have = self.read_current_from_device()
- if not self.should_update():
- return False
- if self.module.check_mode:
- return True
- self.update_on_device()
- return True
-
- def remove(self):
- if self.module.check_mode:
- return True
- self.remove_from_device()
- if self.exists():
- raise F5ModuleError("Failed to delete the resource.")
- return True
-
- def create(self):
- self._set_changed_options()
- if self.module.check_mode:
- return True
- self.create_on_device()
- return True
-
- def profile_exists(self):
- uri = "https://{0}:{1}/mgmt/tm/security/dos/profile/{2}/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.profile),
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def exists(self):
- if not self.profile_exists():
- raise F5ModuleError(
- 'Specified DOS profile: {0} on partition: {1} does not exist.'.format(
- self.want.profile, self.want.partition)
- )
- uri = "https://{0}:{1}/mgmt/tm/security/dos/profile/{2}/application/{3}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.profile),
- self.want.profile
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def create_on_device(self):
- params = self.changes.api_params()
- params['name'] = self.want.profile
- uri = "https://{0}:{1}/mgmt/tm/security/dos/profile/{2}/application/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.profile),
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 409]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return True
-
- def update_on_device(self):
- params = self.changes.api_params()
- uri = "https://{0}:{1}/mgmt/tm/security/dos/profile/{2}/application/{3}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.profile),
- self.want.profile
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def remove_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/security/dos/profile/{2}/application/{3}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.profile),
- self.want.profile
- )
- response = self.client.api.delete(uri)
- if response.status == 200:
- return True
- raise F5ModuleError(response.content)
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/security/dos/profile/{2}/application/{3}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.profile),
- self.want.profile
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return ApiParameters(params=response)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- profile=dict(
- required=True,
- ),
- geolocations=dict(
- type='dict',
- options=dict(
- blacklist=dict(type='list'),
- whitelist=dict(type='list'),
- ),
- ),
- heavy_urls=dict(
- type='dict',
- options=dict(
- auto_detect=dict(type='bool'),
- latency_threshold=dict(type='int'),
- exclude=dict(type='list'),
- include=dict(
- type='list',
- elements='dict',
- options=dict(
- url=dict(required=True),
- threshold=dict(),
- ),
- )
- ),
- ),
- mobile_detection=dict(
- type='dict',
- options=dict(
- enabled=dict(type='bool'),
- allow_android_rooted_device=dict(type='bool'),
- allow_any_android_package=dict(type='bool'),
- allow_any_ios_package=dict(type='bool'),
- allow_jailbroken_devices=dict(type='bool'),
- allow_emulators=dict(type='bool'),
- client_side_challenge_mode=dict(choices=['cshui', 'pass']),
- ios_allowed_package_names=dict(type='list'),
- android_publishers=dict(type='list')
- )
- ),
- rtbh_duration=dict(type='int'),
- rtbh_enable=dict(type='bool'),
- scrubbing_duration=dict(type='int'),
- scrubbing_enable=dict(type='bool'),
- single_page_application=dict(type='bool'),
- trigger_irule=dict(type='bool'),
- partition=dict(
- default='Common',
- fallback=(env_fallback, ['F5_PARTITION'])
- ),
- state=dict(
- default='present',
- choices=['present', 'absent']
- )
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode,
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_asm_policy_fetch.py b/lib/ansible/modules/network/f5/bigip_asm_policy_fetch.py
deleted file mode 100644
index 984bebf02e..0000000000
--- a/lib/ansible/modules/network/f5/bigip_asm_policy_fetch.py
+++ /dev/null
@@ -1,688 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2018, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_asm_policy_fetch
-short_description: Exports the asm policy from remote nodes.
-description:
- - Exports the asm policy from remote nodes.
-version_added: 2.8
-options:
- name:
- description:
- - The name of the policy exported to create a file on the remote device for downloading.
- type: str
- required: True
- dest:
- description:
- - A directory to save the policy file into.
- - This option is ignored when C(inline) is set to C(yes).
- type: path
- file:
- description:
- - The name of the file to be create on the remote device for downloading.
- - When C(binary) is set to C(no) the ASM policy will be in XML format.
- type: str
- inline:
- description:
- - If C(yes), the ASM policy will be exported C(inline) as a string instead of a file.
- - The policy can be be retrieved in playbook C(result) dictionary under C(inline_policy) key.
- type: bool
- compact:
- description:
- - If C(yes), only the ASM policy custom settings will be exported.
- - Only applies to XML type ASM policy exports.
- type: bool
- base64:
- description:
- - If C(yes), the returned C(inline) ASM policy content will be Base64 encoded.
- - Only applies to C(inline) ASM policy exports.
- type: bool
- binary:
- description:
- - If C(yes), the exported ASM policy will be in binary format.
- - Only applies to C(file) ASM policy exports.
- type: bool
- force:
- description:
- - If C(no), the file will only be transferred if it does not exist in the destination.
- default: yes
- type: bool
- partition:
- description:
- - Device partition which contains ASM policy to export.
- type: str
- default: Common
-extends_documentation_fragment: f5
-author:
- - Wojciech Wypior (@wojtek0806)
-'''
-
-EXAMPLES = r'''
-- name: Export policy in binary format
- bigip_asm_policy_fetch:
- name: foobar
- file: export_foo
- dest: /root/download
- binary: yes
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-
-- name: Export policy inline base64 encoded format
- bigip_asm_policy_fetch:
- name: foobar
- inline: yes
- base64: yes
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-
-- name: Export policy in XML format
- bigip_asm_policy_fetch:
- name: foobar
- file: export_foo
- dest: /root/download
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-
-- name: Export compact policy in XML format
- bigip_asm_policy_fetch:
- name: foobar
- file: export_foo.xml
- dest: /root/download/
- compact: yes
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-
-- name: Export policy in binary format, autogenerate name
- bigip_asm_policy_fetch:
- name: foobar
- dest: /root/download/
- binary: yes
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-'''
-
-RETURN = r'''
-name:
- description: Name of the ASM policy to be exported.
- returned: changed
- type: str
- sample: Asm_APP1_Transparent
-dest:
- description: Local path to download exported ASM policy.
- returned: changed
- type: str
- sample: /root/downloads/foobar.xml
-file:
- description:
- - Name of the policy file on the remote BIG-IP to download. If not
- specified, then this will be a randomly generated filename.
- returned: changed
- type: str
- sample: foobar.xml
-inline:
- description: Set when ASM policy to be exported inline
- returned: changed
- type: bool
- sample: yes
-compact:
- description: Set only to export custom ASM policy settings.
- returned: changed
- type: bool
- sample: no
-base64:
- description: Set to encode inline export in base64 format.
- returned: changed
- type: bool
- sample: no
-binary:
- description: Set to export ASM policy in binary format.
- returned: changed
- type: bool
- sample: yes
-'''
-
-import os
-import time
-import tempfile
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.basic import env_fallback
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import fq_name
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.common import flatten_boolean
- from library.module_utils.network.f5.icontrol import download_asm_file
- from library.module_utils.network.f5.icontrol import module_provisioned
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import fq_name
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.common import flatten_boolean
- from ansible.module_utils.network.f5.icontrol import download_asm_file
- from ansible.module_utils.network.f5.icontrol import module_provisioned
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'filename': 'file',
- 'minimal': 'compact',
- 'isBase64': 'base64',
- }
-
- api_attributes = [
- 'inline',
- 'minimal',
- 'isBase64',
- 'policyReference',
- 'filename',
- ]
-
- returnables = [
- 'file',
- 'compact',
- 'base64',
- 'inline',
- 'force',
- 'binary',
- 'dest',
- 'name',
- 'inline_policy',
- ]
-
- updatables = [
-
- ]
-
-
-class ApiParameters(Parameters):
- pass
-
-
-class ModuleParameters(Parameters):
- def _policy_exists(self):
- uri = 'https://{0}:{1}/mgmt/tm/asm/policies/'.format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- query = "?$filter=contains(name,'{0}')+and+contains(partition,'{1}')&$select=name,partition".format(
- self.want.name, self.want.partition
- )
- resp = self.client.api.get(uri + query)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if 'items' in response and response['items'] != []:
- return True
- return False
-
- @property
- def name(self):
- if self._policy_exists():
- return self._values['name']
- else:
- raise F5ModuleError(
- "The specified ASM policy {0} on partition {1} does not exist on device.".format(
- self._values['name'], self._values['partition']
- )
- )
-
- @property
- def file(self):
- if self._values['file'] is not None:
- return self._values['file']
- if self.binary:
- result = next(tempfile._get_candidate_names()) + '.plc'
- else:
- result = next(tempfile._get_candidate_names()) + '.xml'
- self._values['file'] = result
- return result
-
- @property
- def fulldest(self):
- result = None
- if os.path.isdir(self.dest):
- result = os.path.join(self.dest, self.file)
- else:
- if os.path.exists(os.path.dirname(self.dest)):
- result = self.dest
- else:
- try:
- # os.path.exists() can return false in some
- # circumstances where the directory does not have
- # the execute bit for the current user set, in
- # which case the stat() call will raise an OSError
- os.stat(os.path.dirname(result))
- except OSError as e:
- if "permission denied" in str(e).lower():
- raise F5ModuleError(
- "Destination directory {0} is not accessible".format(os.path.dirname(result))
- )
- raise F5ModuleError(
- "Destination directory {0} does not exist".format(os.path.dirname(result))
- )
-
- if not os.access(os.path.dirname(result), os.W_OK):
- raise F5ModuleError(
- "Destination {0} not writable".format(os.path.dirname(result))
- )
- return result
-
- @property
- def inline(self):
- result = flatten_boolean(self._values['inline'])
- if result == 'yes':
- return True
- elif result == 'no':
- return False
-
- @property
- def compact(self):
- result = flatten_boolean(self._values['compact'])
- if result == 'yes':
- return True
- elif result == 'no':
- return False
-
- @property
- def base64(self):
- result = flatten_boolean(self._values['base64'])
- if result == 'yes':
- return True
- elif result == 'no':
- return False
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class UsableChanges(Changes):
- pass
-
-
-class ReportableChanges(Changes):
- pass
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(params=self.module.params)
- self.changes = UsableChanges()
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = UsableChanges(params=changed)
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.client.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def exec_module(self):
- if not module_provisioned(self.client, 'asm'):
- raise F5ModuleError(
- "ASM must be provisioned to use this module."
- )
- result = dict()
-
- self.export()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=True))
- return result
-
- def export(self):
- if self.exists():
- return self.update()
- else:
- return self.create()
-
- def update(self):
- if not self.want.force:
- raise F5ModuleError(
- "File '{0}' already exists.".format(self.want.fulldest)
- )
- self.execute()
-
- def create(self):
- self._set_changed_options()
- if self.module.check_mode:
- return True
- if self.want.binary:
- self.export_binary()
- return True
- self.create_on_device()
- if not self.want.inline:
- self.execute()
- return True
-
- def export_binary(self):
- self.export_binary_on_device()
- self.execute()
- return True
-
- def download(self):
- self.download_from_device(self.want.fulldest)
- if os.path.exists(self.want.fulldest):
- return True
- raise F5ModuleError(
- "Failed to download the remote file."
- )
-
- def execute(self):
- self.download()
- self.remove_temp_policy_from_device()
- return True
-
- def exists(self):
- if not self.want.inline:
- if os.path.exists(self.want.fulldest):
- return True
- return False
-
- def create_on_device(self):
- self._set_policy_link()
- params = self.changes.api_params()
- uri = "https://{0}:{1}/mgmt/tm/asm/tasks/export-policy/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.post(uri, json=params)
-
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- result, output = self.wait_for_task(response['id'])
- if result and output:
- if 'file' in output:
- self.changes.update(dict(inline_policy=output['file']))
- if result:
- return True
-
- def wait_for_task(self, task_id):
- uri = "https://{0}:{1}/mgmt/tm/asm/tasks/export-policy/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- task_id
- )
- while True:
- resp = self.client.api.get(uri)
-
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- if response['status'] in ['COMPLETED', 'FAILURE']:
- break
- time.sleep(1)
-
- if response['status'] == 'FAILURE':
- raise F5ModuleError(
- 'Failed to export ASM policy.'
- )
- if response['status'] == 'COMPLETED':
- if not self.want.inline:
- return True, None
- else:
- return True, response['result']
-
- def _set_policy_link(self):
- policy_link = None
- uri = 'https://{0}:{1}/mgmt/tm/asm/policies/'.format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- query = "?$filter=contains(name,'{0}')+and+contains(partition,'{1}')&$select=name,partition".format(
- self.want.name, self.want.partition
- )
- resp = self.client.api.get(uri + query)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'items' in response and response['items'] != []:
- policy_link = response['items'][0]['selfLink']
-
- if not policy_link:
- raise F5ModuleError("The policy was not found")
-
- self.changes.update(dict(policyReference={'link': policy_link}))
- return True
-
- def export_binary_on_device(self):
- full_name = fq_name(self.want.partition, self.want.name)
- cmd = 'tmsh save asm policy {0} bin-file {1}'.format(full_name, self.want.file)
- uri = "https://{0}:{1}/mgmt/tm/util/bash/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- args = dict(
- command='run',
- utilCmdArgs='-c "{0}"'.format(cmd)
- )
- resp = self.client.api.post(uri, json=args)
-
- try:
- response = resp.json()
- if 'commandResult' in response:
- if 'Unexpected Error' in response['commandResult']:
- raise F5ModuleError(response['commandResult'])
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- self._move_binary_to_download()
-
- return True
-
- def _move_binary_to_download(self):
- name = '{0}~{1}'.format(self.client.provider['user'], self.want.file)
- move_path = '/var/tmp/{0} {1}/{2}'.format(
- self.want.file,
- '/ts/var/rest',
- name
- )
- params = dict(
- command='run',
- utilCmdArgs=move_path
- )
-
- uri = "https://{0}:{1}/mgmt/tm/util/unix-mv/".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
-
- resp = self.client.api.post(uri, json=params)
-
- try:
- response = resp.json()
- if 'commandResult' in response:
- if 'cannot stat' in response['commandResult']:
- raise F5ModuleError(response['commandResult'])
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- return True
-
- def download_from_device(self, dest):
- url = 'https://{0}:{1}/mgmt/tm/asm/file-transfer/downloads/{2}'.format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- self.want.file
- )
- try:
- download_asm_file(self.client, url, dest)
- except F5ModuleError:
- raise F5ModuleError(
- "Failed to download the file."
- )
- if os.path.exists(self.want.dest):
- return True
- return False
-
- def remove_temp_policy_from_device(self):
- name = '{0}~{1}'.format(self.client.provider['user'], self.want.file)
- tpath_name = '/ts/var/rest/{0}'.format(name)
- uri = "https://{0}:{1}/mgmt/tm/util/unix-rm/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- args = dict(
- command='run',
- utilCmdArgs=tpath_name
- )
- resp = self.client.api.post(uri, json=args)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- name=dict(
- required=True,
- ),
- dest=dict(
- type='path'
- ),
- file=dict(),
- inline=dict(
- type='bool'
- ),
- compact=dict(
- type='bool'
- ),
- base64=dict(
- type='bool'
- ),
- binary=dict(
- type='bool'
- ),
- force=dict(
- default='yes',
- type='bool'
- ),
- partition=dict(
- default='Common',
- fallback=(env_fallback, ['F5_PARTITION'])
- )
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
- self.mutually_exclusive = [
- ['binary', 'inline'],
- ['binary', 'compact'],
- ['dest', 'inline'],
- ['file', 'inline']
- ]
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode,
- mutually_exclusive=spec.mutually_exclusive,
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_asm_policy_import.py b/lib/ansible/modules/network/f5/bigip_asm_policy_import.py
deleted file mode 100644
index 46305fd7b6..0000000000
--- a/lib/ansible/modules/network/f5/bigip_asm_policy_import.py
+++ /dev/null
@@ -1,475 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2018, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_asm_policy_import
-short_description: Manage BIG-IP ASM policy imports
-description:
- - Manage BIG-IP ASM policies policy imports.
-version_added: 2.8
-options:
- name:
- description:
- - The ASM policy to create or override.
- type: str
- required: True
- inline:
- description:
- - When specified the ASM policy is created from a provided string.
- - Content needs to be provided in a valid XML format otherwise the operation will fail.
- type: str
- source:
- description:
- - Full path to a policy file to be imported into the BIG-IP ASM.
- - Policy files exported from newer versions of BIG-IP cannot be imported into older
- versions of BIG-IP. The opposite, however, is true; you can import older into
- newer.
- - The file format can be binary of XML.
- type: path
- force:
- description:
- - When set to C(yes) any existing policy with the same name will be overwritten by the new import.
- - Works for both inline and file imports, if the policy does not exist this setting is ignored.
- default: no
- type: bool
- partition:
- description:
- - Device partition to create policy on.
- type: str
- default: Common
-extends_documentation_fragment: f5
-author:
- - Wojciech Wypior (@wojtek0806)
-'''
-
-EXAMPLES = r'''
-- name: Import ASM policy
- bigip_asm_policy_import:
- name: new_asm_policy
- file: /root/asm_policy.xml
- provider:
- server: lb.mydomain.com
- user: admin
- password: secret
- delegate_to: localhost
-
-- name: Import ASM policy inline
- bigip_asm_policy_import:
- name: foo-policy4
- inline: <xml>content</xml>
- provider:
- server: lb.mydomain.com
- user: admin
- password: secret
- delegate_to: localhost
-
-- name: Override existing ASM policy
- bigip_asm_policy:
- name: new_asm_policy
- file: /root/asm_policy_new.xml
- force: yes
- provider:
- server: lb.mydomain.com
- user: admin
- password: secret
- delegate_to: localhost
-'''
-
-RETURN = r'''
-source:
- description: Local path to an ASM policy file.
- returned: changed
- type: str
- sample: /root/some_policy.xml
-inline:
- description: Contents of policy as an inline string
- returned: changed
- type: str
- sample: <xml>foobar contents</xml>
-name:
- description: Name of the ASM policy to be created/overwritten
- returned: changed
- type: str
- sample: Asm_APP1_Transparent
-force:
- description: Set when overwriting an existing policy
- returned: changed
- type: bool
- sample: yes
-'''
-
-import os
-import time
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.basic import env_fallback
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import fq_name
- from library.module_utils.network.f5.common import transform_name
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.icontrol import upload_file
- from library.module_utils.network.f5.icontrol import module_provisioned
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import fq_name
- from ansible.module_utils.network.f5.common import transform_name
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.icontrol import upload_file
- from ansible.module_utils.network.f5.icontrol import module_provisioned
-
-
-class Parameters(AnsibleF5Parameters):
- updatables = []
-
- returnables = [
- 'name',
- 'inline',
- 'source',
- 'force'
- ]
-
- api_attributes = [
- 'file',
- 'name',
- ]
-
- api_map = {
- 'file': 'inline',
- 'filename': 'source',
- }
-
-
-class ApiParameters(Parameters):
- pass
-
-
-class ModuleParameters(Parameters):
- pass
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class UsableChanges(Changes):
- pass
-
-
-class ReportableChanges(Changes):
- pass
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(params=self.module.params)
- self.changes = UsableChanges()
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = UsableChanges(params=changed)
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.client.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def exec_module(self):
- if not module_provisioned(self.client, 'asm'):
- raise F5ModuleError(
- "ASM must be provisioned to use this module."
- )
-
- result = dict()
-
- changed = self.policy_import()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def policy_import(self):
- self._set_changed_options()
- if self.module.check_mode:
- return True
- if self.exists():
- if self.want.force is False:
- return False
- if self.want.inline:
- task = self.inline_import()
- self.wait_for_task(task)
- return True
-
- self.import_file_to_device()
- self.remove_temp_policy_from_device()
- return True
-
- def exists(self):
- uri = 'https://{0}:{1}/mgmt/tm/asm/policies/'.format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
-
- query = "?$filter=contains(name,'{0}')+and+contains(partition,'{1}')&$select=name,partition".format(
- self.want.name, self.want.partition
- )
- resp = self.client.api.get(uri + query)
-
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if 'items' in response and response['items'] != []:
- return True
- return False
-
- def upload_file_to_device(self, content, name):
- url = 'https://{0}:{1}/mgmt/shared/file-transfer/uploads'.format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- try:
- upload_file(self.client, url, content, name)
- except F5ModuleError:
- raise F5ModuleError(
- "Failed to upload the file."
- )
-
- def _get_policy_link(self):
- uri = 'https://{0}:{1}/mgmt/tm/asm/policies/'.format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
-
- query = "?$filter=contains(name,'{0}')+and+contains(partition,'{1}')&$select=name,partition".format(
- self.want.name, self.want.partition
- )
- resp = self.client.api.get(uri + query)
-
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- policy_link = response['items'][0]['selfLink']
- return policy_link
-
- def inline_import(self):
- params = self.changes.api_params()
- uri = "https://{0}:{1}/mgmt/tm/asm/tasks/import-policy/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
-
- if self.want.force:
- params.update(dict(policyReference={'link': self._get_policy_link()}))
- params.pop('name')
-
- resp = self.client.api.post(uri, json=params)
-
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return response['id']
-
- def wait_for_task(self, task_id):
- uri = "https://{0}:{1}/mgmt/tm/asm/tasks/import-policy/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- task_id
- )
- while True:
- resp = self.client.api.get(uri)
-
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- if response['status'] in ['COMPLETED', 'FAILURE']:
- break
- time.sleep(1)
-
- if response['status'] == 'FAILURE':
- raise F5ModuleError(
- 'Failed to import ASM policy.'
- )
- if response['status'] == 'COMPLETED':
- return True
-
- def import_file_to_device(self):
- name = os.path.split(self.want.source)[1]
- self.upload_file_to_device(self.want.source, name)
- time.sleep(2)
-
- full_name = fq_name(self.want.partition, self.want.name)
-
- if self.want.force:
- cmd = 'tmsh load asm policy {0} file /var/config/rest/downloads/{1} overwrite'.format(full_name, name)
- else:
- cmd = 'tmsh load asm policy {0} file /var/config/rest/downloads/{1}'.format(full_name, name)
-
- uri = "https://{0}:{1}/mgmt/tm/util/bash/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- args = dict(
- command='run',
- utilCmdArgs='-c "{0}"'.format(cmd)
- )
- resp = self.client.api.post(uri, json=args)
-
- try:
- response = resp.json()
- if 'commandResult' in response:
- if 'Unexpected Error' in response['commandResult']:
- raise F5ModuleError(response['commandResult'])
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return True
-
- def remove_temp_policy_from_device(self):
- name = os.path.split(self.want.source)[1]
- tpath_name = '/var/config/rest/downloads/{0}'.format(name)
- uri = "https://{0}:{1}/mgmt/tm/util/unix-rm/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- args = dict(
- command='run',
- utilCmdArgs=tpath_name
- )
- resp = self.client.api.post(uri, json=args)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- name=dict(
- required=True,
- ),
- source=dict(type='path'),
- inline=dict(),
- force=dict(
- type='bool',
- default='no'
- ),
- partition=dict(
- default='Common',
- fallback=(env_fallback, ['F5_PARTITION'])
- )
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
- self.mutually_exclusive = [
- ['source', 'inline']
- ]
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode,
- mutually_exclusive=spec.mutually_exclusive
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_asm_policy_manage.py b/lib/ansible/modules/network/f5/bigip_asm_policy_manage.py
deleted file mode 100644
index 8ae317c474..0000000000
--- a/lib/ansible/modules/network/f5/bigip_asm_policy_manage.py
+++ /dev/null
@@ -1,892 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2018, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_asm_policy_manage
-short_description: Manage BIG-IP ASM policies
-description:
- - Manage BIG-IP ASM policies, create from templates and manage global policy settings.
-version_added: 2.8
-options:
- active:
- description:
- - If C(yes) will apply and activate existing inactive policy. If C(no), it will
- deactivate existing active policy. Generally should be C(yes) only in cases where
- you want to activate new or existing policy.
- default: no
- type: bool
- name:
- description:
- - The ASM policy to manage or create.
- type: str
- required: True
- state:
- description:
- - When C(state) is C(present), and C(template) parameter is provided,
- new ASM policy is created from template with the given policy C(name).
- - When C(state) is present and no C(template) parameter is provided
- new blank ASM policy is created with the given policy C(name).
- - When C(state) is C(absent), ensures that the policy is removed, even if it is
- currently active.
- type: str
- choices:
- - present
- - absent
- default: present
- template:
- description:
- - An ASM policy built-in template. If the template does not exist we will raise an error.
- - Once the policy has been created, this value cannot change.
- - The C(Comprehensive), C(Drupal), C(Fundamental), C(Joomla),
- C(Vulnerability Assessment Baseline), and C(Wordpress) templates are only available
- on BIG-IP versions >= 13.
- type: str
- choices:
- - ActiveSync v1.0 v2.0 (http)
- - ActiveSync v1.0 v2.0 (https)
- - Comprehensive
- - Drupal
- - Fundamental
- - Joomla
- - LotusDomino 6.5 (http)
- - LotusDomino 6.5 (https)
- - OWA Exchange 2003 (http)
- - OWA Exchange 2003 (https)
- - OWA Exchange 2003 with ActiveSync (http)
- - OWA Exchange 2003 with ActiveSync (https)
- - OWA Exchange 2007 (http)
- - OWA Exchange 2007 (https)
- - OWA Exchange 2007 with ActiveSync (http)
- - OWA Exchange 2007 with ActiveSync (https)
- - OWA Exchange 2010 (http)
- - OWA Exchange 2010 (https)
- - Oracle 10g Portal (http)
- - Oracle 10g Portal (https)
- - Oracle Applications 11i (http)
- - Oracle Applications 11i (https)
- - PeopleSoft Portal 9 (http)
- - PeopleSoft Portal 9 (https)
- - Rapid Deployment Policy
- - SAP NetWeaver 7 (http)
- - SAP NetWeaver 7 (https)
- - SharePoint 2003 (http)
- - SharePoint 2003 (https)
- - SharePoint 2007 (http)
- - SharePoint 2007 (https)
- - SharePoint 2010 (http)
- - SharePoint 2010 (https)
- - Vulnerability Assessment Baseline
- - Wordpress
- partition:
- description:
- - Device partition to manage resources on.
- type: str
- default: Common
-extends_documentation_fragment: f5
-author:
- - Wojciech Wypior (@wojtek0806)
-'''
-
-EXAMPLES = r'''
-- name: Create ASM policy from template
- bigip_asm_policy:
- name: new_sharepoint_policy
- template: SharePoint 2007 (http)
- state: present
- provider:
- server: lb.mydomain.com
- user: admin
- password: secret
- delegate_to: localhost
-
-- name: Create blank ASM policy
- bigip_asm_policy:
- name: new_blank_policy
- state: present
- provider:
- server: lb.mydomain.com
- user: admin
- password: secret
- delegate_to: localhost
-
-- name: Create blank ASM policy and activate
- bigip_asm_policy:
- name: new_blank_policy
- active: yes
- state: present
- provider:
- server: lb.mydomain.com
- user: admin
- password: secret
- delegate_to: localhost
-
-- name: Activate ASM policy
- bigip_asm_policy:
- name: inactive_policy
- active: yes
- state: present
- provider:
- server: lb.mydomain.com
- user: admin
- password: secret
- delegate_to: localhost
-
-- name: Deactivate ASM policy
- bigip_asm_policy_manage:
- name: active_policy
- state: present
- provider:
- server: lb.mydomain.com
- user: admin
- password: secret
- delegate_to: localhost
-'''
-
-RETURN = r'''
-active:
- description: Set when activating/deactivating ASM policy
- returned: changed
- type: bool
- sample: yes
-state:
- description: Action performed on the target device.
- returned: changed
- type: str
- sample: absent
-template:
- description: Name of the built-in ASM policy template
- returned: changed
- type: str
- sample: OWA Exchange 2007 (https)
-name:
- description: Name of the ASM policy to be managed/created
- returned: changed
- type: str
- sample: Asm_APP1_Transparent
-'''
-
-import time
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.basic import env_fallback
-from distutils.version import LooseVersion
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import fq_name
- from library.module_utils.network.f5.common import transform_name
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.icontrol import tmos_version
- from library.module_utils.network.f5.icontrol import module_provisioned
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import fq_name
- from ansible.module_utils.network.f5.common import transform_name
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.icontrol import tmos_version
- from ansible.module_utils.network.f5.icontrol import module_provisioned
-
-
-class Parameters(AnsibleF5Parameters):
- updatables = [
- 'active',
- ]
-
- returnables = [
- 'name',
- 'template',
- 'active',
- ]
-
- api_attributes = [
- 'name',
- 'active',
- ]
- api_map = {
- }
-
- @property
- def template_link(self):
- if self._values['template_link'] is not None:
- return self._values['template_link']
-
- result = None
-
- uri = "https://{0}:{1}/mgmt/tm/asm/policy-templates/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
-
- query = "?$filter=contains(name,'{0}')".format(self.template.upper())
- resp = self.client.api.get(uri + query)
-
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- if 'items' in response and response['items'] != []:
- result = dict(link=response['items'][0]['selfLink'])
-
- return result
-
- def to_return(self):
- result = {}
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- return result
-
-
-class V1Parameters(Parameters):
- @property
- def template(self):
- if self._values['template'] is None:
- return None
- template_map = {
- 'ActiveSync v1.0 v2.0 (http)': 'POLICY_TEMPLATE_ACTIVESYNC_V1_0_V2_0_HTTP',
- 'ActiveSync v1.0 v2.0 (https)': 'POLICY_TEMPLATE_ACTIVESYNC_V1_0_V2_0_HTTPS',
- 'LotusDomino 6.5 (http)': 'POLICY_TEMPLATE_LOTUSDOMINO_6_5_HTTP',
- 'LotusDomino 6.5 (https)': 'POLICY_TEMPLATE_LOTUSDOMINO_6_5_HTTPS',
- 'OWA Exchange 2003 (http)': 'POLICY_TEMPLATE_OWA_EXCHANGE_2003_HTTP',
- 'OWA Exchange 2003 (https)': 'POLICY_TEMPLATE_OWA_EXCHANGE_2003_HTTPS',
- 'OWA Exchange 2003 with ActiveSync (http)': 'POLICY_TEMPLATE_OWA_EXCHANGE_2003_WITH_ACTIVESYNC_HTTP',
- 'OWA Exchange 2003 with ActiveSync (https)': 'POLICY_TEMPLATE_OWA_EXCHANGE_2003_WITH_ACTIVESYNC_HTTPS',
- 'OWA Exchange 2007 (http)': 'POLICY_TEMPLATE_OWA_EXCHANGE_2007_HTTP',
- 'OWA Exchange 2007 (https)': 'POLICY_TEMPLATE_OWA_EXCHANGE_2007_HTTPS',
- 'OWA Exchange 2007 with ActiveSync (http)': 'POLICY_TEMPLATE_OWA_EXCHANGE_2007_WITH_ACTIVESYNC_HTTP',
- 'OWA Exchange 2007 with ActiveSync (https)': 'POLICY_TEMPLATE_OWA_EXCHANGE_2007_WITH_ACTIVESYNC_HTTPS',
- 'OWA Exchange 2010 (http)': 'POLICY_TEMPLATE_OWA_EXCHANGE_2010_HTTP',
- 'OWA Exchange 2010 (https)': 'POLICY_TEMPLATE_OWA_EXCHANGE_2010_HTTPS',
- 'Oracle 10g Portal (http)': 'POLICY_TEMPLATE_ORACLE_10G_PORTAL_HTTP',
- 'Oracle 10g Portal (https)': 'POLICY_TEMPLATE_ORACLE_10G_PORTAL_HTTPS',
- 'Oracle Applications 11i (http)': 'POLICY_TEMPLATE_ORACLE_APPLICATIONS_11I_HTTP',
- 'Oracle Applications 11i (https)': 'POLICY_TEMPLATE_ORACLE_APPLICATIONS_11I_HTTPS',
- 'PeopleSoft Portal 9 (http)': 'POLICY_TEMPLATE_PEOPLESOFT_PORTAL_9_HTTP',
- 'PeopleSoft Portal 9 (https)': 'POLICY_TEMPLATE_PEOPLESOFT_PORTAL_9_HTTPS',
- 'Rapid Deployment Policy': 'POLICY_TEMPLATE_RAPID_DEPLOYMENT',
- 'SAP NetWeaver 7 (http)': 'POLICY_TEMPLATE_SAP_NETWEAVER_7_HTTP',
- 'SAP NetWeaver 7 (https)': 'POLICY_TEMPLATE_SAP_NETWEAVER_7_HTTPS',
- 'SharePoint 2003 (http)': 'POLICY_TEMPLATE_SHAREPOINT_2003_HTTP',
- 'SharePoint 2003 (https)': 'POLICY_TEMPLATE_SHAREPOINT_2003_HTTPS',
- 'SharePoint 2007 (http)': 'POLICY_TEMPLATE_SHAREPOINT_2007_HTTP',
- 'SharePoint 2007 (https)': 'POLICY_TEMPLATE_SHAREPOINT_2007_HTTPS',
- 'SharePoint 2010 (http)': 'POLICY_TEMPLATE_SHAREPOINT_2010_HTTP',
- 'SharePoint 2010 (https)': 'POLICY_TEMPLATE_SHAREPOINT_2010_HTTPS'
- }
- if self._values['template'] in template_map:
- return template_map[self._values['template']]
- else:
- raise F5ModuleError(
- "The specified template is not valid for this version of BIG-IP."
- )
-
-
-class V2Parameters(Parameters):
- @property
- def template(self):
- if self._values['template'] is None:
- return None
- template_map = {
- 'ActiveSync v1.0 v2.0 (http)': 'POLICY_TEMPLATE_ACTIVESYNC_V1_0_V2_0_HTTP',
- 'ActiveSync v1.0 v2.0 (https)': 'POLICY_TEMPLATE_ACTIVESYNC_V1_0_V2_0_HTTPS',
- 'Comprehensive': 'POLICY_TEMPLATE_COMPREHENSIVE', # v13
- 'Drupal': 'POLICY_TEMPLATE_DRUPAL', # v13
- 'Fundamental': 'POLICY_TEMPLATE_FUNDAMENTAL', # v13
- 'Joomla': 'POLICY_TEMPLATE_JOOMLA', # v13
- 'LotusDomino 6.5 (http)': 'POLICY_TEMPLATE_LOTUSDOMINO_6_5_HTTP',
- 'LotusDomino 6.5 (https)': 'POLICY_TEMPLATE_LOTUSDOMINO_6_5_HTTPS',
- 'OWA Exchange 2003 (http)': 'POLICY_TEMPLATE_OWA_EXCHANGE_2003_HTTP',
- 'OWA Exchange 2003 (https)': 'POLICY_TEMPLATE_OWA_EXCHANGE_2003_HTTPS',
- 'OWA Exchange 2003 with ActiveSync (http)': 'POLICY_TEMPLATE_OWA_EXCHANGE_2003_WITH_ACTIVESYNC_HTTP',
- 'OWA Exchange 2003 with ActiveSync (https)': 'POLICY_TEMPLATE_OWA_EXCHANGE_2003_WITH_ACTIVESYNC_HTTPS',
- 'OWA Exchange 2007 (http)': 'POLICY_TEMPLATE_OWA_EXCHANGE_2007_HTTP',
- 'OWA Exchange 2007 (https)': 'POLICY_TEMPLATE_OWA_EXCHANGE_2007_HTTPS',
- 'OWA Exchange 2007 with ActiveSync (http)': 'POLICY_TEMPLATE_OWA_EXCHANGE_2007_WITH_ACTIVESYNC_HTTP',
- 'OWA Exchange 2007 with ActiveSync (https)': 'POLICY_TEMPLATE_OWA_EXCHANGE_2007_WITH_ACTIVESYNC_HTTPS',
- 'OWA Exchange 2010 (http)': 'POLICY_TEMPLATE_OWA_EXCHANGE_2010_HTTP',
- 'OWA Exchange 2010 (https)': 'POLICY_TEMPLATE_OWA_EXCHANGE_2010_HTTPS',
- 'Oracle 10g Portal (http)': 'POLICY_TEMPLATE_ORACLE_10G_PORTAL_HTTP',
- 'Oracle 10g Portal (https)': 'POLICY_TEMPLATE_ORACLE_10G_PORTAL_HTTPS',
- 'Oracle Applications 11i (http)': 'POLICY_TEMPLATE_ORACLE_APPLICATIONS_11I_HTTP',
- 'Oracle Applications 11i (https)': 'POLICY_TEMPLATE_ORACLE_APPLICATIONS_11I_HTTPS',
- 'PeopleSoft Portal 9 (http)': 'POLICY_TEMPLATE_PEOPLESOFT_PORTAL_9_HTTP',
- 'PeopleSoft Portal 9 (https)': 'POLICY_TEMPLATE_PEOPLESOFT_PORTAL_9_HTTPS',
- 'Rapid Deployment Policy': 'POLICY_TEMPLATE_RAPID_DEPLOYMENT',
- 'SAP NetWeaver 7 (http)': 'POLICY_TEMPLATE_SAP_NETWEAVER_7_HTTP',
- 'SAP NetWeaver 7 (https)': 'POLICY_TEMPLATE_SAP_NETWEAVER_7_HTTPS',
- 'SharePoint 2003 (http)': 'POLICY_TEMPLATE_SHAREPOINT_2003_HTTP',
- 'SharePoint 2003 (https)': 'POLICY_TEMPLATE_SHAREPOINT_2003_HTTPS',
- 'SharePoint 2007 (http)': 'POLICY_TEMPLATE_SHAREPOINT_2007_HTTP',
- 'SharePoint 2007 (https)': 'POLICY_TEMPLATE_SHAREPOINT_2007_HTTPS',
- 'SharePoint 2010 (http)': 'POLICY_TEMPLATE_SHAREPOINT_2010_HTTP',
- 'SharePoint 2010 (https)': 'POLICY_TEMPLATE_SHAREPOINT_2010_HTTPS',
- 'Vulnerability Assessment Baseline': 'POLICY_TEMPLATE_VULNERABILITY_ASSESSMENT', # v13
- 'Wordpress': 'POLICY_TEMPLATE_WORDPRESS' # v13
- }
- return template_map[self._values['template']]
-
-
-class Changes(Parameters):
- @property
- def template(self):
- if self._values['template'] is None:
- return None
- template_map = {
- 'POLICY_TEMPLATE_ACTIVESYNC_V1_0_V2_0_HTTP': 'ActiveSync v1.0 v2.0 (http)',
- 'POLICY_TEMPLATE_ACTIVESYNC_V1_0_V2_0_HTTPS': 'ActiveSync v1.0 v2.0 (https)',
- 'POLICY_TEMPLATE_COMPREHENSIVE': 'Comprehensive',
- 'POLICY_TEMPLATE_DRUPAL': 'Drupal',
- 'POLICY_TEMPLATE_FUNDAMENTAL': 'Fundamental',
- 'POLICY_TEMPLATE_JOOMLA': 'Joomla',
- 'POLICY_TEMPLATE_LOTUSDOMINO_6_5_HTTP': 'LotusDomino 6.5 (http)',
- 'POLICY_TEMPLATE_LOTUSDOMINO_6_5_HTTPS': 'LotusDomino 6.5 (https)',
- 'POLICY_TEMPLATE_OWA_EXCHANGE_2003_HTTP': 'OWA Exchange 2003 (http)',
- 'POLICY_TEMPLATE_OWA_EXCHANGE_2003_HTTPS': 'OWA Exchange 2003 (https)',
- 'POLICY_TEMPLATE_OWA_EXCHANGE_2003_WITH_ACTIVESYNC_HTTP': 'OWA Exchange 2003 with ActiveSync (http)',
- 'POLICY_TEMPLATE_OWA_EXCHANGE_2003_WITH_ACTIVESYNC_HTTPS': 'OWA Exchange 2003 with ActiveSync (https)',
- 'POLICY_TEMPLATE_OWA_EXCHANGE_2007_HTTP': 'OWA Exchange 2007 (http)',
- 'POLICY_TEMPLATE_OWA_EXCHANGE_2007_HTTPS': 'OWA Exchange 2007 (https)',
- 'POLICY_TEMPLATE_OWA_EXCHANGE_2007_WITH_ACTIVESYNC_HTTP': 'OWA Exchange 2007 with ActiveSync (http)',
- 'POLICY_TEMPLATE_OWA_EXCHANGE_2007_WITH_ACTIVESYNC_HTTPS': 'OWA Exchange 2007 with ActiveSync (https)',
- 'POLICY_TEMPLATE_OWA_EXCHANGE_2010_HTTP': 'OWA Exchange 2010 (http)',
- 'POLICY_TEMPLATE_OWA_EXCHANGE_2010_HTTPS': 'OWA Exchange 2010 (https)',
- 'POLICY_TEMPLATE_ORACLE_10G_PORTAL_HTTP': 'Oracle 10g Portal (http)',
- 'POLICY_TEMPLATE_ORACLE_10G_PORTAL_HTTPS': 'Oracle 10g Portal (https)',
- 'POLICY_TEMPLATE_ORACLE_APPLICATIONS_11I_HTTP': 'Oracle Applications 11i (http)',
- 'POLICY_TEMPLATE_ORACLE_APPLICATIONS_11I_HTTPS': 'Oracle Applications 11i (https)',
- 'POLICY_TEMPLATE_PEOPLESOFT_PORTAL_9_HTTP': 'PeopleSoft Portal 9 (http)',
- 'POLICY_TEMPLATE_PEOPLESOFT_PORTAL_9_HTTPS': 'PeopleSoft Portal 9 (https)',
- 'POLICY_TEMPLATE_RAPID_DEPLOYMENT': 'Rapid Deployment Policy',
- 'POLICY_TEMPLATE_SAP_NETWEAVER_7_HTTP': 'SAP NetWeaver 7 (http)',
- 'POLICY_TEMPLATE_SAP_NETWEAVER_7_HTTPS': 'SAP NetWeaver 7 (https)',
- 'POLICY_TEMPLATE_SHAREPOINT_2003_HTTP': 'SharePoint 2003 (http)',
- 'POLICY_TEMPLATE_SHAREPOINT_2003_HTTPS': 'SharePoint 2003 (https)',
- 'POLICY_TEMPLATE_SHAREPOINT_2007_HTTP': 'SharePoint 2007 (http)',
- 'POLICY_TEMPLATE_SHAREPOINT_2007_HTTPS': 'SharePoint 2007 (https)',
- 'POLICY_TEMPLATE_SHAREPOINT_2010_HTTP': 'SharePoint 2010 (http)',
- 'POLICY_TEMPLATE_SHAREPOINT_2010_HTTPS': 'SharePoint 2010 (https)',
- 'POLICY_TEMPLATE_VULNERABILITY_ASSESSMENT': 'Vulnerability Assessment Baseline',
- 'POLICY_TEMPLATE_WORDPRESS': 'Wordpress',
- }
- return template_map[self._values['template']]
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
- @property
- def active(self):
- if self.want.active is True and self.have.active is False:
- return True
- if self.want.active is False and self.have.active is True:
- return False
-
-
-class BaseManager(object):
- def __init__(self, *args, **kwargs):
- self.client = kwargs.get('client', None)
- self.module = kwargs.get('module', None)
- self.have = None
- self.changes = Changes()
-
- def exec_module(self):
- changed = False
- result = dict()
- state = self.want.state
-
- if state == "present":
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
-
- changes = self.changes.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- return result
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = Changes(params=changed)
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = Changes(params=changed)
- return True
- return False
-
- def present(self):
- if self.exists():
- return self.update()
- else:
- return self.create()
-
- def absent(self):
- if not self.exists():
- return False
- else:
- return self.remove()
-
- def create(self):
- if self.want.active is None:
- self.want.update(dict(active=False))
- self._set_changed_options()
- if self.module.check_mode:
- return True
-
- if self.want.template is not None:
- self.create_from_template()
- if self.want.template is None:
- self.create_blank()
- if self.want.active:
- self.activate()
- return True
- else:
- return True
-
- def update(self):
- self.have = self.read_current_from_device()
- if not self.should_update():
- return False
- if self.module.check_mode:
- return True
- self.update_on_device()
- if self.changes.active:
- self.activate()
- return True
-
- def activate(self):
- self.have = self.read_current_from_device()
- task_id = self.apply_on_device()
- if self.wait_for_task(task_id):
- return True
- else:
- raise F5ModuleError('Apply policy task failed.')
-
- def create_blank(self):
- self.create_on_device()
- if self.exists():
- return True
- else:
- raise F5ModuleError(
- 'Failed to create ASM policy: {0}'.format(self.want.name)
- )
-
- def remove(self):
- if self.module.check_mode:
- return True
- self.remove_from_device()
- if self.exists():
- raise F5ModuleError(
- 'Failed to delete ASM policy: {0}'.format(self.want.name)
- )
- return True
-
- def is_activated(self):
- if self.want.active is True:
- return True
- else:
- return False
-
- def exists(self):
- uri = 'https://{0}:{1}/mgmt/tm/asm/policies/'.format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
-
- query = "?$filter=contains(name,'{0}')+and+contains(partition,'{1}')&$select=name,partition".format(
- self.want.name, self.want.partition
- )
- resp = self.client.api.get(uri + query)
-
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if 'items' in response and response['items'] != []:
- return True
- return False
-
- def wait_for_task(self, task_id):
- uri = "https://{0}:{1}/mgmt/tm/asm/tasks/apply-policy/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- task_id
- )
- while True:
- resp = self.client.api.get(uri)
-
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- if response['status'] in ['COMPLETED', 'FAILURE']:
- break
- time.sleep(1)
-
- if response['status'] == 'FAILURE':
- return False
- if response['status'] == 'COMPLETED':
- return True
-
- def _get_policy_id(self):
- policy_id = None
- uri = "https://{0}:{1}/mgmt/tm/asm/policies/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- query = "?$filter=contains(name,'{0}')+and+contains(partition,'{1}')&$select=name,id".format(
- self.want.name, self.want.partition
- )
- resp = self.client.api.get(uri + query)
-
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'items' in response and response['items'] != []:
- policy_id = response['items'][0]['id']
- if not policy_id:
- raise F5ModuleError("The policy was not found")
-
- return policy_id
-
- def update_on_device(self):
- params = self.changes.api_params()
- policy_id = self._get_policy_id()
- uri = "https://{0}:{1}/mgmt/tm/asm/policies/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- policy_id
- )
- if not params['active']:
- resp = self.client.api.patch(uri, json=params)
-
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def read_current_from_device(self):
- policy_id = self._get_policy_id()
- uri = "https://{0}:{1}/mgmt/tm/asm/policies/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- policy_id
- )
- resp = self.client.api.get(uri)
-
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- response.update((dict(self_link=response['selfLink'])))
-
- return Parameters(params=response)
-
- def apply_on_device(self):
- uri = "https://{0}:{1}/mgmt/tm/asm/tasks/apply-policy/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- params = dict(policyReference={'link': self.have.self_link})
- resp = self.client.api.post(uri, json=params)
-
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return response['id']
-
- def create_from_template_on_device(self):
- full_name = fq_name(self.want.partition, self.want.name)
- cmd = 'tmsh create asm policy {0} policy-template {1}'.format(full_name, self.want.template)
- uri = "https://{0}:{1}/mgmt/tm/util/bash/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- args = dict(
- command='run',
- utilCmdArgs='-c "{0}"'.format(cmd)
- )
- resp = self.client.api.post(uri, json=args)
-
- try:
- response = resp.json()
- if 'commandResult' in response:
- if 'Unexpected Error' in response['commandResult']:
- raise F5ModuleError(response['commandResult'])
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def create_on_device(self):
- params = self.changes.api_params()
- params['name'] = self.want.name
- params['partition'] = self.want.partition
- # we need to remove active from params as API will raise an error if the active is set to True,
- # policies can only be activated via apply-policy task endpoint.
- params.pop('active')
- uri = "https://{0}:{1}/mgmt/tm/asm/policies/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.post(uri, json=params)
-
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 401, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- time.sleep(2)
- return True
-
- def remove_from_device(self):
- policy_id = self._get_policy_id()
- uri = "https://{0}:{1}/mgmt/tm/asm/policies/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- policy_id
- )
- response = self.client.api.delete(uri)
- if response.status in [200, 201]:
- return True
- raise F5ModuleError(response.content)
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.kwargs = kwargs
-
- def exec_module(self):
- if not module_provisioned(self.client, 'asm'):
- raise F5ModuleError(
- "ASM must be provisioned to use this module."
- )
- if self.version_is_less_than_13():
- manager = self.get_manager('v1')
- else:
- manager = self.get_manager('v2')
- return manager.exec_module()
-
- def get_manager(self, type):
- if type == 'v1':
- return V1Manager(**self.kwargs)
- elif type == 'v2':
- return V2Manager(**self.kwargs)
-
- def version_is_less_than_13(self):
- version = tmos_version(self.client)
- if LooseVersion(version) < LooseVersion('13.0.0'):
- return True
- else:
- return False
-
-
-class V1Manager(BaseManager):
- def __init__(self, *args, **kwargs):
- module = kwargs.get('module', None)
- client = F5RestClient(**module.params)
- super(V1Manager, self).__init__(client=client, module=module)
- self.want = V1Parameters(params=module.params, client=client)
-
- def create_from_template(self):
- self.create_from_template_on_device()
-
-
-class V2Manager(BaseManager):
- def __init__(self, *args, **kwargs):
- module = kwargs.get('module', None)
- client = F5RestClient(**module.params)
- super(V2Manager, self).__init__(client=client, module=module)
- self.want = V2Parameters(params=module.params, client=client)
-
- # TODO Include creating ASM policies from custom templates in v13
-
- def create_from_template(self):
- if not self.create_from_template_on_device():
- return False
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.template_map = [
- 'ActiveSync v1.0 v2.0 (http)',
- 'ActiveSync v1.0 v2.0 (https)',
- 'Comprehensive',
- 'Drupal',
- 'Fundamental',
- 'Joomla',
- 'LotusDomino 6.5 (http)',
- 'LotusDomino 6.5 (https)',
- 'OWA Exchange 2003 (http)',
- 'OWA Exchange 2003 (https)',
- 'OWA Exchange 2003 with ActiveSync (http)',
- 'OWA Exchange 2003 with ActiveSync (https)',
- 'OWA Exchange 2007 (http)',
- 'OWA Exchange 2007 (https)',
- 'OWA Exchange 2007 with ActiveSync (http)',
- 'OWA Exchange 2007 with ActiveSync (https)',
- 'OWA Exchange 2010 (http)',
- 'OWA Exchange 2010 (https)',
- 'Oracle 10g Portal (http)',
- 'Oracle 10g Portal (https)',
- 'Oracle Applications 11i (http)',
- 'Oracle Applications 11i (https)',
- 'PeopleSoft Portal 9 (http)',
- 'PeopleSoft Portal 9 (https)',
- 'Rapid Deployment Policy',
- 'SAP NetWeaver 7 (http)',
- 'SAP NetWeaver 7 (https)',
- 'SharePoint 2003 (http)',
- 'SharePoint 2003 (https)',
- 'SharePoint 2007 (http)',
- 'SharePoint 2007 (https)',
- 'SharePoint 2010 (http)',
- 'SharePoint 2010 (https)',
- 'Vulnerability Assessment Baseline',
- 'Wordpress',
- ]
- self.supports_check_mode = True
- argument_spec = dict(
- name=dict(
- required=True,
- ),
- template=dict(
- choices=self.template_map
- ),
- active=dict(
- type='bool',
- default='no'
- ),
- state=dict(
- default='present',
- choices=['present', 'absent']
- ),
- partition=dict(
- default='Common',
- fallback=(env_fallback, ['F5_PARTITION'])
- )
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode,
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_asm_policy_server_technology.py b/lib/ansible/modules/network/f5/bigip_asm_policy_server_technology.py
deleted file mode 100644
index f3adea0144..0000000000
--- a/lib/ansible/modules/network/f5/bigip_asm_policy_server_technology.py
+++ /dev/null
@@ -1,482 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2018, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_asm_policy_server_technology
-short_description: Manages Server Technology on ASM policy
-description:
- - Manages Server Technology on ASM policy.
-version_added: 2.8
-options:
- name:
- description:
- - Specifies the name of the server technology to apply on or remove from the ASM policy.
- type: str
- required: True
- choices:
- - jQuery
- - Java Servlets/JSP
- - ASP
- - WebDAV
- - IIS
- - Front Page Server Extensions (FPSE)
- - ASP.NET
- - Microsoft Windows
- - Unix/Linux
- - Macromedia ColdFusion
- - WordPress
- - Apache Tomcat
- - Apache/NCSA HTTP Server
- - Outlook Web Access
- - PHP
- - Microsoft SQL Server
- - Oracle
- - MySQL
- - Lotus Domino
- - BEA Systems WebLogic Server
- - Macromedia JRun
- - Novell
- - Cisco
- - SSI (Server Side Includes)
- - Proxy Servers
- - CGI
- - Sybase/ASE
- - IBM DB2
- - PostgreSQL
- - XML
- - Apache Struts
- - Elasticsearch
- - JBoss
- - Citrix
- - Node.js
- - Django
- - MongoDB
- - Ruby
- - JavaServer Faces (JSF)
- - Joomla
- - Jetty
- policy_name:
- description:
- - Specifies the name of an existing ASM policy to add or remove server technology.
- type: str
- required: True
- state:
- description:
- - When C(present), ensures that the resource exists.
- - When C(absent), ensures the resource is removed.
- type: str
- default: present
- choices:
- - present
- - absent
- partition:
- description:
- - This parameter is only used when identifying ASM policy.
- type: str
- default: Common
-notes:
- - This module is primarily used as a component of configuring ASM policy in Ansible Galaxy ASM Policy Role.
- - Requires BIG-IP >= 13.0.0
-extends_documentation_fragment: f5
-author:
- - Wojciech Wypior (@wojtek0806)
-'''
-
-EXAMPLES = r'''
-- name: Add Server Technology to ASM Policy
- bigip_asm_policy_server_technology:
- name: Joomla
- policy_name: FooPolicy
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-- name: Remove Server Technology from ASM Policy
- bigip_asm_policy_server_technology:
- name: Joomla
- policy_name: FooPolicy
- state: absent
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-'''
-
-RETURN = r'''
-policy_name:
- description: The name of the ASM policy
- returned: changed
- type: str
- sample: FooPolicy
-name:
- description: The name of Server Technology added/removed on ASM policy
- returned: changed
- type: str
- sample: Joomla
-'''
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.basic import env_fallback
-from distutils.version import LooseVersion
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import fq_name
- from library.module_utils.network.f5.common import transform_name
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.icontrol import tmos_version
- from library.module_utils.network.f5.icontrol import module_provisioned
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import fq_name
- from ansible.module_utils.network.f5.common import transform_name
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.icontrol import tmos_version
- from ansible.module_utils.network.f5.icontrol import module_provisioned
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
-
- }
-
- api_attributes = [
-
- ]
-
- returnables = [
- 'policy_name',
- 'name'
-
- ]
-
- updatables = [
-
- ]
-
-
-class ApiParameters(Parameters):
- pass
-
-
-class ModuleParameters(Parameters):
- pass
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class UsableChanges(Changes):
- pass
-
-
-class ReportableChanges(Changes):
- pass
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(params=self.module.params)
- self.have = ApiParameters()
- self.changes = UsableChanges()
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.client.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = Changes(params=changed)
-
- def exec_module(self):
- if not module_provisioned(self.client, 'asm'):
- raise F5ModuleError(
- "ASM must be provisioned to use this module."
- )
- if self.version_is_less_than_13():
- raise F5ModuleError(
- "This module requires TMOS version 13.x and above."
- )
-
- changed = False
- result = dict()
- state = self.want.state
-
- if state == "present":
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def version_is_less_than_13(self):
- version = tmos_version(self.client)
- if LooseVersion(version) < LooseVersion('13.0.0'):
- return True
- else:
- return False
-
- def present(self):
- if self.exists():
- return False
- else:
- return self.create()
-
- def absent(self):
- if self.exists():
- return self.remove()
- return False
-
- def remove(self):
- if self.module.check_mode:
- return True
- self.remove_from_device()
- if self.exists():
- raise F5ModuleError("Failed to delete the resource.")
- return True
-
- def create(self):
- self._set_changed_options()
- if self.module.check_mode:
- return True
- self.create_on_device()
- return True
-
- def exists(self):
- policy_id = self._get_policy_id()
- server_link = self._get_server_tech_link()
- uri = 'https://{0}:{1}/mgmt/tm/asm/policies/{2}/server-technologies/'.format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- policy_id,
- )
- resp = self.client.api.get(uri)
-
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if 'items' in response and response['items'] != []:
- for st in response['items']:
- if st['serverTechnologyReference']['link'] == server_link:
- self.want.tech_id = st['id']
- return True
- return False
-
- def _get_policy_id(self):
- policy_id = None
- uri = "https://{0}:{1}/mgmt/tm/asm/policies/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- query = "?$filter=contains(name,'{0}')+and+contains(partition,'{1}')&$select=name,id".format(
- self.want.policy_name, self.want.partition
- )
- resp = self.client.api.get(uri + query)
-
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'items' in response and response['items'] != []:
- policy_id = response['items'][0]['id']
-
- if not policy_id:
- raise F5ModuleError(
- "The policy with the name {0} does not exist".format(self.want.policy_name)
- )
- return policy_id
-
- def _get_server_tech_link(self):
- link = None
- uri = "https://{0}:{1}/mgmt/tm/asm/server-technologies/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- query = "?$filter=contains(serverTechnologyName,'{0}')".format(self.want.name)
- resp = self.client.api.get(uri + query)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 409, 404]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- if 'items' in response:
- link = response['items'][0]['selfLink']
- return link
- return link
-
- def create_on_device(self):
- policy_id = self._get_policy_id()
-
- uri = "https://{0}:{1}/mgmt/tm/asm/policies/{2}/server-technologies/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- policy_id
- )
-
- params = dict(serverTechnologyReference={'link': self._get_server_tech_link()})
- resp = self.client.api.post(uri, json=params)
-
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 409]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return True
-
- def remove_from_device(self):
- policy_id = self._get_policy_id()
- tech_id = self.want.tech_id
- uri = 'https://{0}:{1}/mgmt/tm/asm/policies/{2}/server-technologies/{3}'.format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- policy_id,
- tech_id,
- )
- response = self.client.api.delete(uri)
- if response.status in [200, 201]:
- return True
- raise F5ModuleError(response.content)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- self.tech = [
- 'jQuery',
- 'Java Servlets/JSP',
- 'ASP',
- 'WebDAV',
- 'IIS',
- 'Front Page Server Extensions (FPSE)',
- 'ASP.NET',
- 'Microsoft Windows',
- 'Unix/Linux',
- 'Macromedia ColdFusion',
- 'WordPress',
- 'Apache Tomcat',
- 'Apache/NCSA HTTP Server',
- 'Outlook Web Access',
- 'PHP',
- 'Microsoft SQL Server',
- 'Oracle',
- 'MySQL',
- 'Lotus Domino',
- 'BEA Systems WebLogic Server',
- 'Macromedia JRun',
- 'Novell',
- 'Cisco',
- 'SSI (Server Side Includes)',
- 'Proxy Servers',
- 'CGI',
- 'Sybase/ASE',
- 'IBM DB2',
- 'PostgreSQL',
- 'XML',
- 'Apache Struts',
- 'Elasticsearch',
- 'JBoss',
- 'Citrix',
- 'Node.js',
- 'Django',
- 'MongoDB',
- 'Ruby',
- 'JavaServer Faces (JSF)',
- 'Joomla',
- 'Jetty'
- ]
- argument_spec = dict(
- policy_name=dict(
- required=True
- ),
- name=dict(
- choices=self.tech,
- required=True
- ),
- state=dict(
- default='present',
- choices=['present', 'absent']
- ),
- partition=dict(
- default='Common',
- fallback=(env_fallback, ['F5_PARTITION'])
- )
-
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode,
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_asm_policy_signature_set.py b/lib/ansible/modules/network/f5/bigip_asm_policy_signature_set.py
deleted file mode 100644
index c9f4f1c8e6..0000000000
--- a/lib/ansible/modules/network/f5/bigip_asm_policy_signature_set.py
+++ /dev/null
@@ -1,721 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2018, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_asm_policy_signature_set
-short_description: Manages Signature Sets on ASM policy
-description:
- - Manages Signature Sets on ASM policy.
-version_added: 2.8
-options:
- name:
- description:
- - Specifies the name of the signature sets to apply on or remove from the ASM policy.
- - Apart from built-in signature sets that ship with the device, users can use user created
- signature sets.
- - When C(All Response Signatures), configures all signatures in the attack signature
- pool that can review responses.
- - When C(All Signatures), configures all attack signatures in the attack signature pool.
- - When C(Apache Struts Signatures), configures signatures that target attacks against
- the Apache Struts web servers. Only available in version 13.x and up.
- - When C(Apache Tomcat Signatures), configures signatures that target attacks against
- the Apache Tomcat web servers. Only available in version 13.x and up.
- - When C(Cisco Signatures), configures signatures that target attacks against Cisco systems.
- Only available in version 13.x and up.
- - When C(Command Execution Signatures), configures signatures involving attacks perpetrated by executing commands.
- - When C(Cross Site Scripting Signatures), configures signatures that target attacks caused
- by cross-site scripting techniques.
- - When C(Directory Indexing Signatures), configures signatures targeting attacks that browse directory listings.
- - When C(Generic Detection Signatures), configures signatures targeting well-known
- or common web and application attacks.
- - When C(HTTP Response Splitting Signatures), configures signatures targeting attacks that
- take advantage of responses for which input values have not been sanitized.
- - When C(High Accuracy Detection Evasion Signatures), configures signatures with a high level of accuracy
- that produce few false positives when identifying evasion attacks. Only available in version 13.x and up.
- - When C(High Accuracy Signatures), configures signatures with a high level of accuracy
- that produce few false positives when identifying evasion attacks.
- - When C(IIS and Windows Signatures), configures signatures that target attacks against IIS
- and Windows based systems. Only available in version 13.x and up.
- - When C(Information Leakage Signatures), configures signatures targeting attacks that are looking for system data
- or debugging information that shows where the system is vulnerable to attack.
- - When C(Java Servlets/JSP Signatures), configures signatures that target attacks against Java Servlets
- and Java Server Pages (JSP) based applications. Only available in version 13.x and up.
- - When C(Low Accuracy Signatures), configures signatures that may result in more false positives
- when identifying attacks.
- - When C(Medium Accuracy Signatures), configures signatures with a medium level of accuracy
- when identifying attacks.
- - When C(OS Command Injection Signatures), configures signatures targeting attacks
- that attempt to run system level commands through a vulnerable application.
- - When C(OWA Signatures), configures signatures that target attacks against
- the Microsoft Outlook Web Access (OWA) application.
- - When C(Other Application Attacks Signatures), configures signatures targeting miscellaneous attacks,
- including session fixation, local file access, injection attempts, header tampering
- and so on, affecting many applications.
- - When C(Path Traversal Signatures), configures signatures targeting attacks that attempt to access files
- and directories that are stored outside the web root folder.
- - When C(Predictable Resource Location Signatures), configures signatures targeting attacks that attempt
- to uncover hidden website content and functionality by forceful browsing, or by directory and file enumeration.
- - When C(Remote File Include Signatures), configures signatures targeting attacks that attempt to exploit
- a remote file include vulnerability that could enable a remote attacker to execute arbitrary commands
- on the server hosting the application.
- - When C(SQL Injection Signatures), configures signatures targeting attacks that attempt to insert (inject)
- a SQL query using the input data from a client to an application.
- - When C(Server Side Code Injection Signatures), configures signatures targeting code injection attacks
- on the server side.
- - When C(WebSphere signatures), configures signatures targeting attacks on many computing platforms
- that are integrated using WebSphere including general database, Microsoft Windows, IIS,
- Microsoft SQL Server, Apache, Oracle, Unix/Linux, IBM DB2, PostgreSQL, and XML.
- - When C(XPath Injection Signatures), configures signatures targeting attacks that attempt to gain access
- to data structures or bypass permissions when a web site uses user-supplied information
- to construct XPath queries for XML data.
- type: str
- required: True
- policy_name:
- description:
- - Specifies the name of an existing ASM policy to add or remove signature sets.
- type: str
- required: True
- alarm:
- description:
- - Specifies if the security policy logs the request data in the Statistics screen,
- when a request matches a signature that is included in the signature set.
- type: bool
- block:
- description:
- - Effective when the security policy`s enforcement mode is Blocking.
- - Determines how the system treats requests that match a signature included in the signature set.
- - When C(yes) the system blocks all requests that match a signature,
- and provides the client with a support ID number.
- - When C(no) the system accepts those requests.
- type: bool
- learn:
- description:
- - Specifies if the security policy learns all requests that match a signature
- that is included in the signature set.
- type: bool
- state:
- description:
- - When C(present), ensures that the resource exists.
- - When C(absent), ensures the resource is removed.
- type: str
- default: present
- choices:
- - present
- - absent
- partition:
- description:
- - This parameter is only used when identifying ASM policy.
- type: str
- default: Common
-notes:
- - This module is primarily used as a component of configuring ASM policy in Ansible Galaxy ASM Policy Role.
-extends_documentation_fragment: f5
-author:
- - Wojciech Wypior (@wojtek0806)
-'''
-
-EXAMPLES = r'''
-- name: Add Signature Set to ASM Policy
- bigip_asm_policy_signature_set:
- name: IIS and Windows Signatures
- policy_name: FooPolicy
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-- name: Remove Signature Set to ASM Policy
- bigip_asm_policy_signature_set:
- name: IIS and Windows Signatures
- policy_name: FooPolicy
- state: absent
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-'''
-
-RETURN = r'''
-policy_name:
- description: The name of the ASM policy
- returned: changed
- type: str
- sample: FooPolicy
-name:
- description: The name of Signature Set added/removed on ASM policy
- returned: changed
- type: str
- sample: Cisco Signatures
-alarm:
- description: Specifies whether the security policy logs the request data in the Statistics screen
- returned: changed
- type: bool
- sample: yes
-block:
- description: Determines how the system treats requests that match a signature included in the signature set
- returned: changed
- type: bool
- sample: no
-learn:
- description: Specifies if the policy learns all requests that match a signature that is included in the signature set
- returned: changed
- type: bool
- sample: yes
-'''
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.basic import env_fallback
-from distutils.version import LooseVersion
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import fq_name
- from library.module_utils.network.f5.common import transform_name
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.common import flatten_boolean
- from library.module_utils.network.f5.icontrol import tmos_version
- from library.module_utils.network.f5.icontrol import module_provisioned
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import fq_name
- from ansible.module_utils.network.f5.common import transform_name
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.common import flatten_boolean
- from ansible.module_utils.network.f5.icontrol import tmos_version
- from ansible.module_utils.network.f5.icontrol import module_provisioned
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
-
- }
-
- api_attributes = [
- 'alarm',
- 'block',
- 'learn',
-
- ]
-
- returnables = [
- 'policy_name',
- 'name',
- 'alarm',
- 'block',
- 'learn',
-
- ]
-
- updatables = [
- 'alarm',
- 'block',
- 'learn',
- ]
-
-
-class ApiParameters(Parameters):
- pass
-
-
-class ModuleParameters(Parameters):
- @property
- def alarm(self):
- result = flatten_boolean(self._values['alarm'])
- if result:
- if result == 'yes':
- return True
- return False
-
- @property
- def block(self):
- result = flatten_boolean(self._values['block'])
- if result:
- if result == 'yes':
- return True
- return False
-
- @property
- def learn(self):
- result = flatten_boolean(self._values['learn'])
- if result:
- if result == 'yes':
- return True
- return False
-
- def _signature_set_exists_on_device(self, name):
- uri = "https://{0}:{1}/mgmt/tm/asm/signature-sets".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
-
- query = "?$select=name"
- resp = self.client.api.get(uri + query)
-
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- if any(p['name'] == name for p in response['items']):
- return True
- return False
-
- @property
- def name(self):
- if self._values['name'] is None:
- return None
-
- version = tmos_version(self.client)
-
- if LooseVersion(version) < LooseVersion('13.0.0'):
- name_list = [
- 'All Response Signatures',
- 'All Signatures',
- 'Command Execution Signatures',
- 'Cross Site Scripting Signatures',
- 'Directory Indexing Signatures',
- 'Generic Detection Signatures',
- 'HTTP Response Splitting Signatures',
- 'High Accuracy Signatures',
- 'Information Leakage Signatures',
- 'Low Accuracy Signatures',
- 'Medium Accuracy Signatures',
- 'OS Command Injection Signatures',
- 'OWA Signatures',
- 'Other Application Attacks Signatures',
- 'Path Traversal Signatures',
- 'Predictable Resource Location Signatures',
- 'Remote File Include Signatures',
- 'SQL Injection Signatures',
- 'Server Side Code Injection Signatures',
- 'WebSphere signatures',
- 'XPath Injection Signatures'
- ]
- else:
- name_list = [
- 'All Response Signatures',
- 'All Signatures',
- 'Apache Struts Signatures',
- 'Apache Tomcat Signatures',
- 'Cisco Signatures',
- 'Command Execution Signatures',
- 'Cross Site Scripting Signatures',
- 'Directory Indexing Signatures',
- 'Generic Detection Signatures',
- 'HTTP Response Splitting Signatures',
- 'High Accuracy Detection Evasion Signatures',
- 'High Accuracy Signatures',
- 'IIS and Windows Signatures',
- 'Information Leakage Signatures',
- 'Java Servlets/JSP Signatures',
- 'Low Accuracy Signatures',
- 'Medium Accuracy Signatures',
- 'OS Command Injection Signatures',
- 'OWA Signatures',
- 'Other Application Attacks Signatures',
- 'Path Traversal Signatures',
- 'Predictable Resource Location Signatures',
- 'Remote File Include Signatures',
- 'SQL Injection Signatures',
- 'Server Side Code Injection Signatures',
- 'WebSphere signatures',
- 'XPath Injection Signatures'
- ]
-
- if self._values['name'] in name_list:
- return self._values['name']
-
- if self._signature_set_exists_on_device(self._values['name']):
- return self._values['name']
-
- raise F5ModuleError(
- "The specified signature {0} set does not exist.".format(
- self._values['name']
- )
- )
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class UsableChanges(Changes):
- pass
-
-
-class ReportableChanges(Changes):
- @property
- def alarm(self):
- return flatten_boolean(self._values['alarm'])
-
- @property
- def learn(self):
- return flatten_boolean(self._values['learn'])
-
- @property
- def block(self):
- return flatten_boolean(self._values['block'])
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(params=self.module.params, client=self.client)
- self.have = ApiParameters()
- self.changes = UsableChanges()
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = UsableChanges(params=changed)
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.client.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def exec_module(self):
- if not module_provisioned(self.client, 'asm'):
- raise F5ModuleError(
- "ASM must be provisioned to use this module."
- )
- changed = False
- result = dict()
- state = self.want.state
-
- if state == "present":
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def present(self):
- if self.exists():
- return self.update()
- else:
- return self.create()
-
- def absent(self):
- if self.exists():
- return self.remove()
- return False
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def update(self):
- self.have = self.read_current_from_device()
- if not self.should_update():
- return False
- if self.module.check_mode:
- return True
- self.update_on_device()
- return True
-
- def remove(self):
- if self.module.check_mode:
- return True
- self.remove_from_device()
- if self.exists():
- raise F5ModuleError("Failed to delete the resource.")
- return True
-
- def create(self):
- self._set_changed_options()
- if self.module.check_mode:
- return True
- self.create_on_device()
- return True
-
- def exists(self):
- policy_id = self._get_policy_id()
- set_link = self._get_signature_set_link()
- uri = 'https://{0}:{1}/mgmt/tm/asm/policies/{2}/signature-sets/'.format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- policy_id,
- )
- resp = self.client.api.get(uri)
-
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'items' in response and response['items'] != []:
- for st in response['items']:
- if st['signatureSetReference'] == set_link:
- self.want.ss_id = st['id']
- return True
- return False
-
- def _get_signature_set_link(self):
- result = None
- signature_set = self.want.name
- uri = "https://{0}:{1}/mgmt/tm/asm/signature-sets".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
-
- query = "?$select=name"
- resp = self.client.api.get(uri + query)
-
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- if 'items' in response and response['items'] != []:
- for item in response['items']:
- if item['name'] == signature_set:
- result = dict(link=item['selfLink'])
-
- return result
-
- def _get_policy_id(self):
- policy_id = None
- uri = "https://{0}:{1}/mgmt/tm/asm/policies/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- query = "?$filter=contains(name,'{0}')+and+contains(partition,'{1}')&$select=name,id".format(
- self.want.policy_name, self.want.partition
- )
- resp = self.client.api.get(uri + query)
-
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'items' in response and response['items'] != []:
- policy_id = response['items'][0]['id']
-
- if not policy_id:
- raise F5ModuleError(
- "The policy with the name {0} does not exist".format(self.want.policy_name)
- )
- return policy_id
-
- def create_on_device(self):
- policy_id = self._get_policy_id()
- params = self.changes.api_params()
- params['signatureSetReference'] = self._get_signature_set_link()
- uri = "https://{0}:{1}/mgmt/tm/asm/policies/{2}/signature-sets/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- policy_id
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 409]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return True
-
- def update_on_device(self):
- policy_id = self._get_policy_id()
- params = self.changes.api_params()
- uri = "https://{0}:{1}/mgmt/tm/asm/policies/{2}/signature-sets/{3}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- policy_id,
- self.want.ss_id
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def remove_from_device(self):
- policy_id = self._get_policy_id()
- uri = 'https://{0}:{1}/mgmt/tm/asm/policies/{2}/signature-sets/{3}'.format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- policy_id,
- self.want.ss_id
- )
- response = self.client.api.delete(uri)
- if response.status in [200, 201]:
- return True
- raise F5ModuleError(response.content)
-
- def read_current_from_device(self):
- policy_id = self._get_policy_id()
- uri = "https://{0}:{1}/mgmt/tm/asm/policies/{2}/signature-sets/{3}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- policy_id,
- self.want.ss_id
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return ApiParameters(params=response)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- policy_name=dict(
- required=True
- ),
- name=dict(
- required=True
- ),
- alarm=dict(
- type='bool'
- ),
- block=dict(
- type='bool'
- ),
- learn=dict(
- type='bool'
- ),
- state=dict(
- default='present',
- choices=['present', 'absent']
- ),
- partition=dict(
- default='Common',
- fallback=(env_fallback, ['F5_PARTITION'])
- )
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode,
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_cli_alias.py b/lib/ansible/modules/network/f5/bigip_cli_alias.py
deleted file mode 100644
index 656f85d0da..0000000000
--- a/lib/ansible/modules/network/f5/bigip_cli_alias.py
+++ /dev/null
@@ -1,418 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2018, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_cli_alias
-short_description: Manage CLI aliases on a BIG-IP
-description:
- - Allows for managing both private and shared aliases on a BIG-IP.
-version_added: 2.7
-options:
- name:
- description:
- - Specifies the name of the alias.
- type: str
- required: True
- scope:
- description:
- - The scope of the alias; whether it is shared on the system, or usable only
- for the user who created it.
- type: str
- default: shared
- choices:
- - private
- - shared
- command:
- description:
- - The command to alias.
- type: str
- description:
- description:
- - Description of the alias.
- type: str
- partition:
- description:
- - Device partition to manage resources on.
- - This parameter is disregarded when the C(scope) is C(private).
- type: str
- default: Common
- state:
- description:
- - When C(present), ensures that the resource exists.
- - When C(absent), ensures the resource is removed.
- type: str
- default: present
- choices:
- - present
- - absent
-extends_documentation_fragment: f5
-author:
- - Tim Rupp (@caphrim007)
- - Wojciech Wypior (@wojtek0806)
-'''
-
-EXAMPLES = r'''
-- name: Create a new alias
- bigip_cli_alias:
- name: sync_device_to_bside
- scope: shared
- command: save /sys config partitions all; run /cm config-sync to-group device-group-1
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-'''
-
-RETURN = r'''
-command:
- description: The new command that is aliased.
- returned: changed
- type: str
- sample: run /util bash
-description:
- description: The new description of the alias.
- returned: changed
- type: str
- sample: Run the bash shell
-'''
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.basic import env_fallback
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.common import transform_name
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.common import transform_name
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'tmCommand': 'command'
- }
-
- api_attributes = [
- 'tmCommand',
- 'description',
- ]
-
- returnables = [
- 'command',
- 'description',
- ]
-
- updatables = [
- 'command',
- 'description',
- ]
-
- @property
- def full_name(self):
- if self.scope == 'shared':
- return transform_name(self.partition, self.name)
- else:
- return self.name
-
-
-class ApiParameters(Parameters):
- pass
-
-
-class ModuleParameters(Parameters):
- pass
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class UsableChanges(Changes):
- pass
-
-
-class ReportableChanges(Changes):
- pass
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(params=self.module.params)
- self.have = ApiParameters()
- self.changes = UsableChanges()
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = UsableChanges(params=changed)
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def exec_module(self):
- changed = False
- result = dict()
- state = self.want.state
-
- if state == "present":
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.client.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def present(self):
- if self.exists():
- return self.update()
- else:
- return self.create()
-
- def exists(self):
- uri = "https://{0}:{1}/mgmt/tm/cli/alias/{2}/{3}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- self.want.scope,
- self.want.full_name
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def update(self):
- self.have = self.read_current_from_device()
- if not self.should_update():
- return False
- if self.module.check_mode:
- return True
- self.update_on_device()
- return True
-
- def remove(self):
- if self.module.check_mode:
- return True
- self.remove_from_device()
- if self.exists():
- raise F5ModuleError("Failed to delete the resource.")
- return True
-
- def create(self):
- self._set_changed_options()
- if self.module.check_mode:
- return True
- self.create_on_device()
- return True
-
- def create_on_device(self):
- params = self.changes.api_params()
- params['name'] = self.want.name
- params['partition'] = self.want.partition
- uri = "https://{0}:{1}/mgmt/tm/cli/alias/{2}/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- self.want.scope
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def update_on_device(self):
- params = self.changes.api_params()
- uri = "https://{0}:{1}/mgmt/tm/cli/alias/{2}/{3}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- self.want.scope,
- self.want.full_name
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def absent(self):
- if self.exists():
- return self.remove()
- return False
-
- def remove_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/cli/alias/{2}/{3}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- self.want.scope,
- self.want.full_name
- )
- resp = self.client.api.delete(uri)
- if resp.status == 200:
- return True
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/cli/alias/{2}/{3}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- self.want.scope,
- self.want.full_name
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return ApiParameters(params=response)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- name=dict(required=True),
- scope=dict(
- choices=['private', 'shared'],
- default='shared'
- ),
- description=dict(),
- command=dict(),
- state=dict(
- default='present',
- choices=['present', 'absent']
- ),
- partition=dict(
- default='Common',
- fallback=(env_fallback, ['F5_PARTITION'])
- )
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode,
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_cli_script.py b/lib/ansible/modules/network/f5/bigip_cli_script.py
deleted file mode 100644
index d9f1b3441c..0000000000
--- a/lib/ansible/modules/network/f5/bigip_cli_script.py
+++ /dev/null
@@ -1,460 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2018, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_cli_script
-short_description: Manage CLI scripts on a BIG-IP
-description:
- - Manages CLI scripts on a BIG-IP. CLI scripts, otherwise known as tmshell scripts
- or TMSH scripts allow you to create custom scripts that can run to manage objects
- within a BIG-IP.
-version_added: 2.7
-options:
- name:
- description:
- - Specifies the name of the script.
- type: str
- required: True
- content:
- description:
- - The content of the script.
- - This parameter is typically used in conjunction with Ansible's C(file), or
- template lookup plugins. If this sounds foreign to you, see the examples
- in this documentation.
- type: str
- description:
- description:
- - Description of the cli script.
- type: str
- partition:
- description:
- - Device partition to manage resources on.
- type: str
- default: Common
- state:
- description:
- - When C(present), ensures that the script exists.
- - When C(absent), ensures the script is removed.
- type: str
- default: present
- choices:
- - present
- - absent
-extends_documentation_fragment: f5
-author:
- - Tim Rupp (@caphrim007)
- - Wojciech Wypior (@wojtek0806)
-'''
-
-EXAMPLES = r'''
-- name: Create a cli script from an existing file
- bigip_cli_script:
- name: foo
- content: "{{ lookup('file', '/absolute/path/to/cli/script.tcl') }}"
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-
-- name: Create a cli script from a jinja template representing a cli script
- bigip_cli_script:
- name: foo
- content: "{{ lookup('template', '/absolute/path/to/cli/script.tcl') }}"
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-'''
-
-RETURN = r'''
-param1:
- description: The new param1 value of the resource.
- returned: changed
- type: bool
- sample: true
-param2:
- description: The new param2 value of the resource.
- returned: changed
- type: str
- sample: Foo is bar
-'''
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.basic import env_fallback
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.common import transform_name
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.common import transform_name
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'apiAnonymous': 'content',
- 'scriptChecksum': 'checksum',
- }
-
- api_attributes = [
- 'apiAnonymous',
- 'description',
- ]
-
- returnables = [
- 'description',
- 'content',
- ]
-
- updatables = [
- 'description',
- 'content',
- ]
-
-
-class ApiParameters(Parameters):
- @property
- def ignore_verification(self):
- return "true"
-
- @property
- def content(self):
- return self._values['content'].strip()
-
-
-class ModuleParameters(Parameters):
- @property
- def ignore_verification(self):
- return "true"
-
- @property
- def content(self):
- if self._values['content'] is None:
- return None
- return self._values['content'].strip()
-
- @property
- def description(self):
- if self._values['description'] is None:
- return None
- elif self._values['description'] in ['none', '']:
- return ''
- return self._values['description']
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class UsableChanges(Changes):
- pass
-
-
-class ReportableChanges(Changes):
- pass
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
- @property
- def content(self):
- if self.want.content is None:
- return None
- if self.have.content is None:
- return self.want.content
- if self.want.content != self.have.content:
- return self.want.content
-
- @property
- def description(self):
- if self.want.description is None:
- return None
- if self.have.description is None and self.want.description == '':
- return None
- if self.want.description != self.have.description:
- return self.want.description
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(params=self.module.params)
- self.have = ApiParameters()
- self.changes = UsableChanges()
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = UsableChanges(params=changed)
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def exec_module(self):
- changed = False
- result = dict()
- state = self.want.state
-
- if state == "present":
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.client.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def present(self):
- if self.exists():
- return self.update()
- else:
- return self.create()
-
- def exists(self):
- uri = "https://{0}:{1}/mgmt/tm/cli/script/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def update(self):
- self.have = self.read_current_from_device()
- if not self.should_update():
- return False
- if self.module.check_mode:
- return True
-
- # Update any missing params
- #
- # The cli/script API is kinda weird in that it wont let us individually
- # PATCH the description. We appear to need to include the content otherwise
- # we get errors about us trying to replace procs that are needed by other
- # scripts, ie, the script we're trying to update.
- params = self.changes.api_params()
- if 'description' in params and 'content' not in params:
- self.changes.update({'content': self.have.content})
- if 'content' in params and 'description' not in params:
- self.changes.update({'description': self.have.description})
-
- self.update_on_device()
- return True
-
- def remove(self):
- if self.module.check_mode:
- return True
- self.remove_from_device()
- if self.exists():
- raise F5ModuleError("Failed to delete the resource.")
- return True
-
- def create(self):
- self._set_changed_options()
- if self.module.check_mode:
- return True
- self.create_on_device()
- return True
-
- def create_on_device(self):
- params = self.changes.api_params()
- params['name'] = self.want.name
- params['partition'] = self.want.partition
- uri = "https://{0}:{1}/mgmt/tm/cli/script/".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def update_on_device(self):
- params = self.changes.api_params()
- uri = "https://{0}:{1}/mgmt/tm/cli/script/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def absent(self):
- if self.exists():
- return self.remove()
- return False
-
- def remove_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/cli/script/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.delete(uri)
- if resp.status == 200:
- return True
-
- def read_current_from_device(self): # lgtm [py/similar-function]
- uri = "https://{0}:{1}/mgmt/tm/cli/script/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return ApiParameters(params=response)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- name=dict(required=True),
- description=dict(),
- content=dict(),
- state=dict(
- default='present',
- choices=['present', 'absent']
- ),
- partition=dict(
- default='Common',
- fallback=(env_fallback, ['F5_PARTITION'])
- )
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode,
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_command.py b/lib/ansible/modules/network/f5/bigip_command.py
deleted file mode 100644
index ac39547273..0000000000
--- a/lib/ansible/modules/network/f5/bigip_command.py
+++ /dev/null
@@ -1,726 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['stableinterface'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_command
-short_description: Run TMSH and BASH commands on F5 devices
-description:
- - Sends a TMSH or BASH command to an BIG-IP node and returns the results
- read from the device. This module includes an argument that will cause
- the module to wait for a specific condition before returning or timing
- out if the condition is not met.
- - This module is B(not) idempotent, nor will it ever be. It is intended as
- a stop-gap measure to satisfy automation requirements until such a time as
- a real module has been developed to configure in the way you need.
- - If you are using this module, you should probably also be filing an issue
- to have a B(real) module created for your needs.
-version_added: 2.4
-options:
- commands:
- description:
- - The commands to send to the remote BIG-IP device over the
- configured provider. The resulting output from the command
- is returned. If the I(wait_for) argument is provided, the
- module is not returned until the condition is satisfied or
- the number of retries as expired.
- - Only C(tmsh) commands are supported. If you are piping or adding additional
- logic that is outside of C(tmsh) (such as grep'ing, awk'ing or other shell
- related things that are not C(tmsh), this behavior is not supported.
- required: True
- type: raw
- wait_for:
- description:
- - Specifies what to evaluate from the output of the command
- and what conditionals to apply. This argument will cause
- the task to wait for a particular conditional to be true
- before moving forward. If the conditional is not true
- by the configured retries, the task fails. See examples.
- type: list
- aliases: ['waitfor']
- match:
- description:
- - The I(match) argument is used in conjunction with the
- I(wait_for) argument to specify the match policy. Valid
- values are C(all) or C(any). If the value is set to C(all)
- then all conditionals in the I(wait_for) must be satisfied. If
- the value is set to C(any) then only one of the values must be
- satisfied.
- type: str
- choices:
- - any
- - all
- default: all
- retries:
- description:
- - Specifies the number of retries a command should by tried
- before it is considered failed. The command is run on the
- target device every retry and evaluated against the I(wait_for)
- conditionals.
- type: int
- default: 10
- interval:
- description:
- - Configures the interval in seconds to wait between retries
- of the command. If the command does not pass the specified
- conditional, the interval indicates how to long to wait before
- trying the command again.
- type: int
- default: 1
- transport:
- description:
- - Configures the transport connection to use when connecting to the
- remote device. The transport argument supports connectivity to the
- device over cli (ssh) or rest.
- required: true
- choices:
- - rest
- - cli
- default: rest
- version_added: 2.5
- warn:
- description:
- - Whether the module should raise warnings related to command idempotency
- or not.
- - Note that the F5 Ansible developers specifically leave this on to make you
- aware that your usage of this module may be better served by official F5
- Ansible modules. This module should always be used as a last resort.
- default: True
- type: bool
- version_added: 2.6
- chdir:
- description:
- - Change into this directory before running the command.
- type: str
- version_added: 2.6
-extends_documentation_fragment: f5
-author:
- - Tim Rupp (@caphrim007)
- - Wojciech Wypior (@wojtek0806)
-'''
-
-EXAMPLES = r'''
-- name: run show version on remote devices
- bigip_command:
- commands: show sys version
- provider:
- server: lb.mydomain.com
- password: secret
- user: admin
- delegate_to: localhost
-
-- name: run show version and check to see if output contains BIG-IP
- bigip_command:
- commands: show sys version
- wait_for: result[0] contains BIG-IP
- provider:
- server: lb.mydomain.com
- password: secret
- user: admin
- register: result
- delegate_to: localhost
-
-- name: run multiple commands on remote nodes
- bigip_command:
- commands:
- - show sys version
- - list ltm virtual
- provider:
- server: lb.mydomain.com
- password: secret
- user: admin
- delegate_to: localhost
-
-- name: run multiple commands and evaluate the output
- bigip_command:
- commands:
- - show sys version
- - list ltm virtual
- wait_for:
- - result[0] contains BIG-IP
- - result[1] contains my-vs
- provider:
- server: lb.mydomain.com
- password: secret
- user: admin
- register: result
- delegate_to: localhost
-
-- name: tmsh prefixes will automatically be handled
- bigip_command:
- commands:
- - show sys version
- - tmsh list ltm virtual
- provider:
- server: lb.mydomain.com
- password: secret
- user: admin
- delegate_to: localhost
-
-- name: Delete all LTM nodes in Partition1, assuming no dependencies exist
- bigip_command:
- commands:
- - delete ltm node all
- chdir: Partition1
- provider:
- server: lb.mydomain.com
- password: secret
- user: admin
- delegate_to: localhost
-'''
-
-RETURN = r'''
-stdout:
- description: The set of responses from the commands.
- returned: always
- type: list
- sample: ['...', '...']
-stdout_lines:
- description: The value of stdout split into a list.
- returned: always
- type: list
- sample: [['...', '...'], ['...'], ['...']]
-failed_conditions:
- description: The list of conditionals that have failed.
- returned: failed
- type: list
- sample: ['...', '...']
-warn:
- description: Whether or not to raise warnings about modification commands.
- returned: changed
- type: bool
- sample: True
-'''
-
-import re
-import time
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.network.common.parsing import FailedConditionsError
-from ansible.module_utils.network.common.parsing import Conditional
-from ansible.module_utils.network.common.utils import ComplexList
-from ansible.module_utils.network.common.utils import to_list
-from ansible.module_utils.six import string_types
-from collections import deque
-
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import fq_name
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.common import transform_name
- from library.module_utils.network.f5.common import is_cli
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import fq_name
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.common import transform_name
- from ansible.module_utils.network.f5.common import is_cli
-
-try:
- from ansible.module_utils.network.f5.common import run_commands
- HAS_CLI_TRANSPORT = True
-except ImportError:
- HAS_CLI_TRANSPORT = False
-
-
-class NoChangeReporter(object):
- stdout_re = [
- # A general error when a resource already exists
- re.compile(r"The requested.*already exists"),
-
- # Returned when creating a duplicate cli alias
- re.compile(r"Data Input Error: shared.*already exists"),
- ]
-
- def find_no_change(self, responses):
- """Searches the response for something that looks like a change
-
- This method borrows heavily from Ansible's ``_find_prompt`` method
- defined in the ``lib/ansible/plugins/connection/network_cli.py::Connection``
- class.
-
- Arguments:
- response (string): The output from the command.
-
- Returns:
- bool: True when change is detected. False otherwise.
- """
- for response in responses:
- for regex in self.stdout_re:
- if regex.search(response):
- return True
- return False
-
-
-class Parameters(AnsibleF5Parameters):
- returnables = ['stdout', 'stdout_lines', 'warnings', 'executed_commands']
-
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- return result
- except Exception:
- return result
-
- @property
- def raw_commands(self):
- if self._values['commands'] is None:
- return []
- if isinstance(self._values['commands'], string_types):
- result = [self._values['commands']]
- else:
- result = self._values['commands']
- return result
-
- def convert_commands(self, commands):
- result = []
- for command in commands:
- tmp = dict(
- command='',
- pipeline=''
- )
-
- command = command.replace("'", "\\'")
- pipeline = command.split('|', 1)
- tmp['command'] = pipeline[0]
- try:
- tmp['pipeline'] = pipeline[1]
- except IndexError:
- pass
- result.append(tmp)
- return result
-
- def convert_commands_cli(self, commands):
- result = []
- for command in commands:
- tmp = dict(
- command='',
- pipeline=''
- )
-
- pipeline = command.split('|', 1)
- tmp['command'] = pipeline[0]
- try:
- tmp['pipeline'] = pipeline[1]
- except IndexError:
- pass
- result.append(tmp)
- return result
-
- def merge_command_dict(self, command):
- if command['pipeline'] != '':
- escape_patterns = r'([$"])'
- command['pipeline'] = re.sub(escape_patterns, r'\\\1', command['pipeline'])
- command['command'] = '{0} | {1}'.format(command['command'], command['pipeline']).strip()
-
- def merge_command_dict_cli(self, command):
- if command['pipeline'] != '':
- command['command'] = '{0} | {1}'.format(command['command'], command['pipeline']).strip()
-
- @property
- def rest_commands(self):
- # ['list ltm virtual']
- commands = self.normalized_commands
- commands = self.convert_commands(commands)
- if self.chdir:
- # ['cd /Common; list ltm virtual']
- for command in commands:
- self.addon_chdir(command)
- # ['tmsh -c "cd /Common; list ltm virtual"']
- for command in commands:
- self.addon_tmsh(command)
- for command in commands:
- self.merge_command_dict(command)
- result = [x['command'] for x in commands]
- return result
-
- @property
- def cli_commands(self):
- # ['list ltm virtual']
- commands = self.normalized_commands
- commands = self.convert_commands_cli(commands)
- if self.chdir:
- # ['cd /Common; list ltm virtual']
- for command in commands:
- self.addon_chdir(command)
- if not self.is_tmsh:
- # ['tmsh -c "cd /Common; list ltm virtual"']
- for command in commands:
- self.addon_tmsh_cli(command)
- for command in commands:
- self.merge_command_dict_cli(command)
- result = [x['command'] for x in commands]
- return result
-
- @property
- def normalized_commands(self):
- if self._values['normalized_commands'] is None:
- return None
- return deque(self._values['normalized_commands'])
-
- @property
- def chdir(self):
- if self._values['chdir'] is None:
- return None
- if self._values['chdir'].startswith('/'):
- return self._values['chdir']
- return '/{0}'.format(self._values['chdir'])
-
- @property
- def user_commands(self):
- commands = self.raw_commands
- return map(self._ensure_tmsh_prefix, commands)
-
- @property
- def wait_for(self):
- return self._values['wait_for'] or list()
-
- def addon_tmsh(self, command):
- escape_patterns = r'([$"])'
- if command['command'].count('"') % 2 != 0:
- raise Exception('Double quotes are unbalanced')
- command['command'] = re.sub(escape_patterns, r'\\\\\\\1', command['command'])
- command['command'] = 'tmsh -c \\\"{0}\\\"'.format(command['command'])
-
- def addon_tmsh_cli(self, command):
- if command['command'].count('"') % 2 != 0:
- raise Exception('Double quotes are unbalanced')
- command['command'] = 'tmsh -c "{0}"'.format(command['command'])
-
- def addon_chdir(self, command):
- command['command'] = "cd {0}; {1}".format(self.chdir, command['command'])
-
-
-class BaseManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = Parameters(params=self.module.params)
- self.want.update({'module': self.module})
- self.changes = Parameters(module=self.module)
- self.valid_configs = [
- 'list', 'show', 'modify cli preference pager disabled'
- ]
- self.changed_command_prefixes = ('modify', 'create', 'delete')
- self.warnings = list()
-
- def _to_lines(self, stdout):
- lines = list()
- for item in stdout:
- if isinstance(item, string_types):
- item = item.split('\n')
- lines.append(item)
- return lines
-
- def exec_module(self):
- result = dict()
-
- changed = self.execute()
-
- result.update(**self.changes.to_return())
- result.update(dict(changed=changed))
- self._announce_warnings(result)
- return result
-
- def _announce_warnings(self, result):
- warnings = result.pop('warnings', [])
- for warning in warnings:
- self.module.warn(warning)
-
- def notify_non_idempotent_commands(self, commands):
- for index, item in enumerate(commands):
- if any(item.startswith(x) for x in self.valid_configs):
- return
- else:
- self.warnings.append(
- 'Using "write" commands is not idempotent. You should use '
- 'a module that is specifically made for that. If such a '
- 'module does not exist, then please file a bug. The command '
- 'in question is "{0}..."'.format(item[0:40])
- )
-
- @staticmethod
- def normalize_commands(raw_commands):
- if not raw_commands:
- return None
- result = []
- for command in raw_commands:
- command = command.strip()
- if command[0:5] == 'tmsh ':
- command = command[4:].strip()
- result.append(command)
- return result
-
- def parse_commands(self):
- results = []
- commands = self._transform_to_complex_commands(self.commands)
-
- for index, item in enumerate(commands):
- # This needs to be removed so that the ComplexList used in to_commands
- # will work correctly.
- output = item.pop('output', None)
-
- if output == 'one-line' and 'one-line' not in item['command']:
- item['command'] += ' one-line'
- elif output == 'text' and 'one-line' in item['command']:
- item['command'] = item['command'].replace('one-line', '')
-
- results.append(item)
- return results
-
- def execute(self):
- if self.want.normalized_commands:
- result = self.want.normalized_commands
- else:
- result = self.normalize_commands(self.want.raw_commands)
- self.want.update({'normalized_commands': result})
- if not result:
- return False
- self.notify_non_idempotent_commands(self.want.normalized_commands)
-
- commands = self.parse_commands()
- retries = self.want.retries
- conditionals = [Conditional(c) for c in self.want.wait_for]
-
- if self.module.check_mode:
- return
-
- while retries > 0:
- responses = self._execute(commands)
- self._check_known_errors(responses)
- for item in list(conditionals):
- if item(responses):
- if self.want.match == 'any':
- conditionals = list()
- break
- conditionals.remove(item)
- if not conditionals:
- break
-
- time.sleep(self.want.interval)
- retries -= 1
- else:
- failed_conditions = [item.raw for item in conditionals]
- errmsg = 'One or more conditional statements have not been satisfied.'
- raise FailedConditionsError(errmsg, failed_conditions)
- stdout_lines = self._to_lines(responses)
- changes = {
- 'stdout': responses,
- 'stdout_lines': stdout_lines,
- 'executed_commands': self.commands
- }
- if self.want.warn:
- changes['warnings'] = self.warnings
- self.changes = Parameters(params=changes, module=self.module)
- return self.determine_change(responses)
-
- def determine_change(self, responses):
- changer = NoChangeReporter()
- if changer.find_no_change(responses):
- return False
- if any(x for x in self.want.normalized_commands if x.startswith(self.changed_command_prefixes)):
- return True
- return False
-
- def _check_known_errors(self, responses):
- # A regex to match the error IDs used in the F5 v2 logging framework.
- # pattern = r'^[0-9A-Fa-f]+:?\d+?:'
-
- for resp in responses:
- if 'usage: tmsh' in resp:
- raise F5ModuleError(
- "tmsh command printed its 'help' message instead of running your command. "
- "This usually indicates unbalanced quotes."
- )
-
- def _transform_to_complex_commands(self, commands):
- spec = dict(
- command=dict(key=True),
- output=dict(
- default='text',
- choices=['text', 'one-line']
- ),
- )
- transform = ComplexList(spec, self.module)
- result = transform(commands)
- return result
-
-
-class V1Manager(BaseManager):
- """Supports CLI (SSH) communication with the remote device
-
- """
- def _execute(self, commands):
- if self.want.is_tmsh:
- command = dict(
- command="modify cli preference pager disabled"
- )
- else:
- command = dict(
- command="tmsh modify cli preference pager disabled"
- )
- self.execute_on_device(command)
- return self.execute_on_device(commands)
-
- @property
- def commands(self):
- return self.want.cli_commands
-
- def is_tmsh(self):
- try:
- self.execute_on_device('tmsh -v')
- except Exception as ex:
- if 'Syntax Error:' in str(ex):
- return True
- raise
- return False
-
- def execute(self):
- self.want.update({'is_tmsh': self.is_tmsh()})
- return super(V1Manager, self).execute()
-
- def execute_on_device(self, commands):
- result = run_commands(self.module, commands)
- return result
-
-
-class V2Manager(BaseManager):
- """Supports REST communication with the remote device
-
- """
- def _execute(self, commands):
- command = dict(
- command="tmsh modify cli preference pager disabled"
- )
- self.execute_on_device(command)
- return self.execute_on_device(commands)
-
- @property
- def commands(self):
- return self.want.rest_commands
-
- def execute_on_device(self, commands):
- responses = []
- uri = "https://{0}:{1}/mgmt/tm/util/bash".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- for item in to_list(commands):
- try:
- args = dict(
- command='run',
- utilCmdArgs='-c "{0}"'.format(item['command'])
- )
- resp = self.client.api.post(uri, json=args)
- response = resp.json()
- if 'commandResult' in response:
- output = u'{0}'.format(response['commandResult'])
- responses.append(output.strip())
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return responses
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.kwargs = kwargs
- self.module = kwargs.get('module', None)
-
- def exec_module(self):
- if is_cli(self.module) and HAS_CLI_TRANSPORT:
- manager = self.get_manager('v1')
- else:
- manager = self.get_manager('v2')
- result = manager.exec_module()
- return result
-
- def get_manager(self, type):
- if type == 'v1':
- return V1Manager(**self.kwargs)
- elif type == 'v2':
- return V2Manager(**self.kwargs)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- commands=dict(
- type='raw',
- required=True
- ),
- wait_for=dict(
- type='list',
- aliases=['waitfor']
- ),
- match=dict(
- default='all',
- choices=['any', 'all']
- ),
- retries=dict(
- default=10,
- type='int'
- ),
- interval=dict(
- default=1,
- type='int'
- ),
- transport=dict(
- type='str',
- default='rest',
- choices=['cli', 'rest']
- ),
- warn=dict(
- type='bool',
- default='yes'
- ),
- chdir=dict()
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_config.py b/lib/ansible/modules/network/f5/bigip_config.py
deleted file mode 100644
index 6ac426a5e5..0000000000
--- a/lib/ansible/modules/network/f5/bigip_config.py
+++ /dev/null
@@ -1,427 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_config
-short_description: Manage BIG-IP configuration sections
-description:
- - Manages a BIG-IP configuration by allowing TMSH commands that
- modify running configuration, or merge SCF formatted files into
- the running configuration. Additionally, this module is of
- significant importance because it allows you to save your running
- configuration to disk. Since the F5 module only manipulate running
- configuration, it is important that you utilize this module to save
- that running config.
-version_added: 2.4
-options:
- save:
- description:
- - The C(save) argument instructs the module to save the
- running-config to startup-config.
- - This operation is performed after any changes are made to the
- current running config. If no changes are made, the configuration
- is still saved to the startup config.
- - This option will always cause the module to return changed.
- type: bool
- default: yes
- reset:
- description:
- - Loads the default configuration on the device.
- - If this option is specified, the default configuration will be
- loaded before any commands or other provided configuration is run.
- type: bool
- default: no
- merge_content:
- description:
- - Loads the specified configuration that you want to merge into
- the running configuration. This is equivalent to using the
- C(tmsh) command C(load sys config from-terminal merge).
- - If you need to read configuration from a file or template, use
- Ansible's C(file) or C(template) lookup plugins respectively.
- type: str
- verify:
- description:
- - Validates the specified configuration to see whether they are
- valid to replace the running configuration.
- - The running configuration will not be changed.
- - When this parameter is set to C(yes), no change will be reported
- by the module.
- type: bool
- default: no
-extends_documentation_fragment: f5
-author:
- - Tim Rupp (@caphrim007)
-'''
-
-EXAMPLES = r'''
-- name: Save the running configuration of the BIG-IP
- bigip_config:
- save: yes
- provider:
- server: lb.mydomain.com
- password: secret
- user: admin
- delegate_to: localhost
-
-- name: Reset the BIG-IP configuration, for example, to RMA the device
- bigip_config:
- reset: yes
- save: yes
- provider:
- server: lb.mydomain.com
- password: secret
- user: admin
- delegate_to: localhost
-
-- name: Load an SCF configuration
- bigip_config:
- merge_content: "{{ lookup('file', '/path/to/config.scf') }}"
- provider:
- server: lb.mydomain.com
- password: secret
- user: admin
- delegate_to: localhost
-'''
-
-RETURN = r'''
-stdout:
- description: The set of responses from the options
- returned: always
- type: list
- sample: ['...', '...']
-stdout_lines:
- description: The value of stdout split into a list
- returned: always
- type: list
- sample: [['...', '...'], ['...'], ['...']]
-'''
-
-try:
- from StringIO import StringIO
-except ImportError:
- from io import StringIO
-
-import os
-import tempfile
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import fq_name
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.icontrol import upload_file
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import fq_name
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.icontrol import upload_file
-
-
-class Parameters(AnsibleF5Parameters):
- returnables = ['stdout', 'stdout_lines']
-
- def to_return(self):
- result = {}
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- return result
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = Parameters(params=self.module.params)
- self.changes = Parameters()
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = Parameters(params=changed)
-
- def _to_lines(self, stdout):
- lines = list()
- for item in stdout:
- if isinstance(item, str):
- item = str(item).split('\n')
- lines.append(item)
- return lines
-
- def exec_module(self):
- result = {}
-
- changed = self.execute()
-
- result.update(**self.changes.to_return())
- result.update(dict(changed=changed))
- return result
-
- def execute(self):
- responses = []
- if self.want.reset:
- response = self.reset()
- responses.append(response)
-
- if self.want.merge_content:
- if self.want.verify:
- response = self.merge(verify=True)
- responses.append(response)
- else:
- response = self.merge(verify=False)
- responses.append(response)
-
- if self.want.save:
- response = self.save()
- responses.append(response)
-
- self._detect_errors(responses)
- changes = {
- 'stdout': responses,
- 'stdout_lines': self._to_lines(responses)
- }
- self.changes = Parameters(params=changes)
- if self.want.verify:
- return False
- return True
-
- def _detect_errors(self, stdout):
- errors = [
- 'Unexpected Error:'
- ]
-
- msg = [x for x in stdout for y in errors if y in x]
- if msg:
- # Error only contains the lines that include the error
- raise F5ModuleError(' '.join(msg))
-
- def reset(self):
- if self.module.check_mode:
- return True
- return self.reset_device()
-
- def reset_device(self):
- command = 'tmsh load sys config default'
- uri = "https://{0}:{1}/mgmt/tm/util/bash".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- args = dict(
- command='run',
- utilCmdArgs='-c "{0}"'.format(command)
- )
- resp = self.client.api.post(uri, json=args)
-
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- if 'commandResult' in response:
- return str(response['commandResult'])
-
- def merge(self, verify=True):
- temp_name = next(tempfile._get_candidate_names())
- remote_path = "/var/config/rest/downloads/{0}".format(temp_name)
- temp_path = '/tmp/' + temp_name
-
- if self.module.check_mode:
- return True
-
- self.upload_to_device(temp_name)
- self.move_on_device(remote_path)
- response = self.merge_on_device(
- remote_path=temp_path, verify=verify
- )
- self.remove_temporary_file(remote_path=temp_path)
- return response
-
- def merge_on_device(self, remote_path, verify=True):
- command = 'tmsh load sys config file {0} merge'.format(
- remote_path
- )
- if verify:
- command += ' verify'
-
- uri = "https://{0}:{1}/mgmt/tm/util/bash".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- args = dict(
- command='run',
- utilCmdArgs='-c "{0}"'.format(command)
- )
- resp = self.client.api.post(uri, json=args)
-
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- if 'commandResult' in response:
- return str(response['commandResult'])
-
- def remove_temporary_file(self, remote_path):
- uri = "https://{0}:{1}/mgmt/tm/util/unix-rm".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- args = dict(
- command='run',
- utilCmdArgs=remote_path
- )
- resp = self.client.api.post(uri, json=args)
-
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def move_on_device(self, remote_path):
- uri = "https://{0}:{1}/mgmt/tm/util/unix-mv".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- args = dict(
- command='run',
- utilCmdArgs='{0} /tmp/{1}'.format(
- remote_path, os.path.basename(remote_path)
- )
- )
- resp = self.client.api.post(uri, json=args)
-
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def upload_to_device(self, temp_name):
- template = StringIO(self.want.merge_content)
- url = 'https://{0}:{1}/mgmt/shared/file-transfer/uploads'.format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- try:
- upload_file(self.client, url, template, temp_name)
- except F5ModuleError:
- raise F5ModuleError(
- "Failed to upload the file."
- )
-
- def save(self):
- if self.module.check_mode:
- return True
- return self.save_on_device()
-
- def save_on_device(self):
- command = 'tmsh save sys config'
- uri = "https://{0}:{1}/mgmt/tm/util/bash".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- args = dict(
- command='run',
- utilCmdArgs='-c "{0}"'.format(command)
- )
- resp = self.client.api.post(uri, json=args)
-
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- if 'commandResult' in response:
- return str(response['commandResult'])
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- reset=dict(
- type='bool',
- default=False
- ),
- merge_content=dict(),
- verify=dict(
- type='bool',
- default=False
- ),
- save=dict(
- type='bool',
- default='yes'
- )
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_configsync_action.py b/lib/ansible/modules/network/f5/bigip_configsync_action.py
deleted file mode 100644
index dcc8db7ae0..0000000000
--- a/lib/ansible/modules/network/f5/bigip_configsync_action.py
+++ /dev/null
@@ -1,432 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['stableinterface'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_configsync_action
-short_description: Perform different actions related to config-sync
-description:
- - Allows one to run different config-sync actions. These actions allow
- you to manually sync your configuration across multiple BIG-IPs when
- those devices are in an HA pair.
-version_added: 2.4
-options:
- device_group:
- description:
- - The device group that you want to perform config-sync actions on.
- type: str
- required: True
- sync_device_to_group:
- description:
- - Specifies that the system synchronizes configuration data from this
- device to other members of the device group. In this case, the device
- will do a "push" to all the other devices in the group. This option
- is mutually exclusive with the C(sync_group_to_device) option.
- type: bool
- sync_most_recent_to_device:
- description:
- - Specifies that the system synchronizes configuration data from the
- device with the most recent configuration. In this case, the device
- will do a "pull" from the most recently updated device. This option
- is mutually exclusive with the C(sync_device_to_group) options.
- type: bool
- overwrite_config:
- description:
- - Indicates that the sync operation overwrites the configuration on
- the target.
- type: bool
- default: no
-notes:
- - Requires the objectpath Python package on the host. This is as easy as
- C(pip install objectpath).
-extends_documentation_fragment: f5
-author:
- - Tim Rupp (@caphrim007)
- - Wojciech Wypior (@wojtek0806)
-'''
-
-EXAMPLES = r'''
-- name: Sync configuration from device to group
- bigip_configsync_action:
- device_group: foo-group
- sync_device_to_group: yes
- provider:
- server: lb.mydomain.com
- user: admin
- password: secret
- delegate_to: localhost
-
-- name: Sync configuration from most recent device to the current host
- bigip_configsync_action:
- device_group: foo-group
- sync_most_recent_to_device: yes
- provider:
- server: lb.mydomain.com
- user: admin
- password: secret
- delegate_to: localhost
-
-- name: Perform an initial sync of a device to a new device group
- bigip_configsync_action:
- device_group: new-device-group
- sync_device_to_group: yes
- provider:
- server: lb.mydomain.com
- user: admin
- password: secret
- delegate_to: localhost
-'''
-
-RETURN = r'''
-# only common fields returned
-'''
-
-import re
-import time
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.parsing.convert_bool import BOOLEANS_TRUE
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import f5_argument_spec
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import f5_argument_spec
-
-try:
- from objectpath import Tree
- HAS_OBJPATH = True
-except ImportError:
- HAS_OBJPATH = False
-
-
-class Parameters(AnsibleF5Parameters):
- api_attributes = []
- returnables = []
-
-
-class ApiParameters(Parameters):
- pass
-
-
-class ModuleParameters(Parameters):
- @property
- def direction(self):
- if self.sync_device_to_group:
- return 'to-group'
- else:
- return 'from-group'
-
- @property
- def sync_device_to_group(self):
- result = self._cast_to_bool(self._values['sync_device_to_group'])
- return result
-
- @property
- def sync_group_to_device(self):
- result = self._cast_to_bool(self._values['sync_group_to_device'])
- return result
-
- @property
- def force_full_push(self):
- if self.overwrite_config:
- return 'force-full-load-push'
- else:
- return ''
-
- @property
- def overwrite_config(self):
- result = self._cast_to_bool(self._values['overwrite_config'])
- return result
-
- def _cast_to_bool(self, value):
- if value is None:
- return None
- elif value in BOOLEANS_TRUE:
- return True
- else:
- return False
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class UsableChanges(Changes):
- pass
-
-
-class ReportableChanges(Changes):
- pass
-
-
-class Difference(object):
- pass
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(params=self.module.params)
- self.changes = UsableChanges()
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.client.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def exec_module(self):
- result = dict()
-
- changed = self.present()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def present(self):
- if not self._device_group_exists():
- raise F5ModuleError(
- "The specified 'device_group' not not exist."
- )
- if self._sync_to_group_required():
- raise F5ModuleError(
- "This device group needs an initial sync. Please use "
- "'sync_device_to_group'"
- )
- if self.exists():
- return False
- else:
- return self.execute()
-
- def _sync_to_group_required(self):
- status = self._get_status_from_resource()
- if status == 'Awaiting Initial Sync' and self.want.sync_group_to_device:
- return True
- return False
-
- def _device_group_exists(self):
- uri = "https://{0}:{1}/mgmt/tm/cm/device-group/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- self.want.device_group
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def execute(self):
- self.execute_on_device()
- self._wait_for_sync()
- return True
-
- def exists(self):
- status = self._get_status_from_resource()
- if status == 'In Sync':
- return True
- else:
- return False
-
- def execute_on_device(self):
- sync_cmd = 'config-sync {0} {1} {2}'.format(
- self.want.direction,
- self.want.device_group,
- self.want.force_full_push
- )
- uri = "https://{0}:{1}/mgmt/tm/cm".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- args = dict(
- command='run',
- utilCmdArgs=sync_cmd
- )
- resp = self.client.api.post(uri, json=args)
-
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def _wait_for_sync(self):
- # Wait no more than half an hour
- for x in range(1, 180):
- time.sleep(3)
- status = self._get_status_from_resource()
-
- # Changes Pending:
- # The existing device has changes made to it that
- # need to be sync'd to the group.
- #
- # Awaiting Initial Sync:
- # This is a new device group and has not had any sync
- # done yet. You _must_ `sync_device_to_group` in this
- # case.
- #
- # Not All Devices Synced:
- # A device group will go into this state immediately
- # after starting the sync and stay until all devices finish.
- #
- if status in ['Changes Pending']:
- details = self._get_details_from_resource()
- self._validate_pending_status(details)
- elif status in ['Awaiting Initial Sync', 'Not All Devices Synced']:
- pass
- elif status == 'In Sync':
- return
- elif status == 'Disconnected':
- raise F5ModuleError(
- "One or more devices are unreachable (disconnected). "
- "Resolve any communication problems before attempting to sync."
- )
- else:
- raise F5ModuleError(status)
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/cm/sync-status/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return response
-
- def _get_status_from_resource(self):
- resource = self.read_current_from_device()
- entries = resource['entries'].copy()
- k, v = entries.popitem()
- status = v['nestedStats']['entries']['status']['description']
- return status
-
- def _get_details_from_resource(self):
- resource = self.read_current_from_device()
- stats = resource['entries'].copy()
- if HAS_OBJPATH:
- tree = Tree(stats)
- else:
- raise F5ModuleError(
- "objectpath module required, install objectpath module to continue. "
- )
- details = list(tree.execute('$..*["details"]["description"]'))
- result = details[::-1]
- return result
-
- def _validate_pending_status(self, details):
- """Validate the content of a pending sync operation
-
- This is a hack. The REST API is not consistent with its 'status' values
- so this method is here to check the returned strings from the operation
- and see if it reported any of these inconsistencies.
-
- :param details:
- :raises F5ModuleError:
- """
- pattern1 = r'.*(?P<msg>Recommended\s+action.*)'
- for detail in details:
- matches = re.search(pattern1, detail)
- if matches:
- raise F5ModuleError(matches.group('msg'))
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = False
-
- argument_spec = dict(
- sync_device_to_group=dict(
- type='bool'
- ),
- sync_most_recent_to_device=dict(
- type='bool'
- ),
- overwrite_config=dict(
- type='bool',
- default='no'
- ),
- device_group=dict(
- required=True
- )
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
-
- self.required_one_of = [
- ['sync_device_to_group', 'sync_most_recent_to_device']
- ]
- self.mutually_exclusive = [
- ['sync_device_to_group', 'sync_most_recent_to_device']
- ]
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode,
- mutually_exclusive=spec.mutually_exclusive,
- required_one_of=spec.required_one_of
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_data_group.py b/lib/ansible/modules/network/f5/bigip_data_group.py
deleted file mode 100644
index ee6e1c840a..0000000000
--- a/lib/ansible/modules/network/f5/bigip_data_group.py
+++ /dev/null
@@ -1,1372 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_data_group
-short_description: Manage data groups on a BIG-IP
-description:
- - Allows for managing data groups on a BIG-IP. Data groups provide a way to store collections
- of values on a BIG-IP for later use in things such as LTM rules, iRules, and ASM policies.
-version_added: 2.6
-options:
- name:
- description:
- - Specifies the name of the data group.
- type: str
- required: True
- description:
- description:
- - The description of the data group.
- type: str
- version_added: 2.8
- type:
- description:
- - The type of records in this data group.
- - This parameter is especially important because it causes BIG-IP to store your data
- in different ways so-as to optimize access to it. For example, it would be wrong
- to specify a list of records containing IP addresses, but label them as a C(string)
- type.
- - This value cannot be changed once the data group is created.
- type: str
- choices:
- - address
- - addr
- - ip
- - string
- - str
- - integer
- - int
- default: string
- internal:
- description:
- - The type of this data group.
- - You should only consider setting this value in cases where you know exactly what
- you're doing, B(or), you are working with a pre-existing internal data group.
- - Be aware that if you deliberately force this parameter to C(yes), and you have a
- either a large number of records or a large total records size, this large amount
- of data will be reflected in your BIG-IP configuration. This can lead to B(long)
- system configuration load times due to needing to parse and verify the large
- configuration.
- - There is a limit of either 4 megabytes or 65,000 records (whichever is more restrictive)
- for uploads when this parameter is C(yes).
- - This value cannot be changed once the data group is created.
- type: bool
- default: no
- external_file_name:
- description:
- - When creating a new data group, this specifies the file name that you want to give an
- external data group file on the BIG-IP.
- - This parameter is ignored when C(internal) is C(yes).
- - This parameter can be used to select an existing data group file to use with an
- existing external data group.
- - If this value is not provided, it will be given the value specified in C(name) and,
- therefore, match the name of the data group.
- - This value may only contain letters, numbers, underscores, dashes, or a period.
- type: str
- records:
- description:
- - Specifies the records that you want to add to a data group.
- - If you have a large number of records, it is recommended that you use C(records_content)
- instead of typing all those records here.
- - The technical limit of either 1. the number of records, or 2. the total size of all
- records, varies with the size of the total resources on your system; in particular,
- RAM.
- - When C(internal) is C(no), at least one record must be specified in either C(records)
- or C(records_content).
- - "When C(type) is: C(ip), C(address), C(addr) if the addresses use non default route domain,
- they must be explicit about it that is they must contain a route domain notation C(%) eg. 10.10.1.1%11.
- This is true regardless if the data group resides in a partition or not."
- type: list
- suboptions:
- key:
- description:
- - The key describing the record in the data group.
- - Your key will be used for validation of the C(type) parameter to this module.
- type: str
- required: True
- value:
- description:
- - The value of the key describing the record in the data group.
- type: raw
- records_src:
- description:
- - Path to a file with records in it.
- - The file should be well-formed. This means that it includes records, one per line,
- that resemble the following format "key separator value". For example, C(foo := bar).
- - BIG-IP is strict about this format, but this module is a bit more lax. It will allow
- you to include arbitrary amounts (including none) of empty space on either side of
- the separator. For an illustration of this, see the Examples section.
- - Record keys are limited in length to no more than 65520 characters.
- - Values of record keys are limited in length to no more than 65520 characters.
- - The total number of records you can have in your BIG-IP is limited by the memory
- of the BIG-IP.
- - The format of this content is slightly different depending on whether you specify
- a C(type) of C(address), C(integer), or C(string). See the examples section for
- examples of the different types of payload formats that are expected in your data
- group file.
- - When C(internal) is C(no), at least one record must be specified in either C(records)
- or C(records_content).
- type: path
- separator:
- description:
- - When specifying C(records_content), this is the string of characters that will
- be used to break apart entries in the C(records_content) into key/value pairs.
- - By default, this parameter's value is C(:=).
- - This value cannot be changed once it is set.
- - This parameter is only relevant when C(internal) is C(no). It will be ignored
- otherwise.
- type: str
- default: ":="
- delete_data_group_file:
- description:
- - When C(yes), will ensure that the remote data group file is deleted.
- - This parameter is only relevant when C(state) is C(absent) and C(internal) is C(no).
- type: bool
- default: no
- partition:
- description:
- - Device partition to manage resources on.
- type: str
- default: Common
- state:
- description:
- - When C(state) is C(present), ensures the data group exists.
- - When C(state) is C(absent), ensures that the data group is removed.
- - The use of state in this module refers to the entire data group, not its members.
- type: str
- choices:
- - present
- - absent
- default: present
-notes:
- - This module does NOT support atomic updates of data group members in a type C(internal) data group.
-extends_documentation_fragment: f5
-author:
- - Tim Rupp (@caphrim007)
- - Wojciech Wypior (@wojtek0806)
- - Greg Crosby (@crosbygw)
-'''
-
-EXAMPLES = r'''
-- name: Create a data group of addresses
- bigip_data_group:
- name: foo
- internal: yes
- records:
- - key: 0.0.0.0/32
- value: External_NAT
- - key: 10.10.10.10
- value: No_NAT
- type: address
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-
-- name: Create a data group of strings
- bigip_data_group:
- name: foo
- internal: yes
- records:
- - key: caddy
- value: ""
- - key: cafeteria
- value: ""
- - key: cactus
- value: ""
- type: str
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-
-- name: Create a data group of IP addresses from a file
- bigip_data_group:
- name: foo
- records_src: /path/to/dg-file
- type: address
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-
-- name: Update an existing internal data group of strings
- bigip_data_group:
- name: foo
- internal: yes
- records:
- - key: caddy
- value: ""
- - key: cafeteria
- value: ""
- - key: cactus
- value: ""
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-
-- name: Show the data format expected for records_content - address 1
- copy:
- dest: /path/to/addresses.txt
- content: |
- network 10.0.0.0 prefixlen 8 := "Network1",
- network 172.16.0.0 prefixlen 12 := "Network2",
- network 192.168.0.0 prefixlen 16 := "Network3",
- network 2402:9400:1000:0:: prefixlen 64 := "Network4",
- host 192.168.20.1 := "Host1",
- host 172.16.1.1 := "Host2",
- host 172.16.1.1/32 := "Host3",
- host 2001:0db8:85a3:0000:0000:8a2e:0370:7334 := "Host4",
- host 2001:0db8:85a3:0000:0000:8a2e:0370:7334/128 := "Host5"
-
-- name: Show the data format expected for records_content - address 2
- copy:
- dest: /path/to/addresses.txt
- content: |
- 10.0.0.0/8 := "Network1",
- 172.16.0.0/12 := "Network2",
- 192.168.0.0/16 := "Network3",
- 2402:9400:1000:0::/64 := "Network4",
- 192.168.20.1 := "Host1",
- 172.16.1.1 := "Host2",
- 172.16.1.1/32 := "Host3",
- 2001:0db8:85a3:0000:0000:8a2e:0370:7334 := "Host4",
- 2001:0db8:85a3:0000:0000:8a2e:0370:7334/128 := "Host5"
-
-- name: Show the data format expected for records_content - string
- copy:
- dest: /path/to/strings.txt
- content: |
- a := alpha,
- b := bravo,
- c := charlie,
- x := x-ray,
- y := yankee,
- z := zulu,
-
-- name: Show the data format expected for records_content - integer
- copy:
- dest: /path/to/integers.txt
- content: |
- 1 := bar,
- 2 := baz,
- 3,
- 4,
-'''
-
-RETURN = r'''
-# only common fields returned
-'''
-
-import hashlib
-import os
-import re
-
-from ansible.module_utils._text import to_text
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.basic import env_fallback
-try:
- from StringIO import StringIO
-except ImportError:
- from io import StringIO
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import transform_name
- from library.module_utils.network.f5.compare import compare_complex_list
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.ipaddress import is_valid_ip_interface
- from library.module_utils.compat.ipaddress import ip_network
- from library.module_utils.compat.ipaddress import ip_interface
- from library.module_utils.network.f5.icontrol import upload_file
- from library.module_utils.network.f5.compare import cmp_str_with_none
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import transform_name
- from ansible.module_utils.network.f5.compare import compare_complex_list
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.ipaddress import is_valid_ip_interface
- from ansible.module_utils.compat.ipaddress import ip_network
- from ansible.module_utils.compat.ipaddress import ip_interface
- from ansible.module_utils.network.f5.icontrol import upload_file
- from ansible.module_utils.network.f5.compare import cmp_str_with_none
-
-
-LINE_LIMIT = 65000
-SIZE_LIMIT_BYTES = 4000000
-
-
-def zero_length(content):
- content.seek(0, os.SEEK_END)
- length = content.tell()
- content.seek(0)
- if length == 0:
- return True
- return False
-
-
-def size_exceeded(content):
- records = content
- records.seek(0, os.SEEK_END)
- size = records.tell()
- records.seek(0)
- if size > SIZE_LIMIT_BYTES:
- return True
- return False
-
-
-def lines_exceeded(content):
- result = False
- for i, line in enumerate(content):
- if i > LINE_LIMIT:
- result = True
- content.seek(0)
- return result
-
-
-class RecordsEncoder(object):
- def __init__(self, record_type=None, separator=None):
- self._record_type = record_type
- self._separator = separator
- self._network_pattern = re.compile(r'^network\s+(?P<addr>[^ ]+)\s+prefixlen\s+(?P<prefix>\d+)\s+.*')
- self._host_pattern = re.compile(r'^host\s+(?P<addr>[^ ]+)\s+.*')
- self._rd_net_pattern = re.compile(r'(?P<addr>[^%]+)%(?P<rd>[0-9]+)/(?P<prefix>[0-9]+)')
- self._rd_host_pattern = re.compile(r'(?P<addr>[^%]+)%(?P<rd>[0-9]+)')
-
- def encode(self, record):
- if isinstance(record, dict):
- return self.encode_dict(record)
- else:
- return self.encode_string(record)
-
- def encode_dict(self, record):
- if self._record_type == 'ip':
- return self.encode_address_from_dict(record)
- elif self._record_type == 'integer':
- return self.encode_integer_from_dict(record)
- else:
- return self.encode_string_from_dict(record)
-
- def encode_rd_address(self, record, match, host=False):
- if host:
- if is_valid_ip_interface(match.group('addr')):
- key = ip_interface(u"{0}".format(match.group('addr')))
- else:
- raise F5ModuleError(
- "When specifying an 'address' type, the value to the left of the separator must be an IP."
- )
- else:
- if is_valid_ip_interface(match.group('addr')):
- key = ip_interface(u"{0}/{1}".format(match.group('addr'), match.group('prefix')))
- else:
- raise F5ModuleError(
- "When specifying an 'address' type, the value to the left of the separator must be an IP."
- )
- if key and 'value' in record:
- if key.network.prefixlen in [32, 128]:
- return self.encode_host(str(key.ip) + '%' + match.group('rd'), record['value'])
- return self.encode_network(
- str(key.network.network_address) + '%' + match.group('rd'), key.network.prefixlen, record['value']
- )
- elif key:
- if key.network.prefixlen in [32, 128]:
- return self.encode_host(str(key.ip) + '%' + match.group('rd'), str(key.ip) + '%' + match.group('rd'))
- return self.encode_network(
- str(key.network.network_address) + '%' + match.group('rd'), key.network.prefixlen,
- str(key.network.network_address) + '%' + match.group('rd')
- )
-
- def encode_address_from_dict(self, record):
- rd_match = re.match(self._rd_net_pattern, record['key'])
- if rd_match:
- return self.encode_rd_address(record, rd_match)
- rd_match = re.match(self._rd_host_pattern, record['key'])
- if rd_match:
- return self.encode_rd_address(record, rd_match, host=True)
- if is_valid_ip_interface(record['key']):
- key = ip_interface(u"{0}".format(str(record['key'])))
- else:
- raise F5ModuleError(
- "When specifying an 'address' type, the value to the left of the separator must be an IP."
- )
- if key and 'value' in record:
- if key.network.prefixlen in [32, 128]:
- return self.encode_host(str(key.ip), record['value'])
- return self.encode_network(
- str(key.network.network_address), key.network.prefixlen, record['value']
- )
- elif key:
- if key.network.prefixlen in [32, 128]:
- return self.encode_host(str(key.ip), str(key.ip))
- return self.encode_network(
- str(key.network.network_address), key.network.prefixlen, str(key.network.network_address)
- )
-
- def encode_integer_from_dict(self, record):
- try:
- int(record['key'])
- except ValueError:
- raise F5ModuleError(
- "When specifying an 'integer' type, the value to the left of the separator must be a number."
- )
- if 'key' in record and 'value' in record:
- return '{0} {1} {2}'.format(record['key'], self._separator, record['value'])
- elif 'key' in record:
- return str(record['key'])
-
- def encode_string_from_dict(self, record):
- if 'key' in record and 'value' in record:
- return '{0} {1} {2}'.format(record['key'], self._separator, record['value'])
- elif 'key' in record:
- return '{0} {1} ""'.format(record['key'], self._separator)
-
- def encode_string(self, record):
- record = record.strip().strip(',')
- if self._record_type == 'ip':
- return self.encode_address_from_string(record)
- elif self._record_type == 'integer':
- return self.encode_integer_from_string(record)
- else:
- return self.encode_string_from_string(record)
-
- def encode_address_from_string(self, record):
- if self._network_pattern.match(record):
- # network 192.168.0.0 prefixlen 16 := "Network3",
- # network 2402:9400:1000:0:: prefixlen 64 := "Network4",
- return record
- elif self._host_pattern.match(record):
- # host 172.16.1.1/32 := "Host3"
- # host 2001:0db8:85a3:0000:0000:8a2e:0370:7334 := "Host4"
- return record
- elif self._rd_net_pattern.match(record) or self._rd_host_pattern.match(record):
- # 192.168.0.0%11/16 := "Network3",
- # 2402:9400:1000:0::%11/64 := "Network4",
- # 192.168.1.1%11/32 := "Host3",
- # 2001:0db8:85a3:0000:0000:8a2e:0370:7334%11 := "Host4"
- return record
- else:
- # 192.168.0.0/16 := "Network3",
- # 2402:9400:1000:0::/64 := "Network4",
- parts = record.split(self._separator)
- if parts[0] == '':
- return
- if not is_valid_ip_interface(parts[0]):
- raise F5ModuleError(
- "When specifying an 'address' type, the value to the left of the separator must be an IP."
- )
- key = ip_interface(u"{0}".format(str(parts[0])))
-
- if len(parts) == 2:
- if key.network.prefixlen in [32, 128]:
- return self.encode_host(str(key.ip), parts[1])
- return self.encode_network(
- str(key.network.network_address), key.network.prefixlen, parts[1]
- )
- elif len(parts) == 1 and parts[0] != '':
- if key.network.prefixlen in [32, 128]:
- return self.encode_host(str(key.ip), str(key.ip))
- return self.encode_network(
- str(key.network.network_address), key.network.prefixlen, str(key.network.network_address)
- )
-
- def encode_host(self, key, value):
- return 'host {0} {1} {2}'.format(str(key), self._separator, str(value))
-
- def encode_network(self, key, prefixlen, value):
- return 'network {0} prefixlen {1} {2} {3}'.format(
- str(key), str(prefixlen), self._separator, str(value)
- )
-
- def encode_integer_from_string(self, record):
- parts = record.split(self._separator)
- if len(parts) == 1 and parts[0] == '':
- return None
- try:
- int(parts[0])
- except ValueError:
- raise F5ModuleError(
- "When specifying an 'integer' type, the value to the left of the separator must be a number."
- )
- if len(parts) == 2:
- return '{0} {1} {2}'.format(parts[0], self._separator, parts[1])
- elif len(parts) == 1:
- return str(parts[0])
-
- def encode_string_from_string(self, record):
- parts = record.split(self._separator)
- if len(parts) == 2:
- return '{0} {1} {2}'.format(parts[0], self._separator, parts[1])
- elif len(parts) == 1 and parts[0] != '':
- return '{0} {1} ""'.format(parts[0], self._separator)
-
-
-class RecordsDecoder(object):
- def __init__(self, record_type=None, separator=None):
- self._record_type = record_type
- self._separator = separator
- self._network_pattern = re.compile(r'^network\s+(?P<addr>[^ ]+)\s+prefixlen\s+(?P<prefix>\d+)\s+.*')
- self._host_pattern = re.compile(r'^host\s+(?P<addr>[^ ]+)\s+.*')
- self._rd_net_ptrn = re.compile(r'^network\s+(?P<addr>[^%]+)%(?P<rd>[0-9]+)\s+prefixlen\s+(?P<prefix>\d+)\s+.*')
- self._rd_host_ptrn = re.compile(r'^host\s+(?P<addr>[^%]+)%(?P<rd>[0-9]+)\s+.*')
-
- def decode(self, record):
- record = record.strip().strip(',')
- if self._record_type == 'ip':
- return self.decode_address_from_string(record)
- else:
- return self.decode_from_string(record)
-
- def decode_address_from_string(self, record):
- matches = self._rd_net_ptrn.match(record)
- if matches:
- # network 192.168.0.0%11 prefixlen 16 := "Network3",
- # network 2402:9400:1000:0::%11 prefixlen 64 := "Network4",
- value = record.split(self._separator)[1].strip().strip('"')
- addr = "{0}%{1}/{2}".format(matches.group('addr'), matches.group('rd'), matches.group('prefix'))
- result = dict(name=addr, data=value)
- return result
- matches = self._network_pattern.match(record)
- if matches:
- # network 192.168.0.0 prefixlen 16 := "Network3",
- # network 2402:9400:1000:0:: prefixlen 64 := "Network4",
- key = u"{0}/{1}".format(matches.group('addr'), matches.group('prefix'))
- addr = ip_network(key)
- value = record.split(self._separator)[1].strip().strip('"')
- result = dict(name=str(addr), data=value)
- return result
- matches = self._rd_host_ptrn.match(record)
- if matches:
- # host 172.16.1.1%11/32 := "Host3"
- # host 2001:0db8:85a3:0000:0000:8a2e:0370:7334%11 := "Host4"
- host = ip_interface(u"{0}".format(matches.group('addr')))
- addr = "{0}%{1}/{2}".format(matches.group('addr'), matches.group('rd'), str(host.network.prefixlen))
- value = record.split(self._separator)[1].strip().strip('"')
- result = dict(name=addr, data=value)
- return result
- matches = self._host_pattern.match(record)
- if matches:
- # host 172.16.1.1/32 := "Host3"
- # host 2001:0db8:85a3:0000:0000:8a2e:0370:7334 := "Host4"
- key = matches.group('addr')
- addr = ip_interface(u"{0}".format(str(key)))
- value = record.split(self._separator)[1].strip().strip('"')
- result = dict(name=str(addr), data=value)
- return result
-
- raise F5ModuleError(
- 'The value "{0}" is not an address'.format(record)
- )
-
- def decode_from_string(self, record):
- parts = record.split(self._separator)
- if len(parts) == 2:
- return dict(name=parts[0].strip(), data=parts[1].strip('"').strip())
- else:
- return dict(name=parts[0].strip(), data="")
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'externalFileName': 'external_file_name',
- }
-
- api_attributes = [
- 'records',
- 'type',
- 'description',
- ]
-
- returnables = [
- 'type',
- 'records',
- 'description',
- ]
-
- updatables = [
- 'records',
- 'checksum',
- 'description',
- ]
-
- @property
- def type(self):
- if self._values['type'] in ['address', 'addr', 'ip']:
- return 'ip'
- elif self._values['type'] in ['integer', 'int']:
- return 'integer'
- elif self._values['type'] in ['string']:
- return 'string'
-
- @property
- def records_src(self):
- try:
- self._values['records_src'].seek(0)
- return self._values['records_src']
- except AttributeError:
- pass
-
- if self._values['records_src']:
- records = open(self._values['records_src'])
- else:
- records = self._values['records']
-
- if records is None:
- return None
-
- # There is a 98% chance that the user will supply a data group that is < 1MB.
- # 99.917% chance it is less than 10 MB. This is well within the range of typical
- # memory available on a system.
- #
- # If this changes, this may need to be changed to use temporary files instead.
- self._values['records_src'] = StringIO()
-
- self._write_records_to_file(records)
- return self._values['records_src']
-
- def _write_records_to_file(self, records):
- bucket_size = 1000000
- bucket = []
- encoder = RecordsEncoder(record_type=self.type, separator=self.separator)
- for record in records:
- result = encoder.encode(record)
- if result:
- bucket.append(to_text(result + ",\n"))
- if len(bucket) == bucket_size:
- self._values['records_src'].writelines(bucket)
- bucket = []
- self._values['records_src'].writelines(bucket)
- self._values['records_src'].seek(0)
-
-
-class ApiParameters(Parameters):
- @property
- def checksum(self):
- if self._values['checksum'] is None:
- return None
- result = self._values['checksum'].split(':')[2]
- return result
-
- @property
- def records_list(self):
- return self._values['records']
-
- @property
- def description(self):
- if self._values['description'] in [None, 'none']:
- return None
- return self._values['description']
-
-
-class ModuleParameters(Parameters):
- @property
- def description(self):
- if self._values['description'] is None:
- return None
- elif self._values['description'] in ['none', '']:
- return ''
- return self._values['description']
-
- @property
- def checksum(self):
- if self._values['checksum']:
- return self._values['checksum']
- if self.records_src is None:
- return None
- result = hashlib.sha1()
- records = self.records_src
- while True:
- data = records.read(4096)
- if not data:
- break
- result.update(data.encode('utf-8'))
- result = result.hexdigest()
- self._values['checksum'] = result
- return result
-
- @property
- def external_file_name(self):
- if self._values['external_file_name'] is None:
- name = self.name
- else:
- name = self._values['external_file_name']
- if re.search(r'[^a-zA-Z0-9-_.]', name):
- raise F5ModuleError(
- "'external_file_name' may only contain letters, numbers, underscores, dashes, or a period."
- )
- return name
-
- @property
- def records(self):
- results = []
- if self.records_src is None:
- return None
- decoder = RecordsDecoder(record_type=self.type, separator=self.separator)
- for record in self.records_src:
- result = decoder.decode(record)
- if result:
- results.append(result)
- return results
-
- @property
- def records_list(self):
- if self._values['records'] is None:
- return None
- return self.records
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class UsableChanges(Changes):
- pass
-
-
-class ReportableChanges(Changes):
- pass
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
- @property
- def records(self):
- # External data groups are compared by their checksum, not their records. This
- # is because the BIG-IP does not store the actual records in the API. It instead
- # stores the checksum of the file. External DGs have the possibility of being huge
- # and we would never want to do a comparison of such huge files.
- #
- # Therefore, comparison is no-op if the DG being worked with is an external DG.
- if self.want.internal is False:
- return None
- if self.have.records is None and self.want.records == []:
- return None
- if self.have.records is None:
- return self.want.records
- result = compare_complex_list(self.want.records, self.have.records)
- return result
-
- @property
- def type(self):
- return None
-
- @property
- def checksum(self):
- if self.want.internal:
- return None
- if self.want.checksum is None:
- return None
- if self.want.checksum != self.have.checksum:
- return True
-
- @property
- def description(self):
- return cmp_str_with_none(self.want.description, self.have.description)
-
-
-class BaseManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(params=self.module.params)
- self.have = ApiParameters()
- self.changes = UsableChanges()
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def exec_module(self):
- changed = False
- result = dict()
- state = self.want.state
-
- if state == "present":
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.client.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def _set_changed_options(self):
- changed = {}
- for key in ApiParameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = UsableChanges(params=changed)
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = ApiParameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def present(self):
- if self.exists():
- return self.update()
- else:
- return self.create()
-
- def absent(self):
- if self.exists():
- return self.remove()
- return False
-
- def remove(self):
- if self.module.check_mode:
- return True
- self.remove_from_device()
- if self.exists():
- raise F5ModuleError("Failed to delete the resource.")
- return True
-
-
-class InternalManager(BaseManager):
- def create(self):
- self._set_changed_options()
- if size_exceeded(self.want.records_src) or lines_exceeded(self.want.records_src):
- raise F5ModuleError(
- "The size of the provided data (or file) is too large for an internal data group."
- )
- if self.module.check_mode:
- return True
- self.create_on_device()
- return True
-
- def update(self):
- self.have = self.read_current_from_device()
- if not self.should_update():
- return False
- if self.module.check_mode:
- return True
- self.update_on_device()
- return True
-
- def exists(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/data-group/internal/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def create_on_device(self):
- params = self.changes.api_params()
- params['name'] = self.want.name
- params['partition'] = self.want.partition
- uri = "https://{0}:{1}/mgmt/tm/ltm/data-group/internal/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403, 409]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def update_on_device(self):
- params = self.changes.api_params()
- uri = "https://{0}:{1}/mgmt/tm/ltm/data-group/internal/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def remove_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/data-group/internal/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.delete(uri)
- if resp.status == 200:
- return True
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/data-group/internal/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return ApiParameters(params=response)
-
-
-class ExternalManager(BaseManager):
- def absent(self):
- result = False
- if self.exists():
- result = self.remove()
- if self.external_file_exists() and self.want.delete_data_group_file:
- result = self.remove_data_group_file_from_device()
- return result
-
- def create(self):
- if zero_length(self.want.records_src):
- raise F5ModuleError(
- "An external data group cannot be empty."
- )
- self._set_changed_options()
- if self.module.check_mode:
- return True
- self.create_on_device()
- return True
-
- def update(self):
- self.have = self.read_current_from_device()
- if not self.should_update():
- return False
- if self.changes.records_src and zero_length(self.want.records_src):
- raise F5ModuleError(
- "An external data group cannot be empty."
- )
- if self.module.check_mode:
- return True
- self.update_on_device()
- return True
-
- def exists(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/data-group/external/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def external_file_exists(self):
- uri = "https://{0}:{1}/mgmt/tm/sys/file/data-group/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.external_file_name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def upload_file_to_device(self, content, name):
- url = 'https://{0}:{1}/mgmt/shared/file-transfer/uploads'.format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- try:
- upload_file(self.client, url, content, name)
- except F5ModuleError:
- raise F5ModuleError(
- "Failed to upload the file."
- )
-
- def _upload_to_file(self, name, type, remote_path, update=False):
- self.upload_file_to_device(self.want.records_src, name)
- if update:
- uri = "https://{0}:{1}/mgmt/tm/sys/file/data-group/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, name)
- )
- params = {'sourcePath': 'file:{0}'.format(remote_path)}
- resp = self.client.api.patch(uri, json=params)
-
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- else:
- uri = "https://{0}:{1}/mgmt/tm/sys/file/data-group/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- params = dict(
- name=name,
- type=type,
- sourcePath='file:{0}'.format(remote_path)
- )
- resp = self.client.api.post(uri, json=params)
-
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return response['name']
-
- def remove_file_on_device(self, remote_path):
- uri = "https://{0}:{1}/mgmt/tm/util/unix-rm/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- args = dict(
- command='run',
- utilCmdArgs=remote_path
- )
- resp = self.client.api.post(uri, json=args)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def create_on_device(self):
- name = self.want.external_file_name
- remote_path = '/var/config/rest/downloads/{0}'.format(name)
- external_file = self._upload_to_file(name, self.want.type, remote_path, update=False)
-
- params = dict(
- name=self.want.name,
- partition=self.want.partition,
- externalFileName=external_file,
- )
- if self.want.description:
- params['description'] = self.want.description
-
- uri = "https://{0}:{1}/mgmt/tm/ltm/data-group/external/".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- resp = self.client.api.post(uri, json=params)
-
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- self.remove_file_on_device(remote_path)
-
- def update_on_device(self):
- params = {}
-
- if self.want.records_src is not None:
- name = self.want.external_file_name
- remote_path = '/var/config/rest/downloads/{0}'.format(name)
- external_file = self._upload_to_file(name, self.have.type, remote_path, update=True)
- params['externalFileName'] = external_file
- if self.changes.description is not None:
- params['description'] = self.changes.description
-
- if not params:
- return
-
- uri = "https://{0}:{1}/mgmt/tm/ltm/data-group/external/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
-
- resp = self.client.api.patch(uri, json=params)
-
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def remove_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/data-group/external/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.delete(uri)
-
- # Remove the remote data group file if asked to
- if self.want.delete_data_group_file:
- self.remove_data_group_file_from_device()
-
- if resp.status == 200:
- return True
-
- def remove_data_group_file_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/sys/file/data-group/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.external_file_name)
- )
- resp = self.client.api.delete(uri)
-
- if resp.status == 200:
- return True
- else:
- return False
-
- def read_current_from_device(self):
- """Reads the current configuration from the device
-
- For an external data group, we are interested in two things from the
- current configuration
-
- * ``checksum``
- * ``type``
-
- The ``checksum`` will allow us to compare the data group value we have
- with the data group value being provided.
-
- The ``type`` will allow us to do validation on the data group value being
- provided (if any).
-
- Returns:
- ExternalApiParameters: Attributes of the remote resource.
- """
-
- uri = "https://{0}:{1}/mgmt/tm/ltm/data-group/external/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp_dg = self.client.api.get(uri)
-
- try:
- response_dg = resp_dg.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response_dg and response_dg['code'] == 400:
- if 'message' in response_dg:
- raise F5ModuleError(response_dg['message'])
- else:
- raise F5ModuleError(resp_dg.content)
-
- external_file = os.path.basename(response_dg['externalFileName'])
- external_file_partition = os.path.dirname(response_dg['externalFileName']).strip('/')
-
- uri = "https://{0}:{1}/mgmt/tm/sys/file/data-group/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(external_file_partition, external_file)
- )
- resp = self.client.api.get(uri)
-
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- result = ApiParameters(params=response)
- result.update({'description': response_dg.get('description', None)})
- return result
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.kwargs = kwargs
- self.module = kwargs.get('module')
-
- def exec_module(self):
- if self.module.params['internal']:
- manager = self.get_manager('internal')
- else:
- manager = self.get_manager('external')
- return manager.exec_module()
-
- def get_manager(self, type):
- if type == 'internal':
- return InternalManager(**self.kwargs)
- elif type == 'external':
- return ExternalManager(**self.kwargs)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- name=dict(required=True),
- type=dict(
- choices=['address', 'addr', 'ip', 'string', 'str', 'integer', 'int'],
- default='string'
- ),
- delete_data_group_file=dict(type='bool'),
- internal=dict(type='bool', default='no'),
- records=dict(
- type='list',
- suboptions=dict(
- key=dict(required=True),
- value=dict(type='raw')
- )
- ),
- records_src=dict(type='path'),
- external_file_name=dict(),
- separator=dict(default=':='),
- description=dict(),
- state=dict(choices=['absent', 'present'], default='present'),
- partition=dict(
- default='Common',
- fallback=(env_fallback, ['F5_PARTITION'])
- )
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
- self.mutually_exclusive = [
- ['records', 'records_content', 'external_file_name']
- ]
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode,
- mutually_exclusive=spec.mutually_exclusive
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_device_auth.py b/lib/ansible/modules/network/f5/bigip_device_auth.py
deleted file mode 100644
index d0cb44d2b9..0000000000
--- a/lib/ansible/modules/network/f5/bigip_device_auth.py
+++ /dev/null
@@ -1,803 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2018, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_device_auth
-short_description: Manage system authentication on a BIG-IP
-description:
- - Manage the system authentication configuration. This module can assist in configuring
- a number of different system authentication types. Note that this module can not be used
- to configure APM authentication types.
-version_added: 2.7
-options:
- type:
- description:
- - The authentication type to manage with this module.
- - Take special note that the parameters supported by this module will vary depending
- on the C(type) that you are configuring.
- - This module only supports a subset, at this time, of the total available auth types.
- type: str
- choices:
- - tacacs
- - local
- servers:
- description:
- - Specifies a list of the IPv4 addresses for servers using the Terminal
- Access Controller Access System (TACACS)+ protocol with which the system
- communicates to obtain authorization data.
- - For each address, an alternate TCP port number may be optionally specified
- by specifying the C(port) key.
- - If no port number is specified, the default port C(49163) is used.
- - This parameter is supported by the C(tacacs) type.
- type: raw
- suboptions:
- address:
- description:
- - The IP address of the server.
- - This field is required, unless you are specifying a simple list of servers.
- In that case, the simple list can specify server IPs. See examples for
- more clarification.
- port:
- description:
- - The port of the server.
- default: 49163
- secret:
- description:
- - Secret key used to encrypt and decrypt packets sent or received from the
- server.
- - B(Do not) use the pound/hash sign in the secret for TACACS+ servers.
- - When configuring TACACS+ auth for the first time, this value is required.
- type: str
- service_name:
- description:
- - Specifies the name of the service that the user is requesting to be
- authorized to use.
- - Identifying what the user is asking to be authorized for, enables the
- TACACS+ server to behave differently for different types of authorization
- requests.
- - When configuring this form of system authentication, this setting is required.
- - Note that the majority of TACACS+ implementations are of service type C(ppp),
- so try that first.
- type: str
- choices:
- - slip
- - ppp
- - arap
- - shell
- - tty-daemon
- - connection
- - system
- - firewall
- protocol_name:
- description:
- - Specifies the protocol associated with the value specified in C(service_name),
- which is a subset of the associated service being used for client authorization
- or system accounting.
- - Note that the majority of TACACS+ implementations are of protocol type C(ip),
- so try that first.
- type: str
- choices:
- - lcp
- - ip
- - ipx
- - atalk
- - vines
- - lat
- - xremote
- - tn3270
- - telnet
- - rlogin
- - pad
- - vpdn
- - ftp
- - http
- - deccp
- - osicp
- - unknown
- authentication:
- description:
- - Specifies the process the system employs when sending authentication requests.
- - When C(use-first-server), specifies that the system sends authentication
- attempts to only the first server in the list.
- - When C(use-all-servers), specifies that the system sends an authentication
- request to each server until authentication succeeds, or until the system has
- sent a request to all servers in the list.
- - This parameter is supported by the C(tacacs) type.
- type: str
- choices:
- - use-first-server
- - use-all-servers
- use_for_auth:
- description:
- - Specifies whether or not this auth source is put in use on the system.
- type: bool
- state:
- description:
- - The state of the authentication configuration on the system.
- - When C(present), guarantees that the system is configured for the specified C(type).
- - When C(absent), sets the system auth source back to C(local).
- type: str
- choices:
- - absent
- - present
- default: present
- update_secret:
- description:
- - C(always) will allow to update secrets if the user chooses to do so.
- - C(on_create) will only set the secret when a C(use_auth_source) is C(yes)
- and TACACS+ is not currently the auth source.
- type: str
- choices:
- - always
- - on_create
- default: always
-extends_documentation_fragment: f5
-author:
- - Tim Rupp (@caphrim007)
-'''
-
-EXAMPLES = r'''
-- name: Set the system auth to TACACS+, default server port
- bigip_device_auth:
- type: tacacs
- authentication: use-all-servers
- protocol_name: ip
- secret: secret
- servers:
- - 10.10.10.10
- - 10.10.10.11
- service_name: ppp
- state: present
- use_for_auth: yes
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-
-- name: Set the system auth to TACACS+, override server port
- bigip_device_auth:
- type: tacacs
- authentication: use-all-servers
- protocol_name: ip
- secret: secret
- servers:
- - address: 10.10.10.10
- port: 1234
- - 10.10.10.11
- service_name: ppp
- use_for_auth: yes
- state: present
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-'''
-
-RETURN = r'''
-servers:
- description: List of servers used in TACACS authentication.
- returned: changed
- type: list
- sample: ['1.2.2.1', '4.5.5.4']
-authentication:
- description: Process the system uses to serve authentication requests when using TACACS.
- returned: changed
- type: str
- sample: use-all-servers
-service_name:
- description: Name of the service the user is requesting to be authorized to use.
- returned: changed
- type: str
- sample: ppp
-protocol_name:
- description: Name of the protocol associated with C(service_name) used for client authentication.
- returned: changed
- type: str
- sample: ip
-'''
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.six import string_types
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import f5_argument_spec
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import f5_argument_spec
-
-
-class BaseParameters(AnsibleF5Parameters):
- @property
- def api_map(self):
- return {}
-
- @property
- def api_attributes(self):
- return []
-
- @property
- def returnables(self):
- return []
-
- @property
- def updatables(self):
- return []
-
-
-class BaseApiParameters(BaseParameters):
- pass
-
-
-class BaseModuleParameters(BaseParameters):
- pass
-
-
-class BaseChanges(BaseParameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class BaseUsableChanges(BaseChanges):
- pass
-
-
-class BaseReportableChanges(BaseChanges):
- pass
-
-
-class TacacsParameters(BaseParameters):
- api_map = {
- 'protocol': 'protocol_name',
- 'service': 'service_name'
- }
-
- api_attributes = [
- 'authentication',
- 'protocol',
- 'service',
- 'secret',
- 'servers'
- ]
-
- returnables = [
- 'servers',
- 'secret',
- 'authentication',
- 'service_name',
- 'protocol_name'
- ]
-
- updatables = [
- 'servers',
- 'secret',
- 'authentication',
- 'service_name',
- 'protocol_name',
- 'auth_source',
- ]
-
-
-class TacacsApiParameters(TacacsParameters):
- pass
-
-
-class TacacsModuleParameters(TacacsParameters):
- @property
- def servers(self):
- if self._values['servers'] is None:
- return None
- result = []
- for server in self._values['servers']:
- if isinstance(server, dict):
- if 'address' not in server:
- raise F5ModuleError(
- "An 'address' field must be provided when specifying separate fields to the 'servers' parameter."
- )
- address = server.get('address')
- port = server.get('port', 49163)
- elif isinstance(server, string_types):
- address = server
- port = 49163
- result.append('{0}:{1}'.format(address, port))
- return result
-
- @property
- def auth_source(self):
- return 'tacacs'
-
-
-class TacacsChanges(BaseChanges, TacacsParameters):
- pass
-
-
-class TacacsUsableChanges(TacacsChanges):
- pass
-
-
-class TacacsReportableChanges(TacacsChanges):
- @property
- def secret(self):
- return None
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- def __default(self, param):
- want = getattr(self.want, param)
- try:
- have = getattr(self.have, param)
- if want != have:
- return want
- except AttributeError:
- return want
-
- @property
- def secret(self):
- if self.want.secret != self.have.secret and self.want.update_secret == 'always':
- return self.want.secret
-
-
-class BaseManager(object):
- def _set_changed_options(self):
- changed = {}
- for key in self.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = self.get_usable_changes(params=changed)
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = self.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = self.get_usable_changes(params=changed)
- return True
- return False
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def exec_module(self):
- changed = False
- result = dict()
- state = self.want.state
-
- if state == "present":
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
-
- reportable = self.get_reportable_changes(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.client.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def present(self):
- if self.exists():
- return self.update()
- return self.create()
-
- def absent(self):
- if self.exists():
- return self.remove()
- return False
-
- def update_auth_source_on_device(self, source):
- """Set the system auth source.
-
- Configuring the authentication source is only one step in the process of setting
- up an auth source. The other step is to inform the system of the auth source
- you want to use.
-
- This method is used for situations where
-
- * The ``use_for_auth`` parameter is set to ``yes``
- * The ``use_for_auth`` parameter is set to ``no``
- * The ``state`` parameter is set to ``absent``
-
- When ``state`` equal to ``absent``, before you can delete the TACACS+ configuration,
- you must set the system auth to "something else". The system ships with a system
- auth called "local", so this is the logical "something else" to use.
-
- When ``use_for_auth`` is no, the same situation applies as when ``state`` equal
- to ``absent`` is done above.
-
- When ``use_for_auth`` is ``yes``, this method will set the current system auth
- state to TACACS+.
-
- Arguments:
- source (string): The source that you want to set on the device.
- """
- params = dict(
- type=source
- )
- uri = 'https://{0}:{1}/mgmt/tm/auth/source/'.format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
-
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def read_current_auth_source_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/auth/source".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return response['type']
-
-
-class LocalManager(BaseManager):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = self.get_module_parameters(params=self.module.params)
- self.have = self.get_api_parameters()
- self.changes = self.get_usable_changes()
-
- @property
- def returnables(self):
- return []
-
- @property
- def updatables(self):
- return []
-
- def get_parameters(self, params=None):
- return BaseParameters(params=params)
-
- def get_usable_changes(self, params=None):
- return BaseUsableChanges(params=params)
-
- def get_reportable_changes(self, params=None):
- return BaseReportableChanges(params=params)
-
- def get_module_parameters(self, params=None):
- return BaseModuleParameters(params=params)
-
- def get_api_parameters(self, params=None):
- return BaseApiParameters(params=params)
-
- def exists(self):
- uri = "https://{0}:{1}/mgmt/tm/auth/source".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- if response['type'] == 'local':
- return True
- return False
-
- def create(self):
- self._set_changed_options()
- if self.module.check_mode:
- return True
- self.update_auth_source_on_device('local')
- return True
-
- def present(self):
- if not self.exists():
- return self.create()
-
- def absent(self):
- raise F5ModuleError(
- "The 'local' type cannot be removed. "
- "Instead, specify a 'state' of 'present' on other types."
- )
-
-
-class TacacsManager(BaseManager):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = self.get_module_parameters(params=self.module.params)
- self.have = self.get_api_parameters()
- self.changes = self.get_usable_changes()
-
- @property
- def returnables(self):
- return TacacsParameters.returnables
-
- @property
- def updatables(self):
- return TacacsParameters.updatables
-
- def get_usable_changes(self, params=None):
- return TacacsUsableChanges(params=params)
-
- def get_reportable_changes(self, params=None):
- return TacacsReportableChanges(params=params)
-
- def get_module_parameters(self, params=None):
- return TacacsModuleParameters(params=params)
-
- def get_api_parameters(self, params=None):
- return TacacsApiParameters(params=params)
-
- def exists(self):
- uri = "https://{0}:{1}/mgmt/tm/auth/tacacs/~Common~system-auth".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def create(self):
- self._set_changed_options()
- if self.module.check_mode:
- return True
- self.create_on_device()
- if self.want.use_for_auth:
- self.update_auth_source_on_device('tacacs')
- return True
-
- def update(self):
- self.have = self.read_current_from_device()
- if not self.should_update():
- return False
- if self.module.check_mode:
- return True
- result = False
- if self.update_on_device():
- result = True
- if self.want.use_for_auth and self.changes.auth_source == 'tacacs':
- self.update_auth_source_on_device('tacacs')
- result = True
- return result
-
- def remove(self):
- if self.module.check_mode:
- return True
- self.update_auth_source_on_device('local')
- self.remove_from_device()
- if self.exists():
- raise F5ModuleError("Failed to delete the resource.")
- return True
-
- def create_on_device(self):
- params = self.changes.api_params()
- params['name'] = 'system-auth'
- uri = "https://{0}:{1}/mgmt/tm/auth/tacacs".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def update_on_device(self):
- params = self.changes.api_params()
- if not params:
- return False
-
- uri = 'https://{0}:{1}/mgmt/tm/auth/tacacs/~Common~system-auth'.format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
-
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return True
-
- def remove_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/auth/tacacs/~Common~system-auth".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- resp = self.client.api.delete(uri)
- if resp.status == 200:
- return True
- raise F5ModuleError(resp.content)
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/auth/tacacs/~Common~system-auth".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- response['auth_source'] = self.read_current_auth_source_from_device()
- return self.get_api_parameters(params=response)
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.kwargs = kwargs
-
- def exec_module(self):
- manager = self.get_manager(self.module.params['type'])
- return manager.exec_module()
-
- def get_manager(self, type):
- if type == 'tacacs':
- return TacacsManager(**self.kwargs)
- elif type == 'local':
- return LocalManager(**self.kwargs)
- else:
- raise F5ModuleError(
- "The provided 'type' is unknown."
- )
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- type=dict(
- required=True,
- choices=['local', 'tacacs']
- ),
- servers=dict(type='raw'),
- secret=dict(no_log=True),
- service_name=dict(
- choices=[
- 'slip', 'ppp', 'arap', 'shell', 'tty-daemon',
- 'connection', 'system', 'firewall'
- ]
- ),
- protocol_name=dict(
- choices=[
- 'lcp', 'ip', 'ipx', 'atalk', 'vines', 'lat',
- 'xremote', 'tn3270', 'telnet', 'rlogin', 'pad',
- 'vpdn', 'ftp', 'http', 'deccp', 'osicp', 'unknown'
- ]
- ),
- authentication=dict(
- choices=[
- 'use-first-server',
- 'use-all-servers'
- ]
- ),
- use_for_auth=dict(type='bool'),
- update_secret=dict(
- choices=['always', 'on_create'],
- default='always'
- ),
- state=dict(
- default='present',
- choices=['present', 'absent']
- ),
-
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode,
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_device_auth_ldap.py b/lib/ansible/modules/network/f5/bigip_device_auth_ldap.py
deleted file mode 100644
index 891c871a57..0000000000
--- a/lib/ansible/modules/network/f5/bigip_device_auth_ldap.py
+++ /dev/null
@@ -1,844 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2018, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_device_auth_ldap
-short_description: Manage LDAP device authentication settings on BIG-IP
-description:
- - Manage LDAP device authentication settings on BIG-IP.
-version_added: 2.8
-options:
- servers:
- description:
- - Specifies the LDAP servers that the system must use to obtain
- authentication information. You must specify a server when you
- create an LDAP configuration object.
- type: list
- port:
- description:
- - Specifies the port that the system uses for access to the remote host server.
- - When configuring LDAP device authentication for the first time, if this parameter
- is not specified, the default port is C(389).
- type: int
- remote_directory_tree:
- description:
- - Specifies the file location (tree) of the user authentication database on the
- server.
- type: str
- scope:
- description:
- - Specifies the level of the remote Active Directory or LDAP directory that the
- system should search for the user authentication.
- type: str
- choices:
- - sub
- - one
- - base
- bind_dn:
- description:
- - Specifies the distinguished name for the Active Directory or LDAP server user
- ID.
- - The BIG-IP client authentication module does not support Active Directory or
- LDAP servers that do not perform bind referral when authenticating referred
- accounts.
- - Therefore, if you plan to use Active Directory or LDAP as your authentication
- source and want to use referred accounts, make sure your servers perform bind
- referral.
- type: str
- bind_password:
- description:
- - Specifies a password for the Active Directory or LDAP server user ID.
- type: str
- user_template:
- description:
- - Specifies the distinguished name of the user who is logging on.
- - You specify the template as a variable that the system replaces with user-specific
- information during the logon attempt.
- - For example, you could specify a user template such as C(%s@siterequest.com) or
- C(uxml:id=%s,ou=people,dc=siterequest,dc=com).
- - When a user attempts to log on, the system replaces C(%s) with the name the user
- specified in the Basic Authentication dialog box, and passes that as the
- distinguished name for the bind operation.
- - The system passes the associated password as the password for the bind operation.
- - This field can contain only one C(%s) and cannot contain any other format
- specifiers.
- type: str
- check_member_attr:
- description:
- - Checks the user's member attribute in the remote LDAP or AD group.
- type: bool
- ssl:
- description:
- - Specifies whether the system uses an SSL port to communicate with the LDAP server.
- type: str
- choices:
- - "yes"
- - "no"
- - start-tls
- ca_cert:
- description:
- - Specifies the name of an SSL certificate from a certificate authority (CA).
- - To remove this value, use the reserved value C(none).
- type: str
- aliases: [ ssl_ca_cert ]
- client_key:
- description:
- - Specifies the name of an SSL client key.
- - To remove this value, use the reserved value C(none).
- type: str
- aliases: [ ssl_client_key ]
- client_cert:
- description:
- - Specifies the name of an SSL client certificate.
- - To remove this value, use the reserved value C(none).
- type: str
- aliases: [ ssl_client_cert ]
- validate_certs:
- description:
- - Specifies whether the system checks an SSL peer, as a result of which the
- system requires and verifies the server certificate.
- type: bool
- aliases: [ ssl_check_peer ]
- login_ldap_attr:
- description:
- - Specifies the LDAP directory attribute containing the local user name that is
- associated with the selected directory entry.
- - When configuring LDAP device authentication for the first time, if this parameter
- is not specified, the default port is C(samaccountname).
- type: str
- fallback_to_local:
- description:
- - Specifies that the system uses the Local authentication method if the remote
- authentication method is not available.
- type: bool
- state:
- description:
- - When C(present), ensures the device authentication method exists.
- - When C(absent), ensures the device authentication method does not exist.
- type: str
- choices:
- - present
- - absent
- default: present
- update_password:
- description:
- - C(always) will always update the C(bind_password).
- - C(on_create) will only set the C(bind_password) for newly created authentication
- mechanisms.
- type: str
- choices:
- - always
- - on_create
- default: always
-extends_documentation_fragment: f5
-author:
- - Tim Rupp (@caphrim007)
- - Wojciech Wypior (@wojtek0806)
-'''
-
-EXAMPLES = r'''
-- name: Create an LDAP authentication object
- bigip_device_auth_ldap:
- name: foo
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-'''
-
-RETURN = r'''
-servers:
- description: LDAP servers used by the system to obtain authentication information.
- returned: changed
- type: list
- sample: ['192.168.1.1', '192.168.1.2']
-port:
- description: The port that the system uses for access to the remote LDAP server.
- returned: changed
- type: int
- sample: 389
-remote_directory_tree:
- description: File location (tree) of the user authentication database on the server.
- returned: changed
- type: str
- sample: "CN=Users,DC=FOOBAR,DC=LOCAL"
-scope:
- description: The level of the remote Active Directory or LDAP directory searched for user authentication.
- returned: changed
- type: str
- sample: base
-bind_dn:
- description: The distinguished name for the Active Directory or LDAP server user ID.
- returned: changed
- type: str
- sample: "user@foobar.local"
-user_template:
- description: The distinguished name of the user who is logging on.
- returned: changed
- type: str
- sample: "uid=%s,ou=people,dc=foobar,dc=local"
-check_member_attr:
- description: The user's member attribute in the remote LDAP or AD group.
- returned: changed
- type: bool
- sample: yes
-ssl:
- description: Specifies whether the system uses an SSL port to communicate with the LDAP server.
- returned: changed
- type: str
- sample: start-tls
-ca_cert:
- description: The name of an SSL certificate from a certificate authority.
- returned: changed
- type: str
- sample: My-Trusted-CA-Bundle.crt
-client_key:
- description: The name of an SSL client key.
- returned: changed
- type: str
- sample: MyKey.key
-client_cert:
- description: The name of an SSL client certificate.
- returned: changed
- type: str
- sample: MyCert.crt
-validate_certs:
- description: Indicates if the system checks an SSL peer.
- returned: changed
- type: bool
- sample: yes
-login_ldap_attr:
- description: The LDAP directory attribute containing the local user name associated with the selected directory entry.
- returned: changed
- type: str
- sample: samaccountname
-fallback_to_local:
- description: Specifies that the system uses the Local authentication method as fallback
- returned: changed
- type: bool
- sample: yes
-'''
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import fq_name
- from library.module_utils.network.f5.common import transform_name
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.common import flatten_boolean
- from library.module_utils.network.f5.compare import cmp_str_with_none
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import fq_name
- from ansible.module_utils.network.f5.common import transform_name
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.common import flatten_boolean
- from ansible.module_utils.network.f5.compare import cmp_str_with_none
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'bindDn': 'bind_dn',
- 'bindPw': 'bind_password',
- 'userTemplate': 'user_template',
- 'fallback': 'fallback_to_local',
- 'loginAttribute': 'login_ldap_attr',
- 'sslCheckPeer': 'validate_certs',
- 'sslClientCert': 'client_cert',
- 'sslClientKey': 'client_key',
- 'sslCaCertFile': 'ca_cert',
- 'checkRolesGroup': 'check_member_attr',
- 'searchBaseDn': 'remote_directory_tree',
- }
-
- api_attributes = [
- 'bindDn',
- 'bindPw',
- 'checkRolesGroup',
- 'loginAttribute',
- 'port',
- 'scope',
- 'searchBaseDn',
- 'servers',
- 'ssl',
- 'sslCaCertFile',
- 'sslCheckPeer',
- 'sslClientCert',
- 'sslClientKey',
- 'userTemplate',
- ]
-
- returnables = [
- 'bind_dn',
- 'bind_password',
- 'check_member_attr',
- 'fallback_to_local',
- 'login_ldap_attr',
- 'port',
- 'remote_directory_tree',
- 'scope',
- 'servers',
- 'ssl',
- 'ca_cert',
- 'validate_certs',
- 'client_cert',
- 'client_key',
- 'user_template',
- ]
-
- updatables = [
- 'bind_dn',
- 'bind_password',
- 'check_member_attr',
- 'fallback_to_local',
- 'login_ldap_attr',
- 'port',
- 'remote_directory_tree',
- 'scope',
- 'servers',
- 'ssl',
- 'ssl_ca_cert',
- 'ssl_check_peer',
- 'ssl_client_cert',
- 'ssl_client_key',
- 'user_template',
- ]
-
- @property
- def ssl_ca_cert(self):
- if self._values['ssl_ca_cert'] is None:
- return None
- elif self._values['ssl_ca_cert'] in ['none', '']:
- return ''
- return fq_name(self.partition, self._values['ssl_ca_cert'])
-
- @property
- def ssl_client_key(self):
- if self._values['ssl_client_key'] is None:
- return None
- elif self._values['ssl_client_key'] in ['none', '']:
- return ''
- return fq_name(self.partition, self._values['ssl_client_key'])
-
- @property
- def ssl_client_cert(self):
- if self._values['ssl_client_cert'] is None:
- return None
- elif self._values['ssl_client_cert'] in ['none', '']:
- return ''
- return fq_name(self.partition, self._values['ssl_client_cert'])
-
- @property
- def ssl_check_peer(self):
- return flatten_boolean(self._values['ssl_check_peer'])
-
- @property
- def fallback_to_local(self):
- return flatten_boolean(self._values['fallback_to_local'])
-
- @property
- def check_member_attr(self):
- return flatten_boolean(self._values['check_member_attr'])
-
- @property
- def login_ldap_attr(self):
- if self._values['login_ldap_attr'] is None:
- return None
- elif self._values['login_ldap_attr'] in ['none', '']:
- return ''
- return self._values['login_ldap_attr']
-
- @property
- def user_template(self):
- if self._values['user_template'] is None:
- return None
- elif self._values['user_template'] in ['none', '']:
- return ''
- return self._values['user_template']
-
- @property
- def ssl(self):
- if self._values['ssl'] is None:
- return None
- elif self._values['ssl'] == 'start-tls':
- return 'start-tls'
- return flatten_boolean(self._values['ssl'])
-
-
-class ApiParameters(Parameters):
- pass
-
-
-class ModuleParameters(Parameters):
- pass
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class UsableChanges(Changes):
- @property
- def ssl_check_peer(self):
- if self._values['ssl_check_peer'] is None:
- return None
- elif self._values['ssl_check_peer'] == 'yes':
- return 'enabled'
- return 'disabled'
-
- @property
- def fallback_to_local(self):
- if self._values['fallback_to_local'] is None:
- return None
- elif self._values['fallback_to_local'] == 'yes':
- return 'true'
- return 'false'
-
- @property
- def check_member_attr(self):
- if self._values['check_member_attr'] is None:
- return None
- elif self._values['check_member_attr'] == 'yes':
- return 'enabled'
- return 'disabled'
-
- @property
- def ssl(self):
- if self._values['ssl'] is None:
- return None
- elif self._values['ssl'] == 'start-tls':
- return 'start-tls'
- elif self._values['ssl'] == 'yes':
- return 'enabled'
- return 'disabled'
-
-
-class ReportableChanges(Changes):
- @property
- def bind_password(self):
- return None
-
- @property
- def ssl_check_peer(self):
- return flatten_boolean(self._values['ssl_check_peer'])
-
- @property
- def check_member_attr(self):
- return flatten_boolean(self._values['check_member_attr'])
-
- @property
- def ssl(self):
- if self._values['ssl'] is None:
- return None
- elif self._values['ssl'] == 'start-tls':
- return 'start-tls'
- return flatten_boolean(self._values['ssl'])
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
- @property
- def login_ldap_attr(self):
- return cmp_str_with_none(self.want.login_ldap_attr, self.have.login_ldap_attr)
-
- @property
- def user_template(self):
- return cmp_str_with_none(self.want.user_template, self.have.user_template)
-
- @property
- def ssl_ca_cert(self):
- return cmp_str_with_none(self.want.ssl_ca_cert, self.have.ssl_ca_cert)
-
- @property
- def ssl_client_key(self):
- return cmp_str_with_none(self.want.ssl_client_key, self.have.ssl_client_key)
-
- @property
- def ssl_client_cert(self):
- return cmp_str_with_none(self.want.ssl_client_cert, self.have.ssl_client_cert)
-
- @property
- def bind_password(self):
- if self.want.bind_password != self.have.bind_password and self.want.update_password == 'always':
- return self.want.bind_password
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(params=self.module.params)
- self.have = ApiParameters()
- self.changes = UsableChanges()
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = UsableChanges(params=changed)
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.client.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def update_auth_source_on_device(self, source):
- """Set the system auth source.
-
- Configuring the authentication source is only one step in the process of setting
- up an auth source. The other step is to inform the system of the auth source
- you want to use.
-
- This method is used for situations where
-
- * The ``use_for_auth`` parameter is set to ``yes``
- * The ``use_for_auth`` parameter is set to ``no``
- * The ``state`` parameter is set to ``absent``
-
- When ``state`` equal to ``absent``, before you can delete the TACACS+ configuration,
- you must set the system auth to "something else". The system ships with a system
- auth called "local", so this is the logical "something else" to use.
-
- When ``use_for_auth`` is no, the same situation applies as when ``state`` equal
- to ``absent`` is done above.
-
- When ``use_for_auth`` is ``yes``, this method will set the current system auth
- state to TACACS+.
-
- Arguments:
- source (string): The source that you want to set on the device.
- """
- params = dict(
- type=source
- )
- uri = 'https://{0}:{1}/mgmt/tm/auth/source/'.format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
-
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def update_fallback_on_device(self, fallback):
- params = dict(
- fallback=fallback
- )
- uri = 'https://{0}:{1}/mgmt/tm/auth/source/'.format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
-
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def exec_module(self):
- changed = False
- result = dict()
- state = self.want.state
-
- if state == "present":
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def present(self):
- if self.exists():
- return self.update()
- else:
- return self.create()
-
- def absent(self):
- if self.exists():
- return self.remove()
- return False
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def update(self):
- self.have = self.read_current_from_device()
- if not self.should_update():
- return False
- if self.module.check_mode:
- return True
- self.update_on_device()
- if self.want.fallback_to_local == 'yes':
- self.update_fallback_on_device('true')
- elif self.want.fallback_to_local == 'no':
- self.update_fallback_on_device('false')
- return True
-
- def remove(self):
- if self.module.check_mode:
- return True
- self.update_auth_source_on_device('local')
- self.remove_from_device()
- if self.exists():
- raise F5ModuleError("Failed to delete the resource.")
- return True
-
- def create(self):
- self._set_changed_options()
- if self.module.check_mode:
- return True
- self.create_on_device()
- if self.want.fallback_to_local == 'yes':
- self.update_fallback_on_device('true')
- elif self.want.fallback_to_local == 'no':
- self.update_fallback_on_device('false')
- return True
-
- def exists(self):
- uri = "https://{0}:{1}/mgmt/tm/auth/ldap/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name('Common', 'system-auth')
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def create_on_device(self):
- params = self.changes.api_params()
- params['name'] = 'system-auth'
- params['partition'] = 'Common'
- uri = "https://{0}:{1}/mgmt/tm/auth/ldap/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 409]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return True
-
- def update_on_device(self):
- params = self.changes.api_params()
- if not params:
- return
- uri = "https://{0}:{1}/mgmt/tm/auth/ldap/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name('Common', 'system-auth')
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def remove_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/auth/ldap/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name('Common', 'system-auth')
- )
- response = self.client.api.delete(uri)
- if response.status == 200:
- return True
- raise F5ModuleError(response.content)
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/auth/ldap/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name('Common', 'system-auth')
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- result = ApiParameters(params=response)
-
- uri = 'https://{0}:{1}/mgmt/tm/auth/source/'.format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- result.update({'fallback': response['fallback']})
- return result
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- servers=dict(type='list'),
- port=dict(type='int'),
- remote_directory_tree=dict(),
- scope=dict(
- choices=['sub', 'one', 'base']
- ),
- bind_dn=dict(),
- bind_password=dict(no_log=True),
- user_template=dict(),
- check_member_attr=dict(type='bool'),
- ssl=dict(
- choices=['yes', 'no', 'start-tls']
- ),
- ca_cert=dict(aliases=['ssl_ca_cert']),
- client_key=dict(aliases=['ssl_client_key']),
- client_cert=dict(aliases=['ssl_client_cert']),
- validate_certs=dict(type='bool', aliases=['ssl_check_peer']),
- login_ldap_attr=dict(),
- fallback_to_local=dict(type='bool'),
- update_password=dict(
- default='always',
- choices=['always', 'on_create']
- ),
- state=dict(default='present', choices=['absent', 'present']),
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode,
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_device_certificate.py b/lib/ansible/modules/network/f5/bigip_device_certificate.py
deleted file mode 100644
index 085b60aea3..0000000000
--- a/lib/ansible/modules/network/f5/bigip_device_certificate.py
+++ /dev/null
@@ -1,627 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2019, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_device_certificate
-short_description: Manage self-signed device certificates
-description:
- - Module used to create and/or renew self-signed device certificates for BIG-IP.
-version_added: 2.9
-options:
- days_valid:
- description:
- - Specifies the interval for which the self-signed certificate is valid.
- - "The maximum value is 25 years: C(9125) days"
- type: int
- required: True
- cert_name:
- description:
- - Specifies the full name of the certificate file.
- - If the name is not default C(server.crt), the module will configure C(httpd) to use them
- prior to restarting the C(httpd) daemon.
- type: str
- default: server.crt
- key_name:
- description:
- - Specifies the full name of the key file.
- - If the name is not default C(server.key), the module will configure C(httpd) to use them
- prior to restarting the C(httpd) daemon.
- type: str
- default: server.key
- key_size:
- description:
- - Specifies the desired key size in bits.
- - Mandatory option when generating a new certificate.
- type: int
- choices:
- - 512
- - 1024
- - 2048
- - 4096
- default: 2048
- issuer:
- description:
- - Certificate properties, required when generating new certificates.
- suboptions:
- country:
- description:
- - Specifies the Country name attribute for the certificate.
- type: str
- state:
- description:
- - Specifies the State or Province attribute for the certificate.
- type: str
- locality:
- description:
- - Specifies the city or town name for the certificate.
- type: str
- organization:
- description:
- - Specifies the Organization attribute for the certificate.
- type: str
- division:
- description:
- - Specifies the department name attribute for the certificate.
- type: str
- common_name:
- description:
- - Specifies Common Name attribute for the certificate.
- type: str
- email:
- description:
- - "Specifies the domain administrator's email address."
- type: str
- type: dict
- add_to_trusted:
- description:
- - Specified if the certificate should be added to the trusted client and server certificate files.
- type: bool
- default: no
- new_cert:
- description:
- - Specified if the module should generate new certificate.
- - When C(yes) the device certificate and key will be replaced
- type: bool
- default: no
- force:
- description:
- - When C(yes), will update or overwrite the existing certificate when it is not expired device.
- - When C(no), the certificate will only be updated/overwritten if expired.
- - Generally should be C(yes) only in cases where you need to update certificate that is about to expire.
- - This option is also needed when generating new certificate to replace non expired one.
- type: bool
- default: no
- transport:
- description:
- - Configures the transport connection to use when connecting to the
- remote device.
- - This module currently supports only connectivity to the device over cli (ssh).
- required: True
- choices:
- - cli
- default: cli
-extends_documentation_fragment: f5
-author:
- - Wojciech Wypior (@wojtek0806)
-'''
-
-EXAMPLES = r'''
-- name: Update expired certificate
- bigip_device_certificate:
- days_valid: 365
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- transport: cli
- server_port: 22
- delegate_to: localhost
-
-- name: Update expired certificate non-default names
- bigip_device_certificate:
- days_valid: 60
- cert_name: custom.crt
- key_name: custom.key
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- transport: cli
- server_port: 22
- delegate_to: localhost
-
-- name: Force update not expired certificate
- bigip_device_certificate:
- days_valid: 365
- force: yes
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- transport: cli
- server_port: 22
- delegate_to: localhost
-
-- name: Create a new certificate to replace expired certificate
- bigip_device_certificate:
- days_valid: 365
- new_cert: yes
- issuer:
- country: US
- state: WA
- common_name: foobar.foo.local
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- transport: cli
- server_port: 22
- delegate_to: localhost
-
-- name: Force create a new custom named certificate to replace not expired certificate
- bigip_device_certificate:
- days_valid: 365
- cert_name: custom.crt
- key_name: custom.key
- new_cert: yes
- force: yes
- issuer:
- country: US
- state: WA
- common_name: foobar.foo.local
- key_size: 2048
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- transport: cli
- server_port: 22
- delegate_to: localhost
-'''
-
-RETURN = r'''
-days_valid:
- description: The interval for which the self-signed certificate is valid.
- returned: changed
- type: int
- sample: 365
-issuer:
- description: Specifies certificate properties.
- type: complex
- returned: changed
- contains:
- country:
- description: The Country name attribute of the certificate.
- returned: changed
- type: str
- sample: US
- state:
- description: The State or Province attribute of the certificate.
- returned: changed
- type: str
- sample: WA
- locality:
- description: The city or town name attribute of the certificate.
- returned: changed
- type: str
- sample: Seattle
- organization:
- description: The Organization attribute of the certificate.
- returned: changed
- type: str
- sample: F5
- division:
- description: The department name attribute of the certificate.
- returned: changed
- type: str
- sample: IT
- common_name:
- description: The Common Name attribute of the certificate.
- returned: changed
- type: str
- sample: foo.bar.local
- email:
- description: "The domain administrator's email address."
- returned: changed
- type: str
- sample: admin@foo.bar.local
-cert_name:
- description: The full name of the certificate file.
- returned: changed
- type: str
- sample: common.crt
-key_name:
- description: The full name of the key file.
- returned: changed
- type: str
- sample: common.key
-key_size:
- description: The desired key size in bits.
- returned: changed
- type: int
- sample: 2048
-'''
-import os
-import ssl
-from datetime import datetime
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.connection import exec_command
-
-
-try:
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.common import is_cli
-except ImportError:
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.common import is_cli
-
-
-class Parameters(AnsibleF5Parameters):
- returnables = [
- 'days_valid',
- 'issuer',
- 'key_size',
- 'cert_name',
- 'key_name',
- ]
-
- updatables = [
- 'days_valid',
- ]
-
-
-class ApiParameters(Parameters):
- pass
-
-
-class ModuleParameters(Parameters):
- issuer_map = {
- 'country': 'C',
- 'state': 'ST',
- 'locality': 'L',
- 'organization': 'O',
- 'division': 'OU',
- 'common_name': 'CN',
- 'email': 'emailAddress'
- }
-
- @property
- def issuer(self):
- if self._values['issuer'] is None:
- return None
- filtered = dict((self.issuer_map[k], v) for k, v in self._values['issuer'].items() if v is not None)
- to_parse = ['{0}={1}'.format(k, v) for k, v in filtered.items()]
- result = '/' + '/'.join(to_parse) + '/'
- return result
-
- @property
- def days_valid(self):
- if 1 <= self._values['days_valid'] <= 9125:
- return self._values['days_valid']
- raise F5ModuleError(
- "Valid 'days_valid' must be in range 1 - 9125 days."
- )
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class UsableChanges(Changes):
- pass
-
-
-class ReportableChanges(Changes):
- issuer_map = {
- 'C': 'country',
- 'ST': 'state',
- 'L': 'locality',
- 'O': 'organization',
- 'OU': 'division',
- 'CN': 'common_name',
- 'emailAddress': 'email'
- }
-
- @property
- def issuer(self):
- if self._values['issuer'] is None:
- return None
- to_dict = [tuple(item.split('=')) for item in self._values['issuer'].strip('/').split('/')]
- result = dict((self.issuer_map[k], v) for k, v in to_dict)
- return result
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.want = ModuleParameters(params=self.module.params)
- self.have = ApiParameters()
- self.changes = UsableChanges()
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = UsableChanges(params=changed)
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def exec_module(self):
- if not is_cli(self.module):
- raise F5ModuleError('Module can only be run via SSH, set the transport property to CLI')
-
- result = dict()
-
- changed = self.present()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- return result
-
- def present(self):
- if self.expired():
- if self.want.new_cert:
- self.create()
- return True
- self.update()
- return True
- if self.want.force and self.want.new_cert:
- self.create()
- return True
- if self.want.force:
- self.update()
- return True
- return False
-
- def create(self):
- self._set_changed_options()
- if self.module.check_mode:
- return True
- self.generate_new()
- return True
-
- def update(self):
- self._update_changed_options()
- if self.module.check_mode:
- return True
- self.update_certificate()
- if self.want.cert_name != 'server.crt' or self.want.key_name != 'server.key':
- self.configure_new_cert()
- self.restart_daemon()
- if self.want.add_to_trusted:
- self.copy_files_to_trusted()
- return True
-
- def expired(self):
- self.have = self.read_current_certificate()
- current_epoch = int(datetime.now().timestamp())
- if current_epoch > self.have.epoch:
- return True
- return False
-
- def generate_new(self):
- self.generate_cert_key()
- if self.want.cert_name != 'server.crt' or self.want.key_name != 'server.key':
- self.configure_new_cert()
- self.restart_daemon()
- if self.want.add_to_trusted:
- self.copy_files_to_trusted()
- return True
-
- def generate_cert_key(self):
- cmd = 'openssl req -x509 -nodes -days {3} -newkey rsa:{4} -keyout {0}/ssl.key/{2} ' \
- '-out {0}/ssl.crt/{1} -subj "{5}"'.format('/config/httpd/conf', self.want.cert_name, self.want.key_name,
- self.want.days_valid, self.want.key_size, self.want.issuer)
- rc, out, err = exec_command(self.module, cmd)
- if rc != 0:
- raise F5ModuleError(err)
-
- def create_csr(self):
- cmd = 'openssl x509 -x509toreq -in {0}/ssl.crt/{1} -out {0}/ssl.csr/{3}.csr -signkey {0}/ssl.key/{2}'.format(
- '/config/httpd/conf', self.want.cert_name, self.want.key_name, os.path.splitext(self.want.cert_name)[0]
- )
-
- rc, out, err = exec_command(self.module, cmd)
- if rc != 0:
- raise F5ModuleError(err)
-
- def update_certificate(self):
- self.create_csr()
- cmd = 'openssl x509 -req -in {0}/ssl.csr/{3}.csr -signkey {0}/ssl.key/{2} -days {4} -out {0}/ssl.crt/{1}'.\
- format('/config/httpd/conf', self.want.cert_name, self.want.key_name,
- os.path.splitext(self.want.cert_name)[0], self.want.days_valid)
- rc, out, err = exec_command(self.module, cmd)
- if rc != 0:
- raise F5ModuleError(err)
-
- def configure_new_cert(self):
- cmd1 = 'tmsh modify sys httpd ssl-certkeyfile /config/httpd/conf/ssl.key/{1}' \
- 'ssl-certfile /config/httpd/conf/ssl.crt/{0}'.format(self.want.cert_name, self.want.key_name)
-
- cmd2 = 'tmsh save /sys config partitions all'
-
- rc, out, err = exec_command(self.module, cmd1)
- if rc != 0:
- raise F5ModuleError(err)
-
- rc, out, err = exec_command(self.module, cmd2)
- if rc != 0:
- raise F5ModuleError(err)
-
- def restart_daemon(self):
- cmd = 'tmsh restart /sys service httpd'
- rc, out, err = exec_command(self.module, cmd)
- if rc != 0:
- raise F5ModuleError(err)
-
- def copy_files_to_trusted(self):
- cmd1 = 'cat /config/httpd/conf/ssl.crt/{0} >> /config/big3d/client.crt'.format(self.want.cert_name)
- cmd2 = 'cat /config/httpd/conf/ssl.crt/{0} >> /config/gtm/server.crt'.format(self.want.cert_name)
- rc, out, err = exec_command(self.module, cmd1)
- if rc != 0:
- raise F5ModuleError(err)
- rc, out, err = exec_command(self.module, cmd2)
- if rc != 0:
- raise F5ModuleError(err)
-
- def read_current_certificate(self):
- result = dict()
- command = 'openssl x509 -in /config/httpd/conf/ssl.crt/{0} -dates -issuer -noout'.format(self.want.cert_name)
- rc, out, err = exec_command(self.module, command)
- if rc == 0:
- result['epoch'] = self._parse_cert_date(out)
- return ApiParameters(params=result)
-
- def _parse_cert_date(self, to_parse):
- c_time = to_parse.split('\n')[1].split('=')[1]
- result = ssl.cert_time_to_seconds(c_time)
- return result
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- key_size=dict(
- type='int',
- choices=[512, 1024, 2048, 4096],
- default=2048
- ),
- cert_name=dict(
- default='server.crt'
- ),
- key_name=dict(
- default='server.key'
- ),
- days_valid=dict(
- type='int',
- required=True
- ),
- issuer=dict(
- type='dict',
- options=dict(
- country=dict(),
- state=dict(),
- locality=dict(),
- organization=dict(),
- division=dict(),
- common_name=dict(),
- email=dict(),
- ),
- required_one_of=[
- ['country', 'state', 'locality', 'organization', 'division', 'common_name', 'email']
- ]
- ),
-
- add_to_trusted=dict(
- type='bool',
- default='no'
- ),
- new_cert=dict(
- type='bool',
- default='no'
- ),
- force=dict(
- type='bool',
- default='no'
- ),
- transport=dict(
- type='str',
- default='cli',
- choices=['cli']
- ),
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
- self.required_if = [
- ['new_cert', 'yes', ['days_valid', 'issuer', 'key_size']]
- ]
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode,
- required_if=spec.required_if,
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_device_connectivity.py b/lib/ansible/modules/network/f5/bigip_device_connectivity.py
deleted file mode 100644
index b794e72ad4..0000000000
--- a/lib/ansible/modules/network/f5/bigip_device_connectivity.py
+++ /dev/null
@@ -1,718 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['stableinterface'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_device_connectivity
-short_description: Manages device IP configuration settings for HA on a BIG-IP
-description:
- - Manages device IP configuration settings for HA on a BIG-IP. Each BIG-IP device
- has synchronization and failover connectivity information (IP addresses) that
- you define as part of HA pairing or clustering. This module allows you to configure
- that information.
-version_added: 2.5
-options:
- config_sync_ip:
- description:
- - Local IP address that the system uses for ConfigSync operations.
- type: str
- mirror_primary_address:
- description:
- - Specifies the primary IP address for the system to use to mirror
- connections.
- type: str
- mirror_secondary_address:
- description:
- - Specifies the secondary IP address for the system to use to mirror
- connections.
- type: str
- unicast_failover:
- description:
- - Desired addresses to use for failover operations. Options C(address)
- and C(port) are supported with dictionary structure where C(address) is the
- local IP address that the system uses for failover operations. Port
- specifies the port that the system uses for failover operations. If C(port)
- is not specified, the default value C(1026) will be used. If you are
- specifying the (recommended) management IP address, use 'management-ip' in
- the address field.
- type: list
- failover_multicast:
- description:
- - When C(yes), ensures that the Failover Multicast configuration is enabled
- and if no further multicast configuration is provided, ensures that
- C(multicast_interface), C(multicast_address) and C(multicast_port) are
- the defaults specified in each option's description. When C(no), ensures
- that Failover Multicast configuration is disabled.
- type: bool
- multicast_interface:
- description:
- - Interface over which the system sends multicast messages associated
- with failover. When C(failover_multicast) is C(yes) and this option is
- not provided, a default of C(eth0) will be used.
- type: str
- multicast_address:
- description:
- - IP address for the system to send multicast messages associated with
- failover. When C(failover_multicast) is C(yes) and this option is not
- provided, a default of C(224.0.0.245) will be used.
- type: str
- multicast_port:
- description:
- - Port for the system to send multicast messages associated with
- failover. When C(failover_multicast) is C(yes) and this option is not
- provided, a default of C(62960) will be used. This value must be between
- 0 and 65535.
- type: int
- cluster_mirroring:
- description:
- - Specifies whether mirroring occurs within the same cluster or between
- different clusters on a multi-bladed system.
- - This parameter is only supported on platforms that have multiple blades,
- such as Viprion hardware. It is not supported on VE.
- type: str
- choices:
- - between-clusters
- - within-cluster
- version_added: 2.7
-notes:
- - This module is primarily used as a component of configuring HA pairs of
- BIG-IP devices.
- - Requires BIG-IP >= 12.0.0
-extends_documentation_fragment: f5
-author:
- - Tim Rupp (@caphrim007)
- - Wojciech Wypior (@wojtek0806)
-'''
-
-EXAMPLES = r'''
-- name: Configure device connectivity for standard HA pair
- bigip_device_connectivity:
- config_sync_ip: 10.1.30.1
- mirror_primary_address: 10.1.30.1
- unicast_failover:
- - address: management-ip
- - address: 10.1.30.1
- provider:
- server: lb.mydomain.com
- user: admin
- password: secret
- delegate_to: localhost
-'''
-
-RETURN = r'''
-changed:
- description: Denotes if the F5 configuration was updated.
- returned: always
- type: bool
-config_sync_ip:
- description: The new value of the C(config_sync_ip) setting.
- returned: changed
- type: str
- sample: 10.1.1.1
-mirror_primary_address:
- description: The new value of the C(mirror_primary_address) setting.
- returned: changed
- type: str
- sample: 10.1.1.2
-mirror_secondary_address:
- description: The new value of the C(mirror_secondary_address) setting.
- returned: changed
- type: str
- sample: 10.1.1.3
-unicast_failover:
- description: The new value of the C(unicast_failover) setting.
- returned: changed
- type: list
- sample: [{'address': '10.1.1.2', 'port': 1026}]
-failover_multicast:
- description: Whether a failover multicast attribute has been changed or not.
- returned: changed
- type: bool
-multicast_interface:
- description: The new value of the C(multicast_interface) setting.
- returned: changed
- type: str
- sample: eth0
-multicast_address:
- description: The new value of the C(multicast_address) setting.
- returned: changed
- type: str
- sample: 224.0.0.245
-multicast_port:
- description: The new value of the C(multicast_port) setting.
- returned: changed
- type: int
- sample: 1026
-cluster_mirroring:
- description: The current cluster-mirroring setting.
- returned: changed
- type: str
- sample: between-clusters
-'''
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.six import iteritems
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import transform_name
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.ipaddress import is_valid_ip
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import transform_name
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.ipaddress import is_valid_ip
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'unicastAddress': 'unicast_failover',
- 'configsyncIp': 'config_sync_ip',
- 'multicastInterface': 'multicast_interface',
- 'multicastIp': 'multicast_address',
- 'multicastPort': 'multicast_port',
- 'mirrorIp': 'mirror_primary_address',
- 'mirrorSecondaryIp': 'mirror_secondary_address',
- 'managementIp': 'management_ip',
- }
- api_attributes = [
- 'configsyncIp',
- 'multicastInterface',
- 'multicastIp',
- 'multicastPort',
- 'mirrorIp',
- 'mirrorSecondaryIp',
- 'unicastAddress',
- ]
- returnables = [
- 'config_sync_ip',
- 'multicast_interface',
- 'multicast_address',
- 'multicast_port',
- 'mirror_primary_address',
- 'mirror_secondary_address',
- 'failover_multicast',
- 'unicast_failover',
- 'cluster_mirroring',
- ]
- updatables = [
- 'config_sync_ip',
- 'multicast_interface',
- 'multicast_address',
- 'multicast_port',
- 'mirror_primary_address',
- 'mirror_secondary_address',
- 'failover_multicast',
- 'unicast_failover',
- 'cluster_mirroring',
- ]
-
- @property
- def multicast_port(self):
- if self._values['multicast_port'] is None:
- return None
- result = int(self._values['multicast_port'])
- if result < 0 or result > 65535:
- raise F5ModuleError(
- "The specified 'multicast_port' must be between 0 and 65535."
- )
- return result
-
- @property
- def multicast_address(self):
- if self._values['multicast_address'] is None:
- return None
- elif self._values['multicast_address'] in ["none", "any6", '']:
- return "any6"
- elif self._values['multicast_address'] == 'any':
- return 'any'
- result = self._get_validated_ip_address('multicast_address')
- return result
-
- @property
- def mirror_primary_address(self):
- if self._values['mirror_primary_address'] is None:
- return None
- elif self._values['mirror_primary_address'] in ["none", "any6", '']:
- return "any6"
- result = self._get_validated_ip_address('mirror_primary_address')
- return result
-
- @property
- def mirror_secondary_address(self):
- if self._values['mirror_secondary_address'] is None:
- return None
- elif self._values['mirror_secondary_address'] in ["none", "any6", '']:
- return "any6"
- result = self._get_validated_ip_address('mirror_secondary_address')
- return result
-
- @property
- def config_sync_ip(self):
- if self._values['config_sync_ip'] is None:
- return None
- elif self._values['config_sync_ip'] in ["none", '']:
- return "none"
- result = self._get_validated_ip_address('config_sync_ip')
- return result
-
- def _validate_unicast_failover_port(self, port):
- try:
- result = int(port)
- except ValueError:
- raise F5ModuleError(
- "The provided 'port' for unicast failover is not a valid number"
- )
- except TypeError:
- result = 1026
- return result
-
- def _validate_unicast_failover_address(self, address):
- if address != 'management-ip':
- if is_valid_ip(address):
- return address
- else:
- raise F5ModuleError(
- "'address' field in unicast failover is not a valid IP address"
- )
- else:
- return address
-
- def _get_validated_ip_address(self, address):
- if is_valid_ip(self._values[address]):
- return self._values[address]
- raise F5ModuleError(
- "The specified '{0}' is not a valid IP address".format(address)
- )
-
-
-class ApiParameters(Parameters):
- @property
- def cluster_mirroring(self):
- if self._values['cluster_mirroring'] is None:
- return None
- if self._values['cluster_mirroring'] == 'between':
- return 'between-clusters'
- return 'within-cluster'
-
-
-class ModuleParameters(Parameters):
- @property
- def unicast_failover(self):
- if self._values['unicast_failover'] is None:
- return None
- if self._values['unicast_failover'] == ['none']:
- return []
- result = []
- for item in self._values['unicast_failover']:
- address = item.get('address', None)
- port = item.get('port', None)
- address = self._validate_unicast_failover_address(address)
- port = self._validate_unicast_failover_port(port)
- result.append(
- dict(
- effectiveIp=address,
- effectivePort=port,
- ip=address,
- port=port
- )
- )
- if result:
- return result
- else:
- return None
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- change = getattr(self, returnable)
- if isinstance(change, dict):
- result.update(change)
- else:
- result[returnable] = change
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class ReportableChanges(Changes):
- returnables = [
- 'config_sync_ip', 'multicast_interface', 'multicast_address',
- 'multicast_port', 'mirror_primary_address', 'mirror_secondary_address',
- 'failover_multicast', 'unicast_failover'
- ]
-
- @property
- def mirror_secondary_address(self):
- if self._values['mirror_secondary_address'] in ['none', 'any6']:
- return 'none'
- return self._values['mirror_secondary_address']
-
- @property
- def mirror_primary_address(self):
- if self._values['mirror_primary_address'] in ['none', 'any6']:
- return 'none'
- return self._values['mirror_primary_address']
-
- @property
- def multicast_address(self):
- if self._values['multicast_address'] in ['none', 'any6']:
- return 'none'
- return self._values['multicast_address']
-
-
-class UsableChanges(Changes):
- @property
- def mirror_primary_address(self):
- if self._values['mirror_primary_address'] == ['any6', 'none', 'any']:
- return "any6"
- else:
- return self._values['mirror_primary_address']
-
- @property
- def mirror_secondary_address(self):
- if self._values['mirror_secondary_address'] == ['any6', 'none', 'any']:
- return "any6"
- else:
- return self._values['mirror_secondary_address']
-
- @property
- def multicast_address(self):
- if self._values['multicast_address'] == ['any6', 'none', 'any']:
- return "any"
- else:
- return self._values['multicast_address']
-
- @property
- def unicast_failover(self):
- if self._values['unicast_failover'] is None:
- return None
- elif self._values['unicast_failover']:
- return self._values['unicast_failover']
- return "none"
-
- @property
- def cluster_mirroring(self):
- if self._values['cluster_mirroring'] is None:
- return None
- elif self._values['cluster_mirroring'] == 'between-clusters':
- return 'between'
- return 'within'
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
- def to_tuple(self, failovers):
- result = []
- for x in failovers:
- for k, v in iteritems(x):
- # Have to do this in cases where the BIG-IP stores the word
- # "management-ip" when you specify the management IP address.
- #
- # Otherwise, a difference would be registered.
- if v == self.have.management_ip:
- v = 'management-ip'
- result += [(str(k), str(v))]
- return result
-
- @property
- def unicast_failover(self):
- if self.want.unicast_failover == [] and self.have.unicast_failover is None:
- return None
- if self.want.unicast_failover is None:
- return None
- if self.have.unicast_failover is None:
- return self.want.unicast_failover
- want = self.to_tuple(self.want.unicast_failover)
- have = self.to_tuple(self.have.unicast_failover)
- if set(want) == set(have):
- return None
- else:
- return self.want.unicast_failover
-
- @property
- def failover_multicast(self):
- values = ['multicast_address', 'multicast_interface', 'multicast_port']
- if self.want.failover_multicast is False:
- if self.have.multicast_interface == 'eth0' and self.have.multicast_address == 'any' and self.have.multicast_port == 0:
- return None
- else:
- result = dict(
- failover_multicast=True,
- multicast_port=0,
- multicast_interface='eth0',
- multicast_address='any'
- )
- return result
- else:
- if all(self.have._values[x] in [None, 'any6', 'any'] for x in values):
- return True
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(params=self.module.params)
- self.have = ApiParameters()
- self.changes = UsableChanges()
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def exec_module(self):
- result = dict()
-
- changed = self.update()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- return result
-
- def update(self):
- self.have = self.read_current_from_device()
- if not self.should_update():
- return False
- if self.module.check_mode:
- return True
- self.update_on_device()
- if self.changes.cluster_mirroring:
- self.update_cluster_mirroring_on_device()
- return True
-
- def update_on_device(self):
- params = self.changes.api_params()
- if not params:
- return
- uri = "https://{0}:{1}/mgmt/tm/cm/device/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- for item in response['items']:
- if item['selfDevice'] == 'true':
- uri = "https://{0}:{1}/mgmt/tm/cm/device/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(item['partition'], item['name'])
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return
- raise F5ModuleError(
- "The host device was not found."
- )
-
- def update_cluster_mirroring_on_device(self):
- uri = "https://{0}:{1}/mgmt/tm/sys/db/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- 'statemirror.clustermirroring'
- )
- payload = {"value": self.changes.cluster_mirroring}
- resp = self.client.api.patch(uri, json=payload)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def read_current_from_device(self):
- db = self.read_cluster_mirroring_from_device()
- uri = "https://{0}:{1}/mgmt/tm/cm/device/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- for item in response['items']:
- if item['selfDevice'] == 'true':
- uri = "https://{0}:{1}/mgmt/tm/cm/device/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(item['partition'], item['name'])
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- if db:
- response['cluster_mirroring'] = db['value']
- return ApiParameters(params=response)
- raise F5ModuleError(
- "The host device was not found."
- )
-
- def read_cluster_mirroring_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/sys/db/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- 'statemirror.clustermirroring'
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return response
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- multicast_port=dict(
- type='int'
- ),
- multicast_address=dict(),
- multicast_interface=dict(),
- failover_multicast=dict(
- type='bool'
- ),
- unicast_failover=dict(
- type='list'
- ),
- mirror_primary_address=dict(),
- mirror_secondary_address=dict(),
- config_sync_ip=dict(),
- cluster_mirroring=dict(
- choices=['within-cluster', 'between-clusters']
- )
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
- self.required_together = [
- ['multicast_address', 'multicast_interface', 'multicast_port']
- ]
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode,
- required_together=spec.required_together
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_device_dns.py b/lib/ansible/modules/network/f5/bigip_device_dns.py
deleted file mode 100644
index 2a9c8c6d74..0000000000
--- a/lib/ansible/modules/network/f5/bigip_device_dns.py
+++ /dev/null
@@ -1,553 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['stableinterface'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_device_dns
-short_description: Manage BIG-IP device DNS settings
-description:
- - Manage BIG-IP device DNS settings.
-version_added: 2.2
-options:
- cache:
- description:
- - Specifies whether the system caches DNS lookups or performs the
- operation each time a lookup is needed. Please note that this applies
- only to Access Policy Manager features, such as ACLs, web application
- rewrites, and authentication.
- type: str
- choices:
- - enabled
- - disabled
- - enable
- - disable
- name_servers:
- description:
- - A list of name servers that the system uses to validate DNS lookups
- type: list
- search:
- description:
- - A list of domains that the system searches for local domain lookups,
- to resolve local host names.
- type: list
- ip_version:
- description:
- - Specifies whether the DNS specifies IP addresses using IPv4 or IPv6.
- type: int
- choices:
- - 4
- - 6
- state:
- description:
- - The state of the variable on the system. When C(present), guarantees
- that an existing variable is set to C(value).
- type: str
- choices:
- - absent
- - present
- default: present
-extends_documentation_fragment: f5
-author:
- - Tim Rupp (@caphrim007)
- - Wojciech Wypior (@wojtek0806)
-'''
-
-EXAMPLES = r'''
-- name: Set the DNS settings on the BIG-IP
- bigip_device_dns:
- name_servers:
- - 208.67.222.222
- - 208.67.220.220
- search:
- - localdomain
- - lab.local
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-'''
-
-RETURN = r'''
-cache:
- description: The new value of the DNS caching
- returned: changed
- type: str
- sample: enabled
-name_servers:
- description: List of name servers that were set
- returned: changed
- type: list
- sample: ['192.0.2.10', '172.17.12.10']
-search:
- description: List of search domains that were set
- returned: changed
- type: list
- sample: ['192.0.2.10', '172.17.12.10']
-ip_version:
- description: IP version that was set that DNS will specify IP addresses in
- returned: changed
- type: int
- sample: 4
-warnings:
- description: The list of warnings (if any) generated by module based on arguments
- returned: always
- type: list
- sample: ['...', '...']
-'''
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import fq_name
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.common import is_empty_list
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import fq_name
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.common import is_empty_list
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'dns.cache': 'cache',
- 'nameServers': 'name_servers',
- 'include': 'ip_version',
- }
-
- api_attributes = [
- 'nameServers', 'search', 'include',
- ]
-
- updatables = [
- 'cache', 'name_servers', 'search', 'ip_version',
- ]
-
- returnables = [
- 'cache', 'name_servers', 'search', 'ip_version',
- ]
-
- absentables = [
- 'name_servers', 'search',
- ]
-
-
-class ApiParameters(Parameters):
- pass
-
-
-class ModuleParameters(Parameters):
- @property
- def search(self):
- search = self._values['search']
- if search is None:
- return None
- if isinstance(search, str) and search != "":
- result = list()
- result.append(str(search))
- return result
- if is_empty_list(search):
- return []
- return search
-
- @property
- def name_servers(self):
- name_servers = self._values['name_servers']
- if name_servers is None:
- return None
- if isinstance(name_servers, str) and name_servers != "":
- result = list()
- result.append(str(name_servers))
- return result
- if is_empty_list(name_servers):
- return []
- return name_servers
-
- @property
- def cache(self):
- if self._values['cache'] is None:
- return None
- if str(self._values['cache']) in ['enabled', 'enable']:
- return 'enable'
- else:
- return 'disable'
-
- @property
- def ip_version(self):
- if self._values['ip_version'] == 6:
- return "options inet6"
- elif self._values['ip_version'] == 4:
- return ""
- else:
- return None
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- change = getattr(self, returnable)
- if isinstance(change, dict):
- result.update(change)
- else:
- result[returnable] = change
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class UsableChanges(Changes):
- pass
-
-
-class ReportableChanges(Changes):
- @property
- def ip_version(self):
- if self._values['ip_version'] == 'options inet6':
- return 6
- elif self._values['ip_version'] == "":
- return 4
- else:
- return None
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
- @property
- def ip_version(self):
- if self.want.ip_version is None:
- return None
- if self.want.ip_version == "" and self.have.ip_version is None:
- return None
- if self.want.ip_version == self.have.ip_version:
- return None
- if self.want.ip_version != self.have.ip_version:
- return self.want.ip_version
-
- @property
- def name_servers(self):
- state = self.want.state
- if self.want.name_servers is None:
- return None
- if state == 'absent':
- if self.have.name_servers is None and self.want.name_servers:
- return None
- if set(self.want.name_servers) == set(self.have.name_servers):
- return []
- if set(self.want.name_servers) != set(self.have.name_servers):
- return list(set(self.want.name_servers).difference(self.have.name_servers))
- if not self.want.name_servers:
- if self.have.name_servers is None:
- return None
- if self.have.name_servers is not None:
- return self.want.name_servers
- if self.have.name_servers is None:
- return self.want.name_servers
- if set(self.want.name_servers) != set(self.have.name_servers):
- return self.want.name_servers
-
- @property
- def search(self):
- state = self.want.state
- if self.want.search is None:
- return None
- if not self.want.search:
- if self.have.search is None:
- return None
- if self.have.search is not None:
- return self.want.search
- if state == 'absent':
- if self.have.search is None and self.want.search:
- return None
- if set(self.want.search) == set(self.have.search):
- return []
- if set(self.want.search) != set(self.have.search):
- return list(set(self.want.search).difference(self.have.search))
- if self.have.search is None:
- return self.want.search
- if set(self.want.search) != set(self.have.search):
- return self.want.search
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.pop('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(params=self.module.params)
- self.have = ApiParameters()
- self.changes = UsableChanges()
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def _absent_changed_options(self):
- diff = Difference(self.want, self.have)
- absentables = Parameters.absentables
- changed = dict()
- for k in absentables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def exec_module(self):
- changed = False
- result = dict()
- state = self.want.state
-
- if state == "present":
- changed = self.update()
- elif state == "absent":
- changed = self.absent()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def update(self):
- self.have = self.read_current_from_device()
- if not self.should_update():
- return False
- if self.module.check_mode:
- return True
- self.update_on_device()
- return True
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def should_absent(self):
- result = self._absent_changed_options()
- if result:
- return True
- return False
-
- def absent(self):
- self.have = self.read_current_from_device()
- if not self.should_absent():
- return False
- if self.module.check_mode:
- return True
- self.absent_on_device()
- return True
-
- def read_dns_cache_setting(self):
- uri = "https://{0}:{1}/mgmt/tm/sys/db/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- 'dns.cache'
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return response
-
- def read_current_from_device(self):
- cache = self.read_dns_cache_setting()
- uri = "https://{0}:{1}/mgmt/tm/sys/dns/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- if cache:
- response['cache'] = cache['value']
- return ApiParameters(params=response)
-
- def update_on_device(self):
- params = self.changes.api_params()
- if params:
- uri = "https://{0}:{1}/mgmt/tm/sys/dns/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- if self.want.cache:
- uri = "https://{0}:{1}/mgmt/tm/sys/db/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- 'dns.cache'
- )
- payload = {"value": self.want.cache}
- resp = self.client.api.patch(uri, json=payload)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def absent_on_device(self):
- params = self.changes.api_params()
- uri = "https://{0}:{1}/mgmt/tm/sys/dns/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- cache=dict(
- choices=['disabled', 'enabled', 'disable', 'enable']
- ),
- name_servers=dict(
- type='list'
- ),
- search=dict(
- type='list'
- ),
- ip_version=dict(
- choices=[4, 6],
- type='int'
- ),
- state=dict(
- default='present',
- choices=['absent', 'present']
- )
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
- self.required_one_of = [
- ['name_servers', 'search', 'ip_version', 'cache']
- ]
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode,
- required_one_of=spec.required_one_of
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_device_group.py b/lib/ansible/modules/network/f5/bigip_device_group.py
deleted file mode 100644
index 20dc8f5eb4..0000000000
--- a/lib/ansible/modules/network/f5/bigip_device_group.py
+++ /dev/null
@@ -1,626 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['stableinterface'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_device_group
-short_description: Manage device groups on a BIG-IP
-description:
- - Managing device groups allows you to create HA pairs and clusters
- of BIG-IP devices. Usage of this module should be done in conjunction
- with the C(bigip_configsync_actions) to sync configuration across
- the pair or cluster if auto-sync is disabled.
-version_added: 2.5
-options:
- name:
- description:
- - Specifies the name of the device group.
- type: str
- required: True
- type:
- description:
- - Specifies that the type of group.
- - A C(sync-failover) device group contains devices that synchronize their
- configuration data and fail over to one another when a device becomes
- unavailable.
- - A C(sync-only) device group has no such failover. When creating a new
- device group, this option will default to C(sync-only).
- - This setting cannot be changed once it has been set.
- type: str
- choices:
- - sync-failover
- - sync-only
- description:
- description:
- - Description of the device group.
- type: str
- auto_sync:
- description:
- - Indicates whether configuration synchronization occurs manually or
- automatically.
- - When creating a new device group, this option will default to C(no).
- type: bool
- save_on_auto_sync:
- description:
- - When performing an auto-sync, specifies whether the configuration
- will be saved or not.
- - When C(no), only the running configuration will be changed on the
- device(s) being synced to.
- - When creating a new device group, this option will default to C(no).
- type: bool
- full_sync:
- description:
- - Specifies whether the system synchronizes the entire configuration
- during synchronization operations.
- - When C(no), the system performs incremental synchronization operations,
- based on the cache size specified in C(max_incremental_sync_size).
- - Incremental configuration synchronization is a mechanism for synchronizing
- a device-group's configuration among its members, without requiring a
- full configuration load for each configuration change.
- - In order for this to work, all devices in the device-group must initially
- agree on the configuration. Typically this requires at least one full
- configuration load to each device.
- - When creating a new device group, this option will default to C(no).
- type: bool
- max_incremental_sync_size:
- description:
- - Specifies the size of the changes cache for incremental sync.
- - For example, using the default, if you make more than 1024 KB worth of
- incremental changes, the system performs a full synchronization operation.
- - Using incremental synchronization operations can reduce the per-device sync/load
- time for configuration changes.
- - This setting is relevant only when C(full_sync) is C(no).
- type: int
- state:
- description:
- - When C(state) is C(present), ensures the device group exists.
- - When C(state) is C(absent), ensures that the device group is removed.
- type: str
- choices:
- - present
- - absent
- default: present
- network_failover:
- description:
- - Indicates whether failover occurs over the network or is hard-wired.
- - This parameter is only valid for C(type)'s that are C(sync-failover).
- type: bool
- version_added: 2.7
-notes:
- - This module is primarily used as a component of configuring HA pairs of
- BIG-IP devices.
- - Requires BIG-IP >= 12.1.x.
-extends_documentation_fragment: f5
-author:
- - Tim Rupp (@caphrim007)
- - Wojciech Wypior (@wojtek0806)
-'''
-
-EXAMPLES = r'''
-- name: Create a sync-only device group
- bigip_device_group:
- name: foo-group
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-
-- name: Create a sync-only device group with auto-sync enabled
- bigip_device_group:
- name: foo-group
- auto_sync: yes
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-'''
-
-RETURN = r'''
-save_on_auto_sync:
- description: The new save_on_auto_sync value of the device group.
- returned: changed
- type: bool
- sample: true
-full_sync:
- description: The new full_sync value of the device group.
- returned: changed
- type: bool
- sample: false
-description:
- description: The new description of the device group.
- returned: changed
- type: str
- sample: this is a device group
-type:
- description: The new type of the device group.
- returned: changed
- type: str
- sample: sync-failover
-auto_sync:
- description: The new auto_sync value of the device group.
- returned: changed
- type: bool
- sample: true
-max_incremental_sync_size:
- description: The new sync size of the device group
- returned: changed
- type: int
- sample: 1000
-network_failover:
- description: Whether or not network failover is enabled.
- returned: changed
- type: bool
- sample: yes
-'''
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.parsing.convert_bool import BOOLEANS_TRUE
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import f5_argument_spec
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import f5_argument_spec
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'saveOnAutoSync': 'save_on_auto_sync',
- 'fullLoadOnSync': 'full_sync',
- 'autoSync': 'auto_sync',
- 'incrementalConfigSyncSizeMax': 'max_incremental_sync_size',
- 'networkFailover': 'network_failover',
- }
- api_attributes = [
- 'saveOnAutoSync',
- 'fullLoadOnSync',
- 'description',
- 'type',
- 'autoSync',
- 'incrementalConfigSyncSizeMax',
- 'networkFailover',
- ]
- returnables = [
- 'save_on_auto_sync',
- 'full_sync',
- 'description',
- 'type',
- 'auto_sync',
- 'max_incremental_sync_size',
- 'network_failover',
- ]
- updatables = [
- 'save_on_auto_sync',
- 'full_sync',
- 'description',
- 'auto_sync',
- 'max_incremental_sync_size',
- 'network_failover',
- ]
-
- @property
- def max_incremental_sync_size(self):
- if not self.full_sync and self._values['max_incremental_sync_size'] is not None:
- if self._values['__warnings'] is None:
- self._values['__warnings'] = []
- self._values['__warnings'].append(
- [
- dict(
- msg='"max_incremental_sync_size has no effect if "full_sync" is not true',
- version='2.4'
- )
- ]
- )
- if self._values['max_incremental_sync_size'] is None:
- return None
- return int(self._values['max_incremental_sync_size'])
-
-
-class ApiParameters(Parameters):
- @property
- def network_failover(self):
- if self._values['network_failover'] is None:
- return None
- elif self._values['network_failover'] == 'enabled':
- return True
- return False
-
- @property
- def auto_sync(self):
- if self._values['auto_sync'] is None:
- return None
- elif self._values['auto_sync'] == 'enabled':
- return True
- return False
-
- @property
- def save_on_auto_sync(self):
- if self._values['save_on_auto_sync'] is None:
- return None
- elif self._values['save_on_auto_sync'] in BOOLEANS_TRUE:
- return True
- else:
- return False
-
- @property
- def full_sync(self):
- if self._values['full_sync'] is None:
- return None
- elif self._values['full_sync'] in BOOLEANS_TRUE:
- return True
- else:
- return False
-
-
-class ModuleParameters(Parameters):
- pass
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- change = getattr(self, returnable)
- if isinstance(change, dict):
- result.update(change)
- else:
- result[returnable] = change
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class UsableChanges(Changes):
- @property
- def network_failover(self):
- if self._values['network_failover'] is None:
- return None
- elif self._values['network_failover']:
- return 'enabled'
- return 'disabled'
-
- @property
- def auto_sync(self):
- if self._values['auto_sync'] is None:
- return None
- elif self._values['auto_sync']:
- return 'enabled'
- return 'disabled'
-
- @property
- def save_on_auto_sync(self):
- if self._values['save_on_auto_sync'] is None:
- return None
- elif self._values['save_on_auto_sync'] in BOOLEANS_TRUE:
- return "true"
- else:
- return "false"
-
- @property
- def full_sync(self):
- if self._values['full_sync'] is None:
- return None
- elif self._values['full_sync'] in BOOLEANS_TRUE:
- return "true"
- else:
- return "false"
-
-
-class ReportableChanges(Changes):
- @property
- def network_failover(self):
- if self._values['network_failover'] is None:
- return None
- elif self._values['network_failover'] == 'enabled':
- return 'yes'
- return 'no'
-
- @property
- def auto_sync(self):
- if self._values['auto_sync'] is None:
- return None
- elif self._values['auto_sync'] == 'enabled':
- return 'yes'
- return 'no'
-
- @property
- def save_on_auto_sync(self):
- if self._values['save_on_auto_sync'] is None:
- return None
- elif self._values['save_on_auto_sync'] in BOOLEANS_TRUE:
- return "yes"
- return "no"
-
- @property
- def full_sync(self):
- if self._values['full_sync'] is None:
- return None
- elif self._values['full_sync'] in BOOLEANS_TRUE:
- return "yes"
- return "no"
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(params=self.module.params)
- self.have = ApiParameters()
- self.changes = UsableChanges()
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = UsableChanges(params=changed)
-
- def _update_changed_options(self): # lgtm [py/similar-function]
- changed = {}
- for key in Parameters.updatables:
- if getattr(self.want, key) is not None:
- attr1 = getattr(self.want, key)
- attr2 = getattr(self.have, key)
- if attr1 != attr2:
- changed[key] = attr1
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def exec_module(self):
- changed = False
- result = dict()
- state = self.want.state
-
- if state == "present":
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def present(self):
- if self.exists():
- return self.update()
- else:
- return self.create()
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def update(self):
- self.have = self.read_current_from_device()
- if not self.should_update():
- return False
- if self.module.check_mode:
- return True
- self.update_on_device()
- return True
-
- def remove(self):
- if self.module.check_mode:
- return True
- self.remove_members_in_group_from_device()
- self.remove_from_device()
- if self.exists():
- raise F5ModuleError("Failed to delete the device group")
- return True
-
- def create(self):
- self._set_changed_options()
- if self.want.type == 'sync-only' and self.want.network_failover is not None:
- raise F5ModuleError(
- "'network_failover' may only be specified when 'type' is 'sync-failover'."
- )
- if self.module.check_mode:
- return True
- self.create_on_device()
- return True
-
- def absent(self):
- if self.exists():
- return self.remove()
- return False
-
- def exists(self):
- uri = "https://{0}:{1}/mgmt/tm/cm/device-group/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- self.want.name
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def remove_members_in_group_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/cm/device-group/{2}/devices/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- self.want.name
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- for item in response['items']:
- new_uri = uri + '{0}'.format(item['name'])
- response = self.client.api.delete(new_uri)
- if response.status == 200:
- return True
- raise F5ModuleError(response.content)
-
- def create_on_device(self):
- params = self.changes.api_params()
- params['name'] = self.want.name
- params['partition'] = self.want.partition
- uri = "https://{0}:{1}/mgmt/tm/cm/device-group/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return response['selfLink']
-
- def update_on_device(self):
- params = self.changes.api_params()
- uri = "https://{0}:{1}/mgmt/tm/cm/device-group/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- self.want.name
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def remove_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/cm/device-group/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- self.want.name
- )
- response = self.client.api.delete(uri)
- if response.status == 200:
- return True
- raise F5ModuleError(response.content)
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/cm/device-group/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- self.want.name
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return ApiParameters(params=response)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- type=dict(
- choices=['sync-failover', 'sync-only']
- ),
- description=dict(),
- auto_sync=dict(
- type='bool',
- default='no'
- ),
- save_on_auto_sync=dict(
- type='bool',
- ),
- full_sync=dict(
- type='bool'
- ),
- name=dict(
- required=True
- ),
- max_incremental_sync_size=dict(
- type='int'
- ),
- state=dict(
- default='present',
- choices=['absent', 'present']
- ),
- network_failover=dict(type='bool'),
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_device_group_member.py b/lib/ansible/modules/network/f5/bigip_device_group_member.py
deleted file mode 100644
index a9ac11685a..0000000000
--- a/lib/ansible/modules/network/f5/bigip_device_group_member.py
+++ /dev/null
@@ -1,293 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['stableinterface'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_device_group_member
-short_description: Manages members in a device group
-description:
- - Manages members in a device group. Members in a device group can only
- be added or removed, never updated. This is because the members are
- identified by unique name values and changing that name would invalidate
- the uniqueness.
-version_added: 2.5
-options:
- name:
- description:
- - Specifies the name of the device that you want to add to the
- device group. Often this will be the hostname of the device.
- This member must be trusted by the device already. Trusting
- can be done with the C(bigip_device_trust) module and the
- C(peer_hostname) option to that module.
- type: str
- required: True
- device_group:
- description:
- - The device group that you want to add the member to.
- type: str
- required: True
- state:
- description:
- - When C(present), ensures that the device group member exists.
- - When C(absent), ensures the device group member is removed.
- type: str
- choices:
- - present
- - absent
- default: present
-extends_documentation_fragment: f5
-author:
- - Tim Rupp (@caphrim007)
- - Wojciech Wypior (@wojtek0806)
-'''
-
-EXAMPLES = r'''
-- name: Add the current device to the "device_trust_group" device group
- bigip_device_group_member:
- name: "{{ inventory_hostname }}"
- device_group: device_trust_group
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-
-- name: Add the hosts in the current scope to "device_trust_group"
- bigip_device_group_member:
- name: "{{ item }}"
- device_group: device_trust_group
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- loop: "{{ hostvars.keys() }}"
- run_once: true
- delegate_to: localhost
-'''
-
-RETURN = r'''
-# only common fields returned
-'''
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import f5_argument_spec
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import f5_argument_spec
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {}
-
- api_attributes = []
-
- returnables = []
-
- updatables = []
-
-
-class ApiParameters(Parameters):
- pass
-
-
-class ModuleParameters(Parameters):
- pass
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- change = getattr(self, returnable)
- if isinstance(change, dict):
- result.update(change)
- else:
- result[returnable] = change
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class UsableChanges(Changes):
- pass
-
-
-class ReportableChanges(Changes):
- pass
-
-
-class Difference(object):
- pass
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = Parameters(params=self.module.params)
- self.have = None
- self.changes = Changes()
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = Changes(params=changed)
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def exec_module(self):
- changed = False
- result = dict()
- state = self.want.state
-
- if state == "present":
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def present(self):
- if self.exists():
- return False
- else:
- return self.create()
-
- def absent(self):
- if self.exists():
- return self.remove()
- return False
-
- def create(self):
- self._set_changed_options()
- if self.module.check_mode:
- return True
- self.create_on_device()
- return True
-
- def remove(self):
- if self.module.check_mode:
- return True
- self.remove_from_device()
- if self.exists():
- raise F5ModuleError("Failed to remove the member from the device group.")
- return True
-
- def exists(self):
- uri = "https://{0}:{1}/mgmt/tm/cm/device-group/{2}/devices/{3}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- self.want.device_group,
- self.want.name
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def create_on_device(self):
- params = self.changes.api_params()
- params['name'] = self.want.name
- params['partition'] = self.want.partition
- uri = "https://{0}:{1}/mgmt/tm/cm/device-group/{2}/devices/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- self.want.device_group
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def remove_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/cm/device-group/{2}/devices/{3}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- self.want.device_group,
- self.want.name
- )
- response = self.client.api.delete(uri)
- if response.status == 200:
- return True
- raise F5ModuleError(response.content)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- name=dict(required=True),
- device_group=dict(required=True),
- state=dict(
- default='present',
- choices=['absent', 'present']
- ),
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_device_ha_group.py b/lib/ansible/modules/network/f5/bigip_device_ha_group.py
deleted file mode 100644
index 51b61ecc7f..0000000000
--- a/lib/ansible/modules/network/f5/bigip_device_ha_group.py
+++ /dev/null
@@ -1,814 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2018, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_device_ha_group
-short_description: Manage HA group settings on a BIG-IP system
-description:
- - Manage HA group settings on a BIG-IP system.
-version_added: 2.8
-options:
- name:
- description:
- - Name of the HA group to create/manage.
- type: str
- required: True
- enable:
- description:
- - When set to C(no) the system disables the ha score feature.
- type: bool
- default: yes
- description:
- description:
- - User created HA group description.
- type: str
- active_bonus:
- description:
- - Specifies the extra value to be added to the active unit's ha score.
- - When system creates HA group this value is set to C(10) by the system.
- type: int
- pools:
- description:
- - Specifies pools to contribute to the ha score.
- - The pools must exist on the BIG-IP otherwise the operation will fail.
- type: list
- suboptions:
- pool_name:
- description:
- - The pool name which is used to contribute to the ha score.
- - Referencing pool can be done in the full path format for example, C(/Common/pool_name).
- - When pool is referenced in full path format, the C(partition) parameter is ignored.
- type: str
- required: True
- attribute:
- description:
- - The pool attribute that contributes to the ha score.
- type: str
- choices:
- - percent-up-members
- default: 'percent-up-members'
- weight:
- description:
- - Maximum value the selected pool attribute contributes to the ha score.
- type: int
- required: True
- minimum_threshold:
- description:
- - Below this value the selected pool attribute contributes nothing to the ha score.
- - This value must be greater than the number of pool members present in the pool.
- - In TMOS versions 12.x this attribute is named C(threshold) however it has been deprecated
- in versions 13.x and above.
- - Specifying this attribute in the module running against v12.x will keep the same behavior
- as if C(threshold) option was set.
- type: int
- partition:
- description:
- - Device partition where the specified pool exists.
- - This parameter is ignored if the C(pool_name) is specified in full path format.
- type: str
- default: Common
- trunks:
- description:
- - Specifies trunks to contribute to the ha score.
- - The trunks must exist on the BIG-IP otherwise the operation will fail.
- type: list
- suboptions:
- trunk_name:
- description:
- - The trunk name which is used to contribute to the ha score.
- type: str
- required: True
- attribute:
- description:
- - The trunk attribute that contributes to the ha score.
- type: str
- choices:
- - percent-up-members
- default: 'percent-up-members'
- weight:
- description:
- - Maximum value the selected trunk attribute contributes to the ha score.
- type: int
- required: True
- minimum_threshold:
- description:
- - Below this value the selected trunk attribute contributes nothing to the ha score.
- - This value must be greater than the number of trunk members.
- - In TMOS versions 12.x this attribute is named C(threshold) however it has been deprecated
- in versions 13.x and above.
- - Specifying this attribute in the module running against v12.x will keep the same behavior
- as if C(threshold) option was set.
- type: int
- state:
- description:
- - When C(present), ensures that the resource exists.
- - When C(absent), ensures the resource is removed.
- type: str
- choices:
- - present
- - absent
- default: present
-notes:
- - This module does not support atomic removal of HA group objects.
-extends_documentation_fragment: f5
-author:
- - Wojciech Wypior (@wojtek0806)
-'''
-
-EXAMPLES = r'''
-- name: Create HA group no members, not active
- bigip_device_ha_group:
- name: foo_ha
- description: empty_foo
- active_bonus: 20
- enable: no
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-
-- name: Create HA group with pools and trunks
- bigip_device_ha_group:
- name: baz_ha
- description: non_empty_baz
- active_bonus: 15
- pools:
- - pool_name: foopool
- weight: 30
- minimum_threshold: 1
- trunks:
- - trunk_name: footrunk
- weight: 70
- minimum_threshold: 2
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-
-- name: Create HA group pools using full_path format
- bigip_device_ha_group:
- name: bar_ha
- description: non_empty_bar
- active_bonus: 12
- pools:
- - pool_name: /Baz/foopool
- weight: 30
- minimum_threshold: 1
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-
-- name: Remove HA group
- bigip_device_ha_group:
- name: foo_ha
- state: absent
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-'''
-
-RETURN = r'''
-name:
- description: Name of the HA group.
- returned: changed
- type: str
- sample: foo_HA
-enable:
- description: Enables or disables HA score feature.
- returned: changed
- type: bool
- sample: yes
-description:
- description: User created HA group description.
- returned: changed
- type: str
- sample: Some Group
-active_bonus:
- description: The extra value to be added to the active unit's ha score.
- returned: changed
- type: int
- sample: 20
-pools:
- description: The pools to contribute to the ha score.
- returned: changed
- type: complex
- contains:
- pool_name:
- description: The pool name which is used to contribute to the ha score.
- returned: changed
- type: str
- sample: foo_pool
- attribute:
- description: The pool attribute that contributes to the ha score.
- returned: changed
- type: str
- sample: percent-up-members
- weight:
- description: Maximum value the selected pool attribute contributes to the ha score.
- returned: changed
- type: int
- sample: 40
- minimum_threshold:
- description: Below this value the selected pool attribute contributes nothing to the ha score.
- returned: changed
- type: int
- sample: 2
- partition:
- description: Device partition where the specified pool exists.
- returned: changed
- type: str
- sample: Common
- sample: hash/dictionary of values
-trunks:
- description: The trunks to contribute to the ha score.
- returned: changed
- type: complex
- contains:
- trunk_name:
- description: The trunk name which is used to contribute to the ha score.
- returned: changed
- type: str
- sample: foo_trunk
- attribute:
- description: The trunk attribute that contributes to the ha score.
- returned: changed
- type: str
- sample: percent-up-members
- weight:
- description: Maximum value the selected trunk attribute contributes to the ha score.
- returned: changed
- type: int
- sample: 40
- minimum_threshold:
- description: Below this value the selected trunk attribute contributes nothing to the ha score.
- returned: changed
- type: int
- sample: 2
- sample: hash/dictionary of values
-'''
-
-from distutils.version import LooseVersion
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.basic import env_fallback
-from ansible.module_utils.six import iteritems
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import fq_name
- from library.module_utils.network.f5.common import transform_name
- from library.module_utils.network.f5.common import flatten_boolean
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.icontrol import tmos_version
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import fq_name
- from ansible.module_utils.network.f5.common import transform_name
- from ansible.module_utils.network.f5.common import flatten_boolean
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.icontrol import tmos_version
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'activeBonus': 'active_bonus'
- }
-
- api_attributes = [
- 'activeBonus',
- 'description',
- 'pools',
- 'trunks',
- 'enabled',
- 'disabled',
- ]
-
- returnables = [
- 'name',
- 'enabled',
- 'disabled',
- 'description',
- 'active_bonus',
- 'pools',
- 'trunks',
- ]
-
- updatables = [
- 'enabled',
- 'disabled',
- 'description',
- 'active_bonus',
- 'pools',
- 'trunks',
- ]
-
-
-class ApiParameters(Parameters):
- @property
- def enabled(self):
- result = flatten_boolean(self._values['enabled'])
- if result == 'yes':
- return True
- return None
-
- @property
- def disabled(self):
- result = flatten_boolean(self._values['disabled'])
- if result == 'yes':
- return True
- return None
-
-
-class ModuleParameters(Parameters):
- @property
- def enabled(self):
- result = flatten_boolean(self._values['enable'])
- if result == 'yes':
- return True
- return None
-
- @property
- def disabled(self):
- result = flatten_boolean(self._values['enable'])
- if result == 'no':
- return True
- return None
-
- @property
- def pools(self):
- version_13 = self._is_v13_and_above()
- result = list()
- if self._values['pools'] is None:
- return None
- for item in self._values['pools']:
- pool = dict()
- pool['name'] = fq_name(item['partition'], item['pool_name'])
- pool['weight'] = self._handle_weight(item['weight'])
- if 'attribute' in item:
- pool['attribute'] = item['attribute']
- if 'minimum_threshold' in item:
- if version_13:
- pool['minimumThreshold'] = item['minimum_threshold']
- else:
- pool['threshold'] = item['minimum_threshold']
- result.append(self._filter_params(pool))
- return result
-
- @property
- def trunks(self):
- version_13 = self._is_v13_and_above()
- result = list()
- if self._values['trunks'] is None:
- return None
- for item in self._values['trunks']:
- trunk = dict()
- trunk['name'] = item['trunk_name']
- trunk['weight'] = self._handle_weight(item['weight'])
- if 'attribute' in item:
- trunk['attribute'] = item['attribute']
- if 'minimum_threshold' in item:
- if version_13:
- trunk['minimumThreshold'] = item['minimum_threshold']
- else:
- trunk['threshold'] = item['minimum_threshold']
- result.append(self._filter_params(trunk))
- return result
-
- def _is_v13_and_above(self):
- version = tmos_version(self.client)
- if LooseVersion(version) >= LooseVersion('13.0.0'):
- return True
- return False
-
- def _handle_weight(self, weight):
- if weight < 10 or weight > 100:
- raise F5ModuleError(
- "Weight value must be in the range: '10 - 100'."
- )
- return weight
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class UsableChanges(Changes):
- pass
-
-
-class ReportableChanges(Changes):
- returnables = [
- 'name',
- 'enable',
- 'description',
- 'active_bonus',
- 'pools',
- 'trunks',
- ]
-
- @property
- def enable(self):
- enabled = flatten_boolean(self._values['enabled'])
- disabled = flatten_boolean(self._values['disabled'])
- if enabled == 'yes':
- return 'yes'
- if disabled == 'yes':
- return 'no'
- return None
-
- @property
- def pools(self):
- result = list()
- if self._values['pools'] is None:
- return None
- for item in self._values['pools']:
- pool = dict()
- pool['pool_name'] = item['name']
- pool['weight'] = item['weight']
- if 'attribute' in item:
- pool['attribute'] = item['attribute']
- if 'minimumThreshold' in item:
- pool['minimum_threshold'] = item['minimumThreshold']
- if 'threshold' in item:
- pool['minimum_threshold'] = item['threshold']
- result.append(pool)
- return result
-
- @property
- def trunks(self):
- result = list()
- if self._values['trunks'] is None:
- return None
- for item in self._values['trunks']:
- trunk = dict()
- trunk['trunk_name'] = item['name']
- trunk['weight'] = item['weight']
- if 'attribute' in item:
- trunk['attribute'] = item['attribute']
- if 'minimumThreshold' in item:
- trunk['minimum_threshold'] = item['minimumThreshold']
- if 'threshold' in item:
- trunk['minimum_threshold'] = item['threshold']
- result.append(trunk)
- return result
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
- def to_tuple(self, items):
- result = []
- for x in items:
- tmp = [(str(k), str(v)) for k, v in iteritems(x)]
- result += tmp
- return result
-
- def _diff_complex_items(self, want, have):
- if want == [] and have is None:
- return None
- if want is None:
- return None
- if have is None:
- return want
- w = self.to_tuple(want)
- h = self.to_tuple(have)
- if set(w).issubset(set(h)):
- return None
- else:
- return want
-
- @property
- def pools(self):
- result = self._diff_complex_items(self.want.pools, self.have.pools)
- return result
-
- @property
- def trunks(self):
- result = self._diff_complex_items(self.want.trunks, self.have.trunks)
- return result
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(params=self.module.params, client=self.client)
- self.have = ApiParameters()
- self.changes = UsableChanges()
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = UsableChanges(params=changed)
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.client.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def exec_module(self):
- changed = False
- result = dict()
- state = self.want.state
-
- if state == "present":
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def present(self):
- if self.exists():
- return self.update()
- else:
- return self.create()
-
- def absent(self):
- if self.exists():
- return self.remove()
- return False
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def update(self):
- self.have = self.read_current_from_device()
- if not self.should_update():
- return False
- if self.module.check_mode:
- return True
- self.update_on_device()
- return True
-
- def remove(self):
- if self.module.check_mode:
- return True
- self.remove_from_device()
- if self.exists():
- raise F5ModuleError("Failed to delete the resource.")
- return True
-
- def create(self):
- self._set_changed_options()
- if self.module.check_mode:
- return True
- self.create_on_device()
- return True
-
- def exists(self):
- uri = "https://{0}:{1}/mgmt/tm/sys/ha-group/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- self.want.name
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def create_on_device(self):
- params = self.changes.api_params()
- params['name'] = self.want.name
- uri = "https://{0}:{1}/mgmt/tm/sys/ha-group/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 409]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return True
-
- def update_on_device(self):
- params = self.changes.api_params()
- uri = "https://{0}:{1}/mgmt/tm/sys/ha-group/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- self.want.name
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def remove_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/sys/ha-group/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- self.want.name
- )
- response = self.client.api.delete(uri)
- if response.status == 200:
- return True
- raise F5ModuleError(response.content)
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/sys/ha-group/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- self.want.name
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return ApiParameters(params=response)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- name=dict(
- required=True
- ),
- enable=dict(
- type='bool',
- default='yes'
- ),
- description=dict(),
- active_bonus=dict(
- type='int'
- ),
- pools=dict(
- type='list',
- elements='dict',
- options=dict(
- pool_name=dict(
- required=True
- ),
- attribute=dict(
- choices=[
- 'percent-up-members'
- ],
- default='percent-up-members'
- ),
- weight=dict(
- required=True,
- type='int'
- ),
- minimum_threshold=dict(
- type='int'
- ),
- partition=dict(
- default='Common',
- fallback=(env_fallback, ['F5_PARTITION'])
- )
- )
- ),
- trunks=dict(
- type='list',
- elements='dict',
- options=dict(
- trunk_name=dict(
- required=True
- ),
- attribute=dict(
- choices=[
- 'percent-up-members'
- ],
- default='percent-up-members'
- ),
- weight=dict(
- required=True,
- type='int'
- ),
- minimum_threshold=dict(
- type='int'
- ),
- )
- ),
- state=dict(
- default='present',
- choices=['present', 'absent']
- )
-
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode,
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_device_httpd.py b/lib/ansible/modules/network/f5/bigip_device_httpd.py
deleted file mode 100644
index 931fc6cf7f..0000000000
--- a/lib/ansible/modules/network/f5/bigip_device_httpd.py
+++ /dev/null
@@ -1,723 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['stableinterface'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_device_httpd
-short_description: Manage HTTPD related settings on BIG-IP
-description:
- - Manages HTTPD related settings on the BIG-IP. These settings are interesting
- to change when you want to set GUI timeouts and other TMUI related settings.
-version_added: 2.5
-options:
- allow:
- description:
- - Specifies, if you have enabled HTTPD access, the IP address or address
- range for other systems that can communicate with this system.
- - To specify all addresses, use the value C(all).
- - IP address can be specified, such as 172.27.1.10.
- - IP ranges can be specified, such as 172.27.*.* or 172.27.0.0/255.255.0.0.
- type: list
- auth_name:
- description:
- - Sets the BIG-IP authentication realm name.
- type: str
- auth_pam_idle_timeout:
- description:
- - Sets the GUI timeout for automatic logout, in seconds.
- type: int
- auth_pam_validate_ip:
- description:
- - Sets the authPamValidateIp setting.
- type: bool
- auth_pam_dashboard_timeout:
- description:
- - Sets whether or not the BIG-IP dashboard will timeout.
- type: bool
- fast_cgi_timeout:
- description:
- - Sets the timeout of FastCGI.
- type: int
- hostname_lookup:
- description:
- - Sets whether or not to display the hostname, if possible.
- type: bool
- log_level:
- description:
- - Sets the minimum httpd log level.
- type: str
- choices:
- - alert
- - crit
- - debug
- - emerg
- - error
- - info
- - notice
- - warn
- max_clients:
- description:
- - Sets the maximum number of clients that can connect to the GUI at once.
- type: int
- redirect_http_to_https:
- description:
- - Whether or not to redirect http requests to the GUI to https.
- type: bool
- ssl_port:
- description:
- - The HTTPS port to listen on.
- type: int
- ssl_cipher_suite:
- description:
- - Specifies the ciphers that the system uses.
- - The values in the suite are separated by colons (:).
- - Can be specified in either a string or list form. The list form is the
- recommended way to provide the cipher suite. See examples for usage.
- - Use the value C(default) to set the cipher suite to the system default.
- This value is equivalent to specifying a list of C(ECDHE-RSA-AES128-GCM-SHA256,
- ECDHE-RSA-AES256-GCM-SHA384,ECDHE-RSA-AES128-SHA,ECDHE-RSA-AES256-SHA,
- ECDHE-RSA-AES128-SHA256,ECDHE-RSA-AES256-SHA384,ECDHE-ECDSA-AES128-GCM-SHA256,
- ECDHE-ECDSA-AES256-GCM-SHA384,ECDHE-ECDSA-AES128-SHA,ECDHE-ECDSA-AES256-SHA,
- ECDHE-ECDSA-AES128-SHA256,ECDHE-ECDSA-AES256-SHA384,AES128-GCM-SHA256,
- AES256-GCM-SHA384,AES128-SHA,AES256-SHA,AES128-SHA256,AES256-SHA256,
- ECDHE-RSA-DES-CBC3-SHA,ECDHE-ECDSA-DES-CBC3-SHA,DES-CBC3-SHA).
- type: raw
- version_added: 2.6
- ssl_protocols:
- description:
- - The list of SSL protocols to accept on the management console.
- - A space-separated list of tokens in the format accepted by the Apache
- mod_ssl SSLProtocol directive.
- - Can be specified in either a string or list form. The list form is the
- recommended way to provide the cipher suite. See examples for usage.
- - Use the value C(default) to set the SSL protocols to the system default.
- This value is equivalent to specifying a list of C(all,-SSLv2,-SSLv3).
- type: raw
- version_added: 2.6
-notes:
- - Requires the requests Python package on the host. This is as easy as
- C(pip install requests).
-requirements:
- - requests
-extends_documentation_fragment: f5
-author:
- - Joe Reifel (@JoeReifel)
- - Tim Rupp (@caphrim007)
-'''
-
-EXAMPLES = r'''
-- name: Set the BIG-IP authentication realm name
- bigip_device_httpd:
- auth_name: BIG-IP
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-
-- name: Set the auth pam timeout to 3600 seconds
- bigip_device_httpd:
- auth_pam_idle_timeout: 1200
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-
-- name: Set the validate IP settings
- bigip_device_httpd:
- auth_pam_validate_ip: on
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-
-- name: Set SSL cipher suite by list
- bigip_device_httpd:
- ssl_cipher_suite:
- - ECDHE-RSA-AES128-GCM-SHA256
- - ECDHE-RSA-AES256-GCM-SHA384
- - ECDHE-RSA-AES128-SHA
- - AES256-SHA256
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-
-- name: Set SSL cipher suite by string
- bigip_device_httpd:
- ssl_cipher_suite: ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-SHA:AES256-SHA256
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-
-- name: Set SSL protocols by list
- bigip_device_httpd:
- ssl_protocols:
- - all
- - -SSLv2
- - -SSLv3
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-
-- name: Set SSL protocols by string
- bigip_device_httpd:
- ssl_protocols: all -SSLv2 -SSLv3
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-'''
-
-RETURN = r'''
-auth_pam_idle_timeout:
- description: The new number of seconds for GUI timeout.
- returned: changed
- type: str
- sample: 1200
-auth_name:
- description: The new authentication realm name.
- returned: changed
- type: str
- sample: 'foo'
-auth_pam_validate_ip:
- description: The new authPamValidateIp setting.
- returned: changed
- type: bool
- sample: on
-auth_pam_dashboard_timeout:
- description: Whether or not the BIG-IP dashboard will timeout.
- returned: changed
- type: bool
- sample: off
-fast_cgi_timeout:
- description: The new timeout of FastCGI.
- returned: changed
- type: int
- sample: 500
-hostname_lookup:
- description: Whether or not to display the hostname, if possible.
- returned: changed
- type: bool
- sample: on
-log_level:
- description: The new minimum httpd log level.
- returned: changed
- type: str
- sample: crit
-max_clients:
- description: The new maximum number of clients that can connect to the GUI at once.
- returned: changed
- type: int
- sample: 20
-redirect_http_to_https:
- description: Whether or not to redirect http requests to the GUI to https.
- returned: changed
- type: bool
- sample: on
-ssl_port:
- description: The new HTTPS port to listen on.
- returned: changed
- type: int
- sample: 10443
-ssl_cipher_suite:
- description: The new ciphers that the system uses.
- returned: changed
- type: str
- sample: ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-SHA
-ssl_cipher_suite_list:
- description: List of the new ciphers that the system uses.
- returned: changed
- type: str
- sample: ['ECDHE-RSA-AES256-GCM-SHA384', 'ECDHE-RSA-AES128-SHA']
-ssl_protocols:
- description: The new list of SSL protocols to accept on the management console.
- returned: changed
- type: str
- sample: all -SSLv2 -SSLv3
-'''
-
-import time
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.six import string_types
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import f5_argument_spec
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import f5_argument_spec
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'authPamIdleTimeout': 'auth_pam_idle_timeout',
- 'authPamValidateIp': 'auth_pam_validate_ip',
- 'authName': 'auth_name',
- 'authPamDashboardTimeout': 'auth_pam_dashboard_timeout',
- 'fastcgiTimeout': 'fast_cgi_timeout',
- 'hostnameLookup': 'hostname_lookup',
- 'logLevel': 'log_level',
- 'maxClients': 'max_clients',
- 'redirectHttpToHttps': 'redirect_http_to_https',
- 'sslPort': 'ssl_port',
- 'sslCiphersuite': 'ssl_cipher_suite',
- 'sslProtocol': 'ssl_protocols'
- }
-
- api_attributes = [
- 'authPamIdleTimeout', 'authPamValidateIp', 'authName', 'authPamDashboardTimeout',
- 'fastcgiTimeout', 'hostnameLookup', 'logLevel', 'maxClients', 'sslPort',
- 'redirectHttpToHttps', 'allow', 'sslCiphersuite', 'sslProtocol'
- ]
-
- returnables = [
- 'auth_pam_idle_timeout', 'auth_pam_validate_ip', 'auth_name',
- 'auth_pam_dashboard_timeout', 'fast_cgi_timeout', 'hostname_lookup',
- 'log_level', 'max_clients', 'redirect_http_to_https', 'ssl_port',
- 'allow', 'ssl_cipher_suite', 'ssl_protocols', 'ssl_cipher_suite_list',
- ]
-
- updatables = [
- 'auth_pam_idle_timeout', 'auth_pam_validate_ip', 'auth_name',
- 'auth_pam_dashboard_timeout', 'fast_cgi_timeout', 'hostname_lookup',
- 'log_level', 'max_clients', 'redirect_http_to_https', 'ssl_port',
- 'allow', 'ssl_cipher_suite', 'ssl_protocols'
- ]
-
- _ciphers = "ECDHE-RSA-AES128-GCM-SHA256:" \
- "ECDHE-RSA-AES256-GCM-SHA384:" \
- "ECDHE-RSA-AES128-SHA:" \
- "ECDHE-RSA-AES256-SHA:" \
- "ECDHE-RSA-AES128-SHA256:" \
- "ECDHE-RSA-AES256-SHA384:" \
- "ECDHE-ECDSA-AES128-GCM-SHA256:" \
- "ECDHE-ECDSA-AES256-GCM-SHA384:" \
- "ECDHE-ECDSA-AES128-SHA:" \
- "ECDHE-ECDSA-AES256-SHA:" \
- "ECDHE-ECDSA-AES128-SHA256:" \
- "ECDHE-ECDSA-AES256-SHA384:" \
- "AES128-GCM-SHA256:" \
- "AES256-GCM-SHA384:" \
- "AES128-SHA:" \
- "AES256-SHA:" \
- "AES128-SHA256:" \
- "AES256-SHA256:" \
- "ECDHE-RSA-DES-CBC3-SHA:" \
- "ECDHE-ECDSA-DES-CBC3-SHA:" \
- "DES-CBC3-SHA"
-
- _protocols = 'all -SSLv2 -SSLv3'
-
- @property
- def auth_pam_idle_timeout(self):
- if self._values['auth_pam_idle_timeout'] is None:
- return None
- return int(self._values['auth_pam_idle_timeout'])
-
- @property
- def fast_cgi_timeout(self):
- if self._values['fast_cgi_timeout'] is None:
- return None
- return int(self._values['fast_cgi_timeout'])
-
- @property
- def max_clients(self):
- if self._values['max_clients'] is None:
- return None
- return int(self._values['max_clients'])
-
- @property
- def ssl_port(self):
- if self._values['ssl_port'] is None:
- return None
- return int(self._values['ssl_port'])
-
-
-class ModuleParameters(Parameters):
- @property
- def auth_pam_validate_ip(self):
- if self._values['auth_pam_validate_ip'] is None:
- return None
- if self._values['auth_pam_validate_ip']:
- return "on"
- return "off"
-
- @property
- def auth_pam_dashboard_timeout(self):
- if self._values['auth_pam_dashboard_timeout'] is None:
- return None
- if self._values['auth_pam_dashboard_timeout']:
- return "on"
- return "off"
-
- @property
- def hostname_lookup(self):
- if self._values['hostname_lookup'] is None:
- return None
- if self._values['hostname_lookup']:
- return "on"
- return "off"
-
- @property
- def redirect_http_to_https(self):
- if self._values['redirect_http_to_https'] is None:
- return None
- if self._values['redirect_http_to_https']:
- return "enabled"
- return "disabled"
-
- @property
- def allow(self):
- if self._values['allow'] is None:
- return None
- if self._values['allow'][0] == 'all':
- return 'all'
- if self._values['allow'][0] == '':
- return ''
- allow = self._values['allow']
- result = list(set([str(x) for x in allow]))
- result = sorted(result)
- return result
-
- @property
- def ssl_cipher_suite(self):
- if self._values['ssl_cipher_suite'] is None:
- return None
- if isinstance(self._values['ssl_cipher_suite'], string_types):
- ciphers = self._values['ssl_cipher_suite'].strip()
- else:
- ciphers = self._values['ssl_cipher_suite']
- if not ciphers:
- raise F5ModuleError(
- "ssl_cipher_suite may not be set to 'none'"
- )
- if ciphers == 'default':
- ciphers = ':'.join(Parameters._ciphers.split(':'))
- elif isinstance(self._values['ssl_cipher_suite'], string_types):
- ciphers = ':'.join(ciphers.split(':'))
- else:
- ciphers = ':'.join(ciphers)
- return ciphers
-
- @property
- def ssl_protocols(self):
- if self._values['ssl_protocols'] is None:
- return None
- if isinstance(self._values['ssl_protocols'], string_types):
- protocols = self._values['ssl_protocols'].strip()
- else:
- protocols = self._values['ssl_protocols']
- if not protocols:
- raise F5ModuleError(
- "ssl_protocols may not be set to 'none'"
- )
- if protocols == 'default':
- protocols = ' '.join(Parameters._protocols.split(' '))
- elif isinstance(protocols, string_types):
- protocols = ' '.join(protocols.split(' '))
- else:
- protocols = ' '.join(protocols)
- return protocols
-
-
-class ApiParameters(Parameters):
- @property
- def allow(self):
- if self._values['allow'] is None:
- return ''
- if self._values['allow'][0] == 'All':
- return 'all'
- allow = self._values['allow']
- result = list(set([str(x) for x in allow]))
- result = sorted(result)
- return result
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class UsableChanges(Changes):
- pass
-
-
-class ReportableChanges(Changes):
- @property
- def ssl_cipher_suite(self):
- default = ':'.join(Parameters._ciphers.split(':'))
- if self._values['ssl_cipher_suite'] == default:
- return 'default'
- else:
- return self._values['ssl_cipher_suite']
-
- @property
- def ssl_cipher_suite_list(self):
- return self._values['ssl_cipher_suite'].split(':')
-
- @property
- def ssl_protocols(self):
- default = ' '.join(Parameters._protocols.split(' '))
- if self._values['ssl_protocols'] == default:
- return 'default'
- else:
- return self._values['ssl_protocols']
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
- @property
- def allow(self):
- if self.want.allow is None:
- return None
- if self.want.allow == 'all' and self.have.allow == 'all':
- return None
- if self.want.allow == 'all':
- return ['All']
- if self.want.allow == '' and self.have.allow == '':
- return None
- if self.want.allow == '':
- return []
- if self.want.allow != self.have.allow:
- return self.want.allow
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(params=self.module.params)
- self.have = ApiParameters()
- self.changes = UsableChanges()
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = Changes(params=changed)
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def exec_module(self):
- result = dict()
-
- changed = self.present()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def present(self):
- return self.update()
-
- def update(self):
- self.have = self.read_current_from_device()
- if not self.should_update():
- return False
- if self.module.check_mode:
- return True
- self.update_on_device()
- return True
-
- def update_on_device(self):
- params = self.changes.api_params()
- uri = "https://{0}:{1}/mgmt/tm/sys/httpd".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
-
- try:
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- except Exception as ex:
- valid = [
- 'Remote end closed connection',
- 'Connection aborted',
- ]
- # BIG-IP will kill your management connection when you change the HTTP
- # redirect setting. So this catches that and handles it gracefully.
- if 'redirectHttpToHttps' in params:
- if any(i for i in valid if i in str(ex)):
- # Wait for BIG-IP web server to settle after changing this
- time.sleep(2)
- return True
- raise F5ModuleError(str(ex))
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/sys/httpd".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return ApiParameters(params=response)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- allow=dict(
- type='list'
- ),
- auth_name=dict(),
- auth_pam_idle_timeout=dict(
- type='int'
- ),
- fast_cgi_timeout=dict(
- type='int'
- ),
- max_clients=dict(
- type='int'
- ),
- ssl_port=dict(
- type='int'
- ),
- auth_pam_validate_ip=dict(
- type='bool'
- ),
- auth_pam_dashboard_timeout=dict(
- type='bool'
- ),
- hostname_lookup=dict(
- type='bool'
- ),
- log_level=dict(
- choices=[
- 'alert', 'crit', 'debug', 'emerg',
- 'error', 'info', 'notice', 'warn'
- ]
- ),
- redirect_http_to_https=dict(
- type='bool'
- ),
- ssl_cipher_suite=dict(type='raw'),
- ssl_protocols=dict(type='raw')
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode,
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_device_info.py b/lib/ansible/modules/network/f5/bigip_device_info.py
deleted file mode 100644
index 48a639222a..0000000000
--- a/lib/ansible/modules/network/f5/bigip_device_info.py
+++ /dev/null
@@ -1,16266 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# Copyright: (c) 2013, Matt Hite <mhite@hotmail.com>
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_device_info
-short_description: Collect information from F5 BIG-IP devices
-description:
- - Collect information from F5 BIG-IP devices.
- - This module was called C(bigip_device_facts) before Ansible 2.9. The usage did not change.
-version_added: 2.7
-options:
- gather_subset:
- description:
- - When supplied, this argument will restrict the information returned to a given subset.
- - Can specify a list of values to include a larger subset.
- - Values can also be used with an initial C(!) to specify that a specific subset
- should not be collected.
- type: list
- required: True
- choices:
- - all
- - monitors
- - profiles
- - asm-policy-stats
- - asm-policies
- - asm-server-technologies
- - asm-signature-sets
- - client-ssl-profiles
- - devices
- - device-groups
- - external-monitors
- - fasthttp-profiles
- - fastl4-profiles
- - gateway-icmp-monitors
- - gtm-pools
- - gtm-servers
- - gtm-wide-ips
- - gtm-a-pools
- - gtm-a-wide-ips
- - gtm-aaaa-pools
- - gtm-aaaa-wide-ips
- - gtm-cname-pools
- - gtm-cname-wide-ips
- - gtm-mx-pools
- - gtm-mx-wide-ips
- - gtm-naptr-pools
- - gtm-naptr-wide-ips
- - gtm-srv-pools
- - gtm-srv-wide-ips
- - http-monitors
- - https-monitors
- - http-profiles
- - iapp-services
- - iapplx-packages
- - icmp-monitors
- - interfaces
- - internal-data-groups
- - irules
- - ltm-pools
- - ltm-policies
- - nodes
- - oneconnect-profiles
- - partitions
- - provision-info
- - self-ips
- - server-ssl-profiles
- - software-volumes
- - software-images
- - software-hotfixes
- - ssl-certs
- - ssl-keys
- - system-db
- - system-info
- - tcp-monitors
- - tcp-half-open-monitors
- - tcp-profiles
- - traffic-groups
- - trunks
- - udp-profiles
- - users
- - vcmp-guests
- - virtual-addresses
- - virtual-servers
- - vlans
- - "!all"
- - "!monitors"
- - "!profiles"
- - "!asm-policy-stats"
- - "!asm-policies"
- - "!asm-server-technologies"
- - "!asm-signature-sets"
- - "!client-ssl-profiles"
- - "!devices"
- - "!device-groups"
- - "!external-monitors"
- - "!fasthttp-profiles"
- - "!fastl4-profiles"
- - "!gateway-icmp-monitors"
- - "!gtm-pools"
- - "!gtm-servers"
- - "!gtm-wide-ips"
- - "!gtm-a-pools"
- - "!gtm-a-wide-ips"
- - "!gtm-aaaa-pools"
- - "!gtm-aaaa-wide-ips"
- - "!gtm-cname-pools"
- - "!gtm-cname-wide-ips"
- - "!gtm-mx-pools"
- - "!gtm-mx-wide-ips"
- - "!gtm-naptr-pools"
- - "!gtm-naptr-wide-ips"
- - "!gtm-srv-pools"
- - "!gtm-srv-wide-ips"
- - "!http-monitors"
- - "!https-monitors"
- - "!http-profiles"
- - "!iapp-services"
- - "!iapplx-packages"
- - "!icmp-monitors"
- - "!interfaces"
- - "!internal-data-groups"
- - "!irules"
- - "!ltm-pools"
- - "!ltm-policies"
- - "!nodes"
- - "!oneconnect-profiles"
- - "!partitions"
- - "!provision-info"
- - "!self-ips"
- - "!server-ssl-profiles"
- - "!software-volumes"
- - "!software-images"
- - "!software-hotfixes"
- - "!ssl-certs"
- - "!ssl-keys"
- - "!system-db"
- - "!system-info"
- - "!tcp-monitors"
- - "!tcp-half-open-monitors"
- - "!tcp-profiles"
- - "!traffic-groups"
- - "!trunks"
- - "!udp-profiles"
- - "!users"
- - "!vcmp-guests"
- - "!virtual-addresses"
- - "!virtual-servers"
- - "!vlans"
- aliases: ['include']
-extends_documentation_fragment: f5
-author:
- - Tim Rupp (@caphrim007)
- - Wojciech Wypior (@wojtek0806)
-'''
-
-EXAMPLES = r'''
-- name: Collect BIG-IP information
- bigip_device_info:
- gather_subset:
- - interfaces
- - vlans
- provider:
- server: lb.mydomain.com
- user: admin
- password: secret
- delegate_to: localhost
-
-- name: Collect all BIG-IP information
- bigip_device_info:
- gather_subset:
- - all
- provider:
- server: lb.mydomain.com
- user: admin
- password: secret
- delegate_to: localhost
-
-- name: Collect all BIG-IP information except trunks
- bigip_device_info:
- gather_subset:
- - all
- - "!trunks"
- provider:
- server: lb.mydomain.com
- user: admin
- password: secret
- delegate_to: localhost
-'''
-
-RETURN = r'''
-asm_policy_stats:
- description: Miscellaneous ASM policy related information.
- returned: When C(asm-policy-stats) is specified in C(gather_subset).
- type: complex
- contains:
- policies:
- description:
- - The total number of ASM policies on the device.
- returned: queried
- type: int
- sample: 3
- policies_active:
- description:
- - The number of ASM policies that are marked as active.
- returned: queried
- type: int
- sample: 3
- policies_attached:
- description:
- - The number of ASM policies that are attached to virtual servers.
- returned: queried
- type: int
- sample: 1
- policies_inactive:
- description:
- - The number of ASM policies that are marked as inactive.
- returned: queried
- type: int
- sample: 0
- policies_unattached:
- description:
- - The number of ASM policies that are not attached to a virtual server.
- returned: queried
- type: int
- sample: 3
- sample: hash/dictionary of values
-asm_policies:
- description: Detailed information for ASM policies present on device.
- returned: When C(asm-policies) is specified in C(gather_subset).
- type: complex
- contains:
- full_path:
- description:
- - Full name of the resource as known to BIG-IP.
- returned: queried
- type: str
- sample: /Common/foo_policy
- name:
- description:
- - Relative name of the resource in BIG-IP.
- returned: queried
- type: str
- sample: foo_policy
- policy_id:
- description:
- - Generated ID of the ASM policy resource.
- returned: queried
- type: str
- sample: l0Ckxe-7yHsXp8U5tTgbFQ
- active:
- description:
- - Indicates if an ASM policy is active.
- returned: queried
- type: bool
- sample: yes
- protocol_independent:
- description:
- - Indicates if the ASM policy differentiates between HTTP/WS and HTTPS/WSS URLs.
- returned: queried
- type: bool
- sample: no
- has_parent:
- description:
- - Indicates if the ASM policy is a child of another ASM policy.
- returned: queried
- type: bool
- sample: no
- type:
- description:
- - The type of policy, can be C(Security) or C(Parent).
- returned: queried
- type: str
- sample: security
- virtual_servers:
- description:
- - Virtual server or servers which have this policy assigned to them.
- returned: queried
- type: list
- sample: ['/Common/foo_VS/']
- allowed_response_codes:
- description:
- - Lists the response status codes between 400 and 599 that the security profile considers legal.
- returned: queried
- type: list
- sample: ['400', '404']
- description:
- description:
- - Description of the resource.
- returned: queried
- type: str
- sample: Significant Policy Description
- learning_mode:
- description:
- - Determine how the policy is built.
- returned: queried
- type: str
- sample: manual
- enforcement_mode:
- description:
- - Specifies whether blocking is active or inactive for the ASM policy.
- returned: queried
- type: str
- sample: blocking
- trust_xff:
- description:
- - Indicates the system has confidence in an XFF (X-Forwarded-For) header in the request.
- returned: queried
- type: bool
- sample: yes
- custom_xff_headers:
- description:
- - List of custom XFF headers trusted by the system.
- returned: queried
- type: str
- sample: asm-proxy1
- case_insensitive:
- description:
- - Indicates if the ASM policy treats file types, URLs, and parameters as case sensitive.
- returned: queried
- type: bool
- sample: yes
- signature_staging:
- description:
- - Specifies if the staging feature is active on the ASM policy.
- returned: queried
- type: bool
- sample: yes
- place_signatures_in_staging:
- description:
- - Specifies if the system places new or updated signatures in staging
- for the number of days specified in the enforcement readiness period.
- returned: queried
- type: bool
- sample: no
- enforcement_readiness_period:
- description:
- - Period in days both security policy entities and attack signatures
- remain in staging mode before the system suggests to enforce them.
- returned: queried
- type: int
- sample: 8
- path_parameter_handling:
- description:
- - Specifies how the system handles path parameters that are attached to path segments in URIs.
- returned: queried
- type: str
- sample: ignore
- trigger_asm_irule_event:
- description:
- - Indicates if iRule event is enabled.
- returned: queried
- type: str
- sample: disabled
- inspect_http_uploads:
- description:
- - Specify if the system should inspect all http uploads.
- returned: queried
- type: bool
- sample: yes
- mask_credit_card_numbers_in_request:
- description:
- - Indicates if the system masks credit card numbers.
- returned: queried
- type: bool
- sample: no
- maximum_http_header_length:
- description:
- - Maximum length of an HTTP header name and value that the system processes.
- returned: queried
- type: int
- sample: 8192
- use_dynamic_session_id_in_url:
- description:
- - Specifies how the security policy processes URLs that use dynamic sessions.
- returned: queried
- type: bool
- sample: no
- maximum_cookie_header_length:
- description:
- - Maximum length of a cookie header name and value that the system processes.
- returned: queried
- type: int
- sample: 8192
- application_language:
- description:
- - The language encoding for the web application.
- returned: queried
- type: str
- sample: utf-8
- disallowed_geolocations:
- description:
- - Displays countries that may not access the web application.
- returned: queried
- type: str
- sample: Argentina
- csrf_protection_enabled:
- description:
- - Specifies if CSRF protection is active on the ASM policy.
- returned: queried
- type: bool
- sample: yes
- csrf_protection_ssl_only:
- description:
- - Specifies that only HTTPS URLs will be checked for CSRF protection.
- returned: queried
- type: bool
- sample: yes
- csrf_protection_expiration_time_in_seconds:
- description:
- - Specifies how long, in seconds, a configured CSRF token is valid before it expires.
- returned: queried
- type: int
- sample: 600
- csrf_urls:
- description:
- - Specifies a list of URLs for CSRF token verification.
- - In version 13.0.0 and above this has become a sub-collection and a list of dictionaries.
- - In version 12.x this is a list of simple strings.
- returned: queried
- type: complex
- contains:
- csrf_url_required_parameters:
- description:
- - Indicates whether to ignore or require one of the specified parameters is present
- in a request when checking if the URL entry matches the request.
- returned: queried
- type: str
- sample: ignore
- csrf_url_parameters_list:
- description:
- - List of parameters to look for in a request when checking if the URL entry matches the request.
- returned: queried
- type: list
- sample: ['fooparam']
- csrf_url:
- description:
- - Specifies an URL to protect.
- returned: queried
- type: str
- sample: ['/foo.html']
- csrf_url_method:
- description:
- - Method for the specified URL.
- returned: queried
- type: str
- sample: POST
- csrf_url_enforcement_action:
- description:
- - Indicates the action specified for the system to take when the URL entry matches.
- returned: queried
- type: str
- sample: none
- csrf_url_id:
- description:
- - Specified the generated ID for the configured CSRF url resource.
- returned: queried
- type: str
- sample: l0Ckxe-7yHsXp8U5tTgbFQ
- csrf_url_wildcard_order:
- description:
- - Specified the order in which the wildcard URLs are enforced.
- returned: queried
- type: str
- sample: 1
- sample: hash/dictionary of values
-asm_server_technologies:
- description: Detailed information for ASM server technologies present on device.
- returned: When C(asm-server-technologies) is specified in C(gather_subset).
- type: complex
- contains:
- id:
- description:
- - Displays the generated ID for the server technology resource.
- returned: queried
- type: str
- sample: l0Ckxe-7yHsXp8U5tTgbFQ
- server_technology_name:
- description:
- - Human friendly name of the server technology resource.
- returned: queried
- type: str
- sample: Wordpress
- server_technology_references:
- description:
- - List of dictionaries containing API self links of the associated technology resources.
- returned: queried
- type: complex
- contains:
- link:
- description:
- - A self link to an associated server technology.
- sample: https://localhost/mgmt/tm/asm/server-technologies/NQG7CT02OBC2cQWbnP7T-A?ver=13.1.0
- sample: hash/dictionary of values
-asm_signature_sets:
- description: Detailed information for ASM signature sets present on device.
- returned: When C(asm-signature-sets) is specified in C(gather_subset).
- type: complex
- contains:
- name:
- description:
- - Name of the signature set
- returned: queried
- type: str
- sample: WebSphere signatures
- id:
- description:
- - Displays the generated ID for the signature set resource.
- returned: queried
- type: str
- sample: l0Ckxe-7yHsXp8U5tTgbFQ
- type:
- description:
- - The method used to select signatures to be a part of the signature set.
- returned: queried
- type: str
- sample: filter-based
- category:
- description:
- - Displays the category of the signature set.
- returned: queried
- type: str
- sample: filter-based
- is_user_defined:
- description:
- - Specifies that this signature set was added by a user.
- returned: queried
- type: bool
- sample: no
- assign_to_policy_by_default:
- description:
- - Indicates whether the system assigns this signature set to a new created security policy by default.
- returned: queried
- type: bool
- sample: yes
- default_alarm:
- description:
- - Displays whether the security policy logs the request data in the Statistics
- screen if a request matches a signature that is included in the signature set
- returned: queried
- type: bool
- sample: yes
- default_block:
- description:
- - Displays, when the security policy's enforcement mode is Blocking,
- how the system treats requests that match a signature included in the signature set.
- returned: queried
- type: bool
- sample: yes
- default_learn:
- description:
- - Displays whether the security policy learns all requests that match a signature
- that is included in the signature set.
- returned: queried
- type: bool
- sample: yes
- sample: hash/dictionary of values
-client_ssl_profiles:
- description: Client SSL Profile related information.
- returned: When C(client-ssl-profiles) is specified in C(gather_subset).
- type: complex
- contains:
- full_path:
- description:
- - Full name of the resource as known to BIG-IP.
- returned: queried
- type: str
- sample: /Common/bigip02.internal
- name:
- description:
- - Relative name of the resource in BIG-IP.
- returned: queried
- type: str
- sample: bigip02.internal
- alert_timeout:
- description:
- - Maximum time period in seconds to keep the SSL session active after alert
- message is sent, or indefinite.
- returned: queried
- type: int
- sample: 0
- allow_non_ssl:
- description:
- - Enables or disables non-SSL connections.
- returned: queried
- type: bool
- sample: yes
- authenticate_depth:
- description:
- - Specifies the authenticate depth. This is the client certificate chain maximum traversal depth.
- returned: queried
- type: int
- sample: 9
- authenticate_frequency:
- description:
- - Specifies how often the system authenticates a user.
- returned: queried
- type: str
- sample: once
- ca_file:
- description:
- - Specifies the certificate authority (CA) file name.
- returned: queried
- type: str
- sample: /Common/default-ca.crt
- cache_size:
- description:
- - Specifies the SSL session cache size.
- returned: queried
- type: int
- sample: 262144
- cache_timeout:
- description:
- - Specifies the SSL session cache timeout value.
- returned: queried
- type: int
- sample: 3600
- certificate_file:
- description:
- - Specifies the name of the certificate installed on the traffic
- management system for the purpose of terminating or initiating
- an SSL connection.
- returned: queried
- type: str
- sample: /Common/default.crt
- chain_file:
- description:
- - Specifies or builds a certificate chain file that a client can
- use to authenticate the profile.
- returned: queried
- type: str
- sample: /Common/ca-chain.crt
- ciphers:
- description:
- - Specifies a list of cipher names.
- returned: queried
- type: str
- sample: ['DEFAULT']
- crl_file:
- description:
- - Specifies the certificate revocation list file name.
- returned: queried
- type: str
- sample: /Common/default.crl
- parent:
- description:
- - Parent of the profile
- returned: queried
- type: str
- sample: /Common/clientssl
- description:
- description:
- - Description of the profile.
- returned: queried
- type: str
- sample: My profile
- modssl_methods:
- description:
- - Enables or disables ModSSL method emulation.
- returned: queried
- type: bool
- sample: no
- peer_certification_mode:
- description:
- - Specifies the peer certificate mode.
- returned: queried
- type: str
- sample: ignore
- sni_require:
- description:
- - When this option is C(yes), a client connection that does not
- specify a known server name or does not support SNI extension will
- be rejected.
- returned: queried
- type: bool
- sample: no
- sni_default:
- description:
- - When C(yes), this profile is the default SSL profile when the server
- name in a client connection does not match any configured server
- names, or a client connection does not specify any server name at
- all.
- returned: queried
- type: bool
- sample: yes
- strict_resume:
- description:
- - Enables or disables strict-resume.
- returned: queried
- type: bool
- sample: yes
- profile_mode_enabled:
- description:
- - Specifies the profile mode, which enables or disables SSL
- processing.
- returned: queried
- type: bool
- sample: yes
- renegotiation_maximum_record_delay:
- description:
- - Maximum number of SSL records that the traffic
- management system can receive before it renegotiates an SSL
- session.
- returned: queried
- type: int
- sample: 0
- renegotiation_period:
- description:
- - Number of seconds required to renegotiate an SSL
- session.
- returned: queried
- type: int
- sample: 0
- renegotiation:
- description:
- - Specifies whether renegotiations are enabled.
- returned: queried
- type: bool
- sample: yes
- server_name:
- description:
- - Specifies the server names to be matched with SNI (server name
- indication) extension information in ClientHello from a client
- connection.
- returned: queried
- type: str
- sample: bigip01
- session_ticket:
- description:
- - Enables or disables session-ticket.
- returned: queried
- type: bool
- sample: no
- unclean_shutdown:
- description:
- - Whether to force the SSL profile to perform a clean shutdown of all SSL
- connections or not
- returned: queried
- type: bool
- sample: no
- retain_certificate:
- description:
- - APM module requires storing certificate in SSL session. When
- C(no), certificate will not be stored in SSL session.
- returned: queried
- type: bool
- sample: yes
- secure_renegotiation_mode:
- description:
- - Specifies the secure renegotiation mode.
- returned: queried
- type: str
- sample: require
- handshake_timeout:
- description:
- - Specifies the handshake timeout in seconds.
- returned: queried
- type: int
- sample: 10
- forward_proxy_certificate_extension_include:
- description:
- - Specifies the extensions of the web server certificates to be
- included in the generated certificates using SSL Forward Proxy.
- returned: queried
- type: list
- sample: ["basic-constraints", "subject-alternative-name"]
- forward_proxy_certificate_lifespan:
- description:
- - Specifies the lifespan of the certificate generated using the SSL
- forward proxy feature.
- returned: queried
- type: int
- sample: 30
- forward_proxy_lookup_by_ipaddr_port:
- description:
- - Specifies whether to perform certificate look up by IP address and
- port number.
- returned: queried
- type: bool
- sample: no
- forward_proxy_enabled:
- description:
- - Enables or disables SSL forward proxy feature.
- returned: queried
- type: bool
- sample: yes
- forward_proxy_ca_passphrase:
- description:
- - Specifies the passphrase of the key file that is used as the
- certification authority key when SSL forward proxy feature is
- enabled.
- returned: queried
- type: str
- forward_proxy_ca_certificate_file:
- description:
- - Specifies the name of the certificate file that is used as the
- certification authority certificate when SSL forward proxy feature
- is enabled.
- returned: queried
- type: str
- forward_proxy_ca_key_file:
- description:
- - Specifies the name of the key file that is used as the
- certification authority key when SSL forward proxy feature is
- enabled.
- returned: queried
- type: str
- sample: hash/dictionary of values
-devices:
- description: Device related information.
- returned: When C(devices) is specified in C(gather_subset).
- type: complex
- contains:
- full_path:
- description:
- - Full name of the resource as known to BIG-IP.
- returned: queried
- type: str
- sample: /Common/bigip02.internal
- name:
- description:
- - Relative name of the resource in BIG-IP.
- returned: queried
- type: str
- sample: bigip02.internal
- active_modules:
- description:
- - The currently licensed and provisioned modules on the device.
- returned: queried
- type: list
- sample: ["DNS Services (LAB)", "PSM, VE"]
- base_mac_address:
- description:
- - Media Access Control address (MAC address) of the device.
- returned: queried
- type: str
- sample: "fa:16:3e:c3:42:6f"
- build:
- description:
- - The minor version information of the total product version.
- returned: queried
- type: str
- sample: 0.0.1
- chassis_id:
- description:
- - Serial number of the device.
- returned: queried
- type: str
- sample: 11111111-2222-3333-444444444444
- chassis_type:
- description:
- - Displays the chassis type. The possible values are C(individual) and C(viprion).
- returned: queried
- type: str
- sample: individual
- comment:
- description:
- - User comments about the device.
- returned: queried
- type: str
- sample: My device
- configsync_address:
- description:
- - IP address used for configuration synchronization.
- returned: queried
- type: str
- sample: 10.10.10.10
- contact:
- description:
- - Administrator contact information.
- returned: queried
- type: str
- sample: The User
- description:
- description:
- - Description of the device.
- returned: queried
- type: str
- sample: My device
- edition:
- description:
- - Displays the software edition.
- returned: queried
- type: str
- sample: Point Release 7
- failover_state:
- description:
- - Device failover state.
- returned: queried
- type: str
- sample: active
- hostname:
- description:
- - Device hostname
- returned: queried
- type: str
- sample: bigip02.internal
- location:
- description:
- - Specifies the physical location of the device.
- returned: queried
- type: str
- sample: London
- management_address:
- description:
- - IP address of the management interface.
- returned: queried
- type: str
- sample: 3.3.3.3
- marketing_name:
- description:
- - Marketing name of the device platform.
- returned: queried
- type: str
- sample: BIG-IP Virtual Edition
- multicast_address:
- description:
- - Specifies the multicast IP address used for failover.
- returned: queried
- type: str
- sample: 4.4.4.4
- optional_modules:
- description:
- - Modules that are available for the current platform, but are not currently licensed.
- returned: queried
- type: list
- sample: ["App Mode (TMSH Only, No Root/Bash)", "BIG-IP VE, Multicast Routing"]
- platform_id:
- description:
- - Displays the device platform identifier.
- returned: queried
- type: str
- sample: Z100
- primary_mirror_address:
- description:
- - Specifies the IP address used for state mirroring.
- returned: queried
- type: str
- sample: 5.5.5.5
- product:
- description:
- - Displays the software product name.
- returned: queried
- type: str
- sample: BIG-IP
- secondary_mirror_address:
- description:
- - Secondary IP address used for state mirroring.
- returned: queried
- type: str
- sample: 2.2.2.2
- self:
- description:
- - Whether this device is the one that was queried for information, or not.
- returned: queried
- type: bool
- sample: yes
- software_version:
- description:
- - Displays the software version number.
- returned: queried
- type: str
- sample: 13.1.0.7
- timelimited_modules:
- description:
- - Displays the licensed modules that are time-limited.
- returned: queried
- type: list
- sample: ["IP Intelligence, 3Yr, ...", "PEM URL Filtering, 3Yr, ..."]
- timezone:
- description:
- - Displays the time zone configured on the device.
- returned: queried
- type: str
- sample: UTC
- unicast_addresses:
- description:
- - Specifies the entire set of unicast addresses used for failover.
- returned: queried
- type: complex
- contains:
- effective_ip:
- description:
- - The IP address that peers can use to reach this unicast address IP.
- returned: queried
- type: str
- sample: 5.4.3.5
- effective_port:
- description:
- - The port that peers can use to reach this unicast address.
- returned: queried
- type: int
- sample: 1026
- ip:
- description:
- - The IP address that the failover daemon will listen on for packets from its peers.
- returned: queried
- type: str
- sample: 5.4.3.5
- port:
- description:
- - The IP port that the failover daemon uses to accept packets from its peers.
- returned: queried
- type: int
- sample: 1026
- sample: hash/dictionary of values
-device_groups:
- description: Device group related information.
- returned: When C(device-groups) is specified in C(gather_subset).
- type: complex
- contains:
- full_path:
- description:
- - Full name of the resource as known to BIG-IP.
- returned: queried
- type: str
- sample: /Common/fasthttp
- name:
- description:
- - Relative name of the resource in BIG-IP.
- returned: queried
- type: str
- sample: fasthttp
- autosync_enabled:
- description:
- - Whether the device group automatically synchronizes configuration data to its members.
- returned: queried
- type: bool
- sample: no
- description:
- description:
- - Description of the device group.
- returned: queried
- type: str
- sample: My device group
- devices:
- description:
- - List of devices that are in the group. Devices are listed by their C(full_path).
- returned: queried
- type: list
- sample: [/Common/bigip02.internal]
- full_load_on_sync:
- description:
- - Specifies that the entire configuration for a device group is sent when configuration
- synchronization is performed.
- returned: queried
- type: bool
- sample: yes
- incremental_config_sync_size_maximum:
- description:
- - Specifies the maximum size (in KB) to devote to incremental config sync cached transactions.
- returned: queried
- type: int
- sample: 1024
- network_failover_enabled:
- description:
- - Specifies whether network failover is used.
- returned: queried
- type: bool
- sample: yes
- type:
- description:
- - Specifies the type of device group.
- returned: queried
- type: str
- sample: sync-only
- asm_sync_enabled:
- description:
- - Specifies whether to synchronize ASM configurations of device group members.
- returned: queried
- type: bool
- sample: yes
- sample: hash/dictionary of values
-external_monitors:
- description: External monitor related information.
- returned: When C(external-monitors) is specified in C(gather_subset).
- type: complex
- contains:
- full_path:
- description:
- - Full name of the resource as known to BIG-IP.
- returned: queried
- type: str
- sample: /Common/external
- name:
- description:
- - Relative name of the resource in BIG-IP.
- returned: queried
- type: str
- sample: external
- parent:
- description:
- - Profile from which this profile inherits settings.
- returned: queried
- type: str
- sample: external
- description:
- description:
- - Description of the resource.
- returned: queried
- type: str
- sample: My monitor
- destination:
- description:
- - Specifies the IP address and service port of the resource that is
- the destination of this monitor.
- returned: queried
- type: str
- sample: "*:*"
- args:
- description:
- - Specifies any command-line arguments that the script requires.
- returned: queried
- type: str
- sample: arg1 arg2 arg3
- external_program:
- description:
- - Specifies the name of the file for the monitor to use.
- returned: queried
- type: str
- sample: /Common/arg_example
- variables:
- description:
- - Specifies any variables that the script requires.
- type: complex
- sample: { "key1": "val", "key_2": "val 2" }
- interval:
- description:
- - Specifies, in seconds, the frequency at which the system issues
- the monitor check when either the resource is down or the status
- of the resource is unknown.
- returned: queried
- type: int
- sample: 5
- manual_resume:
- description:
- - Specifies whether the system automatically changes the status of a
- resource to up at the next successful monitor check.
- returned: queried
- type: bool
- sample: yes
- time_until_up:
- description:
- - Specifies the amount of time, in seconds, after the first
- successful response before a node is marked up.
- returned: queried
- type: int
- sample: 0
- timeout:
- description:
- - Specifies the number of seconds the target has in which to respond
- to the monitor request.
- returned: queried
- type: int
- sample: 16
- up_interval:
- description:
- - Specifies, in seconds, the frequency at which the system issues
- the monitor check when the resource is up.
- returned: queried
- type: int
- sample: 0
- sample: hash/dictionary of values
-fasthttp_profiles:
- description: FastHTTP profile related information.
- returned: When C(fasthttp-profiles) is specified in C(gather_subset).
- type: complex
- contains:
- full_path:
- description:
- - Full name of the resource as known to BIG-IP.
- returned: queried
- type: str
- sample: /Common/fasthttp
- name:
- description:
- - Relative name of the resource in BIG-IP.
- returned: queried
- type: str
- sample: fasthttp
- client_close_timeout:
- description:
- - Number of seconds after which the system closes a client connection, when
- the system either receives a client FIN packet or sends a FIN packet to the client.
- returned: queried
- type: int
- sample: 5
- oneconnect_idle_timeout_override:
- description:
- - Number of seconds after which a server-side connection in a OneConnect pool
- is eligible for deletion, when the connection has no traffic.
- returned: queried
- type: int
- sample: 0
- oneconnect_maximum_reuse:
- description:
- - Maximum number of times that the system can re-use a current connection.
- returned: queried
- type: int
- sample: 0
- oneconnect_maximum_pool_size:
- description:
- - Maximum number of connections to a load balancing pool.
- returned: queried
- type: int
- sample: 2048
- oneconnect_minimum_pool_size:
- description:
- - Minimum number of connections to a load balancing pool.
- returned: queried
- type: int
- sample: 0
- oneconnect_replenish':
- description:
- - Specifies, when C(yes), that the system will not keep a steady-state maximum of
- connections to the back-end unless the number of connections to the pool have
- dropped beneath the C(minimum_pool_size) specified in the profile.
- returned: queried
- type: bool
- sample: yes
- oneconnect_ramp_up_increment:
- description:
- - The increment in which the system makes additional connections available, when
- all available connections are in use.
- returned: queried
- type: int
- sample: 4
- parent:
- description:
- - Profile from which this profile inherits settings.
- returned: queried
- type: str
- sample: fasthttp
- description:
- description:
- - Description of the resource.
- returned: queried
- type: str
- sample: My profile
- force_http_1_0_response:
- description:
- - Specifies, when C(yes), that the server sends responses to clients in the HTTP/1.0
- format.
- returned: queried
- type: bool
- sample: no
- request_header_insert:
- description:
- - A string that the system inserts as a header in an HTTP request. If the header
- exists already, the system does not replace it.
- returned: queried
- type: str
- sample: "X-F5-Authentication: foo"
- http_1_1_close_workarounds:
- description:
- - Specifies, when C(yes), that the server uses workarounds for HTTP 1.1 close issues.
- returned: queried
- type: bool
- sample: no
- idle_timeout:
- description:
- - Length of time that a connection is idle (has no traffic) before the connection
- is eligible for deletion.
- returned: queried
- type: int
- sample: 300
- insert_x_forwarded_for:
- description:
- - Whether the system inserts the X-Forwarded-For header in an HTTP request with the
- client IP address, to use with connection pooling.
- returned: queried
- type: bool
- sample: no
- maximum_header_size:
- description:
- - Maximum amount of HTTP header data that the system buffers before making a load
- balancing decision.
- returned: queried
- type: int
- sample: 32768
- maximum_requests:
- description:
- - Maximum number of requests that the system can receive on a client-side connection,
- before the system closes the connection.
- returned: queried
- type: int
- sample: 0
- maximum_segment_size_override:
- description:
- - Maximum segment size (MSS) override for server-side connections.
- returned: queried
- type: int
- sample: 0
- receive_window_size:
- description:
- - Amount of data the BIG-IP system can accept without acknowledging the server.
- returned: queried
- type: int
- sample: 0
- reset_on_timeout:
- description:
- - Specifies, when C(yes), that the system sends a reset packet (RST) in addition to
- deleting the connection, when a connection exceeds the idle timeout value.
- returned: queried
- type: bool
- sample: yes
- server_close_timeout:
- description:
- - Number of seconds after which the system closes a client connection, when the system
- either receives a server FIN packet or sends a FIN packet to the server.
- returned: queried
- type: int
- sample: 5
- server_sack:
- description:
- - Whether the BIG-IP system processes Selective ACK (Sack) packets in cookie responses
- from the server.
- returned: queried
- type: bool
- sample: no
- server_timestamp:
- description:
- - Whether the BIG-IP system processes timestamp request packets in cookie responses
- from the server.
- returned: queried
- type: bool
- sample: no
- unclean_shutdown:
- description:
- - How the system handles closing connections. Values provided may be C(enabled), C(disabled),
- or C(fast).
- returned: queried
- type: str
- sample: enabled
- sample: hash/dictionary of values
-fastl4_profiles:
- description: FastL4 profile related information.
- returned: When C(fastl4-profiles) is specified in C(gather_subset).
- type: complex
- contains:
- full_path:
- description:
- - Full name of the resource as known to BIG-IP.
- returned: queried
- type: str
- sample: /Common/fastl4
- name:
- description:
- - Relative name of the resource in BIG-IP.
- returned: queried
- type: str
- sample: fastl4
- client_timeout:
- description:
- - Specifies late binding client timeout in seconds.
- - This is the number of seconds allowed for a client to transmit enough data to
- select a server pool.
- - If this timeout expires, the timeout-recovery option dictates whether
- to drop the connection or fallback to the normal FastL4 load-balancing method
- to pick a server pool.
- returned: queried
- type: int
- sample: 30
- parent:
- description:
- - Profile from which this profile inherits settings.
- returned: queried
- type: str
- sample: fastl4
- description:
- description:
- - Description of the resource.
- returned: queried
- type: str
- sample: My profile
- explicit_flow_migration:
- description:
- - Specifies whether to have the iRule code determine exactly when
- the FIX stream drops down to the ePVA hardware.
- returned: queried
- type: bool
- sample: yes
- hardware_syn_cookie:
- description:
- - Enables or disables hardware SYN cookie support when PVA10 is present on the system.
- - This option is deprecated in version 13.0.0 and is replaced by C(syn-cookie-enable).
- returned: queried
- type: bool
- sample: no
- idle_timeout:
- description:
- - Specifies the number of seconds that a connection is idle before the connection is
- eligible for deletion.
- - Values will be in the range of 0 to 4294967295 (inclusive).
- - C(0) is equivalent to the TMUI value "immediate".
- - C(4294967295) is equivalent to the TMUI value "indefinite".
- returned: queried
- type: int
- sample: 300
- dont_fragment_flag:
- description:
- - Describes the Don't Fragment (DF) bit setting in the IP Header of
- the outgoing TCP packet.
- - When C(pmtu), sets the outgoing IP Header DF bit based on IP pmtu
- setting(tm.pathmtudiscovery).
- - When C(preserve), sets the outgoing Packet's IP Header DF bit to be same as incoming
- IP Header DF bit.
- - When C(set), sets the outgoing packet's IP Header DF bit.
- - When C(clear), clears the outgoing packet's IP Header DF bit.
- returned: queried
- type: str
- sample: pmtu
- ip_tos_to_client:
- description:
- - Specifies an IP Type of Service (ToS) number for the client-side.
- - This option specifies the ToS level that the traffic management
- system assigns to IP packets when sending them to clients.
- returned: queried
- type: str or int
- sample: 200
- ip_tos_to_server:
- description:
- - Specifies an IP ToS number for the server side.
- - This option specifies the ToS level that the traffic management system assigns
- to IP packets when sending them to servers.
- returned: queried
- type: str or int
- sample: pass-through
- ttl_mode:
- description:
- - Describe the outgoing TCP packet's IP Header TTL mode.
- - When C(proxy), sets the outgoing IP Header TTL value to 255/64 for ipv4/ipv6
- respectively.
- - When C(preserve), sets the outgoing IP Header TTL value to be same as the
- incoming IP Header TTL value.
- - When C(decrement), sets the outgoing IP Header TTL value to be one less than
- the incoming TTL value.
- - When C(set), sets the outgoing IP Header TTL value to a specific value(as
- specified by C(ttl_v4) or C(ttl_v6).
- returned: queried
- type: str
- sample: preserve
- ttl_v4:
- description:
- - Specify the outgoing packet's IP Header TTL value for IPv4 traffic.
- - Maximum value that can be specified is 255.
- returned: queried
- type: int
- sample: 200
- ttl_v6:
- description:
- - Specify the outgoing packet's IP Header TTL value for IPv6
- traffic.
- - Maximum value that can be specified is 255.
- returned: queried
- type: int
- sample: 300
- keep_alive_interval:
- description:
- - Specifies the keep-alive probe interval, in seconds.
- - A value of 0 indicates keep-alive is disabled.
- returned: queried
- type: int
- sample: 10
- late_binding:
- description:
- - Specifies whether to enable or disable intelligent selection of a
- back-end server pool.
- returned: queried
- type: bool
- sample: yes
- link_qos_to_client:
- description:
- - Specifies a Link Quality of Service (QoS) (VLAN priority) number
- for the client side.
- - This option specifies the QoS level that the system assigns to packets
- when sending them to clients.
- returned: queried
- type: int or string
- sample: 7
- link_qos_to_server:
- description:
- - Specifies a Link QoS (VLAN priority) number for the server side.
- - This option specifies the QoS level that the system assigns to
- packets when sending them to servers.
- returned: queried
- type: int or string
- sample: 5
- loose_close:
- description:
- - Specifies that the system closes a loosely-initiated connection
- when the system receives the first FIN packet from either the
- client or the server.
- returned: queried
- type: bool
- sample: no
- loose_init:
- description:
- - Specifies that the system initializes a connection when it
- receives any Transmission Control Protocol (TCP) packet, rather
- than requiring a SYN packet for connection initiation.
- returned: queried
- type: bool
- sample: yes
- mss_override:
- description:
- - Specifies a maximum segment size (MSS) override for server
- connections. Note that this is also the MSS advertised to a client
- when a client first connects.
- - C(0) (zero), means the option is disabled. Otherwise, the value will be
- between 256 and 9162.
- returned: queried
- type: int
- sample: 500
- priority_to_client:
- description:
- - Specifies internal packet priority for the client side.
- - This option specifies the internal packet priority that the system
- assigns to packets when sending them to clients.
- returned: queried
- type: int or string
- sample: 300
- priority_to_server:
- description:
- - Specifies internal packet priority for the server side.
- - This option specifies the internal packet priority that the system
- assigns to packets when sending them to servers.
- returned: queried
- type: int or string
- sample: 200
- pva_acceleration:
- description:
- - Specifies the Packet Velocity(r) ASIC acceleration policy.
- returned: queried
- type: str
- sample: full
- pva_dynamic_client_packets:
- description:
- - Specifies the number of client packets before dynamic ePVA
- hardware re-offloading occurs.
- - Values will be between 0 and 10.
- returned: queried
- type: int
- sample: 8
- pva_dynamic_server_packets:
- description:
- - Specifies the number of server packets before dynamic ePVA
- hardware re-offloading occurs.
- - Values will be between 0 and 10.
- returned: queried
- type: int
- sample: 5
- pva_flow_aging:
- description:
- - Specifies if automatic aging from ePVA flow cache is enabled or not.
- returned: queried
- type: bool
- sample: yes
- pva_flow_evict:
- description:
- - Specifies if this flow can be evicted upon hash collision with a
- new flow learn snoop request.
- returned: queried
- type: bool
- sample: no
- pva_offload_dynamic:
- description:
- - Specifies whether PVA flow dynamic offloading is enabled or not.
- returned: queried
- type: bool
- sample: yes
- pva_offload_state:
- description:
- - Specifies at what stage the ePVA performs hardware offload.
- - When C(embryonic), implies at TCP CSYN or the first client UDP packet.
- - When C(establish), implies TCP 3WAY handshaking or UDP CS round trip are
- confirmed.
- returned: queried
- type: str
- sample: embryonic
- reassemble_fragments:
- description:
- - Specifies whether to reassemble fragments.
- returned: queried
- type: bool
- sample: yes
- receive_window:
- description:
- - Specifies the window size to use, in bytes.
- - The maximum is 2^31 for window scale enabling.
- returned: queried
- type: int
- sample: 1000
- reset_on_timeout:
- description:
- - Specifies whether you want to reset connections on timeout.
- returned: queried
- type: bool
- sample: yes
- rtt_from_client:
- description:
- - Enables or disables the TCP timestamp options to measure the round
- trip time to the client.
- returned: queried
- type: bool
- sample: no
- rtt_from_server:
- description:
- - Enables or disables the TCP timestamp options to measure the round
- trip time to the server.
- returned: queried
- type: bool
- sample: yes
- server_sack:
- description:
- - Specifies whether to support server sack option in cookie response
- by default.
- returned: queried
- type: bool
- sample: no
- server_timestamp:
- description:
- - Specifies whether to support server timestamp option in cookie
- response by default.
- returned: queried
- type: bool
- sample: yes
- software_syn_cookie:
- description:
- - Enables or disables software SYN cookie support when PVA10 is not present
- on the system.
- - This option is deprecated in version 13.0.0 and is replaced by
- C(syn_cookie_enabled).
- returned: queried
- type: bool
- sample: yes
- syn_cookie_enabled:
- description:
- - Enables syn-cookies capability on this virtual server.
- returned: queried
- type: bool
- sample: no
- syn_cookie_mss:
- description:
- - Specifies a maximum segment size (MSS) for server connections when
- SYN Cookie is enabled.
- returned: queried
- type: int
- sample: 2000
- syn_cookie_whitelist:
- description:
- - Specifies whether or not to use a SYN Cookie WhiteList when doing
- software SYN Cookies.
- returned: queried
- type: bool
- sample: no
- tcp_close_timeout:
- description:
- - Specifies a TCP close timeout in seconds.
- returned: queried
- type: int
- sample: 100
- generate_init_seq_number:
- description:
- - Specifies whether you want to generate TCP sequence numbers on all
- SYNs that conform with RFC1948, and allow timestamp recycling.
- returned: queried
- type: bool
- sample: yes
- tcp_handshake_timeout:
- description:
- - Specifies a TCP handshake timeout in seconds.
- returned: queried
- type: int
- sample: 5
- strip_sack:
- description:
- - Specifies whether you want to block the TCP SackOK option from
- passing to the server on an initiating SYN.
- returned: queried
- type: bool
- sample: yes
- tcp_time_wait_timeout:
- description:
- - Specifies a TCP time_wait timeout in milliseconds.
- returned: queried
- type: int
- sample: 60
- tcp_timestamp_mode:
- description:
- - Specifies how you want to handle the TCP timestamp.
- returned: queried
- type: str
- sample: preserve
- tcp_window_scale_mode:
- description:
- - Specifies how you want to handle the TCP window scale.
- returned: queried
- type: str
- sample: preserve
- timeout_recovery:
- description:
- - Specifies late binding timeout recovery mode. This is the action
- to take when late binding timeout occurs on a connection.
- - When C(disconnect), only the L7 iRule actions are acceptable to
- pick a server.
- - When C(fallback), the normal FastL4 load-balancing methods are acceptable
- to pick a server.
- returned: queried
- type: str
- sample: fallback
- sample: hash/dictionary of values
-gateway_icmp_monitors:
- description: Gateway ICMP monitor related information.
- returned: When C(gateway-icmp-monitors) is specified in C(gather_subset).
- type: complex
- contains:
- full_path:
- description:
- - Full name of the resource as known to BIG-IP.
- returned: queried
- type: str
- sample: /Common/gateway_icmp
- name:
- description:
- - Relative name of the resource in BIG-IP.
- returned: queried
- type: str
- sample: gateway_icmp
- parent:
- description:
- - Profile from which this profile inherits settings.
- returned: queried
- type: str
- sample: gateway_icmp
- description:
- description:
- - Description of the resource.
- returned: queried
- type: str
- sample: My monitor
- adaptive:
- description:
- - Whether adaptive response time monitoring is enabled for this monitor.
- returned: queried
- type: bool
- sample: no
- adaptive_divergence_type:
- description:
- - Specifies whether the adaptive-divergence-value is C(relative) or
- C(absolute).
- returned: queried
- type: str
- sample: relative
- adaptive_divergence_value:
- description:
- - Specifies how far from mean latency each monitor probe is allowed
- to be.
- returned: queried
- type: int
- sample: 25
- adaptive_limit:
- description:
- - Specifies the hard limit, in milliseconds, which the probe is not
- allowed to exceed, regardless of the divergence value.
- returned: queried
- type: int
- sample: 200
- adaptive_sampling_timespan:
- description:
- - Specifies the size of the sliding window, in seconds, which
- records probe history.
- returned: queried
- type: int
- sample: 300
- destination:
- description:
- - Specifies the IP address and service port of the resource that is
- the destination of this monitor.
- returned: queried
- type: str
- sample: "*:*"
- interval:
- description:
- - Specifies, in seconds, the frequency at which the system issues
- the monitor check when either the resource is down or the status
- of the resource is unknown.
- returned: queried
- type: int
- sample: 5
- manual_resume:
- description:
- - Specifies whether the system automatically changes the status of a
- resource to up at the next successful monitor check.
- returned: queried
- type: bool
- sample: yes
- time_until_up:
- description:
- - Specifies the amount of time, in seconds, after the first
- successful response before a node is marked up.
- returned: queried
- type: int
- sample: 0
- timeout:
- description:
- - Specifies the number of seconds the target has in which to respond
- to the monitor request.
- returned: queried
- type: int
- sample: 16
- transparent:
- description:
- - Specifies whether the monitor operates in transparent mode.
- returned: queried
- type: bool
- sample: no
- up_interval:
- description:
- - Specifies, in seconds, the frequency at which the system issues
- the monitor check when the resource is up.
- returned: queried
- type: int
- sample: 0
- sample: hash/dictionary of values
-gtm_pools:
- description:
- - GTM pool related information.
- - Every "type" of pool has the exact same list of possible information. Therefore,
- the list of information here is presented once instead of 6 times.
- returned: When any of C(gtm-pools) or C(gtm-*-pools) is specified in C(gather_subset).
- type: complex
- contains:
- full_path:
- description:
- - Full name of the resource as known to BIG-IP.
- returned: queried
- type: str
- sample: /Common/pool1
- name:
- description:
- - Relative name of the resource in BIG-IP.
- returned: queried
- type: str
- sample: pool1
- alternate_mode:
- description:
- - The load balancing mode that the system uses to load balance name resolution
- requests among the members of the pool.
- returned: queried
- type: str
- sample: drop-packet
- dynamic_ratio:
- description:
- - Whether or not the dynamic ratio load balancing algorithm is enabled for this
- pool.
- returned: queried
- type: bool
- sample: yes
- enabled:
- description:
- - Is the pool enabled.
- returned: queried
- type: bool
- disabled:
- description:
- - Is the pool disabled.
- returned: queried
- type: bool
- fallback_mode:
- description:
- - Specifies the load balancing mode that the system uses to load balance
- name resolution amongst the pool members if the preferred and alternate
- modes are unsuccessful in picking a pool.
- returned: queried
- type: str
- load_balancing_mode:
- description:
- - Specifies the preferred load balancing mode that the system uses to load
- balance requests across pool members.
- returned: queried
- type: str
- manual_resume:
- description:
- - Whether manual resume is enabled for this pool.
- returned: queried
- type: bool
- max_answers_returned:
- description:
- - Maximum number of available virtual servers that the system lists in a
- response.
- returned: queried
- type: int
- members:
- description:
- - Lists of members (and their configurations) in the pool.
- returned: queried
- type: complex
- partition:
- description:
- - Partition the pool exists on.
- returned: queried
- qos_hit_ratio:
- description:
- - Weight of the Hit Ratio performance factor for the QoS dynamic load
- balancing method.
- returned: queried
- type: int
- qos_hops:
- description:
- - Weight of the Hops performance factor when load balancing mode or fallback mode
- is QoS.
- returned: queried
- type: int
- qos_kilobytes_second:
- description:
- - Weight assigned to Kilobytes per Second performance factor when load balancing
- option is QoS.
- returned: queried
- type: int
- qos_lcs:
- description:
- - Weight assign to the Link Capacity performance factor when load balancing option
- is QoS.
- returned: queried
- type: int
- qos_packet_rate:
- description:
- - Weight assign to the Packet Rate performance factor when load balancing option
- is QoS.
- returned: queried
- type: int
- qos_rtt:
- description:
- - Weight assign to the Round Trip Time performance factor when load balancing option
- is QoS.
- returned: queried
- type: int
- qos_topology:
- description:
- - Weight assign to the Topology performance factor when load balancing option
- is QoS.
- returned: queried
- type: int
- qos_vs_capacity:
- description:
- - Weight assign to the Virtual Server performance factor when load balancing option
- is QoS.
- returned: queried
- type: int
- qos_vs_score:
- description:
- - Weight assign to the Virtual Server Score performance factor when load balancing
- option is QoS.
- returned: queried
- type: int
- ttl:
- description:
- - Number of seconds that the IP address, once found, is valid.
- returned: queried
- type: int
- verify_member_availability:
- description:
- - Whether or not the system verifies the availability of the members before
- sending a connection to them.
- returned: queried
- type: bool
- sample: hash/dictionary of values
-gtm_servers:
- description:
- - GTM server related information.
- returned: When C(gtm-servers) is specified in C(gather_subset).
- type: complex
- contains:
- full_path:
- description:
- - Full name of the resource as known to BIG-IP.
- returned: queried
- type: str
- sample: /Common/server1
- name:
- description:
- - Relative name of the resource in BIG-IP.
- returned: queried
- type: str
- sample: server1
- datacenter:
- description:
- - Full name of the datacenter this server belongs to.
- returned: queried
- type: str
- enabled:
- description:
- - Whether the server is enabled.
- returned: queried
- type: bool
- disabled:
- description:
- - Whether the server is disabled.
- returned: queried
- type: bool
- expose_route_domains:
- description:
- - Allow the GTM server to auto-discover the LTM virtual servers from all
- route domains.
- returned: queried
- type: bool
- iq_allow_path:
- description:
- - Whether the GTM uses this BIG-IP system to conduct a path probe before
- delegating traffic to it.
- returned: queried
- type: bool
- iq_allow_service_check:
- description:
- - Whether the GTM uses this BIG-IP system to conduct a service check probe
- before delegating traffic to it.
- returned: queried
- type: bool
- iq_allow_snmp:
- description:
- - Whether the GTM uses this BIG-IP system to conduct an SNMP probe
- before delegating traffic to it.
- returned: queried
- type: bool
- limit_cpu_usage:
- description:
- - For a server configured as a generic host, specifies the percent of CPU
- usage, otherwise has no effect.
- returned: queried
- type: int
- limit_cpu_usage_status:
- description:
- - Whether C(limit_cpu_usage) is enabled for this server.
- returned: queried
- type: bool
- limit_max_bps:
- description:
- - Maximum allowable data throughput rate in bits per second for this server.
- returned: queried
- type: int
- limit_max_bps_status:
- description:
- - Whether C(limit_max_bps) is enabled for this server.
- returned: queried
- type: bool
- limit_max_connections:
- description:
- - Maximum number of concurrent connections, combined, for this server.
- returned: queried
- type: int
- limit_max_connections_status:
- description:
- - Whether C(limit_max_connections) is enabled for this server.
- type: bool
- limit_max_pps:
- description:
- - Maximum allowable data transfer rate, in packets per second, for this server.
- returned: queried
- type: int
- limit_max_pps_status:
- description:
- - Whether C(limit_max_pps) is enabled for this server.
- returned: queried
- type: bool
- limit_mem_available:
- description:
- - For a server configured as a generic host, specifies the available memory
- required by the virtual servers on the server.
- - If available memory falls below this limit, the system marks the server as
- unavailable.
- returned: queried
- type: int
- limit_mem_available_status:
- description:
- - Whether C(limit_mem_available) is enabled for this server.
- returned: queried
- type: bool
- link_discovery:
- description:
- - Specifies whether the system auto-discovers the links for this server.
- returned: queried
- type: str
- monitors:
- description:
- - Specifies health monitors that the system uses to determine whether this
- server is available for load balancing.
- returned: queried
- type: list
- sample: ['/Common/https_443', '/Common/icmp']
- monitor_type:
- description:
- - Whether one or monitors need to pass, or all monitors need to pass.
- returned: queried
- type: str
- sample: and_list
- product:
- description:
- - Specifies the server type.
- returned: queried
- type: str
- prober_fallback:
- description:
- - The type of prober to use to monitor this servers resources when the
- preferred type is not available.
- returned: queried
- type: str
- prober_preference:
- description:
- - Specifies the type of prober to use to monitor this servers resources.
- returned: queried
- type: str
- virtual_server_discovery:
- description:
- - Whether the system auto-discovers the virtual servers for this server.
- returned: queried
- type: str
- addresses:
- description:
- - Specifies the server IP addresses for the server.
- returned: queried
- type: complex
- devices:
- description:
- - Specifies the names of the devices that represent this server.
- returned: queried
- type: complex
- virtual_servers:
- description:
- - Virtual servers that are resources for this server.
- returned: queried
- type: complex
- sample: hash/dictionary of values
-gtm_wide_ips:
- description:
- - GTM Wide IP related information.
- - Every "type" of wide-ip has the exact same list of possible information. Therefore,
- the list of information here is presented once instead of 6 times.
- returned: When any of C(gtm-wide-ips) or C(gtm-*-wide-ips) is specified in C(gather_subset).
- type: complex
- contains:
- full_path:
- description:
- - Full name of the resource as known to BIG-IP.
- returned: queried
- type: str
- sample: /Common/wide1
- name:
- description:
- - Relative name of the resource in BIG-IP.
- returned: queried
- type: str
- sample: wide1
- description:
- description:
- - Description of the wide ip.
- returned: queried
- type: str
- enabled:
- description:
- - Whether the Wide IP is enabled.
- returned: queried
- type: bool
- disabled:
- description:
- - Whether the Wide IP is disabled.
- returned: queried
- type: bool
- failure_rcode:
- description:
- - Specifies the DNS RCODE used when C(failure_rcode_response) is C(yes).
- returned: queried
- type: int
- failure_rcode_response:
- description:
- - When C(yes), specifies that the system returns a RCODE response to
- Wide IP requests after exhausting all load-balancing methods.
- returned: queried
- type: bool
- failure_rcode_ttl:
- description:
- - Specifies the negative caching TTL of the SOA for the RCODE response.
- returned: queried
- type: int
- last_resort_pool:
- description:
- - Specifies which pool, as listed in Pool List, for the system to use as
- the last resort pool for the wide IP.
- returned: queried
- type: str
- minimal_response:
- description:
- - Specifies that the system forms the smallest allowable DNS response to
- a query.
- returned: queried
- type: str
- persist_cidr_ipv4:
- description:
- - Specifies the number of bits the system uses to identify IPv4 addresses
- when persistence is enabled.
- returned: queried
- type: int
- persist_cidr_ipv6:
- description:
- - Specifies the number of bits the system uses to identify IPv6 addresses
- when persistence is enabled.
- returned: queried
- type: int
- pool_lb_mode:
- description:
- - Specifies the load balancing method used to select a pool in this wide IP.
- returned: queried
- type: str
- ttl_persistence:
- description:
- - Specifies, in seconds, the length of time for which the persistence
- entry is valid.
- returned: queried
- type: int
- pools:
- description:
- - Specifies the pools that this wide IP uses for load balancing.
- returned: queried
- type: complex
- sample: hash/dictionary of values
-http_monitors:
- description: HTTP monitor related information.
- returned: When C(http-monitors) is specified in C(gather_subset).
- type: complex
- contains:
- full_path:
- description:
- - Full name of the resource as known to BIG-IP.
- returned: queried
- type: str
- sample: /Common/http
- name:
- description:
- - Relative name of the resource in BIG-IP.
- returned: queried
- type: str
- sample: http
- parent:
- description:
- - Profile from which this profile inherits settings.
- returned: queried
- type: str
- sample: http
- description:
- description:
- - Description of the resource.
- returned: queried
- type: str
- sample: My monitor
- adaptive:
- description:
- - Whether adaptive response time monitoring is enabled for this monitor.
- returned: queried
- type: bool
- sample: no
- adaptive_divergence_type:
- description:
- - Specifies whether the adaptive-divergence-value is C(relative) or
- C(absolute).
- returned: queried
- type: str
- sample: relative
- adaptive_divergence_value:
- description:
- - Specifies how far from mean latency each monitor probe is allowed
- to be.
- returned: queried
- type: int
- sample: 25
- adaptive_limit:
- description:
- - Specifies the hard limit, in milliseconds, which the probe is not
- allowed to exceed, regardless of the divergence value.
- returned: queried
- type: int
- sample: 200
- adaptive_sampling_timespan:
- description:
- - Specifies the size of the sliding window, in seconds, which
- records probe history.
- returned: queried
- type: int
- sample: 300
- destination:
- description:
- - Specifies the IP address and service port of the resource that is
- the destination of this monitor.
- returned: queried
- type: str
- sample: "*:*"
- interval:
- description:
- - Specifies, in seconds, the frequency at which the system issues
- the monitor check when either the resource is down or the status
- of the resource is unknown.
- returned: queried
- type: int
- sample: 5
- ip_dscp:
- description:
- - Specifies the differentiated services code point (DSCP).
- returned: queried
- type: int
- sample: 0
- manual_resume:
- description:
- - Specifies whether the system automatically changes the status of a
- resource to up at the next successful monitor check.
- returned: queried
- type: bool
- sample: yes
- receive_string:
- description:
- - Specifies the text string that the monitor looks for in the
- returned resource.
- returned: queried
- type: str
- sample: check string
- receive_disable_string:
- description:
- - Specifies a text string that the monitor looks for in the returned
- resource. If the text string is matched in the returned resource,
- the corresponding node or pool member is marked session disabled.
- returned: queried
- type: str
- sample: check disable string
- reverse:
- description:
- - Specifies whether the monitor operates in reverse mode. When the
- monitor is in reverse mode, a successful check marks the monitored
- object down instead of up.
- returned: queried
- type: bool
- sample: no
- send_string:
- description:
- - Specifies the text string that the monitor sends to the target
- object.
- returned: queried
- type: str
- sample: "GET /\\r\\n"
- time_until_up:
- description:
- - Specifies the amount of time, in seconds, after the first
- successful response before a node is marked up.
- returned: queried
- type: int
- sample: 0
- timeout:
- description:
- - Specifies the number of seconds the target has in which to respond
- to the monitor request.
- returned: queried
- type: int
- sample: 16
- transparent:
- description:
- - Specifies whether the monitor operates in transparent mode.
- returned: queried
- type: bool
- sample: no
- up_interval:
- description:
- - Specifies, in seconds, the frequency at which the system issues
- the monitor check when the resource is up.
- returned: queried
- type: int
- sample: 0
- username:
- description:
- - Specifies the username, if the monitored target requires
- authentication.
- returned: queried
- type: str
- sample: user1
- sample: hash/dictionary of values
-https_monitors:
- description: HTTPS monitor related information.
- returned: When C(https-monitors) is specified in C(gather_subset).
- type: complex
- contains:
- full_path:
- description:
- - Full name of the resource as known to BIG-IP.
- returned: queried
- type: str
- sample: /Common/http
- name:
- description:
- - Relative name of the resource in BIG-IP.
- returned: queried
- type: str
- sample: http
- parent:
- description:
- - Profile from which this profile inherits settings.
- returned: queried
- type: str
- sample: http
- description:
- description:
- - Description of the resource.
- returned: queried
- type: str
- sample: My monitor
- adaptive:
- description:
- - Whether adaptive response time monitoring is enabled for this monitor.
- returned: queried
- type: bool
- sample: no
- adaptive_divergence_type:
- description:
- - Specifies whether the adaptive-divergence-value is C(relative) or
- C(absolute).
- returned: queried
- type: str
- sample: relative
- adaptive_divergence_value:
- description:
- - Specifies how far from mean latency each monitor probe is allowed
- to be.
- returned: queried
- type: int
- sample: 25
- adaptive_limit:
- description:
- - Specifies the hard limit, in milliseconds, which the probe is not
- allowed to exceed, regardless of the divergence value.
- returned: queried
- type: int
- sample: 200
- adaptive_sampling_timespan:
- description:
- - Specifies the size of the sliding window, in seconds, which
- records probe history.
- returned: queried
- type: int
- sample: 300
- destination:
- description:
- - Specifies the IP address and service port of the resource that is
- the destination of this monitor.
- returned: queried
- type: str
- sample: "*:*"
- interval:
- description:
- - Specifies, in seconds, the frequency at which the system issues
- the monitor check when either the resource is down or the status
- of the resource is unknown.
- returned: queried
- type: int
- sample: 5
- ip_dscp:
- description:
- - Specifies the differentiated services code point (DSCP).
- returned: queried
- type: int
- sample: 0
- manual_resume:
- description:
- - Specifies whether the system automatically changes the status of a
- resource to up at the next successful monitor check.
- returned: queried
- type: bool
- sample: yes
- receive_string:
- description:
- - Specifies the text string that the monitor looks for in the
- returned resource.
- returned: queried
- type: str
- sample: check string
- receive_disable_string:
- description:
- - Specifies a text string that the monitor looks for in the returned
- resource. If the text string is matched in the returned resource,
- the corresponding node or pool member is marked session disabled.
- returned: queried
- type: str
- sample: check disable string
- reverse:
- description:
- - Specifies whether the monitor operates in reverse mode. When the
- monitor is in reverse mode, a successful check marks the monitored
- object down instead of up.
- returned: queried
- type: bool
- sample: no
- send_string:
- description:
- - Specifies the text string that the monitor sends to the target
- object.
- returned: queried
- type: str
- sample: "GET /\\r\\n"
- ssl_profile:
- description:
- - Specifies the SSL profile to use for the HTTPS monitor.
- returned: queried
- type: str
- sample: /Common/serverssl
- time_until_up:
- description:
- - Specifies the amount of time, in seconds, after the first
- successful response before a node is marked up.
- returned: queried
- type: int
- sample: 0
- timeout:
- description:
- - Specifies the number of seconds the target has in which to respond
- to the monitor request.
- returned: queried
- type: int
- sample: 16
- transparent:
- description:
- - Specifies whether the monitor operates in transparent mode.
- returned: queried
- type: bool
- sample: no
- up_interval:
- description:
- - Specifies, in seconds, the frequency at which the system issues
- the monitor check when the resource is up.
- returned: queried
- type: int
- sample: 0
- username:
- description:
- - Specifies the username, if the monitored target requires
- authentication.
- returned: queried
- type: str
- sample: user1
- sample: hash/dictionary of values
-http_profiles:
- description: HTTP profile related information.
- returned: When C(http-profiles) is specified in C(gather_subset).
- type: complex
- contains:
- full_path:
- description:
- - Full name of the resource as known to BIG-IP.
- returned: queried
- type: str
- sample: /Common/http
- name:
- description:
- - Relative name of the resource in BIG-IP.
- returned: queried
- type: str
- sample: http
- parent:
- description:
- - Profile from which this profile inherits settings.
- returned: queried
- type: str
- sample: http
- description:
- description:
- - Description of the resource.
- returned: queried
- type: str
- sample: My profile
- accept_xff:
- description:
- - Enables or disables trusting the client IP address, and statistics
- from the client IP address, based on the request's X-Forwarded-For
- (XFF) headers, if they exist.
- returned: queried
- type: bool
- sample: yes
- allow_truncated_redirects:
- description:
- - Specifies the pass-through behavior when a redirect lacking the
- trailing carriage-return and line feed pair at the end of the headers
- is parsed.
- - When C(no), will silently drop the invalid HTTP.
- returned: queried
- type: bool
- sample: no
- excess_client_headers:
- description:
- - Specifies the pass-through behavior when C(max_header_count) value is
- exceeded by the client.
- - When C(reject), rejects the connection.
- returned: queried
- type: str
- sample: reject
- excess_server_headers:
- description:
- - Specifies the pass-through behavior when C(max_header_count) value is
- exceeded by the server.
- - When C(reject), rejects the connection.
- returned: queried
- type: str
- sample: reject
- known_methods:
- description:
- - Optimizes the behavior of a known HTTP method in the list.
- - The default methods include the following HTTP/1.1 methods. CONNECT,
- DELETE, GET, HEAD, LOCK, OPTIONS, POST, PROPFIND, PUT, TRACE, UNLOCK.
- - If a known method is deleted from the C(known_methods) list, the
- BIG-IP system applies the C(unknown_method) setting to manage that traffic.
- returned: queried
- type: list
- sample: ['CONNECT', 'DELETE', ...]
- max_header_count:
- description:
- - Specifies the maximum number of headers the system supports.
- returned: queried
- type: int
- sample: 64
- max_header_size:
- description:
- - Specifies the maximum size in bytes the system allows for all HTTP
- request headers combined, including the request line.
- returned: queried
- type: int
- sample: 32768
- max_requests:
- description:
- - Specifies the number of requests that the system accepts on a per-connection
- basis.
- returned: queried
- type: int
- sample: 0
- oversize_client_headers:
- description:
- - Specifies the pass-through behavior when the C(max_header_size) value
- is exceeded by the client.
- returned: queried
- type: str
- sample: reject
- oversize_server_headers:
- description:
- - Specifies the pass-through behavior when the C(max_header_size) value
- is exceeded by the server.
- returned: queried
- type: str
- sample: reject
- pipeline_action:
- description:
- - Enables or disables HTTP/1.1 pipelining.
- returned: queried
- type: str
- sample: allow
- unknown_method:
- description:
- - Specifies the behavior (allow, reject, or pass through) when an unknown
- HTTP method is parsed.
- returned: queried
- type: str
- sample: allow
- default_connect_handling:
- description:
- - Specifies the behavior of the proxy service when handling outbound requests.
- returned: queried
- type: str
- sample: deny
- hsts_include_subdomains:
- description:
- - When C(yes), applies the HSTS policy to the HSTS host and its subdomains.
- returned: queried
- type: bool
- sample: yes
- hsts_enabled:
- description:
- - When C(yes), enables the HTTP Strict Transport Security settings.
- returned: queried
- type: bool
- sample: yes
- insert_x_forwarded_for:
- description:
- - When C(yes), specifies that the system inserts an X-Forwarded-For header in
- an HTTP request with the client IP address, to use with connection pooling.
- returned: queried
- type: bool
- sample: no
- lws_max_columns:
- description:
- - Specifies the maximum column width for any given line, when inserting an HTTP
- header in an HTTP request.
- returned: queried
- type: int
- sample: 80
- onconnect_transformations:
- description:
- - When C(yes), specifies, that the system performs HTTP header transformations
- for the purpose of keeping connections open.
- returned: queried
- type: bool
- sample: yes
- proxy_mode:
- description:
- - Specifies the proxy mode for this profile. Either reverse, explicit, or transparent.
- returned: queried
- type: str
- sample: reverse
- redirect_rewrite:
- description:
- - Specifies whether the system rewrites the URIs that are part of HTTP
- redirect (3XX) responses
- returned: queried
- type: str
- sample: none
- request_chunking:
- description:
- - Specifies how the system handles HTTP content that is chunked by a client.
- returned: queried
- type: str
- sample: preserve
- response_chunking:
- description:
- - Specifies how the system handles HTTP content that is chunked by a server.
- returned: queried
- type: str
- sample: selective
- server_agent_name:
- description:
- - Specifies the string used as the server name in traffic generated by LTM.
- returned: queried
- type: str
- sample: BigIP
- sflow_poll_interval:
- description:
- - The maximum interval in seconds between two pollings.
- returned: queried
- type: int
- sample: 0
- sflow_sampling_rate:
- description:
- - Specifies the ratio of packets observed to the samples generated.
- returned: queried
- type: int
- sample: 0
- via_request:
- description:
- - Specifies whether to Remove, Preserve, or Append Via headers included in
- a client request to an origin web server.
- returned: queried
- type: str
- sample: preserve
- via_response:
- description:
- - Specifies whether to Remove, Preserve, or Append Via headers included in
- an origin web server response to a client.
- returned: queried
- type: str
- sample: preserve
- sample: hash/dictionary of values
-iapp_services:
- description: iApp v1 service related information.
- returned: When C(iapp-services) is specified in C(gather_subset).
- type: complex
- contains:
- full_path:
- description:
- - Full name of the resource as known to BIG-IP.
- returned: queried
- type: str
- sample: /Common/service1
- name:
- description:
- - Relative name of the resource in BIG-IP.
- returned: queried
- type: str
- sample: service1
- device_group:
- description:
- - The device group the iApp service is part of.
- returned: queried
- type: str
- sample: /Common/dg1
- inherited_device_group:
- description:
- - Whether the device group is inherited or not.
- returned: queried
- type: bool
- sample: yes
- inherited_traffic_group:
- description:
- - Whether the traffic group is inherited or not.
- returned: queried
- type: bool
- sample: yes
- strict_updates:
- description:
- - Whether strict updates are enabled or not.
- returned: queried
- type: bool
- sample: yes
- template_modified:
- description:
- - Whether template that the service is based on is modified from its
- default value, or not.
- returned: queried
- type: bool
- sample: yes
- traffic_group:
- description:
- - Traffic group the service is a part of.
- returned: queried
- type: str
- sample: /Common/tg
- tables:
- description:
- - List of the tabular data used to create the service.
- returned: queried
- type: complex
- sample: [{"name": "basic__snatpool_members"},...]
- variables:
- description:
- - List of the variable data used to create the service.
- returned: queried
- type: complex
- sample: [{"name": "afm__policy"},{"encrypted": "no"},{"value": "/#no_not_use#"},...]
- metadata:
- description:
- - List of the metadata data used to create the service..
- returned: queried
- type: complex
- sample: [{"name": "var1"},{"persist": "true"},...]
- lists:
- description:
- - List of the lists data used to create the service.
- returned: queried
- type: complex
- sample: [{"name": "irules__irules"},{"value": []},...]
- description:
- description:
- - Description of the service
- returned: queried
- type: str
- sample: My service
- sample: hash/dictionary of values
-icmp_monitors:
- description: ICMP monitor related information.
- returned: When C(icmp-monitors) is specified in C(gather_subset).
- type: complex
- contains:
- full_path:
- description:
- - Full name of the resource as known to BIG-IP.
- returned: queried
- type: str
- sample: /Common/icmp
- name:
- description:
- - Relative name of the resource in BIG-IP.
- returned: queried
- type: str
- sample: icmp
- parent:
- description:
- - Profile from which this profile inherits settings.
- returned: queried
- type: str
- sample: icmp
- description:
- description:
- - Description of the resource.
- returned: queried
- type: str
- sample: My monitor
- adaptive:
- description:
- - Whether adaptive response time monitoring is enabled for this monitor.
- returned: queried
- type: bool
- sample: no
- adaptive_divergence_type:
- description:
- - Specifies whether the adaptive-divergence-value is C(relative) or
- C(absolute).
- returned: queried
- type: str
- sample: relative
- adaptive_divergence_value:
- description:
- - Specifies how far from mean latency each monitor probe is allowed
- to be.
- returned: queried
- type: int
- sample: 25
- adaptive_limit:
- description:
- - Specifies the hard limit, in milliseconds, which the probe is not
- allowed to exceed, regardless of the divergence value.
- returned: queried
- type: int
- sample: 200
- adaptive_sampling_timespan:
- description:
- - Specifies the size of the sliding window, in seconds, which
- records probe history.
- returned: queried
- type: int
- sample: 300
- destination:
- description:
- - Specifies the IP address and service port of the resource that is
- the destination of this monitor.
- returned: queried
- type: str
- sample: "*:*"
- interval:
- description:
- - Specifies, in seconds, the frequency at which the system issues
- the monitor check when either the resource is down or the status
- of the resource is unknown.
- returned: queried
- type: int
- sample: 5
- manual_resume:
- description:
- - Specifies whether the system automatically changes the status of a
- resource to up at the next successful monitor check.
- type: bool
- sample: yes
- time_until_up:
- description:
- - Specifies the amount of time, in seconds, after the first
- successful response before a node is marked up.
- returned: queried
- type: int
- sample: 0
- timeout:
- description:
- - Specifies the number of seconds the target has in which to respond
- to the monitor request.
- returned: queried
- type: int
- sample: 16
- transparent:
- description:
- - Specifies whether the monitor operates in transparent mode.
- returned: queried
- type: bool
- sample: no
- up_interval:
- description:
- - Specifies, in seconds, the frequency at which the system issues
- the monitor check when the resource is up.
- returned: queried
- type: int
- sample: 0
- sample: hash/dictionary of values
-interfaces:
- description: Interface related information.
- returned: When C(interfaces) is specified in C(gather_subset).
- type: complex
- contains:
- full_path:
- description:
- - Full name of the resource as known to BIG-IP.
- returned: queried
- type: str
- sample: /Common/interface1
- name:
- description:
- - Relative name of the resource in BIG-IP.
- returned: queried
- type: str
- sample: interface1
- active_media_type:
- description:
- - Displays the current media setting for the interface.
- returned: queried
- type: str
- sample: 100TX-FD
- flow_control:
- description:
- - Specifies how the system controls the sending of PAUSE frames for
- flow control.
- returned: queried
- type: str
- sample: tx-rx
- description:
- description:
- - Description of the interface
- returned: queried
- type: str
- sample: My interface
- bundle:
- description:
- - The bundle capability on the port.
- returned: queried
- type: str
- sample: not-supported
- bundle_speed:
- description:
- - The bundle-speed on the port when bundle capability is
- enabled.
- returned: queried
- type: str
- sample: 100G
- enabled:
- description:
- - Whether the interface is enabled or not
- returned: queried
- type: bool
- sample: yes
- if_index:
- description:
- - The index assigned to this interface.
- returned: queried
- type: int
- sample: 32
- mac_address:
- description:
- - Displays the 6-byte ethernet address in non-case-sensitive
- hexadecimal colon notation.
- returned: queried
- type: str
- sample: "00:0b:09:88:00:9a"
- media_sfp:
- description:
- - The settings for an SFP (pluggable) interface.
- returned: queried
- type: str
- sample: auto
- lldp_admin:
- description:
- - Sets the sending or receiving of LLDP packets on that interface.
- Should be one of C(disable), C(txonly), C(rxonly) or C(txrx).
- returned: queried
- type: str
- sample: txonly
- mtu:
- description:
- - Displays the Maximum Transmission Unit (MTU) of the interface,
- which is the maximum number of bytes in a frame without IP
- fragmentation.
- returned: queried
- type: int
- sample: 1500
- prefer_port:
- description:
- - Indicates which side of a combo port the interface uses, if both
- sides of the port have the potential for external links.
- returned: queried
- type: str
- sample: sfp
- sflow_poll_interval:
- description:
- - Specifies the maximum interval in seconds between two
- pollings.
- returned: queried
- type: int
- sample: 0
- sflow_poll_interval_global:
- description:
- - Specifies whether the global interface poll-interval setting
- overrides the object-level poll-interval setting.
- returned: queried
- type: bool
- sample: yes
- stp_auto_edge_port:
- description:
- - STP edge port detection.
- returned: queried
- type: bool
- sample: yes
- stp_enabled:
- description:
- - Whether STP is enabled or not.
- returned: queried
- type: bool
- sample: no
- stp_link_type:
- description:
- - Specifies the STP link type for the interface.
- returned: queried
- type: str
- sample: auto
- sample: hash/dictionary of values
-irules:
- description: iRule related information.
- returned: When C(irules) is specified in C(gather_subset).
- type: complex
- contains:
- full_path:
- description:
- - Full name of the resource as known to BIG-IP.
- returned: queried
- type: str
- sample: /Common/irul1
- name:
- description:
- - Relative name of the resource in BIG-IP.
- returned: queried
- type: str
- sample: irule1
- ignore_verification:
- description:
- - Whether the verification of the iRule should be ignored or not.
- returned: queried
- type: bool
- sample: no
- checksum:
- description:
- - Checksum of the iRule as calculated by BIG-IP.
- returned: queried
- type: str
- sample: d41d8cd98f00b204e9800998ecf8427e
- definition:
- description:
- - The actual definition of the iRule.
- returned: queried
- type: str
- sample: when HTTP_REQUEST ...
- signature:
- description:
- - The calculated signature of the iRule.
- returned: queried
- type: str
- sample: WsYy2M6xMqvosIKIEH/FSsvhtWMe6xKOA6i7f...
- sample: hash/dictionary of values
-ltm_pools:
- description: List of LTM (Local Traffic Manager) pools.
- returned: When C(ltm-pools) is specified in C(gather_subset).
- type: complex
- contains:
- active_member_count:
- description:
- - The number of active pool members in the pool.
- returned: queried
- type: int
- sample: 3
- all_avg_queue_entry_age:
- description:
- - Average queue entry age, for both the pool and its members.
- returned: queried
- type: int
- sample: 5
- all_max_queue_entry_age_ever:
- description:
- - Maximum queue entry age ever, for both the pool and its members.
- returned: queried
- type: int
- sample: 2
- all_max_queue_entry_age_recently:
- description:
- - Maximum queue entry age recently, for both the pool and its members.
- returned: queried
- type: int
- sample: 5
- all_num_connections_queued_now:
- description:
- - Number of connections queued now, for both the pool and its members.
- returned: queried
- type: int
- sample: 20
- all_num_connections_serviced:
- description:
- - Number of connections serviced, for both the pool and its members.
- returned: queried
- type: int
- sample: 15
- all_queue_head_entry_age:
- description:
- - Queue head entry age, for both the pool and its members.
- returned: queried
- type: int
- sample: 4
- available_member_count:
- description:
- - The number of available pool members in the pool.
- returned: queried
- type: int
- sample: 4
- availability_status:
- description:
- - The availability of the pool.
- returned: queried
- type: str
- sample: offline
- allow_nat:
- description:
- - Whether NATs are automatically enabled or disabled for any connections using this pool.
- returned: queried
- type: bool
- sample: yes
- allow_snat:
- description:
- - Whether SNATs are automatically enabled or disabled for any connections using this pool.
- returned: queried
- type: bool
- sample: yes
- client_ip_tos:
- description:
- - Whether the system sets a Type of Service (ToS) level within a packet sent to the client,
- based on the targeted pool.
- - Values can range from C(0) to C(255), or be set to C(pass-through) or C(mimic).
- returned: queried
- type: str
- sample: pass-through
- client_link_qos:
- description:
- - Whether the system sets a Quality of Service (QoS) level within a packet sent to the client,
- based on the targeted pool.
- - Values can range from C(0) to C(7), or be set to C(pass-through).
- returned: queried
- type: str
- sample: pass-through
- current_sessions:
- description:
- - Current sessions.
- returned: queried
- type: int
- sample: 2
- description:
- description:
- - Description of the pool.
- returned: queried
- type: str
- sample: my pool
- enabled_status:
- description:
- - The enabled-ness of the pool.
- returned: queried
- type: str
- sample: enabled
- full_path:
- description:
- - Full name of the resource as known to BIG-IP.
- returned: queried
- type: str
- sample: /Common/pool1
- ignore_persisted_weight:
- description:
- - Do not count the weight of persisted connections on pool members when making load balancing decisions.
- returned: queried
- type: bool
- sample: no
- lb_method:
- description:
- - Load balancing method used by the pool.
- returned: queried
- type: str
- sample: round-robin
- member_count:
- description:
- - Total number of members in the pool.
- returned: queried
- type: int
- sample: 50
- metadata:
- description:
- - Dictionary of arbitrary key/value pairs set on the pool.
- returned: queried
- type: complex
- sample: hash/dictionary of values
- minimum_active_members:
- description:
- - Whether the system load balances traffic according to the priority number assigned to the pool member.
- - This parameter is identical to C(priority_group_activation) and is just an alias for it.
- returned: queried
- type: int
- sample: 2
- minimum_up_members:
- description:
- - The minimum number of pool members that must be up.
- returned: queried
- type: int
- sample: 1
- minimum_up_members_action:
- description:
- - The action to take if the C(minimum_up_members_checking) is enabled and the number of active pool
- members falls below the number specified in C(minimum_up_members).
- returned: queried
- type: str
- sample: failover
- minimum_up_members_checking:
- description:
- - Enables or disables the C(minimum_up_members) feature.
- returned: queried
- type: bool
- sample: no
- name:
- description:
- - Relative name of the resource in BIG-IP.
- returned: queried
- type: str
- sample: pool1
- pool_avg_queue_entry_age:
- description:
- - Average queue entry age, for the pool only.
- returned: queried
- type: int
- sample: 5
- pool_max_queue_entry_age_ever:
- description:
- - Maximum queue entry age ever, for the pool only.
- returned: queried
- type: int
- sample: 2
- pool_max_queue_entry_age_recently:
- description:
- - Maximum queue entry age recently, for the pool only.
- returned: queried
- type: int
- sample: 5
- pool_num_connections_queued_now:
- description:
- - Number of connections queued now, for the pool only.
- returned: queried
- type: int
- sample: 20
- pool_num_connections_serviced:
- description:
- - Number of connections serviced, for the pool only.
- returned: queried
- type: int
- sample: 15
- pool_queue_head_entry_age:
- description:
- - Queue head entry age, for the pool only.
- returned: queried
- type: int
- sample: 4
- priority_group_activation:
- description:
- - Whether the system load balances traffic according to the priority number assigned to the pool member.
- - This parameter is identical to C(minimum_active_members) and is just an alias for it.
- returned: queried
- type: int
- sample: 2
- queue_depth_limit:
- description:
- - The maximum number of connections that may simultaneously be queued to go to any member of this pool.
- returned: queried
- type: int
- sample: 3
- queue_on_connection_limit:
- description:
- - Enable or disable queuing connections when pool member or node connection limits are reached.
- returned: queried
- type: bool
- sample: yes
- queue_time_limit:
- description:
- - Specifies the maximum time, in milliseconds, a connection will remain enqueued.
- returned: queried
- type: int
- sample: 0
- real_session:
- description:
- - The actual REST API value for the C(session) attribute.
- - This is different from the C(state) return value, insofar as the return value
- can be considered a generalization of all available sessions, instead of the
- specific value of the session.
- returned: queried
- type: str
- sample: monitor-enabled
- real_state:
- description:
- - The actual REST API value for the C(state) attribute.
- - This is different from the C(state) return value, insofar as the return value
- can be considered a generalization of all available states, instead of the
- specific value of the state.
- returned: queried
- type: str
- sample: up
- reselect_tries:
- description:
- - The number of times the system tries to contact a pool member after a passive failure.
- returned: queried
- type: int
- sample: 0
- server_ip_tos:
- description:
- - The Type of Service (ToS) level to use when sending packets to a server.
- returned: queried
- type: str
- sample: pass-through
- server_link_qos:
- description:
- - The Quality of Service (QoS) level to use when sending packets to a server.
- returned: queried
- type: str
- sample: pass-through
- service_down_action:
- description:
- - The action to take if the service specified in the pool is marked down.
- returned: queried
- type: str
- sample: none
- server_side_bits_in:
- description:
- - Number of server-side ingress bits.
- returned: queried
- type: int
- sample: 1000
- server_side_bits_out:
- description:
- - Number of server-side egress bits.
- returned: queried
- type: int
- sample: 200
- server_side_current_connections:
- description:
- - Number of current connections server-side.
- returned: queried
- type: int
- sample: 300
- server_side_max_connections:
- description:
- - Maximum number of connections server-side.
- returned: queried
- type: int
- sample: 40
- server_side_pkts_in:
- description:
- - Number of server-side ingress packets.
- returned: queried
- type: int
- sample: 1098384
- server_side_pkts_out:
- description:
- - Number of server-side egress packets.
- returned: queried
- type: int
- sample: 3484734
- server_side_total_connections:
- description:
- - Total number of connections.
- returned: queried
- type: int
- sample: 24
- slow_ramp_time:
- description:
- - The ramp time for the pool.
- - This provides the ability to cause a pool member that has just been enabled,
- or marked up, to receive proportionally less traffic than other members in the pool.
- returned: queried
- type: int
- sample: 10
- status_reason:
- description:
- - If there is a problem with the status of the pool, that problem is reported here.
- returned: queried
- type: str
- sample: The children pool member(s) are down.
- members:
- description: List of LTM (Local Traffic Manager) pools.
- returned: when members exist in the pool.
- type: complex
- contains:
- address:
- description: IP address of the pool member.
- returned: queried
- type: str
- sample: 1.1.1.1
- connection_limit:
- description: The maximum number of concurrent connections allowed for a pool member.
- returned: queried
- type: int
- sample: 0
- description:
- description: The description of the pool member.
- returned: queried
- type: str
- sample: pool member 1
- dynamic_ratio:
- description:
- - A range of numbers that you want the system to use in conjunction with the ratio load balancing method.
- returned: queried
- type: int
- sample: 1
- ephemeral:
- description:
- - Whether the node backing the pool member is ephemeral or not.
- returned: queried
- type: bool
- sample: yes
- fqdn_autopopulate:
- description:
- - Whether the node should scale to the IP address set returned by DNS.
- returned: queried
- type: bool
- sample: yes
- full_path:
- description:
- - Full name of the resource as known to BIG-IP.
- - Includes the port in the name
- returned: queried
- type: str
- sample: "/Common/member:80"
- inherit_profile:
- description:
- - Whether the pool member inherits the encapsulation profile from the parent pool.
- returned: queried
- type: bool
- sample: no
- logging:
- description:
- - Whether the monitor applied should log its actions.
- returned: queried
- type: bool
- sample: no
- monitors:
- description:
- - Monitors active on the pool member. Monitor names are in their "full_path" form.
- returned: queried
- type: list
- sample: ['/Common/http']
- name:
- description:
- - Relative name of the resource in BIG-IP.
- returned: queried
- type: str
- sample: "member:80"
- partition:
- description:
- - Partition that the member exists on.
- returned: queried
- type: str
- sample: Common
- priority_group:
- description:
- - The priority group within the pool for this pool member.
- returned: queried
- type: int
- sample: 0
- encapsulation_profile:
- description:
- - The encapsulation profile to use for the pool member.
- returned: queried
- type: str
- sample: ip4ip4
- rate_limit:
- description:
- - The maximum number of connections per second allowed for a pool member.
- returned: queried
- type: bool
- sample: no
- ratio:
- description:
- - The weight of the pool for load balancing purposes.
- returned: queried
- type: int
- sample: 1
- session:
- description:
- - Enables or disables the pool member for new sessions.
- returned: queried
- type: str
- sample: monitor-enabled
- state:
- description:
- - Controls the state of the pool member, overriding any monitors.
- returned: queried
- type: str
- sample: down
- total_requests:
- description:
- - Total requests.
- returned: queried
- type: int
- sample: 8
- sample: hash/dictionary of values
-ltm_policies:
- description: List of LTM (Local Traffic Manager) policies.
- returned: When C(ltm-policies) is specified in C(gather_subset).
- type: complex
- contains:
- name:
- description:
- - Relative name of the resource in BIG-IP.
- returned: queried
- type: str
- sample: policy1
- full_path:
- description:
- - Full name of the resource as known to BIG-IP.
- returned: queried
- type: str
- sample: /Common/policy1
- description:
- description:
- - Description of the policy.
- returned: queried
- type: str
- sample: My policy
- strategy:
- description:
- - The match strategy for the policy.
- returned: queried
- type: str
- sample: /Common/first-match
- requires:
- description:
- - Aspects of the system required by this policy.
- returned: queried
- type: list
- sample: ['http']
- controls:
- description:
- - Aspects of the system controlled by this policy.
- returned: queried
- type: list
- sample: ['forwarding']
- status:
- description:
- - Indicates published or draft policy status.
- returned: queried
- type: str
- sample: draft
- rules:
- description:
- - List of LTM (Local Traffic Manager) policy rules.
- returned: when rules are defined in the policy.
- type: complex
- contains:
- actions:
- description:
- - The actions the policy will take when a match is encountered.
- returned: when actions are defined in the rule.
- type: complex
- contains:
- http_reply:
- description:
- - Indicate if the action will affects a reply to a given HTTP request.
- returned: when defined in the action.
- type: bool
- sample: yes
- redirect:
- description:
- - This action will redirect a request.
- returned: when defined in the action.
- type: bool
- sample: no
- request:
- description:
- - This policy action is performed on connection requests.
- returned: when defined in the action.
- type: bool
- sample: no
- location:
- description:
- - This action will come from the given location.
- returned: when defined in the action.
- type: str
- sample: "tcl:https://[getfield [HTTP::host] \\\":\\\" 1][HTTP::uri]"
- sample: hash/dictionary of values
- conditions:
- description:
- - The conditions that a policy will match on.
- returned: when conditions are defined in the rule.
- type: complex
- contains:
- case_insensitive:
- description:
- - The value matched on is case insensitive.
- returned: when defined in the condition.
- type: bool
- sample: no
- case_sensitive:
- description:
- - The value matched on is case sensitive.
- returned: when defined in the condition.
- type: bool
- sample: yes
- contains_string:
- description:
- - The value matches if it contains a certain string.
- returned: when defined in the condition.
- type: bool
- sample: yes
- external:
- description:
- - The value matched on is from the external side of a connection.
- returned: when defined in the condition.
- type: bool
- sample: yes
- http_basic_auth:
- description:
- - This condition matches on basic HTTP authorization.
- returned: when defined in the condition.
- type: bool
- sample: no
- http_host:
- description:
- - This condition matches on an HTTP host.
- returned: when defined in the condition.
- type: bool
- sample: yes
- http_uri:
- description:
- - This condition matches on an HTTP URI.
- returned: when defined in the condition.
- type: bool
- sample: no
- request:
- description:
- - This policy will match on a request.
- returned: when defined in the condition.
- type: bool
- sample: yes
- username:
- description:
- - Matches on a username.
- returned: when defined in the condition.
- type: bool
- sample: yes
- all:
- description:
- - Matches all.
- returned: when defined in the condition.
- type: bool
- sample: yes
- values:
- description:
- - The specified values will be matched on.
- returned: when defined in the condition.
- type: list
- sample: ['foo.bar.com', 'baz.cool.com']
- sample: hash/dictionary of values
- sample: hash/dictionary of values
- sample: hash/dictionary of values
-nodes:
- description: Node related information.
- returned: When C(nodes) is specified in C(gather_subset).
- type: complex
- contains:
- full_path:
- description:
- - Full name of the resource as known to BIG-IP.
- returned: queried
- type: str
- sample: /Common/5.6.7.8
- name:
- description:
- - Relative name of the resource in BIG-IP.
- returned: queried
- type: str
- sample: 5.6.7.8
- ratio:
- description:
- - Fixed size ratio used for node during C(Ratio) load balancing.
- returned: queried
- type: int
- sample: 10
- description:
- description:
- - Description of the node.
- returned: queried
- type: str
- sample: My node
- connection_limit:
- description:
- - Maximum number of connections that node can handle.
- returned: queried
- type: int
- sample: 100
- address:
- description:
- - IP address of the node.
- returned: queried
- type: str
- sample: 2.3.4.5
- dynamic_ratio:
- description:
- - Dynamic ratio number for the node used when doing C(Dynamic Ratio) load balancing.
- returned: queried
- type: int
- sample: 200
- rate_limit:
- description:
- - Maximum number of connections per second allowed for node.
- returned: queried
- type: int
- sample: 1000
- monitor_status:
- description:
- - Status of the node as reported by the monitor(s) associated with it.
- - This value is also used in determining node C(state).
- returned: queried
- type: str
- sample: down
- session_status:
- description:
- - This value is also used in determining node C(state).
- returned: queried
- type: str
- sample: enabled
- availability_status:
- description:
- - The availability of the node.
- returned: queried
- type: str
- sample: offline
- enabled_status:
- description:
- - The enabled-ness of the node.
- returned: queried
- type: str
- sample: enabled
- status_reason:
- description:
- - If there is a problem with the status of the node, that problem is reported here.
- returned: queried
- type: str
- sample: /Common/https_443 No successful responses received...
- monitor_rule:
- description:
- - A string representation of the full monitor rule.
- returned: queried
- type: str
- sample: /Common/https_443 and /Common/icmp
- monitors:
- description:
- - A list of the monitors identified in the C(monitor_rule).
- returned: queried
- type: list
- sample: ['/Common/https_443', '/Common/icmp']
- monitor_type:
- description:
- - The C(monitor_type) field related to the C(bigip_node) module, for this nodes
- monitors.
- returned: queried
- type: str
- sample: and_list
- sample: hash/dictionary of values
-oneconnect_profiles:
- description: OneConnect profile related information.
- returned: When C(oneconnect-profiles) is specified in C(gather_subset).
- type: complex
- contains:
- full_path:
- description:
- - Full name of the resource as known to BIG-IP.
- returned: queried
- type: str
- sample: /Common/oneconnect
- name:
- description:
- - Relative name of the resource in BIG-IP.
- returned: queried
- type: str
- sample: oneconnect
- parent:
- description:
- - Profile from which this profile inherits settings.
- returned: queried
- type: str
- sample: oneconnect
- description:
- description:
- - Description of the resource.
- returned: queried
- type: str
- sample: My profile
- idle_timeout_override:
- description:
- - Specifies the number of seconds that a connection is idle before
- the connection flow is eligible for deletion.
- returned: queried
- type: int
- sample: 1000
- limit_type:
- description:
- - When C(none), simultaneous in-flight requests and responses over TCP
- connections to a pool member are counted toward the limit.
- - When C(idle), idle connections will be dropped as the TCP connection
- limit is reached.
- - When C(strict), the TCP connection limit is honored with no
- exceptions. This means that idle connections will prevent new TCP
- connections from being made until they expire, even if they could
- otherwise be reused.
- returned: queried
- type: str
- sample: idle
- max_age:
- description:
- - Specifies the maximum age, in number of seconds, of a connection
- in the connection reuse pool.
- returned: queried
- type: int
- sample: 100
- max_reuse:
- description:
- - Specifies the maximum number of times that a server connection can
- be reused.
- returned: queried
- type: int
- sample: 1000
- max_size:
- description:
- - Specifies the maximum number of connections that the system holds
- in the connection reuse pool.
- - If the pool is already full, then the server connection closes after
- the response is completed.
- returned: queried
- type: int
- sample: 1000
- share_pools:
- description:
- - Indicates that connections may be shared not only within a virtual
- server, but also among similar virtual servers.
- returned: queried
- type: bool
- sample: yes
- source_mask:
- description:
- - Specifies a source IP mask.
- - If no mask is provided, the value C(any6) is used.
- returned: queried
- type: str
- sample: 255.255.255.0
- sample: hash/dictionary of values
-partitions:
- description: Partition related information.
- returned: When C(partitions) is specified in C(gather_subset).
- type: complex
- contains:
- full_path:
- description:
- - Full name of the resource as known to BIG-IP.
- returned: queried
- type: str
- sample: Common
- name:
- description:
- - Relative name of the resource in BIG-IP.
- returned: queried
- type: str
- sample: Common
- description:
- description:
- - Description of the partition.
- returned: queried
- type: str
- sample: Tenant 1
- default_route_domain:
- description:
- - ID of the route domain that is associated with the IP addresses that reside
- in the partition.
- returned: queried
- type: int
- sample: 0
- sample: hash/dictionary of values
-provision_info:
- description: Module provisioning related information.
- returned: When C(provision-info) is specified in C(gather_subset).
- type: complex
- contains:
- full_path:
- description:
- - Full name of the resource as known to BIG-IP.
- returned: queried
- type: str
- sample: asm
- name:
- description:
- - Relative name of the resource in BIG-IP.
- returned: queried
- type: str
- sample: asm
- cpu_ratio:
- description:
- - Ratio of CPU allocated to this module.
- - Only relevant if C(level) was specified as C(custom). Otherwise, this value
- will be reported as C(0).
- returned: queried
- type: int
- sample: 0
- disk_ratio:
- description:
- - Ratio of disk allocated to this module.
- - Only relevant if C(level) was specified as C(custom). Otherwise, this value
- will be reported as C(0).
- returned: queried
- type: int
- sample: 0
- memory_ratio:
- description:
- - Ratio of memory allocated to this module.
- - Only relevant if C(level) was specified as C(custom). Otherwise, this value
- will be reported as C(0).
- returned: queried
- type: int
- sample: 0
- level:
- description:
- - Provisioned level of the module on BIG-IP.
- - Valid return values can include C(none), C(minimum), C(nominal), C(dedicated)
- and C(custom).
- returned: queried
- type: int
- sample: 0
- sample: hash/dictionary of values
-self_ips:
- description: Self-IP related information.
- returned: When C(self-ips) is specified in C(gather_subset).
- type: complex
- contains:
- full_path:
- description:
- - Full name of the resource as known to BIG-IP.
- returned: queried
- type: str
- sample: /Common/self1
- name:
- description:
- - Relative name of the resource in BIG-IP.
- returned: queried
- type: str
- sample: self1
- description:
- description:
- - Description of the Self-IP.
- returned: queried
- type: str
- sample: My self-ip
- netmask:
- description:
- - Netmask portion of the IP address. In dotted notation.
- returned: queried
- type: str
- sample: 255.255.255.0
- netmask_cidr:
- description:
- - Netmask portion of the IP address. In CIDR notation.
- returned: queried
- type: int
- sample: 24
- floating:
- description:
- - Whether the Self-IP is a floating address or not.
- returned: queried
- type: bool
- sample: yes
- traffic_group:
- description:
- - Traffic group the Self-IP is associated with.
- returned: queried
- type: str
- sample: /Common/traffic-group-local-only
- service_policy:
- description:
- - Service policy assigned to the Self-IP.
- returned: queried
- type: str
- sample: /Common/service1
- vlan:
- description:
- - VLAN associated with the Self-IP.
- returned: queried
- type: str
- sample: /Common/vlan1
- allow_access_list:
- description:
- - List of protocols and optionally their ports that are allowed to access the
- Self-IP. Also known as port-lockdown in the web interface.
- - Items in the list are in the format of "protocol:port". Some items may not
- have a port associated with them and in those cases the port is C(0).
- returned: queried
- type: list
- sample: ['tcp:80', 'egp:0']
- traffic_group_inherited:
- description:
- - Whether or not the traffic group is inherited.
- returned: queried
- type: bool
- sample: no
- sample: hash/dictionary of values
-server_ssl_profiles:
- description: Server SSL related information.
- returned: When C(server-ssl-profiles) is specified in C(gather_subset).
- type: complex
- contains:
- full_path:
- description:
- - Full name of the resource as known to BIG-IP.
- returned: queried
- type: str
- sample: serverssl
- name:
- description:
- - Relative name of the resource in BIG-IP.
- returned: queried
- type: str
- sample: serverssl
- description:
- description:
- - Description of the resource.
- returned: queried
- type: str
- sample: My profile
- parent:
- description:
- - Profile from which this profile inherits settings.
- returned: queried
- type: str
- sample: serverssl
- alert_timeout:
- description:
- - Maximum time period in seconds to keep the SSL
- session active after alert message is sent, or indefinite.
- returned: queried
- type: str
- sample: 100
- allow_expired_crl:
- description:
- - Use the specified CRL file even if it has expired.
- returned: queried
- type: bool
- sample: yes
- authentication_frequency:
- description:
- - Specifies the frequency of authentication.
- returned: queried
- type: str
- sample: once
- authenticate_depth:
- description:
- - The client certificate chain maximum traversal depth
- returned: queried
- type: int
- sample: 9
- authenticate_name:
- description:
- - Common Name (CN) that is embedded in a server certificate.
- - The system authenticates a server based on the specified CN.
- returned: queried
- type: str
- sample: foo
- bypass_on_client_cert_fail:
- description:
- - Enables or disables SSL forward proxy bypass on failing to get
- client certificate that server asks for.
- returned: queried
- type: bool
- sample: yes
- bypass_on_handshake_alert:
- description:
- - Enables or disables SSL forward proxy bypass on receiving
- handshake_failure, protocol_version or unsupported_extension alert
- message during the serverside SSL handshake.
- returned: queried
- type: bool
- sample: no
- c3d_ca_cert:
- description:
- - Name of the certificate file that is used as the
- certification authority certificate when SSL client certificate
- constrained delegation is enabled.
- returned: queried
- type: str
- sample: /Common/cacert.crt
- c3d_ca_key:
- description:
- - Name of the key file that is used as the
- certification authority key when SSL client certificate
- constrained delegation is enabled.
- returned: queried
- type: str
- sample: /Common/default.key
- c3d_cert_extension_includes:
- description:
- - Extensions of the client certificates to be included
- in the generated certificates using SSL client certificate
- constrained delegation.
- returned: queried
- type: list
- sample: [ "basic-constraints", "extended-key-usage", ... ]
- c3d_cert_lifespan:
- description:
- - Lifespan of the certificate generated using the SSL
- client certificate constrained delegation.
- returned: queried
- type: int
- sample: 24
- ca_file:
- description:
- - Certificate authority file name.
- returned: queried
- type: str
- sample: default.crt
- cache_size:
- description:
- - The SSL session cache size.
- returned: queried
- type: int
- sample: 262144
- cache_timeout:
- description:
- - The SSL session cache timeout value, which is the usable
- lifetime seconds of negotiated SSL session IDs.
- returned: queried
- type: int
- sample: 86400
- cert:
- description:
- - The name of the certificate installed on the traffic
- management system for the purpose of terminating or initiating an
- SSL connection.
- returned: queried
- type: str
- sample: /Common/default.crt
- chain:
- description:
- - Specifies or builds a certificate chain file that a client can use
- to authenticate the profile.
- returned: queried
- type: str
- sample: /Common/default.crt
- cipher_group:
- description:
- - Specifies a cipher group.
- returned: queried
- type: str
- ciphers:
- description:
- - Specifies a cipher name.
- returned: queried
- type: str
- sample: DEFAULT
- crl_file:
- description:
- - Specifies the certificate revocation list file name.
- returned: queried
- type: str
- expire_cert_response_control:
- description:
- - Specifies the BIGIP action when the server certificate has
- expired.
- returned: queried
- type: str
- sample: drop
- handshake_timeout:
- description:
- - Specifies the handshake timeout in seconds.
- returned: queried
- type: str
- sample: 10
- key:
- description:
- - Specifies the key file name. Specifies the name of the key
- installed on the traffic management system for the purpose of
- terminating or initiating an SSL connection.
- returned: queried
- type: str
- sample: /Common/default.key
- max_active_handshakes:
- description:
- - Specifies the maximum number allowed SSL active handshakes.
- returned: queried
- type: str
- sample: 100
- mod_ssl_methods:
- description:
- - Enables or disables ModSSL methods.
- returned: queried
- type: bool
- sample: yes
- mode:
- description:
- - Enables or disables SSL processing.
- returned: queried
- type: bool
- sample: no
- ocsp:
- description:
- - Specifies the name of ocsp profile for purpose of validating
- status of server certificate.
- returned: queried
- type: str
- options:
- description:
- - Enables options, including some industry-related workarounds.
- returned: queried
- type: list
- sample: [ "netscape-reuse-cipher-change-bug", "dont-insert-empty-fragments" ]
- peer_cert_mode:
- description:
- - Specifies the peer certificate mode.
- returned: queried
- type: str
- sample: ignore
- proxy_ssl:
- description:
- - Allows further modification of application traffic within
- an SSL tunnel while still allowing the server to perform necessary
- authorization, authentication, auditing steps.
- returned: queried
- type: bool
- sample: yes
- proxy_ssl_passthrough:
- description:
- - Allows Proxy SSL to passthrough the traffic when ciphersuite negotiated
- between the client and server is not supported.
- returned: queried
- type: bool
- sample: yes
- renegotiate_period:
- description:
- - Number of seconds from the initial connect time
- after which the system renegotiates an SSL session.
- returned: queried
- type: str
- sample: indefinite
- renegotiate_size:
- description:
- - Specifies a throughput size, in megabytes, of SSL renegotiation.
- returned: queried
- type: str
- sample: indefinite
- renegotiation:
- description:
- - Whether renegotiations are enabled.
- returned: queried
- type: bool
- sample: yes
- retain_certificate:
- description:
- - APM module requires storing certificate in SSL session. When C(no),
- certificate will not be stored in SSL session.
- returned: queried
- type: bool
- sample: no
- generic_alert:
- description:
- - Enables or disables generic-alert.
- returned: queried
- type: bool
- sample: yes
- secure_renegotiation:
- description:
- - Specifies the secure renegotiation mode.
- returned: queried
- type: str
- sample: require
- server_name:
- description:
- - Server name to be included in SNI (server name
- indication) extension during SSL handshake in ClientHello.
- returned: queried
- type: str
- session_mirroring:
- description:
- - Enables or disables the mirroring of sessions to high availability
- peer.
- returned: queried
- type: bool
- sample: yes
- session_ticket:
- description:
- - Enables or disables session-ticket.
- returned: queried
- type: bool
- sample: no
- sni_default:
- description:
- - When C(yes), this profile is the default SSL profile when the server
- name in a client connection does not match any configured server
- names, or a client connection does not specify any server name at
- all.
- returned: queried
- type: bool
- sample: yes
- sni_require:
- description:
- - When C(yes), connections to a server that does not support SNI
- extension will be rejected.
- returned: queried
- type: bool
- sample: no
- ssl_c3d:
- description:
- - Enables or disables SSL Client certificate constrained delegation.
- returned: queried
- type: bool
- sample: yes
- ssl_forward_proxy_enabled:
- description:
- - Enables or disables ssl-forward-proxy feature.
- returned: queried
- type: bool
- sample: no
- ssl_sign_hash:
- description:
- - Specifies SSL sign hash algorithm which is used to sign and verify
- SSL Server Key Exchange and Certificate Verify messages for the
- specified SSL profiles.
- returned: queried
- type: str
- sample: sha1
- ssl_forward_proxy_bypass:
- description:
- - Enables or disables ssl-forward-proxy-bypass feature.
- returned: queried
- type: bool
- sample: yes
- strict_resume:
- description:
- - Enables or disables the resumption of SSL sessions after an
- unclean shutdown.
- returned: queried
- type: bool
- sample: no
- unclean_shutdown:
- description:
- - Specifies, when C(yes), that the SSL profile performs unclean
- shutdowns of all SSL connections, which means that underlying TCP
- connections are closed without exchanging the required SSL
- shutdown alerts.
- returned: queried
- type: bool
- sample: yes
- untrusted_cert_response_control:
- description:
- - Specifies the BIGIP action when the server certificate has
- untrusted CA.
- returned: queried
- type: str
- sample: drop
- sample: hash/dictionary of values
-software_hotfixes:
- description: List of software hotfixes.
- returned: When C(software-hotfixes) is specified in C(gather_subset).
- type: complex
- contains:
- name:
- description:
- - Name of the image.
- returned: queried
- type: str
- sample: Hotfix-BIGIP-13.0.0.3.0.1679-HF3.iso
- full_path:
- description:
- - Full name of the resource as known to BIG-IP.
- returned: queried
- type: str
- sample: Hotfix-BIGIP-13.0.0.3.0.1679-HF3.iso
- build:
- description:
- - Build number of the image.
- - This is usually a sub-string of the C(name).
- returned: queried
- type: str
- sample: 3.0.1679
- checksum:
- description:
- - MD5 checksum of the image.
- - Note that this is the checksum that is stored inside the ISO. It is not
- the actual checksum of the ISO.
- returned: queried
- type: str
- sample: df1ec715d2089d0fa54c0c4284656a98
- product:
- description:
- - Product contained in the ISO.
- returned: queried
- type: str
- sample: BIG-IP
- id:
- description:
- - ID component of the image.
- - This is usually a sub-string of the C(name).
- returned: queried
- type: str
- sample: HF3
- title:
- description:
- - Human friendly name of the image.
- returned: queried
- type: str
- sample: Hotfix Version 3.0.1679
- verified:
- description:
- - Whether or not the system has verified this image.
- returned: queried
- type: bool
- sample: yes
- version:
- description:
- - Version of software contained in the image.
- - This is a sub-string of the C(name).
- returned: queried
- type: str
- sample: 13.0.0
- sample: hash/dictionary of values
-software_images:
- description: List of software images.
- returned: When C(software-images) is specified in C(gather_subset).
- type: complex
- contains:
- name:
- description:
- - Name of the image.
- returned: queried
- type: str
- sample: BIGIP-13.1.0.7-0.0.1.iso
- full_path:
- description:
- - Full name of the resource as known to BIG-IP.
- returned: queried
- type: str
- sample: BIGIP-13.1.0.7-0.0.1.iso
- build:
- description:
- - Build number of the image.
- - This is usually a sub-string of the C(name).
- returned: queried
- type: str
- sample: 0.0.1
- build_date:
- description:
- - Date of the build.
- returned: queried
- type: str
- sample: "2018-05-05T15:26:30"
- checksum:
- description:
- - MD5 checksum of the image.
- - Note that this is the checksum that is stored inside the ISO. It is not
- the actual checksum of the ISO.
- returned: queried
- type: str
- sample: df1ec715d2089d0fa54c0c4284656a98
- file_size:
- description:
- - Size, in megabytes, of the image.
- returned: queried
- type: int
- sample: 1938
- last_modified:
- description:
- - Last modified date of the ISO.
- returned: queried
- type: str
- sample: "2018-05-05T15:26:30"
- product:
- description:
- - Product contained in the ISO.
- returned: queried
- type: str
- sample: BIG-IP
- verified:
- description:
- - Whether or not the system has verified this image.
- returned: queried
- type: bool
- sample: yes
- version:
- description:
- - Version of software contained in the image.
- - This is a sub-string of the C(name).
- returned: queried
- type: str
- sample: 13.1.0.7
- sample: hash/dictionary of values
-software_volumes:
- description: List of software volumes.
- returned: When C(software-volumes) is specified in C(gather_subset).
- type: complex
- contains:
- active:
- description:
- - Whether the volume is currently active or not.
- - An active volume contains the currently running version of software.
- returned: queried
- type: bool
- sample: yes
- base_build:
- description:
- - Base build version of the software installed in the volume.
- - When a hotfix is installed, this refers to the base version of software
- that the hotfix requires.
- returned: queried
- type: str
- sample: 0.0.6
- build:
- description:
- - Build version of the software installed in the volume.
- returned: queried
- type: str
- sample: 0.0.6
- full_path:
- description:
- - Full name of the resource as known to BIG-IP.
- returned: queried
- type: str
- sample: HD1.1
- default_boot_location:
- description:
- - Whether this volume is the default boot location or not.
- returned: queried
- type: bool
- sample: yes
- name:
- description:
- - Relative name of the resource in BIG-IP.
- - This usually matches the C(full_name).
- returned: queried
- type: str
- sample: HD1.1
- product:
- description:
- - The F5 product installed in this slot.
- - This should always be BIG-IP.
- returned: queried
- type: str
- sample: BIG-IP
- status:
- description:
- - Status of the software installed, or being installed, in the volume.
- - When C(complete), indicates that the software has completed installing.
- returned: queried
- type: str
- sample: complete
- version:
- description:
- - Version of software installed in the volume, excluding the C(build) number.
- returned: queried
- type: str
- sample: 13.1.0.4
- sample: hash/dictionary of values
-ssl_certs:
- description: SSL certificate related information.
- returned: When C(ssl-certs) is specified in C(gather_subset).
- type: complex
- contains:
- full_path:
- description:
- - Full name of the resource as known to BIG-IP.
- returned: queried
- type: str
- sample: /Common/cert1
- name:
- description:
- - Relative name of the resource in BIG-IP.
- returned: queried
- type: str
- sample: cert1
- key_type:
- description:
- - Specifies the type of cryptographic key associated with this certificate.
- returned: queried
- type: str
- sample: rsa-private
- key_size:
- description:
- - Specifies the size (in bytes) of the file associated with this file object.
- returned: queried
- type: int
- sample: 2048
- system_path:
- description:
- - Path on the BIG-IP where the cert can be found.
- returned: queried
- type: str
- sample: /config/ssl/ssl.crt/f5-irule.crt
- sha1_checksum:
- description:
- - SHA1 checksum of the certificate.
- returned: queried
- type: str
- sample: 1306e84e1e6a2da53816cefe1f684b80d6be1e3e
- subject:
- description:
- - Specifies X509 information of the certificate's subject.
- returned: queried
- type: str
- sample: "emailAddress=support@f5.com,CN=..."
- last_update_time:
- description:
- - Specifies the last time at which the file-object was
- updated/modified.
- returned: queried
- type: str
- sample: "2018-05-15T21:11:15Z"
- issuer:
- description:
- - Specifies X509 information of the certificate's issuer.
- returned: queried
- type: str
- sample: "emailAddress=support@f5.com,...CN=support.f5.com,"
- is_bundle:
- description:
- - Specifies whether the certificate file is a bundle (that is,
- whether it contains more than one certificate).
- returned: queried
- type: bool
- sample: no
- fingerprint:
- description:
- - Displays the SHA-256 fingerprint of the certificate.
- returned: queried
- type: str
- sample: "SHA256/88:A3:05:...:59:01:EA:5D:B0"
- expiration_date:
- description:
- - Specifies a string representation of the expiration date of the
- certificate.
- returned: queried
- type: str
- sample: "Aug 13 21:21:29 2031 GMT"
- expiration_timestamp:
- description:
- - Specifies the date at which this certificate expires. Stored as a
- POSIX time.
- returned: queried
- type: int
- sample: 1944422489
- create_time:
- description:
- - Specifies the time at which the file-object was created.
- returned: queried
- type: str
- sample: "2018-05-15T21:11:15Z"
- sample: hash/dictionary of values
-ssl_keys:
- description: SSL certificate related information.
- returned: When C(ssl-certs) is specified in C(gather_subset).
- type: complex
- contains:
- full_path:
- description:
- - Full name of the resource as known to BIG-IP.
- returned: queried
- type: str
- sample: /Common/key1
- name:
- description:
- - Relative name of the resource in BIG-IP.
- returned: queried
- type: str
- sample: key1
- key_type:
- description:
- - Specifies the cryptographic type of the key in question. That is,
- which algorithm this key is compatible with.
- returned: queried
- type: str
- sample: rsa-private
- key_size:
- description:
- - Specifies the size of the cryptographic key associated with this
- file object, in bits.
- returned: queried
- type: int
- sample: 2048
- security_type:
- description:
- - Specifies the type of security used to handle or store the key.
- returned: queried
- type: str
- sample: normal
- system_path:
- description:
- - The path on the filesystem where the key is stored.
- returned: queried
- type: str
- sample: /config/ssl/ssl.key/default.key
- sha1_checksum:
- description:
- - The SHA1 checksum of the key.
- returned: queried
- type: str
- sample: 1fcf7de3dd8e834d613099d8e10b2060cd9ecc9f
- sample: hash/dictionary of values
-system_db:
- description: System DB related information.
- returned: When C(system-db) is specified in C(gather_subset).
- type: complex
- contains:
- full_path:
- description:
- - Full name of the resource as known to BIG-IP.
- returned: queried
- type: str
- sample: vendor.wwwurl
- name:
- description:
- - Relative name of the resource in BIG-IP.
- returned: queried
- type: str
- sample: vendor.wwwurl
- default:
- description:
- - Default value of the key.
- returned: queried
- type: str
- sample: www.f5.com
- scf_config:
- description:
- - Whether the database key would be found in an SCF config or not.
- returned: queried
- type: str
- sample: false
- value:
- description:
- - The value of the key
- returned: queried
- type: str
- sample: www.f5.com
- value_range:
- description:
- - The accepted range of values for the key
- returned: queried
- type: str
- sample: string
- sample: hash/dictionary of values
-system_info:
- description: Traffic group related information.
- returned: When C(traffic-groups) is specified in C(gather_subset).
- type: complex
- contains:
- base_mac_address:
- description:
- - Media Access Control address (MAC address) of the device.
- returned: queried
- type: str
- sample: "fa:16:3e:c3:42:6f"
- marketing_name:
- description:
- - Marketing name of the device platform.
- returned: queried
- type: str
- sample: BIG-IP Virtual Edition
- time:
- description:
- - Mapping of the current time information to specific time-named keys.
- returned: queried
- type: complex
- contains:
- day:
- description:
- - The current day of the month, in numeric form.
- returned: queried
- type: int
- sample: 7
- hour:
- description:
- - The current hour of the day in 24-hour form.
- returned: queried
- type: int
- sample: 18
- minute:
- description:
- - The current minute of the hour.
- returned: queried
- type: int
- sample: 16
- month:
- description:
- - The current month, in numeric form.
- returned: queried
- type: int
- sample: 6
- second:
- description:
- - The current second of the minute.
- returned: queried
- type: int
- sample: 51
- year:
- description:
- - The current year in 4-digit form.
- returned: queried
- type: int
- sample: 2018
- hardware_information:
- description:
- - Information related to the hardware (drives and CPUs) of the system.
- type: complex
- returned: queried
- contains:
- model:
- description:
- - The model of the hardware.
- returned: queried
- type: str
- sample: Virtual Disk
- name:
- description:
- - The name of the hardware.
- returned: queried
- type: str
- sample: HD1
- type:
- description:
- - The type of hardware.
- returned: queried
- type: str
- sample: physical-disk
- versions:
- description:
- - Hardware specific properties.
- returned: queried
- type: complex
- contains:
- name:
- description:
- - Name of the property.
- returned: queried
- type: str
- sample: Size
- version:
- description:
- - Value of the property.
- returned: queried
- type: str
- sample: 154.00G
- package_edition:
- description:
- - Displays the software edition.
- returned: queried
- type: str
- sample: Point Release 7
- package_version:
- description:
- - A string combining the C(product_build) and C(product_build_date).
- returned: queried
- type: str
- sample: "Build 0.0.1 - Tue May 15 15:26:30 PDT 2018"
- product_code:
- description:
- - Code identifying the product.
- returned: queried
- type: str
- sample: BIG-IP
- product_build:
- description:
- - Build version of the release version.
- returned: queried
- type: str
- sample: 0.0.1
- product_version:
- description:
- - Major product version of the running software.
- returned: queried
- type: str
- sample: 13.1.0.7
- product_built:
- description:
- - Unix timestamp of when the product was built.
- returned: queried
- type: int
- sample: 180515152630
- product_build_date:
- description:
- - Human readable build date.
- returned: queried
- type: str
- sample: "Tue May 15 15:26:30 PDT 2018"
- product_changelist:
- description:
- - Changelist that product branches from.
- returned: queried
- type: int
- sample: 2557198
- product_jobid:
- description:
- - ID of the job that built the product version.
- returned: queried
- type: int
- sample: 1012030
- chassis_serial:
- description:
- - Serial of the chassis.
- returned: queried
- type: str
- sample: 11111111-2222-3333-444444444444
- host_board_part_revision:
- description:
- - Revision of the host board.
- returned: queried
- type: str
- host_board_serial:
- description:
- - Serial of the host board.
- returned: queried
- type: str
- platform:
- description:
- - Platform identifier.
- returned: queried
- type: str
- sample: Z100
- switch_board_part_revision:
- description:
- - Switch board revision.
- returned: queried
- type: str
- switch_board_serial:
- description:
- - Serial of the switch board.
- returned: queried
- type: str
- uptime:
- description:
- - Time, in seconds, since the system booted.
- returned: queried
- type: int
- sample: 603202
- sample: hash/dictionary of values
-tcp_monitors:
- description: TCP monitor related information.
- returned: When C(tcp-monitors) is specified in C(gather_subset).
- type: complex
- contains:
- full_path:
- description:
- - Full name of the resource as known to BIG-IP.
- returned: queried
- type: str
- sample: /Common/tcp
- name:
- description:
- - Relative name of the resource in BIG-IP.
- returned: queried
- type: str
- sample: tcp
- parent:
- description:
- - Profile from which this profile inherits settings.
- returned: queried
- type: str
- sample: tcp
- description:
- description:
- - Description of the resource.
- returned: queried
- type: str
- sample: My monitor
- adaptive:
- description:
- - Whether adaptive response time monitoring is enabled for this monitor.
- returned: queried
- type: bool
- sample: no
- adaptive_divergence_type:
- description:
- - Specifies whether the adaptive-divergence-value is C(relative) or
- C(absolute).
- returned: queried
- type: str
- sample: relative
- adaptive_divergence_value:
- description:
- - Specifies how far from mean latency each monitor probe is allowed
- to be.
- returned: queried
- type: int
- sample: 25
- adaptive_limit:
- description:
- - Specifies the hard limit, in milliseconds, which the probe is not
- allowed to exceed, regardless of the divergence value.
- returned: queried
- type: int
- sample: 200
- adaptive_sampling_timespan:
- description:
- - Specifies the size of the sliding window, in seconds, which
- records probe history.
- returned: queried
- type: int
- sample: 300
- destination:
- description:
- - Specifies the IP address and service port of the resource that is
- the destination of this monitor.
- returned: queried
- type: str
- sample: "*:*"
- interval:
- description:
- - Specifies, in seconds, the frequency at which the system issues
- the monitor check when either the resource is down or the status
- of the resource is unknown.
- returned: queried
- type: int
- sample: 5
- ip_dscp:
- description:
- - Specifies the differentiated services code point (DSCP).
- returned: queried
- type: int
- sample: 0
- manual_resume:
- description:
- - Specifies whether the system automatically changes the status of a
- resource to up at the next successful monitor check.
- returned: queried
- type: bool
- sample: yes
- reverse:
- description:
- - Specifies whether the monitor operates in reverse mode. When the
- monitor is in reverse mode, a successful check marks the monitored
- object down instead of up.
- returned: queried
- type: bool
- sample: no
- time_until_up:
- description:
- - Specifies the amount of time, in seconds, after the first
- successful response before a node is marked up.
- returned: queried
- type: int
- sample: 0
- timeout:
- description:
- - Specifies the number of seconds the target has in which to respond
- to the monitor request.
- returned: queried
- type: int
- sample: 16
- transparent:
- description:
- - Specifies whether the monitor operates in transparent mode.
- returned: queried
- type: bool
- sample: no
- up_interval:
- description:
- - Specifies, in seconds, the frequency at which the system issues
- the monitor check when the resource is up.
- returned: queried
- type: int
- sample: 0
- sample: hash/dictionary of values
-tcp_half_open_monitors:
- description: TCP Half-open monitor related information.
- returned: When C(tcp-half-open-monitors) is specified in C(gather_subset).
- type: complex
- contains:
- full_path:
- description:
- - Full name of the resource as known to BIG-IP.
- returned: queried
- type: str
- sample: /Common/tcp
- name:
- description:
- - Relative name of the resource in BIG-IP.
- returned: queried
- type: str
- sample: tcp
- parent:
- description:
- - Profile from which this profile inherits settings.
- returned: queried
- type: str
- sample: tcp
- description:
- description:
- - Description of the resource.
- returned: queried
- type: str
- sample: My monitor
- destination:
- description:
- - Specifies the IP address and service port of the resource that is
- the destination of this monitor.
- returned: queried
- type: str
- sample: "*:*"
- interval:
- description:
- - Specifies, in seconds, the frequency at which the system issues
- the monitor check when either the resource is down or the status
- of the resource is unknown.
- returned: queried
- type: int
- sample: 5
- manual_resume:
- description:
- - Specifies whether the system automatically changes the status of a
- resource to up at the next successful monitor check.
- returned: queried
- type: bool
- sample: yes
- time_until_up:
- description:
- - Specifies the amount of time, in seconds, after the first
- successful response before a node is marked up.
- returned: queried
- type: int
- sample: 0
- timeout:
- description:
- - Specifies the number of seconds the target has in which to respond
- to the monitor request.
- returned: queried
- type: int
- sample: 16
- transparent:
- description:
- - Specifies whether the monitor operates in transparent mode.
- returned: queried
- type: bool
- sample: no
- up_interval:
- description:
- - Specifies, in seconds, the frequency at which the system issues
- the monitor check when the resource is up.
- returned: queried
- type: int
- sample: 0
- sample: hash/dictionary of values
-tcp_profiles:
- description: TCP profile related information.
- returned: When C(tcp-profiles) is specified in C(gather_subset).
- type: complex
- contains:
- full_path:
- description:
- - Full name of the resource as known to BIG-IP.
- returned: queried
- type: str
- sample: tcp
- name:
- description:
- - Relative name of the resource in BIG-IP.
- returned: queried
- type: str
- sample: /Common/tcp
- parent:
- description:
- - Profile from which this profile inherits settings.
- returned: queried
- type: str
- sample: tcp
- description:
- description:
- - Description of the resource.
- returned: queried
- type: str
- sample: My profile
- abc:
- description:
- - Appropriate Byte Counting (RFC 3465)
- - When C(yes), increases the congestion window by basing the increase
- amount on the number of previously unacknowledged bytes that each ACK covers.
- returned: queried
- type: bool
- sample: yes
- ack_on_push:
- description:
- - Specifies, when C(yes), significantly improved performance to Microsoft
- Windows and MacOS peers who are writing out on a very small send buffer.
- returned: queried
- type: bool
- sample: no
- auto_proxy_buffer:
- description:
- - Specifies, C(yes), that the system uses the network measurements to set
- the optimal proxy buffer size.
- returned: queried
- type: bool
- sample: yes
- auto_receive_window:
- description:
- - Specifies, when C(yes), that the system uses the network measurements to
- set the optimal receive window size.
- returned: queried
- type: bool
- sample: no
- auto_send_buffer:
- description:
- - Specifies, when C(yes), that the system uses the network measurements to
- set the optimal send buffer size.
- returned: queried
- type: bool
- sample: yes
- close_wait:
- description:
- - Specifies the length of time that a TCP connection remains in the LAST-ACK
- state before quitting.
- - In addition to a numeric value, the value of this fact may also be one of
- C(immediate) or C(indefinite).
- - When C(immediate), specifies that the TCP connection closes immediately
- after entering the LAST-ACK state.
- - When C(indefinite), specifies that TCP connections in the LAST-ACK state
- do not close until they meet the maximum retransmissions timeout.
- returned: queried
- type: str
- sample: indefinite
- congestion_metrics_cache:
- description:
- - Specifies, when C(yes), that the system uses a cache for storing congestion
- metrics.
- - Subsequently, because these metrics are already known and cached, the initial
- slow-start ramp for previously-encountered peers improves.
- returned: queried
- type: bool
- sample: yes
- congestion_metrics_cache_timeout:
- description:
- - Specifies the number of seconds for which entries in the congestion metrics
- cache are valid.
- returned: queried
- type: int
- sample: 0
- congestion_control:
- description:
- - Specifies the algorithm to use to share network resources among competing
- users to reduce congestion.
- - Return values may include, C(high-speed), C(cdg), C(chd), C(none), C(cubic),
- C(illinois), C(new-reno), C(reno), C(scalable), C(vegas), C(westwood), and
- C(woodside).
- returned: queried
- type: str
- sample: high-speed
- deferred_accept:
- description:
- - Specifies, when C(yes), that the system defers allocation of the connection
- chain context until the system has received the payload from the client.
- - Enabling this setting is useful in dealing with 3-way handshake denial-of-service
- attacks.
- returned: queried
- type: bool
- sample: yes
- delay_window_control:
- description:
- - Specifies that the system uses an estimate of queuing delay as a measure of
- congestion to control, in addition to the normal loss-based control, the amount
- of data sent.
- returned: queried
- type: bool
- sample: yes
- delayed_acks:
- description:
- - Specifies, when checked (enabled), that the system can send fewer than one ACK
- (acknowledgment) segment per data segment received.
- returned: queried
- type: bool
- sample: yes
- dsack:
- description:
- - D-SACK (RFC 2883)
- - Specifies, when C(yes), the use of the selective ACK (SACK) option to acknowledge
- duplicate segments.
- returned: queried
- type: bool
- sample: yes
- early_retransmit:
- description:
- - Specifies, when C(yes), that the system uses early retransmit (as specified in
- RFC 5827) to reduce the recovery time for connections that are receive- buffer
- or user-data limited.
- returned: queried
- type: bool
- sample: yes
- explicit_congestion_notification:
- description:
- - Specifies, when C(yes), that the system uses the TCP flags CWR (congestion window
- reduction) and ECE (ECN-Echo) to notify its peer of congestion and congestion
- counter-measures.
- returned: queried
- type: bool
- sample: yes
- enhanced_loss_recovery:
- description:
- - Specifies whether the system uses enhanced loss recovery to recover from random
- packet losses more effectively.
- returned: queried
- type: bool
- sample: yes
- fast_open:
- description:
- - Specifies, when C(yes), that the system supports TCP Fast Open, which reduces
- latency by allowing a client to include the first packet of data with the SYN
- returned: queried
- type: bool
- sample: yes
- fast_open_cookie_expiration:
- description:
- - Specifies the number of seconds that a Fast Open Cookie delivered to a client
- is valid for SYN packets from that client.
- returned: queried
- type: int
- sample: 1000
- fin_wait_1:
- description:
- - Specifies the length of time that a TCP connection is in the FIN-WAIT-1 or
- CLOSING state before quitting.
- returned: queried
- type: str
- sample: indefinite
- fin_wait_2:
- description:
- - Specifies the length of time that a TCP connection is in the FIN-WAIT-2 state
- before quitting.
- returned: queried
- type: str
- sample: 100
- idle_timeout:
- description:
- - Specifies the length of time that a connection is idle (has no traffic) before
- the connection is eligible for deletion.
- returned: queried
- type: str
- sample: 300
- initial_congestion_window_size:
- description:
- - Specifies the initial congestion window size for connections to this destination.
- returned: queried
- type: int
- sample: 3
- initial_receive_window_size:
- description:
- - Specifies the initial receive window size for connections to this destination.
- returned: queried
- type: int
- sample: 5
- dont_fragment_flag:
- description:
- - Specifies the Don't Fragment (DF) bit setting in the IP Header of the outgoing
- TCP packet.
- returned: queried
- type: str
- sample: pmtu
- ip_tos:
- description:
- - Specifies the L3 Type of Service (ToS) level that the system inserts in TCP
- packets destined for clients.
- returned: queried
- type: str
- sample: mimic
- time_to_live:
- description:
- - Specifies the outgoing TCP packet's IP Header TTL mode.
- returned: queried
- type: str
- sample: proxy
- time_to_live_v4:
- description:
- - Specifies the outgoing packet's IP Header TTL value for IPv4 traffic.
- returned: queried
- type: int
- sample: 255
- time_to_live_v6:
- description:
- - Specifies the outgoing packet's IP Header TTL value for IPv6 traffic.
- returned: queried
- type: int
- sample: 64
- keep_alive_interval:
- description:
- - Specifies how frequently the system sends data over an idle TCP
- connection, to determine whether the connection is still valid.
- returned: queried
- type: str
- sample: 50
- limited_transmit_recovery:
- description:
- - Specifies, when C(yes), that the system uses limited transmit recovery
- revisions for fast retransmits (as specified in RFC 3042) to reduce
- the recovery time for connections on a lossy network.
- returned: queried
- type: bool
- sample: yes
- link_qos:
- description:
- - Specifies the L2 Quality of Service (QoS) level that the system inserts
- in TCP packets destined for clients.
- returned: queried
- type: str
- sample: 200
- max_segment_retrans:
- description:
- - Specifies the maximum number of times that the system resends data segments.
- returned: queried
- type: int
- sample: 8
- max_syn_retrans:
- description:
- - Specifies the maximum number of times that the system resends a SYN
- packet when it does not receive a corresponding SYN-ACK.
- returned: queried
- type: int
- sample: 3
- max_segment_size:
- description:
- - Specifies the largest amount of data that the system can receive in a
- single TCP segment, not including the TCP and IP headers.
- returned: queried
- type: int
- sample: 1460
- md5_signature:
- description:
- - Specifies, when C(yes), to use RFC2385 TCP-MD5 signatures to protect
- TCP traffic against intermediate tampering.
- returned: queried
- type: bool
- sample: yes
- minimum_rto:
- description:
- - Specifies the minimum length of time the system waits for
- acknowledgements of data sent before resending the data.
- returned: queried
- type: int
- sample: 1000
- multipath_tcp:
- description:
- - Specifies, when C(yes), that the system accepts Multipath TCP (MPTCP)
- connections, which allow multiple client-side flows to connect to a
- single server-side flow.
- returned: queried
- type: bool
- sample: yes
- mptcp_checksum:
- description:
- - Specifies, when C(yes), that the system calculates the checksum for
- MPTCP connections.
- returned: queried
- type: bool
- sample: no
- mptcp_checksum_verify:
- description:
- - Specifies, when C(yes), that the system verifies the checksum for
- MPTCP connections.
- returned: queried
- type: bool
- sample: no
- mptcp_fallback:
- description:
- - Specifies an action on fallback, that is, when MPTCP transitions
- to regular TCP, because something prevents MPTCP from working correctly.
- returned: queried
- type: str
- sample: reset
- mptcp_fast_join:
- description:
- - Specifies, when C(yes), a FAST join, allowing data to be sent on the
- MP_JOIN_SYN, which can allow a server response to occur in parallel
- with the JOIN.
- returned: queried
- type: bool
- sample: no
- mptcp_idle_timeout:
- description:
- - Specifies the number of seconds that an MPTCP connection is idle
- before the connection is eligible for deletion.
- returned: queried
- type: int
- sample: 300
- mptcp_join_max:
- description:
- - Specifies the highest number of MPTCP connections that can join to
- a given connection.
- returned: queried
- type: int
- sample: 5
- mptcp_make_after_break:
- description:
- - Specifies that make-after-break functionality is supported, allowing
- for long-lived MPTCP sessions.
- returned: queried
- type: bool
- sample: no
- mptcp_no_join_dss_ack:
- description:
- - Specifies, when checked (enabled), that no DSS option is sent on the
- JOIN ACK.
- returned: queried
- type: bool
- sample: no
- mptcp_rto_max:
- description:
- - Specifies the number of RTOs (retransmission timeouts) before declaring
- the subflow dead.
- returned: queried
- type: int
- sample: 5
- mptcp_retransmit_min:
- description:
- - Specifies the minimum value (in msec) of the retransmission timer for
- these MPTCP flows.
- returned: queried
- type: int
- sample: 1000
- mptcp_subflow_max:
- description:
- - Specifies the maximum number of MPTCP subflows for a single flow.
- returned: queried
- type: int
- sample: 6
- mptcp_timeout:
- description:
- - Specifies, in seconds, the timeout value to discard long-lived sessions
- that do not have an active flow.
- returned: queried
- type: int
- sample: 3600
- nagle_algorithm:
- description:
- - Specifies whether the system applies Nagle's algorithm to reduce the
- number of short segments on the network.
- returned: queried
- type: bool
- sample: no
- pkt_loss_ignore_burst:
- description:
- - Specifies the probability of performing congestion control when
- multiple packets are lost, even if the Packet Loss Ignore Rate was
- not exceeded.
- returned: queried
- type: int
- sample: 0
- pkt_loss_ignore_rate:
- description:
- - Specifies the threshold of packets lost per million at which the
- system performs congestion control.
- returned: queried
- type: int
- sample: 0
- proxy_buffer_high:
- description:
- - Specifies the proxy buffer level, in bytes, at which the receive window
- is closed.
- returned: queried
- type: int
- sample: 49152
- proxy_buffer_low:
- description:
- - Specifies the proxy buffer level, in bytes, at which the receive window
- is opened.
- returned: queried
- type: int
- sample: 32768
- proxy_max_segment:
- description:
- - Specifies, when C(yes), that the system attempts to advertise the same
- maximum segment size (MSS) to the server-side connection as that of the
- client-side connection.
- returned: queried
- type: bool
- sample: yes
- proxy_options:
- description:
- - Specifies, when C(yes), that the system advertises an option (such as
- time stamps) to the server only when the option is negotiated with the
- client.
- returned: queried
- type: bool
- sample: no
- push_flag:
- description:
- - Specifies how the BIG-IP system receives ACKs.
- returned: queried
- type: str
- sample: default
- rate_pace:
- description:
- - Specifies, when C(yes), that the system paces the egress packets to
- avoid dropping packets, allowing for optimum goodput.
- returned: queried
- type: bool
- sample: yes
- rate_pace_max_rate:
- description:
- - Specifies the maximum rate in bytes per second to which the system
- paces TCP data transmission.
- returned: queried
- type: int
- sample: 0
- receive_window:
- description:
- - Specifies the maximum advertised RECEIVE window size.
- returned: queried
- type: int
- sample: 65535
- reset_on_timeout:
- description:
- - Specifies, when C(yes), that the system sends a reset packet (RST)
- in addition to deleting the connection, when a connection exceeds
- the idle timeout value.
- returned: queried
- type: bool
- sample: yes
- retransmit_threshold:
- description:
- - Specifies the number of duplicate ACKs (retransmit threshold) to start
- fast recovery.
- returned: queried
- type: int
- sample: 3
- selective_acks:
- description:
- - Specifies, when C(yes), that the system processes data using
- selective ACKs (SACKs) whenever possible, to improve system performance.
- returned: queried
- type: bool
- sample: yes
- selective_nack:
- description:
- - Specifies, when C(yes), that the system processes data using a selective
- negative acknowledgment (SNACK) whenever possible, to improve system
- performance.
- returned: queried
- type: bool
- sample: yes
- send_buffer:
- description:
- - Specifies the SEND window size.
- returned: queried
- type: int
- sample: 65535
- slow_start:
- description:
- - Specifies, when C(yes), that the system uses Slow-Start Congestion
- Avoidance as described in RFC3390 in order to ramp up traffic without
- causing excessive congestion on the link.
- returned: queried
- type: bool
- sample: yes
- syn_cookie_enable:
- description:
- - Specifies the default (if no DoS profile is associated) number of
- embryonic connections that are allowed on any virtual server,
- before SYN Cookie challenges are enabled for that virtual server.
- returned: queried
- type: bool
- sample: yes
- syn_cookie_white_list:
- description:
- - Specifies whether or not to use a SYN Cookie WhiteList when doing
- software SYN Cookies.
- returned: queried
- type: bool
- sample: no
- syn_retrans_to_base:
- description:
- - Specifies the initial RTO (Retransmission TimeOut) base multiplier
- for SYN retransmissions.
- returned: queried
- type: int
- sample: 3000
- tail_loss_probe:
- description:
- - Specifies, when C(yes), that the system uses Tail Loss Probe to
- reduce the number of retransmission timeouts.
- returned: queried
- type: bool
- sample: yes
- time_wait_recycle:
- description:
- - Specifies, when C(yes), that connections in a TIME-WAIT state are
- reused when the system receives a SYN packet, indicating a request
- for a new connection.
- returned: queried
- type: bool
- sample: yes
- time_wait:
- description:
- - Specifies the length of time that a TCP connection remains in the
- TIME-WAIT state before entering the CLOSED state.
- returned: queried
- type: str
- sample: 2000
- timestamps:
- description:
- - Specifies, when C(yes), that the system uses the timestamps extension
- for TCP (as specified in RFC 1323) to enhance high-speed network performance.
- returned: queried
- type: bool
- sample: yes
- verified_accept:
- description:
- - Specifies, when C(yes), that the system can actually communicate with
- the server before establishing a client connection.
- returned: queried
- type: bool
- sample: yes
- zero_window_timeout:
- description:
- - Specifies the timeout in milliseconds for terminating a connection
- with an effective zero length TCP transmit window.
- returned: queried
- type: str
- sample: 2000
- sample: hash/dictionary of values
-traffic_groups:
- description: Traffic group related information.
- returned: When C(traffic-groups) is specified in C(gather_subset).
- type: complex
- contains:
- full_path:
- description:
- - Full name of the resource as known to BIG-IP.
- returned: queried
- type: str
- sample: /Common/tg1
- name:
- description:
- - Relative name of the resource in BIG-IP.
- returned: queried
- type: str
- sample: tg1
- description:
- description:
- - Description of the traffic group.
- returned: queried
- type: str
- sample: My traffic group
- auto_failback_enabled:
- description:
- - Specifies whether the traffic group fails back to the default
- device.
- returned: queried
- type: bool
- sample: yes
- auto_failback_time:
- description:
- - Specifies the time required to fail back.
- returned: queried
- type: int
- sample: 60
- ha_load_factor:
- description:
- - Specifies a number for this traffic group that represents the load
- this traffic group presents to the system relative to other
- traffic groups.
- returned: queried
- type: int
- sample: 1
- ha_order:
- description:
- - This list of devices specifies the order in which the devices will
- become active for the traffic group when a failure occurs.
- returned: queried
- type: list
- sample: ['/Common/device1', '/Common/device2']
- is_floating:
- description:
- - Indicates whether the traffic group can fail over to other devices
- in the device group.
- returned: queried
- type: bool
- sample: no
- mac_masquerade_address:
- description:
- - Specifies a MAC address for the traffic group.
- returned: queried
- type: str
- sample: "00:98:76:54:32:10"
- sample: hash/dictionary of values
-trunks:
- description: Trunk related information.
- returned: When C(trunks) is specified in C(gather_subset).
- type: complex
- contains:
- full_path:
- description:
- - Full name of the resource as known to BIG-IP.
- returned: queried
- type: str
- sample: /Common/trunk1
- name:
- description:
- - Relative name of the resource in BIG-IP.
- returned: queried
- type: str
- sample: trunk1
- description:
- description:
- - Description of the Trunk.
- returned: queried
- type: str
- sample: My trunk
- media_speed:
- description:
- - Speed of the media attached to the trunk.
- returned: queried
- type: int
- sample: 10000
- lacp_mode:
- description:
- - The operation mode for LACP.
- returned: queried
- type: str
- sample: passive
- lacp_enabled:
- description:
- - Whether LACP is enabled or not.
- returned: queried
- type: bool
- sample: yes
- stp_enabled:
- description:
- - Whether Spanning Tree Protocol (STP) is enabled or not.
- returned: queried
- type: bool
- sample: yes
- operational_member_count:
- description:
- - Number of working members associated with the trunk.
- returned: queried
- type: int
- sample: 1
- media_status:
- description:
- - Whether the media that is part of the trunk is up or not.
- returned: queried
- type: bool
- sample: yes
- link_selection_policy:
- description:
- - The LACP policy that the trunk uses to determine which member link can handle
- new traffic.
- returned: queried
- type: str
- sample: maximum-bandwidth
- lacp_timeout:
- description:
- - The rate at which the system sends the LACP control packets.
- returned: queried
- type: int
- sample: 10
- interfaces:
- description:
- - The list of interfaces that are part of the trunk.
- returned: queried
- type: list
- sample: ['1.2', '1.3']
- distribution_hash:
- description:
- - The basis for the has that the system uses as the frame distribution algorithm.
- - The system uses this hash to determine which interface to use for forwarding
- traffic.
- returned: queried
- type: str
- sample: src-dst-ipport
- configured_member_count:
- description:
- - The number of configured members that are associated with the trunk.
- returned: queried
- type: int
- sample: 1
- sample: hash/dictionary of values
-udp_profiles:
- description: UDP profile related information.
- returned: When C(udp-profiles) is specified in C(gather_subset).
- type: complex
- contains:
- full_path:
- description:
- - Full name of the resource as known to BIG-IP.
- returned: queried
- type: str
- sample: udp
- name:
- description:
- - Relative name of the resource in BIG-IP.
- returned: queried
- type: str
- sample: /Common/udp
- parent:
- description:
- - Profile from which this profile inherits settings.
- returned: queried
- type: str
- sample: udp
- description:
- description:
- - Description of the resource.
- returned: queried
- type: str
- sample: My profile
- allow_no_payload:
- description:
- - Allow the passage of datagrams that contain header information, but no essential data.
- returned: queried
- type: bool
- sample: yes
- buffer_max_bytes:
- description:
- - Ingress buffer byte limit. Maximum allowed value is 16777215.
- returned: queried
- type: int
- sample: 655350
- buffer_max_packets:
- description:
- - Ingress buffer packet limit. Maximum allowed value is 255.
- returned: queried
- type: int
- sample: 0
- datagram_load_balancing:
- description:
- - Load balance UDP datagram by datagram
- returned: queried
- type: bool
- sample: yes
- idle_timeout:
- description:
- - Number of seconds that a connection is idle before
- the connection is eligible for deletion.
- - In addition to a number, may be one of the values C(indefinite), or
- C(immediate).
- returned: queried
- type: bool
- sample: 200
- ip_df_mode:
- description:
- - Describes the Don't Fragment (DF) bit setting in the outgoing UDP
- packet.
- - May be one of C(pmtu), C(preserve), C(set), or C(clear).
- - When C(pmtu), sets the outgoing UDP packet DF big based on the ip
- pmtu setting.
- - When C(preserve), preserves the incoming UDP packet Don't Fragment bit.
- - When C(set), sets the outgoing UDP packet DF bit.
- - When C(clear), clears the outgoing UDP packet DF bit.
- returned: queried
- type: str
- sample: pmtu
- ip_tos_to_client:
- description:
- - The Type of Service level that the traffic management
- system assigns to UDP packets when sending them to clients.
- - May be numeric, or the values C(pass-through) or C(mimic).
- returned: queried
- type: str
- sample: mimic
- ip_ttl_mode:
- description:
- - The outgoing UDP packet's TTL mode.
- - Valid modes are C(proxy), C(preserve), C(decrement), and C(set).
- - When C(proxy), set the IP TTL of ipv4 to the default value of 255 and
- ipv6 to the default value of 64.
- - When C(preserve), set the IP TTL to the original packet TTL value.
- - When C(decrement), set the IP TTL to the original packet TTL value minus 1.
- - When C(set), set the IP TTL with the specified values in C(ip_ttl_v4) and
- C(ip_ttl_v6) values in the same profile.
- returned: queried
- type: str
- sample: proxy
- ip_ttl_v4:
- description:
- - IPv4 TTL.
- returned: queried
- type: int
- sample: 10
- ip_ttl_v6:
- description:
- - IPv6 TTL.
- returned: queried
- type: int
- sample: 100
- link_qos_to_client:
- description:
- - The Quality of Service level that the system assigns to
- UDP packets when sending them to clients.
- - May be either numeric, or the value C(pass-through).
- returned: queried
- type: str
- sample: pass-through
- no_checksum:
- description:
- - Whether the checksum processing is enabled or disabled.
- - Note that if the datagram is IPv6, the system always performs
- checksum processing.
- returned: queried
- type: bool
- sample: yes
- proxy_mss:
- description:
- - When C(yes), specifies that the system advertises the same mss
- to the server as was negotiated with the client.
- returned: queried
- type: bool
- sample: yes
- sample: hash/dictionary of values
-users:
- description: Details of the users on the system.
- returned: When C(users) is specified in C(gather_subset).
- type: complex
- contains:
- description:
- description:
- - Description of the resource.
- returned: queried
- type: str
- sample: Admin user
- full_path:
- description:
- - Full name of the resource as known to BIG-IP.
- returned: queried
- type: str
- sample: admin
- name:
- description:
- - Relative name of the resource in BIG-IP.
- returned: queried
- type: str
- sample: admin
- partition_access:
- description:
- - Partition that user has access to, including user role.
- returned: queried
- type: complex
- contains:
- name:
- description:
- - Name of partition
- returned: queried
- type: str
- sample: all-partitions
- role:
- description:
- - Role allowed to user on partition.
- returned: queried
- type: str
- sample: auditor
- shell:
- description:
- - The shell assigned to the user account.
- returned: queried
- type: str
- sample: tmsh
-vcmp_guests:
- description: vCMP related information.
- returned: When C(vcmp-guests) is specified in C(gather_subset).
- type: complex
- contains:
- full_path:
- description:
- - Full name of the resource as known to BIG-IP.
- returned: queried
- type: str
- sample: guest1
- name:
- description:
- - Relative name of the resource in BIG-IP.
- returned: queried
- type: str
- sample: guest1
- allowed_slots:
- description:
- - List of slots that the guest is allowed to be assigned to.
- returned: queried
- type: list
- sample: [0, 1, 3]
- assigned_slots:
- description:
- - Slots that the guest is assigned to.
- returned: queried
- type: list
- sample: [0]
- boot_priority:
- description:
- - Specifies boot priority of the guest. Lower number means earlier to boot.
- returned: queried
- type: int
- sample: 65535
- cores_per_slot:
- description:
- - Number of cores that the system allocates to the guest.
- returned: queried
- type: int
- sample: 2
- hostname:
- description:
- - FQDN assigned to the guest.
- returned: queried
- type: str
- sample: guest1.localdomain
- hotfix_image:
- description:
- - hotfix image to install onto any of this guest's newly created virtual disks.
- returned: queried
- type: str
- sample: Hotfix-BIGIP-12.1.3.4-0.0.2-hf1.iso
- initial_image:
- description:
- - Software image to install onto any of this guest's newly created virtual disks.
- returned: queried
- type: str
- sample: BIGIP-12.1.3.4-0.0.2.iso
- mgmt_route:
- description:
- - Management gateway IP address for the guest.
- returned: queried
- type: str
- sample: 2.2.2.1
- mgmt_address:
- description:
- - Management IP address configuration for the guest.
- returned: queried
- type: str
- sample: 2.3.2.3
- mgmt_network:
- description:
- - Accessibility of this vCMP guest's management network.
- returned: queried
- type: str
- sample: bridged
- vlans:
- description:
- - List of VLANs on which the guest is either enabled or disabled.
- returned: queried
- type: list
- sample: ['/Common/vlan1', '/Common/vlan2']
- min_number_of_slots:
- description:
- - Specifies the minimum number of slots that the guest must be assigned to.
- returned: queried
- type: int
- sample: 2
- number_of_slots:
- description:
- - Specifies the number of slots the guest should be assigned to.
- - This number is always greater than, or equal to, C(min_number_of_slots).
- returned: queried
- type: int
- sample: 2
- ssl_mode:
- description:
- - The SSL hardware allocation mode for the guest.
- returned: queried
- type: str
- sample: shared
- state:
- description:
- - Specifies the state of the guest.
- - May be one of C(configured), C(provisioned), or C(deployed).
- - Each state implies the actions of all states before it.
- returned: queried
- type: str
- sample: provisioned
- virtual_disk:
- description:
- - The filename of the virtual disk to use for this guest.
- returned: queried
- type: str
- sample: guest1.img
- sample: hash/dictionary of values
-virtual_addresses:
- description: Virtual address related information.
- returned: When C(virtual-addresses) is specified in C(gather_subset).
- type: complex
- contains:
- full_path:
- description:
- - Full name of the resource as known to BIG-IP.
- returned: queried
- type: str
- sample: /Common/2.3.4.5
- name:
- description:
- - Relative name of the resource in BIG-IP.
- returned: queried
- type: str
- sample: 2.3.4.5
- address:
- description:
- - The virtual IP address.
- returned: queried
- type: str
- sample: 2.3.4.5
- arp_enabled:
- description:
- - Whether or not ARP is enabled for the specified virtual address.
- returned: queried
- type: bool
- sample: yes
- auto_delete_enabled:
- description:
- - Indicates if the virtual address will be deleted automatically on
- deletion of the last associated virtual server or not.
- returned: queried
- type: bool
- sample: no
- connection_limit:
- description:
- - Concurrent connection limit for one or more virtual
- servers.
- returned: queried
- type: int
- sample: 0
- description:
- description:
- - The description of the virtual address.
- returned: queried
- type: str
- sample: My virtual address
- enabled:
- description:
- - Whether the virtual address is enabled or not.
- returned: queried
- type: bool
- sample: yes
- icmp_echo:
- description:
- - Whether the virtual address should reply to ICMP echo requests.
- returned: queried
- type: bool
- sample: yes
- floating:
- description:
- - Property derived from traffic-group. A floating virtual
- address is a virtual address for a VLAN that serves as a shared
- address by all devices of a BIG-IP traffic-group.
- returned: queried
- type: bool
- sample: yes
- netmask:
- description:
- - Netmask of the virtual address.
- returned: queried
- type: str
- sample: 255.255.255.255
- route_advertisement:
- description:
- - Specifies the route advertisement setting for the virtual address.
- returned: queried
- type: bool
- sample: no
- traffic_group:
- description:
- - Traffic group on which the virtual address is active.
- returned: queried
- type: str
- sample: /Common/traffic-group-1
- spanning:
- description:
- - Whether or not spanning is enabled for the specified virtual address.
- returned: queried
- type: bool
- sample: no
- inherited_traffic_group:
- description:
- - Indicates if the traffic-group is inherited from the parent folder.
- returned: queried
- type: bool
- sample: no
- sample: hash/dictionary of values
-virtual_servers:
- description: Virtual address related information.
- returned: When C(virtual-addresses) is specified in C(gather_subset).
- type: complex
- contains:
- availability_status:
- description:
- - The availability of the virtual server.
- returned: queried
- type: str
- sample: offline
- full_path:
- description:
- - Full name of the resource as known to BIG-IP.
- returned: queried
- type: str
- sample: /Common/2.3.4.5
- name:
- description:
- - Relative name of the resource in BIG-IP.
- returned: queried
- type: str
- sample: 2.3.4.5
- auto_lasthop:
- description:
- - When enabled, allows the system to send return traffic to the MAC address
- that transmitted the request, even if the routing table points to a different
- network or interface.
- returned: queried
- type: str
- sample: default
- bw_controller_policy:
- description:
- - The bandwidth controller for the system to use to enforce a throughput policy
- for incoming network traffic.
- returned: queried
- type: str
- sample: /Common/bw1
- client_side_bits_in:
- description:
- - Number of client-side ingress bits.
- returned: queried
- type: int
- sample: 1000
- client_side_bits_out:
- description:
- - Number of client-side egress bits.
- returned: queried
- type: int
- sample: 200
- client_side_current_connections:
- description:
- - Number of current connections client-side.
- returned: queried
- type: int
- sample: 300
- client_side_evicted_connections:
- description:
- - Number of evicted connections client-side.
- returned: queried
- type: int
- sample: 100
- client_side_max_connections:
- description:
- - Maximum number of connections client-side.
- returned: queried
- type: int
- sample: 40
- client_side_pkts_in:
- description:
- - Number of client-side ingress packets.
- returned: queried
- type: int
- sample: 1098384
- client_side_pkts_out:
- description:
- - Number of client-side egress packets.
- returned: queried
- type: int
- sample: 3484734
- client_side_slow_killed:
- description:
- - Number of slow connections killed, client-side.
- returned: queried
- type: int
- sample: 234
- client_side_total_connections:
- description:
- - Total number of connections.
- returned: queried
- type: int
- sample: 24
- cmp_enabled:
- description:
- - Whether or not clustered multi-processor (CMP) acceleration is enabled.
- returned: queried
- type: bool
- sample: yes
- cmp_mode:
- description:
- - The clustered-multiprocessing mode.
- returned: queried
- type: str
- sample: all-cpus
- connection_limit:
- description:
- - Maximum number of concurrent connections you want to allow for the virtual server.
- returned: queried
- type: int
- sample: 100
- description:
- description:
- - The description of the virtual server.
- returned: queried
- type: str
- sample: My virtual
- enabled:
- description:
- - Whether or not the virtual is enabled.
- returned: queried
- type: bool
- sample: yes
- ephemeral_bits_in:
- description:
- - Number of ephemeral ingress bits.
- returned: queried
- type: int
- sample: 1000
- ephemeral_bits_out:
- description:
- - Number of ephemeral egress bits.
- returned: queried
- type: int
- sample: 200
- ephemeral_current_connections:
- description:
- - Number of ephemeral current connections.
- returned: queried
- type: int
- sample: 300
- ephemeral_evicted_connections:
- description:
- - Number of ephemeral evicted connections.
- returned: queried
- type: int
- sample: 100
- ephemeral_max_connections:
- description:
- - Maximum number of ephemeral connections.
- returned: queried
- type: int
- sample: 40
- ephemeral_pkts_in:
- description:
- - Number of ephemeral ingress packets.
- returned: queried
- type: int
- sample: 1098384
- ephemeral_pkts_out:
- description:
- - Number of ephemeral egress packets.
- returned: queried
- type: int
- sample: 3484734
- ephemeral_slow_killed:
- description:
- - Number of ephemeral slow connections killed.
- returned: queried
- type: int
- sample: 234
- ephemeral_total_connections:
- description:
- - Total number of ephemeral connections.
- returned: queried
- type: int
- sample: 24
- total_software_accepted_syn_cookies:
- description:
- - SYN Cookies Total Software Accepted.
- returned: queried
- type: int
- sample: 0
- total_hardware_accepted_syn_cookies:
- description:
- - SYN Cookies Total Hardware Accepted.
- returned: queried
- type: int
- sample: 0
- total_hardware_syn_cookies:
- description:
- - SYN Cookies Total Hardware
- returned: queried
- type: int
- sample: 0
- hardware_syn_cookie_instances:
- description:
- - Hardware SYN Cookie Instances
- returned: queried
- type: int
- sample: 0
- total_software_rejected_syn_cookies:
- description:
- - Total Software Rejected
- returned: queried
- type: int
- sample: 0
- software_syn_cookie_instances:
- description:
- - Software SYN Cookie Instances
- returned: queried
- type: int
- sample: 0
- current_syn_cache:
- description:
- - Current SYN Cache
- returned: queried
- type: int
- sample: 0
- max_conn_duration:
- description:
- - Max Conn Duration/msec
- returned: queried
- type: int
- sample: 0
- mean_conn_duration:
- description:
- - Mean Conn Duration/msec
- returned: queried
- type: int
- sample: 0
- min_conn_duration:
- description:
- - Min Conn Duration/msec
- returned: queried
- type: int
- sample: 0
- cpu_usage_ratio_last_5_min:
- description:
- - CPU Usage Ratio (%) Last 5 Minutes
- returned: queried
- type: int
- sample: 0
- cpu_usage_ratio_last_5_sec:
- description:
- - CPU Usage Ratio (%) Last 5 Seconds
- returned: queried
- type: int
- sample: 0
- cpu_usage_ratio_last_1_min:
- description:
- - CPU Usage Ratio (%) Last 1 Minute
- returned: queried
- type: int
- sample: 0
- syn_cache_overflow:
- description:
- - SYN Cache Overflow
- returned: queried
- type: int
- sample: 0
- total_software_syn_cookies:
- description:
- - Total Software
- returned: queried
- type: int
- sample: 0
- syn_cookies_status:
- description:
- - SYN Cookies Status
- returned: queried
- type: str
- sample: not-activated
- fallback_persistence_profile:
- description:
- - Fallback persistence profile for the virtual server to use
- when the default persistence profile is not available.
- returned: queried
- type: str
- sample: /Common/fallback1
- persistence_profile:
- description:
- - The persistence profile you want the system to use as the default
- for this virtual server.
- returned: queried
- type: str
- sample: /Common/persist1
- translate_port:
- description:
- - Enables or disables port translation.
- returned: queried
- type: bool
- sample: yes
- translate_address:
- description:
- - Enables or disables address translation for the virtual server.
- returned: queried
- type: bool
- sample: yes
- vlans:
- description:
- - List of VLANs on which the virtual server is either enabled or disabled.
- returned: queried
- type: list
- sample: ['/Common/vlan1', '/Common/vlan2']
- destination:
- description:
- - Name of the virtual address and service on which the virtual server
- listens for connections.
- returned: queried
- type: str
- sample: /Common/2.2.3.3%1:76
- last_hop_pool:
- description:
- - Name of the last hop pool that you want the virtual
- server to use to direct reply traffic to the last hop router.
- returned: queried
- type: str
- sample: /Common/pool1
- nat64_enabled:
- description:
- - Whether or not NAT64 is enabled.
- returned: queried
- type: bool
- sample: yes
- source_port_behavior:
- description:
- - Specifies whether the system preserves the source port of the connection.
- returned: queried
- type: str
- sample: preserve
- ip_intelligence_policy:
- description:
- - IP Intelligence policy assigned to the virtual
- returned: queried
- type: str
- sample: /Common/ip1
- protocol:
- description:
- - IP protocol for which you want the virtual server to direct traffic.
- returned: queried
- type: str
- sample: tcp
- default_pool:
- description:
- - Pool name that you want the virtual server to use as the default pool.
- returned: queried
- type: str
- sample: /Common/pool1
- rate_limit_mode:
- description:
- - Indicates whether the rate limit is applied per virtual object,
- per source address, per destination address, or some combination
- thereof.
- returned: queried
- type: str
- sample: object
- rate_limit_source_mask:
- description:
- - Specifies a mask, in bits, to be applied to the source address as
- part of the rate limiting.
- returned: queried
- type: int
- sample: 0
- rate_limit:
- description:
- - Maximum number of connections per second allowed for a virtual server.
- returned: queried
- type: int
- sample: 34
- snat_type:
- description:
- - Specifies the type of source address translation associated
- with the specified virtual server.
- returned: queried
- type: str
- sample: none
- snat_pool:
- description:
- - Specifies the name of a LSN or SNAT pool used by the specified virtual server.
- returned: queried
- type: str
- sample: /Common/pool1
- status_reason:
- description:
- - If there is a problem with the status of the virtual, that problem is reported here.
- returned: queried
- type: str
- sample: The children pool member(s) either don't have service checking...
- gtm_score:
- description:
- - Specifies a score that is associated with the virtual server.
- returned: queried
- type: int
- sample: 0
- rate_class:
- description:
- - Name of an existing rate class that you want the
- virtual server to use to enforce a throughput policy for incoming
- network traffic.
- returned: queried
- type: str
- rate_limit_destination_mask:
- description:
- - Specifies a mask, in bits, to be applied to the destination
- address as part of the rate limiting.
- returned: queried
- type: int
- sample: 32
- source_address:
- description:
- - Specifies an IP address or network from which the virtual server
- will accept traffic.
- returned: queried
- type: str
- sample: 0.0.0./0
- authentication_profile:
- description:
- - Specifies a list of authentication profile names, separated by
- spaces, that the virtual server uses to manage authentication.
- returned: queried
- type: list
- sample: ['/Common/ssl_drldp']
- connection_mirror_enabled:
- description:
- - Whether or not connection mirroring is enabled.
- returned: queried
- type: bool
- sample: yes
- irules:
- description:
- - List of iRules that customize the virtual server to direct and manage traffic.
- returned: queried
- type: list
- sample: ['/Common/rule1', /Common/rule2']
- security_log_profiles:
- description:
- - Specifies the log profile applied to the virtual server.
- returned: queried
- type: list
- sample: ['/Common/global-network', '/Common/local-dos']
- type:
- description:
- - Virtual server type.
- returned: queried
- type: str
- sample: standard
- destination_address:
- description:
- - Address portion of the C(destination).
- returned: queried
- type: str
- sample: 2.3.3.2
- destination_port:
- description:
- - Port potion of the C(destination).
- returned: queried
- type: int
- sample: 80
- profiles:
- description:
- - List of the profiles attached to the virtual.
- type: complex
- contains:
- context:
- description:
- - Which side of the connection the profile affects; either C(all),
- C(client-side) or C(server-side).
- returned: queried
- type: str
- sample: client-side
- full_path:
- description:
- - Full name of the resource as known to BIG-IP.
- returned: queried
- type: str
- sample: /Common/tcp
- name:
- description:
- - Relative name of the resource in BIG-IP.
- returned: queried
- type: str
- sample: tcp
- total_requests:
- description:
- - Total requests.
- returned: queried
- type: int
- sample: 8
- sample: hash/dictionary of values
-vlans:
- description: List of VLAN information.
- returned: When C(vlans) is specified in C(gather_subset).
- type: complex
- contains:
- auto_lasthop:
- description:
- - Allows the system to send return traffic to the MAC address that transmitted the
- request, even if the routing table points to a different network or interface.
- returned: queried
- type: str
- sample: enabled
- cmp_hash_algorithm:
- description:
- - Specifies how the traffic on the VLAN will be disaggregated.
- returned: queried
- type: str
- sample: default
- description:
- description:
- - Description of the VLAN.
- returned: queried
- type: str
- sample: My vlan
- failsafe_action:
- description:
- - Action for the system to take when the fail-safe mechanism is triggered.
- returned: queried
- type: str
- sample: reboot
- failsafe_enabled:
- description:
- - Whether failsafe is enabled or not.
- returned: queried
- type: bool
- sample: yes
- failsafe_timeout:
- description:
- - Number of seconds that an active unit can run without detecting network traffic
- on this VLAN before it starts a failover.
- returned: queried
- type: int
- sample: 90
- if_index:
- description:
- - Index assigned to this VLAN. It is a unique identifier assigned for all objects
- displayed in the SNMP IF-MIB.
- returned: queried
- type: int
- sample: 176
- learning_mode:
- description:
- - Whether switch ports placed in the VLAN are configured for switch learning,
- forwarding only, or dropped.
- returned: queried
- type: str
- sample: enable-forward
- interfaces:
- description:
- - List of tagged or untagged interfaces and trunks that you want to configure for the VLAN.
- returned: queried
- type: complex
- contains:
- full_path:
- description:
- - Full name of the resource as known to BIG-IP.
- returned: queried
- type: str
- sample: 1.3
- name:
- description:
- - Relative name of the resource in BIG-IP.
- returned: queried
- type: str
- sample: 1.3
- tagged:
- description:
- - Whether the interface is tagged or not.
- returned: queried
- type: bool
- sample: no
- mtu:
- description:
- - Specific maximum transition unit (MTU) for the VLAN.
- returned: queried
- type: int
- sample: 1500
- sflow_poll_interval:
- description:
- - Maximum interval in seconds between two pollings.
- returned: queried
- type: int
- sample: 0
- sflow_poll_interval_global:
- description:
- - Whether the global VLAN poll-interval setting, overrides the object-level
- poll-interval setting.
- returned: queried
- type: bool
- sample: no
- sflow_sampling_rate:
- description:
- - Ratio of packets observed to the samples generated.
- returned: queried
- type: int
- sample: 0
- sflow_sampling_rate_global:
- description:
- - Whether the global VLAN sampling-rate setting, overrides the object-level
- sampling-rate setting.
- returned: queried
- type: bool
- sample: yes
- source_check_enabled:
- description:
- - Specifies that only connections that have a return route in the routing table are accepted.
- returned: queried
- type: bool
- sample: yes
- true_mac_address:
- description:
- - Media access control (MAC) address for the lowest-numbered interface assigned to this VLAN.
- returned: queried
- type: str
- sample: "fa:16:3e:10:da:ff"
- tag:
- description:
- - Tag number for the VLAN.
- returned: queried
- type: int
- sample: 30
- sample: hash/dictionary of values
-'''
-
-import datetime
-import math
-import re
-import time
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.network.common.utils import to_netmask
-from ansible.module_utils.parsing.convert_bool import BOOLEANS_TRUE
-from ansible.module_utils.six import iteritems
-from ansible.module_utils.six import string_types
-from collections import namedtuple
-from distutils.version import LooseVersion
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.common import fq_name
- from library.module_utils.network.f5.common import flatten_boolean
- from library.module_utils.network.f5.common import transform_name
- from library.module_utils.network.f5.ipaddress import is_valid_ip
- from library.module_utils.network.f5.icontrol import modules_provisioned
- from library.module_utils.network.f5.icontrol import tmos_version
- from library.module_utils.network.f5.urls import parseStats
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.common import fq_name
- from ansible.module_utils.network.f5.common import flatten_boolean
- from ansible.module_utils.network.f5.common import transform_name
- from ansible.module_utils.network.f5.ipaddress import is_valid_ip
- from ansible.module_utils.network.f5.icontrol import modules_provisioned
- from ansible.module_utils.network.f5.icontrol import tmos_version
- from ansible.module_utils.network.f5.urls import parseStats
-
-
-class BaseManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = kwargs.get('client', None)
- self.kwargs = kwargs
-
- # A list of modules currently provisioned on the device.
- #
- # This list is used by different fact managers to check to see
- # if they should even attempt to gather information. If the module is
- # not provisioned, then it is likely that the REST API will not
- # return valid data.
- #
- # For example, ASM (at the time of this writing 13.x/14.x) will
- # raise an exception if you attempt to query its APIs if it is
- # not provisioned. An example error message is shown below.
- #
- # {
- # "code": 400,
- # "message": "java.net.ConnectException: Connection refused (Connection refused)",
- # "referer": "172.18.43.40",
- # "restOperationId": 18164160,
- # "kind": ":resterrorresponse"
- # }
- #
- # This list is provided to the specific fact manager by the
- # master ModuleManager of this module.
- self.provisioned_modules = []
-
- def exec_module(self):
- results = []
- facts = self.read_facts()
- for item in facts:
- attrs = item.to_return()
- results.append(attrs)
- return results
-
-
-class Parameters(AnsibleF5Parameters):
- @property
- def gather_subset(self):
- if isinstance(self._values['gather_subset'], string_types):
- self._values['gather_subset'] = [self._values['gather_subset']]
- elif not isinstance(self._values['gather_subset'], list):
- raise F5ModuleError(
- "The specified gather_subset must be a list."
- )
- tmp = list(set(self._values['gather_subset']))
- tmp.sort()
- self._values['gather_subset'] = tmp
-
- return self._values['gather_subset']
-
-
-class BaseParameters(Parameters):
- @property
- def enabled(self):
- return flatten_boolean(self._values['enabled'])
-
- @property
- def disabled(self):
- return flatten_boolean(self._values['disabled'])
-
- def _remove_internal_keywords(self, resource):
- resource.pop('kind', None)
- resource.pop('generation', None)
- resource.pop('selfLink', None)
- resource.pop('isSubcollection', None)
- resource.pop('fullPath', None)
-
- def to_return(self):
- result = {}
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- return result
-
-
-class AsmPolicyStatsParameters(BaseParameters):
- api_map = {
-
- }
-
- returnables = [
- 'policies',
- 'policies_active',
- 'policies_attached',
- 'policies_inactive',
- 'policies_unattached',
- ]
-
- @property
- def policies(self):
- if self._values['policies'] is None or len(self._values['policies']) == 0:
- return None
- return len(self._values['policies'])
-
- @property
- def policies_active(self):
- if self._values['policies'] is None or len(self._values['policies']) == 0:
- return None
- return len([x for x in self._values['policies'] if x['active'] is True])
-
- @property
- def policies_inactive(self):
- if self._values['policies'] is None or len(self._values['policies']) == 0:
- return None
- return len([x for x in self._values['policies'] if x['active'] is not True])
-
- @property
- def policies_attached(self):
- if self._values['policies'] is None or len(self._values['policies']) == 0:
- return None
- return len([x for x in self._values['policies'] if x['active'] is True and len(x['virtualServers']) > 0])
-
- @property
- def policies_unattached(self):
- if self._values['policies'] is None or len(self._values['policies']) == 0:
- return None
- return len([x for x in self._values['policies'] if x['active'] is True and len(x['virtualServers']) == 0])
-
-
-class AsmPolicyStatsFactManager(BaseManager):
- def __init__(self, *args, **kwargs):
- self.client = kwargs.get('client', None)
- self.module = kwargs.get('module', None)
- super(AsmPolicyStatsFactManager, self).__init__(**kwargs)
- self.want = AsmPolicyStatsParameters(params=self.module.params)
-
- def exec_module(self):
- facts = self._exec_module()
- result = dict(asm_policy_stats=facts)
- return result
-
- def _exec_module(self):
- if 'asm' not in self.provisioned_modules:
- return []
- facts = self.read_facts()
- results = facts.to_return()
- return results
-
- def read_facts(self):
- collection = self.read_collection_from_device()
- params = AsmPolicyStatsParameters(params=collection)
- return params
-
- def read_collection_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/asm/policies".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return dict(
- policies=response['items']
- )
-
-
-class AsmPolicyFactParameters(BaseParameters):
- api_map = {
- 'hasParent': 'has_parent',
- 'protocolIndependent': 'protocol_independent',
- 'virtualServers': 'virtual_servers',
- 'allowedResponseCodes': 'allowed_response_codes',
- 'learningMode': 'learning_mode',
- 'enforcementMode': 'enforcement_mode',
- 'customXffHeaders': 'custom_xff_headers',
- 'caseInsensitive': 'case_insensitive',
- 'stagingSettings': 'staging_settings',
- 'applicationLanguage': 'application_language',
- 'trustXff': 'trust_xff',
- 'geolocation-enforcement': 'geolocation_enforcement',
- 'disallowedLocations': 'disallowed_locations',
- 'signature-settings': 'signature_settings',
- 'header-settings': 'header_settings',
- 'cookie-settings': 'cookie_settings',
- 'policy-builder': 'policy_builder',
- 'disallowed-geolocations': 'disallowed_geolocations',
- 'whitelist-ips': 'whitelist_ips',
- 'fullPath': 'full_path',
- 'csrf-protection': 'csrf_protection',
- }
-
- returnables = [
- 'full_path',
- 'name',
- 'policy_id',
- 'active',
- 'protocol_independent',
- 'has_parent',
- 'type',
- 'virtual_servers',
- 'allowed_response_codes',
- 'description',
- 'learning_mode',
- 'enforcement_mode',
- 'custom_xff_headers',
- 'case_insensitive',
- 'signature_staging',
- 'place_signatures_in_staging',
- 'enforcement_readiness_period',
- 'path_parameter_handling',
- 'trigger_asm_irule_event',
- 'inspect_http_uploads',
- 'mask_credit_card_numbers_in_request',
- 'maximum_http_header_length',
- 'use_dynamic_session_id_in_url',
- 'maximum_cookie_header_length',
- 'application_language',
- 'trust_xff',
- 'disallowed_geolocations',
- 'csrf_urls',
- 'csrf_protection_enabled',
- 'csrf_protection_ssl_only',
- 'csrf_protection_expiration_time_in_seconds',
- ]
-
- def _morph_keys(self, key_map, item):
- for k, v in iteritems(key_map):
- item[v] = item.pop(k, None)
- result = self._filter_params(item)
- return result
-
- @property
- def active(self):
- return flatten_boolean(self._values['active'])
-
- @property
- def case_insensitive(self):
- return flatten_boolean(self._values['case_insensitive'])
-
- @property
- def has_parent(self):
- return flatten_boolean(self._values['has_parent'])
-
- @property
- def policy_id(self):
- if self._values['id'] is None:
- return None
- return self._values['id']
-
- @property
- def signature_staging(self):
- if 'staging_settings' in self._values:
- if self._values['staging_settings'] is None:
- return None
- if 'signatureStaging' in self._values['staging_settings']:
- return flatten_boolean(self._values['staging_settings']['signatureStaging'])
- if 'signature_settings' in self._values:
- if self._values['signature_settings'] is None:
- return None
- if 'signatureStaging' in self._values['signature_settings']:
- return flatten_boolean(self._values['signature_settings']['signatureStaging'])
-
- @property
- def place_signatures_in_staging(self):
- if 'staging_settings' in self._values:
- if self._values['staging_settings'] is None:
- return None
- if 'placeSignaturesInStaging' in self._values['staging_settings']:
- return flatten_boolean(self._values['staging_settings']['placeSignaturesInStaging'])
- if 'signature_settings' in self._values:
- if self._values['signature_settings'] is None:
- return None
- if 'signatureStaging' in self._values['signature_settings']:
- return flatten_boolean(self._values['signature_settings']['placeSignaturesInStaging'])
-
- @property
- def enforcement_readiness_period(self):
- if 'staging_settings' in self._values:
- if self._values['staging_settings'] is None:
- return None
- if 'enforcementReadinessPeriod' in self._values['staging_settings']:
- return self._values['staging_settings']['enforcementReadinessPeriod']
- if 'general' in self._values:
- if self._values['general'] is None:
- return None
- if 'signatureStaging' in self._values['general']:
- return self._values['general']['enforcementReadinessPeriod']
-
- @property
- def path_parameter_handling(self):
- if 'attributes' in self._values:
- if self._values['attributes'] is None:
- return None
- if 'pathParameterHandling' in self._values['attributes']:
- return self._values['attributes']['pathParameterHandling']
- if 'general' in self._values:
- if self._values['general'] is None:
- return None
- if 'pathParameterHandling' in self._values['general']:
- return self._values['general']['pathParameterHandling']
-
- @property
- def trigger_asm_irule_event(self):
- if 'attributes' in self._values:
- if self._values['attributes'] is None:
- return None
- if 'triggerAsmIruleEvent' in self._values['attributes']:
- return self._values['attributes']['triggerAsmIruleEvent']
- if 'general' in self._values:
- if self._values['general'] is None:
- return None
- if 'triggerAsmIruleEvent' in self._values['general']:
- return self._values['general']['triggerAsmIruleEvent']
-
- @property
- def inspect_http_uploads(self):
- if 'attributes' in self._values:
- if self._values['attributes'] is None:
- return None
- if 'inspectHttpUploads' in self._values['attributes']:
- return flatten_boolean(self._values['attributes']['inspectHttpUploads'])
- if 'antivirus' in self._values:
- if self._values['antivirus'] is None:
- return None
- if 'inspectHttpUploads' in self._values['antivirus']:
- return flatten_boolean(self._values['antivirus']['inspectHttpUploads'])
-
- @property
- def mask_credit_card_numbers_in_request(self):
- if 'attributes' in self._values:
- if self._values['attributes'] is None:
- return None
- if 'maskCreditCardNumbersInRequest' in self._values['attributes']:
- return flatten_boolean(self._values['attributes']['maskCreditCardNumbersInRequest'])
- if 'general' in self._values:
- if self._values['general'] is None:
- return None
- if 'maskCreditCardNumbersInRequest' in self._values['general']:
- return flatten_boolean(self._values['general']['maskCreditCardNumbersInRequest'])
-
- @property
- def maximum_http_header_length(self):
- if 'attributes' in self._values:
- if self._values['attributes'] is None:
- return None
- if 'maximumHttpHeaderLength' in self._values['attributes']:
- if self._values['attributes']['maximumHttpHeaderLength'] == 'any':
- return 'any'
- return int(self._values['attributes']['maximumHttpHeaderLength'])
-
- if 'header_settings' in self._values:
- if self._values['header_settings'] is None:
- return None
- if 'maximumHttpHeaderLength' in self._values['header_settings']:
- if self._values['header_settings']['maximumHttpHeaderLength'] == 'any':
- return 'any'
- return int(self._values['header_settings']['maximumHttpHeaderLength'])
-
- @property
- def use_dynamic_session_id_in_url(self):
- if 'attributes' in self._values:
- if self._values['attributes'] is None:
- return None
- if 'useDynamicSessionIdInUrl' in self._values['attributes']:
- return flatten_boolean(self._values['attributes']['useDynamicSessionIdInUrl'])
- if 'general' in self._values:
- if self._values['general'] is None:
- return None
- if 'useDynamicSessionIdInUrl' in self._values['general']:
- return flatten_boolean(self._values['general']['useDynamicSessionIdInUrl'])
-
- @property
- def maximum_cookie_header_length(self):
- if 'attributes' in self._values:
- if self._values['attributes'] is None:
- return None
- if 'maximumCookieHeaderLength' in self._values['attributes']:
- if self._values['attributes']['maximumCookieHeaderLength'] == 'any':
- return 'any'
- return int(self._values['attributes']['maximumCookieHeaderLength'])
- if 'cookie_settings' in self._values:
- if self._values['cookie_settings'] is None:
- return None
- if 'maximumCookieHeaderLength' in self._values['cookie_settings']:
- if self._values['cookie_settings']['maximumCookieHeaderLength'] == 'any':
- return 'any'
- return int(self._values['cookie_settings']['maximumCookieHeaderLength'])
-
- @property
- def trust_xff(self):
- if 'trust_xff' in self._values:
- if self._values['trust_xff'] is None:
- return None
- return flatten_boolean(self._values['trust_xff'])
- if 'general' in self._values:
- if self._values['general'] is None:
- return None
- if 'trustXff' in self._values['general']:
- return flatten_boolean(self._values['general']['trustXff'])
-
- @property
- def custom_xff_headers(self):
- if 'custom_xff_headers' in self._values:
- if self._values['custom_xff_headers'] is None:
- return None
- return self._values['custom_xff_headers']
- if 'general' in self._values:
- if self._values['general'] is None:
- return None
- if 'customXffHeaders' in self._values['general']:
- return self._values['general']['customXffHeaders']
-
- @property
- def allowed_response_codes(self):
- if 'allowed_response_codes' in self._values:
- if self._values['allowed_response_codes'] is None:
- return None
- return self._values['allowed_response_codes']
- if 'general' in self._values:
- if self._values['general'] is None:
- return None
- if 'allowedResponseCodes' in self._values['general']:
- return self._values['general']['allowedResponseCodes']
-
- @property
- def learning_mode(self):
- if 'policy_builder' in self._values:
- if self._values['policy_builder'] is None:
- return None
- if 'learningMode' in self._values['policy_builder']:
- return self._values['policy_builder']['learningMode']
-
- @property
- def disallowed_locations(self):
- if 'geolocation_enforcement' in self._values:
- if self._values['geolocation_enforcement'] is None:
- return None
- return self._values['geolocation_enforcement']['disallowedLocations']
-
- @property
- def disallowed_geolocations(self):
- if 'disallowed_geolocations' in self._values:
- if self._values['disallowed_geolocations'] is None:
- return None
- return self._values['disallowed_geolocations']
-
- @property
- def csrf_protection_enabled(self):
- if 'csrf_protection' in self._values:
- return flatten_boolean(self._values['csrf_protection']['enabled'])
-
- @property
- def csrf_protection_ssl_only(self):
- if 'csrf_protection' in self._values:
- if 'sslOnly' in self._values['csrf_protection']:
- return flatten_boolean(self._values['csrf_protection']['sslOnly'])
-
- @property
- def csrf_protection_expiration_time_in_seconds(self):
- if 'csrf_protection' in self._values:
- if 'expirationTimeInSeconds' in self._values['csrf_protection']:
- if self._values['csrf_protection']['expirationTimeInSeconds'] is None:
- return None
- if self._values['csrf_protection']['expirationTimeInSeconds'] == 'disabled':
- return 'disabled'
- return int(self._values['csrf_protection']['expirationTimeInSeconds'])
-
- def format_csrf_collection(self, items):
- result = list()
- key_map = {
- 'requiredParameters': 'csrf_url_required_parameters',
- 'url': 'csrf_url',
- 'method': 'csrf_url_method',
- 'enforcementAction': 'csrf_url_enforcement_action',
- 'id': 'csrf_url_id',
- 'wildcardOrder': 'csrf_url_wildcard_order',
- 'parametersList': 'csrf_url_parameters_list'
- }
- for item in items:
- self._remove_internal_keywords(item)
- item.pop('lastUpdateMicros')
- output = self._morph_keys(key_map, item)
- result.append(output)
- return result
-
- @property
- def csrf_urls(self):
- if 'csrfUrls' in self._values:
- if self._values['csrfUrls'] is None:
- return None
- return self._values['csrfUrls']
- if 'csrf-urls' in self._values:
- if self._values['csrf-urls'] is None:
- return None
- return self.format_csrf_collection(self._values['csrf-urls'])
-
- @property
- def protocol_independent(self):
- return flatten_boolean(self._values['protocol_independent'])
-
-
-# TODO include: web-scraping,ip-intelligence,session-tracking,
-# TODO login-enforcement,data-guard,redirection-protection,vulnerability-assessment, parentPolicyReference
-
-
-class AsmPolicyFactManager(BaseManager):
- def __init__(self, *args, **kwargs):
- self.client = kwargs.get('client', None)
- self.module = kwargs.get('module', None)
- super(AsmPolicyFactManager, self).__init__(**kwargs)
- self.want = AsmPolicyFactParameters(params=self.module.params)
-
- def exec_module(self):
- facts = self._exec_module()
- result = dict(asm_policies=facts)
- return result
-
- def _exec_module(self):
- if 'asm' not in self.provisioned_modules:
- return []
- manager = self.get_manager()
- return manager._exec_module()
-
- def get_manager(self):
- if self.version_is_less_than_13():
- return AsmPolicyFactManagerV12(**self.kwargs)
- else:
- return AsmPolicyFactManagerV13(**self.kwargs)
-
- def version_is_less_than_13(self):
- version = tmos_version(self.client)
- if LooseVersion(version) < LooseVersion('13.0.0'):
- return True
- else:
- return False
-
- def read_facts(self):
- results = []
- collection = self.increment_read()
- for resource in collection:
- params = AsmPolicyFactParameters(params=resource)
- results.append(params)
- return results
-
- def increment_read(self):
- n = 0
- result = []
- while True:
- items = self.read_collection_from_device(skip=n)
- if not items:
- break
- result.extend(items)
- n = n + 10
- return result
-
-
-class AsmPolicyFactManagerV12(AsmPolicyFactManager):
- def _exec_module(self):
- results = []
- facts = self.read_facts()
- for item in facts:
- attrs = item.to_return()
- results.append(attrs)
- results = sorted(results, key=lambda k: k['full_path'])
- return results
-
- def read_collection_from_device(self, skip=0):
- uri = "https://{0}:{1}/mgmt/tm/asm/policies".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
-
- to_expand = 'policy-builder,geolocation-enforcement,csrf-protection'
- query = '?$top=10&$skip={0}&$expand={1}'.format(skip, to_expand)
-
- resp = self.client.api.get(uri + query)
-
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- if 'items' not in response:
- return None
- return response['items']
-
-
-class AsmPolicyFactManagerV13(AsmPolicyFactManager):
- def _exec_module(self):
- results = []
- facts = self.read_facts()
- for item in facts:
- attrs = item.to_return()
- results.append(attrs)
- results = sorted(results, key=lambda k: k['full_path'])
- return results
-
- def read_collection_from_device(self, skip=0):
- uri = "https://{0}:{1}/mgmt/tm/asm/policies".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- to_expand = 'general,signature-settings,header-settings,cookie-settings,antivirus,' \
- 'policy-builder,csrf-protection,csrf-urls'
- query = '?$top=10&$skip={0}&$expand={1}'.format(skip, to_expand)
- resp = self.client.api.get(uri + query)
-
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- if 'items' not in response:
- return None
-
- return response['items']
-
-
-class AsmServerTechnologyFactParameters(BaseParameters):
- api_map = {
- 'serverTechnologyName': 'server_technology_name',
- 'serverTechnologyReferences': 'server_technology_references',
- }
-
- returnables = [
- 'id',
- 'server_technology_name',
- 'server_technology_references',
- ]
-
-
-class AsmServerTechnologyFactManager(BaseManager):
- def __init__(self, *args, **kwargs):
- self.client = kwargs.get('client', None)
- self.module = kwargs.get('module', None)
- super(AsmServerTechnologyFactManager, self).__init__(**kwargs)
- self.want = AsmServerTechnologyFactParameters(params=self.module.params)
-
- def exec_module(self):
- facts = self._exec_module()
- result = dict(asm_server_technologies=facts)
- return result
-
- def _exec_module(self):
- results = []
- if 'asm' not in self.provisioned_modules:
- return results
- if self.version_is_less_than_13():
- return results
- facts = self.read_facts()
- for item in facts:
- attrs = item.to_return()
- results.append(attrs)
- results = sorted(results, key=lambda k: k['server_technology_name'])
- return results
-
- def version_is_less_than_13(self):
- version = tmos_version(self.client)
- if LooseVersion(version) < LooseVersion('13.0.0'):
- return True
- else:
- return False
-
- def read_facts(self):
- results = []
- collection = self.read_collection_from_device()
- for resource in collection:
- params = AsmServerTechnologyFactParameters(params=resource)
- results.append(params)
- return results
-
- def read_collection_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/asm/server-technologies".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- if 'items' not in response:
- return []
- result = response['items']
- return result
-
-
-class AsmSignatureSetsFactParameters(BaseParameters):
- api_map = {
- 'isUserDefined': 'is_user_defined',
- 'assignToPolicyByDefault': 'assign_to_policy_by_default',
- 'defaultAlarm': 'default_alarm',
- 'defaultBlock': 'default_block',
- 'defaultLearn': 'default_learn',
- }
-
- returnables = [
- 'name',
- 'id',
- 'type',
- 'category',
- 'is_user_defined',
- 'assign_to_policy_by_default',
- 'default_alarm',
- 'default_block',
- 'default_learn',
- ]
-
- @property
- def is_user_defined(self):
- return flatten_boolean(self._values['is_user_defined'])
-
- @property
- def assign_to_policy_by_default(self):
- return flatten_boolean(self._values['assign_to_policy_by_default'])
-
- @property
- def default_alarm(self):
- return flatten_boolean(self._values['default_alarm'])
-
- @property
- def default_block(self):
- return flatten_boolean(self._values['default_block'])
-
- @property
- def default_learn(self):
- return flatten_boolean(self._values['default_learn'])
-
-# TODO: add the following: filter, systems, signatureReferences
-
-
-class AsmSignatureSetsFactManager(BaseManager):
- def __init__(self, *args, **kwargs):
- self.client = kwargs.get('client', None)
- self.module = kwargs.get('module', None)
- super(AsmSignatureSetsFactManager, self).__init__(**kwargs)
- self.want = AsmSignatureSetsFactParameters(params=self.module.params)
-
- def exec_module(self):
- facts = self._exec_module()
- result = dict(asm_signature_sets=facts)
- return result
-
- def _exec_module(self):
- results = []
- if 'asm' not in self.provisioned_modules:
- return results
- facts = self.read_facts()
- for item in facts:
- attrs = item.to_return()
- results.append(attrs)
- results = sorted(results, key=lambda k: k['name'])
- return results
-
- def read_facts(self):
- results = []
- collection = self.increment_read()
- for resource in collection:
- params = AsmSignatureSetsFactParameters(params=resource)
- results.append(params)
- return results
-
- def increment_read(self):
- n = 0
- result = []
- while True:
- items = self.read_collection_from_device(skip=n)
- if not items:
- break
- result.extend(items)
- n = n + 5
- return result
-
- def read_collection_from_device(self, skip=0):
- uri = "https://{0}:{1}/mgmt/tm/asm/signature-sets".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- query = '?$top=5&$skip={0}'.format(skip)
- resp = self.client.api.get(uri + query)
-
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- if 'items' not in response:
- return None
-
- return response['items']
-
-
-class ClientSslProfilesParameters(BaseParameters):
- api_map = {
- 'fullPath': 'full_path',
- 'alertTimeout': 'alert_timeout',
- 'allowNonSsl': 'allow_non_ssl',
- 'authenticateDepth': 'authenticate_depth',
- 'authenticate': 'authenticate_frequency',
- 'caFile': 'ca_file',
- 'cacheSize': 'cache_size',
- 'cacheTimeout': 'cache_timeout',
- 'cert': 'certificate_file',
- 'chain': 'chain_file',
- 'crlFile': 'crl_file',
- 'defaultsFrom': 'parent',
- 'modSslMethods': 'modssl_methods',
- 'peerCertMode': 'peer_certification_mode',
- 'sniRequire': 'sni_require',
- 'strictResume': 'strict_resume',
- 'mode': 'profile_mode_enabled',
- 'renegotiateMaxRecordDelay': 'renegotiation_maximum_record_delay',
- 'renegotiatePeriod': 'renegotiation_period',
- 'serverName': 'server_name',
- 'sessionTicket': 'session_ticket',
- 'sniDefault': 'sni_default',
- 'uncleanShutdown': 'unclean_shutdown',
- 'retainCertificate': 'retain_certificate',
- 'secureRenegotiation': 'secure_renegotiation_mode',
- 'handshakeTimeout': 'handshake_timeout',
- 'certExtensionIncludes': 'forward_proxy_certificate_extension_include',
- 'certLifespan': 'forward_proxy_certificate_lifespan',
- 'certLookupByIpaddrPort': 'forward_proxy_lookup_by_ipaddr_port',
- 'sslForwardProxy': 'forward_proxy_enabled',
- 'proxyCaPassphrase': 'forward_proxy_ca_passphrase',
- 'proxyCaCert': 'forward_proxy_ca_certificate_file',
- 'proxyCaKey': 'forward_proxy_ca_key_file'
- }
-
- returnables = [
- 'full_path',
- 'name',
- 'alert_timeout',
- 'allow_non_ssl',
- 'authenticate_depth',
- 'authenticate_frequency',
- 'ca_file',
- 'cache_size',
- 'cache_timeout',
- 'certificate_file',
- 'chain_file',
- 'ciphers',
- 'crl_file',
- 'parent',
- 'description',
- 'modssl_methods',
- 'peer_certification_mode',
- 'sni_require',
- 'sni_default',
- 'strict_resume',
- 'profile_mode_enabled',
- 'renegotiation_maximum_record_delay',
- 'renegotiation_period',
- 'renegotiation',
- 'server_name',
- 'session_ticket',
- 'unclean_shutdown',
- 'retain_certificate',
- 'secure_renegotiation_mode',
- 'handshake_timeout',
- 'forward_proxy_certificate_extension_include',
- 'forward_proxy_certificate_lifespan',
- 'forward_proxy_lookup_by_ipaddr_port',
- 'forward_proxy_enabled',
- 'forward_proxy_ca_passphrase',
- 'forward_proxy_ca_certificate_file',
- 'forward_proxy_ca_key_file'
- ]
-
- @property
- def alert_timeout(self):
- if self._values['alert_timeout'] is None:
- return None
- if self._values['alert_timeout'] == 'indefinite':
- return 0
- return int(self._values['alert_timeout'])
-
- @property
- def renegotiation_maximum_record_delay(self):
- if self._values['renegotiation_maximum_record_delay'] is None:
- return None
- if self._values['renegotiation_maximum_record_delay'] == 'indefinite':
- return 0
- return int(self._values['renegotiation_maximum_record_delay'])
-
- @property
- def renegotiation_period(self):
- if self._values['renegotiation_period'] is None:
- return None
- if self._values['renegotiation_period'] == 'indefinite':
- return 0
- return int(self._values['renegotiation_period'])
-
- @property
- def handshake_timeout(self):
- if self._values['handshake_timeout'] is None:
- return None
- if self._values['handshake_timeout'] == 'indefinite':
- return 0
- return int(self._values['handshake_timeout'])
-
- @property
- def allow_non_ssl(self):
- if self._values['allow_non_ssl'] is None:
- return None
- if self._values['allow_non_ssl'] == 'disabled':
- return 'no'
- return 'yes'
-
- @property
- def forward_proxy_enabled(self):
- if self._values['forward_proxy_enabled'] is None:
- return None
- if self._values['forward_proxy_enabled'] == 'disabled':
- return 'no'
- return 'yes'
-
- @property
- def renegotiation(self):
- if self._values['renegotiation'] is None:
- return None
- if self._values['renegotiation'] == 'disabled':
- return 'no'
- return 'yes'
-
- @property
- def forward_proxy_lookup_by_ipaddr_port(self):
- if self._values['forward_proxy_lookup_by_ipaddr_port'] is None:
- return None
- if self._values['forward_proxy_lookup_by_ipaddr_port'] == 'disabled':
- return 'no'
- return 'yes'
-
- @property
- def unclean_shutdown(self):
- if self._values['unclean_shutdown'] is None:
- return None
- if self._values['unclean_shutdown'] == 'disabled':
- return 'no'
- return 'yes'
-
- @property
- def session_ticket(self):
- if self._values['session_ticket'] is None:
- return None
- if self._values['session_ticket'] == 'disabled':
- return 'no'
- return 'yes'
-
- @property
- def retain_certificate(self):
- if self._values['retain_certificate'] is None:
- return None
- if self._values['retain_certificate'] == 'true':
- return 'yes'
- return 'no'
-
- @property
- def server_name(self):
- if self._values['server_name'] in [None, 'none']:
- return None
- return self._values['server_name']
-
- @property
- def forward_proxy_ca_certificate_file(self):
- if self._values['forward_proxy_ca_certificate_file'] in [None, 'none']:
- return None
- return self._values['forward_proxy_ca_certificate_file']
-
- @property
- def forward_proxy_ca_key_file(self):
- if self._values['forward_proxy_ca_key_file'] in [None, 'none']:
- return None
- return self._values['forward_proxy_ca_key_file']
-
- @property
- def authenticate_frequency(self):
- if self._values['authenticate_frequency'] is None:
- return None
- return self._values['authenticate_frequency']
-
- @property
- def ca_file(self):
- if self._values['ca_file'] in [None, 'none']:
- return None
- return self._values['ca_file']
-
- @property
- def certificate_file(self):
- if self._values['certificate_file'] in [None, 'none']:
- return None
- return self._values['certificate_file']
-
- @property
- def chain_file(self):
- if self._values['chain_file'] in [None, 'none']:
- return None
- return self._values['chain_file']
-
- @property
- def crl_file(self):
- if self._values['crl_file'] in [None, 'none']:
- return None
- return self._values['crl_file']
-
- @property
- def ciphers(self):
- if self._values['ciphers'] in [None, 'none']:
- return None
- return self._values['ciphers'].split(' ')
-
- @property
- def modssl_methods(self):
- if self._values['modssl_methods'] is None:
- return None
- if self._values['modssl_methods'] == 'disabled':
- return 'no'
- return 'yes'
-
- @property
- def strict_resume(self):
- if self._values['strict_resume'] is None:
- return None
- if self._values['strict_resume'] == 'disabled':
- return 'no'
- return 'yes'
-
- @property
- def profile_mode_enabled(self):
- if self._values['profile_mode_enabled'] is None:
- return None
- if self._values['profile_mode_enabled'] == 'disabled':
- return 'no'
- return 'yes'
-
- @property
- def sni_require(self):
- if self._values['sni_require'] is None:
- return None
- if self._values['sni_require'] == 'false':
- return 'no'
- return 'yes'
-
- @property
- def sni_default(self):
- if self._values['sni_default'] is None:
- return None
- if self._values['sni_default'] == 'false':
- return 'no'
- return 'yes'
-
-
-class ClientSslProfilesFactManager(BaseManager):
- def __init__(self, *args, **kwargs):
- self.client = kwargs.get('client', None)
- self.module = kwargs.get('module', None)
- super(ClientSslProfilesFactManager, self).__init__(**kwargs)
- self.want = ClientSslProfilesParameters(params=self.module.params)
-
- def exec_module(self):
- facts = self._exec_module()
- result = dict(client_ssl_profiles=facts)
- return result
-
- def _exec_module(self):
- results = []
- facts = self.read_facts()
- for item in facts:
- attrs = item.to_return()
- results.append(attrs)
- results = sorted(results, key=lambda k: k['full_path'])
- return results
-
- def read_facts(self):
- results = []
- collection = self.read_collection_from_device()
- for resource in collection:
- params = ClientSslProfilesParameters(params=resource)
- results.append(params)
- return results
-
- def read_collection_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/profile/client-ssl".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- if 'items' not in response:
- return []
- result = response['items']
- return result
-
-
-class DeviceGroupsParameters(BaseParameters):
- api_map = {
- 'fullPath': 'full_path',
- 'autoSync': 'autosync_enabled',
- 'asmSync': 'asm_sync_enabled',
- 'devicesReference': 'devices',
- 'fullLoadOnSync': 'full_load_on_sync',
- 'incrementalConfigSyncSizeMax': 'incremental_config_sync_size_maximum',
- 'networkFailover': 'network_failover_enabled'
- }
-
- returnables = [
- 'full_path',
- 'name',
- 'autosync_enabled',
- 'description',
- 'devices',
- 'full_load_on_sync',
- 'incremental_config_sync_size_maximum',
- 'network_failover_enabled',
- 'type',
- 'asm_sync_enabled'
- ]
-
- @property
- def network_failover_enabled(self):
- if self._values['network_failover_enabled'] is None:
- return None
- if self._values['network_failover_enabled'] == 'enabled':
- return 'yes'
- return 'no'
-
- @property
- def asm_sync_enabled(self):
- if self._values['asm_sync_enabled'] is None:
- return None
- if self._values['asm_sync_enabled'] == 'disabled':
- return 'no'
- return 'yes'
-
- @property
- def autosync_enabled(self):
- if self._values['autosync_enabled'] is None:
- return None
- if self._values['autosync_enabled'] == 'disabled':
- return 'no'
- return 'yes'
-
- @property
- def full_load_on_sync(self):
- if self._values['full_load_on_sync'] is None:
- return None
- if self._values['full_load_on_sync'] == 'true':
- return 'yes'
- return 'no'
-
- @property
- def devices(self):
- if self._values['devices'] is None or 'items' not in self._values['devices']:
- return None
- result = [x['fullPath'] for x in self._values['devices']['items']]
- result.sort()
- return result
-
-
-class DeviceGroupsFactManager(BaseManager):
- def __init__(self, *args, **kwargs):
- self.client = kwargs.get('client', None)
- self.module = kwargs.get('module', None)
- super(DeviceGroupsFactManager, self).__init__(**kwargs)
- self.want = DeviceGroupsParameters(params=self.module.params)
-
- def exec_module(self):
- facts = self._exec_module()
- result = dict(device_groups=facts)
- return result
-
- def _exec_module(self):
- results = []
- facts = self.read_facts()
- for item in facts:
- attrs = item.to_return()
- results.append(attrs)
- results = sorted(results, key=lambda k: k['full_path'])
- return results
-
- def read_facts(self):
- results = []
- collection = self.read_collection_from_device()
- for resource in collection:
- params = DeviceGroupsParameters(params=resource)
- results.append(params)
- return results
-
- def read_collection_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/cm/device-group/?expandSubcollections=true".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- if 'items' not in response:
- return []
- result = response['items']
- return result
-
-
-class DevicesParameters(BaseParameters):
- api_map = {
- 'fullPath': 'full_path',
- 'activeModules': 'active_modules',
- 'baseMac': 'base_mac_address',
- 'chassisId': 'chassis_id',
- 'chassisType': 'chassis_type',
- 'configsyncIp': 'configsync_address',
- 'failoverState': 'failover_state',
- 'managementIp': 'management_address',
- 'marketingName': 'marketing_name',
- 'multicastIp': 'multicast_address',
- 'optionalModules': 'optional_modules',
- 'platformId': 'platform_id',
- 'mirrorIp': 'primary_mirror_address',
- 'mirrorSecondaryIp': 'secondary_mirror_address',
- 'version': 'software_version',
- 'timeLimitedModules': 'timelimited_modules',
- 'timeZone': 'timezone',
- 'unicastAddress': 'unicast_addresses',
- 'selfDevice': 'self'
- }
-
- returnables = [
- 'full_path',
- 'name',
- 'active_modules',
- 'base_mac_address',
- 'build',
- 'chassis_id',
- 'chassis_type',
- 'comment',
- 'configsync_address',
- 'contact',
- 'description',
- 'edition',
- 'failover_state',
- 'hostname',
- 'location',
- 'management_address',
- 'marketing_name',
- 'multicast_address',
- 'optional_modules',
- 'platform_id',
- 'primary_mirror_address',
- 'product',
- 'secondary_mirror_address',
- 'self',
- 'software_version',
- 'timelimited_modules',
- 'timezone',
- 'unicast_addresses',
- ]
-
- @property
- def active_modules(self):
- if self._values['active_modules'] is None:
- return None
- result = []
- for x in self._values['active_modules']:
- parts = x.split('|')
- result += parts[2:]
- return list(set(result))
-
- @property
- def self(self):
- result = flatten_boolean(self._values['self'])
- return result
-
- @property
- def configsync_address(self):
- if self._values['configsync_address'] in [None, 'none']:
- return None
- return self._values['configsync_address']
-
- @property
- def primary_mirror_address(self):
- if self._values['primary_mirror_address'] in [None, 'any6']:
- return None
- return self._values['primary_mirror_address']
-
- @property
- def secondary_mirror_address(self):
- if self._values['secondary_mirror_address'] in [None, 'any6']:
- return None
- return self._values['secondary_mirror_address']
-
- @property
- def unicast_addresses(self):
- if self._values['unicast_addresses'] is None:
- return None
- result = []
-
- for addr in self._values['unicast_addresses']:
- tmp = {}
- for key in ['effectiveIp', 'effectivePort', 'ip', 'port']:
- if key in addr:
- renamed_key = self.convert(key)
- tmp[renamed_key] = addr.get(key, None)
- if tmp:
- result.append(tmp)
- if result:
- return result
-
- def convert(self, name):
- s1 = re.sub('(.)([A-Z][a-z]+)', r'\1_\2', name)
- return re.sub('([a-z0-9])([A-Z])', r'\1_\2', s1).lower()
-
-
-class DevicesFactManager(BaseManager):
- def __init__(self, *args, **kwargs):
- self.client = kwargs.get('client', None)
- self.module = kwargs.get('module', None)
- super(DevicesFactManager, self).__init__(**kwargs)
- self.want = DevicesParameters(params=self.module.params)
-
- def exec_module(self):
- facts = self._exec_module()
- result = dict(devices=facts)
- return result
-
- def _exec_module(self):
- results = []
- facts = self.read_facts()
- for item in facts:
- attrs = item.to_return()
- results.append(attrs)
- results = sorted(results, key=lambda k: k['full_path'])
- return results
-
- def read_facts(self):
- results = []
- collection = self.read_collection_from_device()
- for resource in collection:
- params = DevicesParameters(params=resource)
- results.append(params)
- return results
-
- def read_collection_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/cm/device".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- if 'items' not in response:
- return []
- result = response['items']
- return result
-
-
-class ExternalMonitorsParameters(BaseParameters):
- api_map = {
- 'fullPath': 'full_path',
- 'defaultsFrom': 'parent',
- 'adaptiveDivergenceType': 'adaptive_divergence_type',
- 'adaptiveDivergenceValue': 'adaptive_divergence_value',
- 'adaptiveLimit': 'adaptive_limit',
- 'adaptiveSamplingTimespan': 'adaptive_sampling_timespan',
- 'manualResume': 'manual_resume',
- 'timeUntilUp': 'time_until_up',
- 'upInterval': 'up_interval',
- 'run': 'external_program',
- 'apiRawValues': 'variables',
- }
-
- returnables = [
- 'full_path',
- 'name',
- 'parent',
- 'description',
- 'args',
- 'destination',
- 'external_program',
- 'interval',
- 'manual_resume',
- 'time_until_up',
- 'timeout',
- 'up_interval',
- 'variables',
- ]
-
- @property
- def description(self):
- if self._values['description'] in [None, 'none']:
- return None
- return self._values['description']
-
- @property
- def manual_resume(self):
- return flatten_boolean(self._values['manual_resume'])
-
- @property
- def variables(self):
- if self._values['variables'] is None:
- return None
- result = {}
- for k, v in iteritems(self._values['variables']):
- k = k.replace('userDefined ', '').strip()
- result[k] = v
- return result
-
-
-class ExternalMonitorsFactManager(BaseManager):
- def __init__(self, *args, **kwargs):
- self.client = kwargs.get('client', None)
- self.module = kwargs.get('module', None)
- super(ExternalMonitorsFactManager, self).__init__(**kwargs)
- self.want = ExternalMonitorsParameters(params=self.module.params)
-
- def exec_module(self):
- facts = self._exec_module()
- result = dict(external_monitors=facts)
- return result
-
- def _exec_module(self):
- results = []
- facts = self.read_facts()
- for item in facts:
- attrs = item.to_return()
- results.append(attrs)
- results = sorted(results, key=lambda k: k['full_path'])
- return results
-
- def read_facts(self):
- results = []
- collection = self.read_collection_from_device()
- for resource in collection:
- params = ExternalMonitorsParameters(params=resource)
- results.append(params)
- return results
-
- def read_collection_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/monitor/external".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- if 'items' not in response:
- return []
- result = response['items']
- return result
-
-
-class FastHttpProfilesParameters(BaseParameters):
- api_map = {
- 'fullPath': 'full_path',
- 'clientCloseTimeout': 'client_close_timeout',
- 'connpoolIdleTimeoutOverride': 'oneconnect_idle_timeout_override',
- 'connpoolMaxReuse': 'oneconnect_maximum_reuse',
- 'connpoolMaxSize': 'oneconnect_maximum_pool_size',
- 'connpoolMinSize': 'oneconnect_minimum_pool_size',
- 'connpoolReplenish': 'oneconnect_replenish',
- 'connpoolStep': 'oneconnect_ramp_up_increment',
- 'defaultsFrom': 'parent',
- 'forceHttp_10Response': 'force_http_1_0_response',
- 'headerInsert': 'request_header_insert',
- 'http_11CloseWorkarounds': 'http_1_1_close_workarounds',
- 'idleTimeout': 'idle_timeout',
- 'insertXforwardedFor': 'insert_x_forwarded_for',
- 'maxHeaderSize': 'maximum_header_size',
- 'maxRequests': 'maximum_requests',
- 'mssOverride': 'maximum_segment_size_override',
- 'receiveWindowSize': 'receive_window_size',
- 'resetOnTimeout': 'reset_on_timeout',
- 'serverCloseTimeout': 'server_close_timeout',
- 'serverSack': 'server_sack',
- 'serverTimestamp': 'server_timestamp',
- 'uncleanShutdown': 'unclean_shutdown'
- }
-
- returnables = [
- 'full_path',
- 'name',
- 'client_close_timeout',
- 'oneconnect_idle_timeout_override',
- 'oneconnect_maximum_reuse',
- 'oneconnect_maximum_pool_size',
- 'oneconnect_minimum_pool_size',
- 'oneconnect_replenish',
- 'oneconnect_ramp_up_increment',
- 'parent',
- 'description',
- 'force_http_1_0_response',
- 'request_header_insert',
- 'http_1_1_close_workarounds',
- 'idle_timeout',
- 'insert_x_forwarded_for',
- 'maximum_header_size',
- 'maximum_requests',
- 'maximum_segment_size_override',
- 'receive_window_size',
- 'reset_on_timeout',
- 'server_close_timeout',
- 'server_sack',
- 'server_timestamp',
- 'unclean_shutdown'
- ]
-
- @property
- def request_header_insert(self):
- if self._values['request_header_insert'] in [None, 'none']:
- return None
- return self._values['request_header_insert']
-
- @property
- def server_timestamp(self):
- return flatten_boolean(self._values['server_timestamp'])
-
- @property
- def server_sack(self):
- return flatten_boolean(self._values['server_sack'])
-
- @property
- def reset_on_timeout(self):
- return flatten_boolean(self._values['reset_on_timeout'])
-
- @property
- def insert_x_forwarded_for(self):
- return flatten_boolean(self._values['insert_x_forwarded_for'])
-
- @property
- def http_1_1_close_workarounds(self):
- return flatten_boolean(self._values['http_1_1_close_workarounds'])
-
- @property
- def force_http_1_0_response(self):
- return flatten_boolean(self._values['force_http_1_0_response'])
-
- @property
- def oneconnect_replenish(self):
- return flatten_boolean(self._values['oneconnect_replenish'])
-
- @property
- def idle_timeout(self):
- if self._values['idle_timeout'] is None:
- return None
- elif self._values['idle_timeout'] == 'immediate':
- return 0
- elif self._values['idle_timeout'] == 'indefinite':
- return 4294967295
- return int(self._values['idle_timeout'])
-
-
-class FastHttpProfilesFactManager(BaseManager):
- def __init__(self, *args, **kwargs):
- self.client = kwargs.get('client', None)
- self.module = kwargs.get('module', None)
- super(FastHttpProfilesFactManager, self).__init__(**kwargs)
- self.want = FastHttpProfilesParameters(params=self.module.params)
-
- def exec_module(self):
- facts = self._exec_module()
- result = dict(fasthttp_profiles=facts)
- return result
-
- def _exec_module(self):
- results = []
- facts = self.read_facts()
- for item in facts:
- attrs = item.to_return()
- results.append(attrs)
- results = sorted(results, key=lambda k: k['full_path'])
- return results
-
- def read_facts(self):
- results = []
- collection = self.read_collection_from_device()
- for resource in collection:
- params = FastHttpProfilesParameters(params=resource)
- results.append(params)
- return results
-
- def read_collection_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/profile/fasthttp".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- if 'items' not in response:
- return []
- result = response['items']
- return result
-
-
-class FastL4ProfilesParameters(BaseParameters):
- api_map = {
- 'fullPath': 'full_path',
- 'clientTimeout': 'client_timeout',
- 'defaultsFrom': 'parent',
- 'explicitFlowMigration': 'explicit_flow_migration',
- 'hardwareSynCookie': 'hardware_syn_cookie',
- 'idleTimeout': 'idle_timeout',
- 'ipDfMode': 'dont_fragment_flag',
- 'ipTosToClient': 'ip_tos_to_client',
- 'ipTosToServer': 'ip_tos_to_server',
- 'ipTtlMode': 'ttl_mode',
- 'ipTtlV4': 'ttl_v4',
- 'ipTtlV6': 'ttl_v6',
- 'keepAliveInterval': 'keep_alive_interval',
- 'lateBinding': 'late_binding',
- 'linkQosToClient': 'link_qos_to_client',
- 'linkQosToServer': 'link_qos_to_server',
- 'looseClose': 'loose_close',
- 'looseInitialization': 'loose_init',
- 'mssOverride': 'mss_override',
- 'priorityToClient': 'priority_to_client',
- 'priorityToServer': 'priority_to_server',
- 'pvaAcceleration': 'pva_acceleration',
- 'pvaDynamicClientPackets': 'pva_dynamic_client_packets',
- 'pvaDynamicServerPackets': 'pva_dynamic_server_packets',
- 'pvaFlowAging': 'pva_flow_aging',
- 'pvaFlowEvict': 'pva_flow_evict',
- 'pvaOffloadDynamic': 'pva_offload_dynamic',
- 'pvaOffloadState': 'pva_offload_state',
- 'reassembleFragments': 'reassemble_fragments',
- 'receiveWindowSize': 'receive_window',
- 'resetOnTimeout': 'reset_on_timeout',
- 'rttFromClient': 'rtt_from_client',
- 'rttFromServer': 'rtt_from_server',
- 'serverSack': 'server_sack',
- 'serverTimestamp': 'server_timestamp',
- 'softwareSynCookie': 'software_syn_cookie',
- 'synCookieEnable': 'syn_cookie_enabled',
- 'synCookieMss': 'syn_cookie_mss',
- 'synCookieWhitelist': 'syn_cookie_whitelist',
- 'tcpCloseTimeout': 'tcp_close_timeout',
- 'tcpGenerateIsn': 'generate_init_seq_number',
- 'tcpHandshakeTimeout': 'tcp_handshake_timeout',
- 'tcpStripSack': 'strip_sack',
- 'tcpTimeWaitTimeout': 'tcp_time_wait_timeout',
- 'tcpTimestampMode': 'tcp_timestamp_mode',
- 'tcpWscaleMode': 'tcp_window_scale_mode',
- 'timeoutRecovery': 'timeout_recovery',
- }
-
- returnables = [
- 'full_path',
- 'name',
- 'client_timeout',
- 'parent',
- 'description',
- 'explicit_flow_migration',
- 'hardware_syn_cookie',
- 'idle_timeout',
- 'dont_fragment_flag',
- 'ip_tos_to_client',
- 'ip_tos_to_server',
- 'ttl_mode',
- 'ttl_v4',
- 'ttl_v6',
- 'keep_alive_interval',
- 'late_binding',
- 'link_qos_to_client',
- 'link_qos_to_server',
- 'loose_close',
- 'loose_init',
- 'mss_override', # Maximum Segment Size Override
- 'priority_to_client',
- 'priority_to_server',
- 'pva_acceleration',
- 'pva_dynamic_client_packets',
- 'pva_dynamic_server_packets',
- 'pva_flow_aging',
- 'pva_flow_evict',
- 'pva_offload_dynamic',
- 'pva_offload_state',
- 'reassemble_fragments',
- 'receive_window',
- 'reset_on_timeout',
- 'rtt_from_client',
- 'rtt_from_server',
- 'server_sack',
- 'server_timestamp',
- 'software_syn_cookie',
- 'syn_cookie_enabled',
- 'syn_cookie_mss',
- 'syn_cookie_whitelist',
- 'tcp_close_timeout',
- 'generate_init_seq_number',
- 'tcp_handshake_timeout',
- 'strip_sack',
- 'tcp_time_wait_timeout',
- 'tcp_timestamp_mode',
- 'tcp_window_scale_mode',
- 'timeout_recovery',
- ]
-
- @property
- def description(self):
- if self._values['description'] in [None, 'none']:
- return None
- return self._values['description']
-
- @property
- def strip_sack(self):
- return flatten_boolean(self._values['strip_sack'])
-
- @property
- def generate_init_seq_number(self):
- return flatten_boolean(self._values['generate_init_seq_number'])
-
- @property
- def syn_cookie_whitelist(self):
- return flatten_boolean(self._values['syn_cookie_whitelist'])
-
- @property
- def syn_cookie_enabled(self):
- return flatten_boolean(self._values['syn_cookie_enabled'])
-
- @property
- def software_syn_cookie(self):
- return flatten_boolean(self._values['software_syn_cookie'])
-
- @property
- def server_timestamp(self):
- return flatten_boolean(self._values['server_timestamp'])
-
- @property
- def server_sack(self):
- return flatten_boolean(self._values['server_sack'])
-
- @property
- def rtt_from_server(self):
- return flatten_boolean(self._values['rtt_from_server'])
-
- @property
- def rtt_from_client(self):
- return flatten_boolean(self._values['rtt_from_client'])
-
- @property
- def reset_on_timeout(self):
- return flatten_boolean(self._values['reset_on_timeout'])
-
- @property
- def explicit_flow_migration(self):
- return flatten_boolean(self._values['explicit_flow_migration'])
-
- @property
- def reassemble_fragments(self):
- return flatten_boolean(self._values['reassemble_fragments'])
-
- @property
- def pva_flow_aging(self):
- return flatten_boolean(self._values['pva_flow_aging'])
-
- @property
- def pva_flow_evict(self):
- return flatten_boolean(self._values['pva_flow_evict'])
-
- @property
- def pva_offload_dynamic(self):
- return flatten_boolean(self._values['pva_offload_dynamic'])
-
- @property
- def hardware_syn_cookie(self):
- return flatten_boolean(self._values['hardware_syn_cookie'])
-
- @property
- def loose_close(self):
- return flatten_boolean(self._values['loose_close'])
-
- @property
- def loose_init(self):
- return flatten_boolean(self._values['loose_init'])
-
- @property
- def late_binding(self):
- return flatten_boolean(self._values['late_binding'])
-
- @property
- def tcp_handshake_timeout(self):
- if self._values['tcp_handshake_timeout'] is None:
- return None
- elif self._values['tcp_handshake_timeout'] == 'immediate':
- return 0
- elif self._values['tcp_handshake_timeout'] == 'indefinite':
- return 4294967295
- return int(self._values['tcp_handshake_timeout'])
-
- @property
- def idle_timeout(self):
- if self._values['idle_timeout'] is None:
- return None
- elif self._values['idle_timeout'] == 'immediate':
- return 0
- elif self._values['idle_timeout'] == 'indefinite':
- return 4294967295
- return int(self._values['idle_timeout'])
-
- @property
- def tcp_close_timeout(self):
- if self._values['tcp_close_timeout'] is None:
- return None
- elif self._values['tcp_close_timeout'] == 'immediate':
- return 0
- elif self._values['tcp_close_timeout'] == 'indefinite':
- return 4294967295
- return int(self._values['tcp_close_timeout'])
-
- @property
- def keep_alive_interval(self):
- if self._values['keep_alive_interval'] is None:
- return None
- elif self._values['keep_alive_interval'] == 'disabled':
- return 0
- return int(self._values['keep_alive_interval'])
-
- @property
- def ip_tos_to_client(self):
- if self._values['ip_tos_to_client'] is None:
- return None
- try:
- return int(self._values['ip_tos_to_client'])
- except ValueError:
- return self._values['ip_tos_to_client']
-
- @property
- def ip_tos_to_server(self):
- if self._values['ip_tos_to_server'] is None:
- return None
- try:
- return int(self._values['ip_tos_to_server'])
- except ValueError:
- return self._values['ip_tos_to_server']
-
- @property
- def link_qos_to_client(self):
- if self._values['link_qos_to_client'] is None:
- return None
- try:
- return int(self._values['link_qos_to_client'])
- except ValueError:
- return self._values['link_qos_to_client']
-
- @property
- def link_qos_to_server(self):
- if self._values['link_qos_to_server'] is None:
- return None
- try:
- return int(self._values['link_qos_to_server'])
- except ValueError:
- return self._values['link_qos_to_server']
-
- @property
- def priority_to_client(self):
- if self._values['priority_to_client'] is None:
- return None
- try:
- return int(self._values['priority_to_client'])
- except ValueError:
- return self._values['priority_to_client']
-
- @property
- def priority_to_server(self):
- if self._values['priority_to_server'] is None:
- return None
- try:
- return int(self._values['priority_to_server'])
- except ValueError:
- return self._values['priority_to_server']
-
-
-class FastL4ProfilesFactManager(BaseManager):
- def __init__(self, *args, **kwargs):
- self.client = kwargs.get('client', None)
- self.module = kwargs.get('module', None)
- super(FastL4ProfilesFactManager, self).__init__(**kwargs)
- self.want = FastL4ProfilesParameters(params=self.module.params)
-
- def exec_module(self):
- facts = self._exec_module()
- result = dict(fastl4_profiles=facts)
- return result
-
- def _exec_module(self):
- results = []
- facts = self.read_facts()
- for item in facts:
- attrs = item.to_return()
- results.append(attrs)
- results = sorted(results, key=lambda k: k['full_path'])
- return results
-
- def read_facts(self):
- results = []
- collection = self.read_collection_from_device()
- for resource in collection:
- params = FastL4ProfilesParameters(params=resource)
- results.append(params)
- return results
-
- def read_collection_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/profile/fastl4".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- if 'items' not in response:
- return []
- result = response['items']
- return result
-
-
-class GatewayIcmpMonitorsParameters(BaseParameters):
- api_map = {
- 'fullPath': 'full_path',
- 'defaultsFrom': 'parent',
- 'adaptiveDivergenceType': 'adaptive_divergence_type',
- 'adaptiveDivergenceValue': 'adaptive_divergence_value',
- 'adaptiveLimit': 'adaptive_limit',
- 'adaptiveSamplingTimespan': 'adaptive_sampling_timespan',
- 'manualResume': 'manual_resume',
- 'timeUntilUp': 'time_until_up',
- 'upInterval': 'up_interval',
- }
-
- returnables = [
- 'full_path',
- 'name',
- 'parent',
- 'description',
- 'adaptive',
- 'adaptive_divergence_type',
- 'adaptive_divergence_value',
- 'adaptive_limit',
- 'adaptive_sampling_timespan',
- 'destination',
- 'interval',
- 'manual_resume',
- 'time_until_up',
- 'timeout',
- 'transparent',
- 'up_interval',
- ]
-
- @property
- def description(self):
- if self._values['description'] in [None, 'none']:
- return None
- return self._values['description']
-
- @property
- def transparent(self):
- return flatten_boolean(self._values['transparent'])
-
- @property
- def manual_resume(self):
- return flatten_boolean(self._values['manual_resume'])
-
- @property
- def adaptive(self):
- return flatten_boolean(self._values['adaptive'])
-
-
-class GatewayIcmpMonitorsFactManager(BaseManager):
- def __init__(self, *args, **kwargs):
- self.client = kwargs.get('client', None)
- self.module = kwargs.get('module', None)
- super(GatewayIcmpMonitorsFactManager, self).__init__(**kwargs)
- self.want = GatewayIcmpMonitorsParameters(params=self.module.params)
-
- def exec_module(self):
- facts = self._exec_module()
- result = dict(gateway_icmp_monitors=facts)
- return result
-
- def _exec_module(self):
- results = []
- facts = self.read_facts()
- for item in facts:
- attrs = item.to_return()
- results.append(attrs)
- results = sorted(results, key=lambda k: k['full_path'])
- return results
-
- def read_facts(self):
- results = []
- collection = self.read_collection_from_device()
- for resource in collection:
- params = GatewayIcmpMonitorsParameters(params=resource)
- results.append(params)
- return results
-
- def read_collection_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/monitor/gateway-icmp".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- if 'items' not in response:
- return []
- result = response['items']
- return result
-
-
-class GtmXPoolsParameters(BaseParameters):
- api_map = {
- 'alternateMode': 'alternate_mode',
- 'dynamicRatio': 'dynamic_ratio',
- 'fallbackMode': 'fallback_mode',
- 'fullPath': 'full_path',
- 'loadBalancingMode': 'load_balancing_mode',
- 'manualResume': 'manual_resume',
- 'maxAnswersReturned': 'max_answers_returned',
- 'qosHitRatio': 'qos_hit_ratio',
- 'qosHops': 'qos_hops',
- 'qosKilobytesSecond': 'qos_kilobytes_second',
- 'qosLcs': 'qos_lcs',
- 'qosPacketRate': 'qos_packet_rate',
- 'qosRtt': 'qos_rtt',
- 'qosTopology': 'qos_topology',
- 'qosVsCapacity': 'qos_vs_capacity',
- 'qosVsScore': 'qos_vs_score',
- 'verifyMemberAvailability': 'verify_member_availability',
- 'membersReference': 'members'
- }
-
- returnables = [
- 'alternate_mode',
- 'dynamic_ratio',
- 'enabled',
- 'disabled',
- 'fallback_mode',
- 'full_path',
- 'load_balancing_mode',
- 'manual_resume',
- 'max_answers_returned',
- 'members',
- 'name',
- 'partition',
- 'qos_hit_ratio',
- 'qos_hops',
- 'qos_kilobytes_second',
- 'qos_lcs',
- 'qos_packet_rate',
- 'qos_rtt',
- 'qos_topology',
- 'qos_vs_capacity',
- 'qos_vs_score',
- 'ttl',
- 'verify_member_availability',
- ]
-
- @property
- def verify_member_availability(self):
- return flatten_boolean(self._values['verify_member_availability'])
-
- @property
- def dynamic_ratio(self):
- return flatten_boolean(self._values['dynamic_ratio'])
-
- @property
- def max_answers_returned(self):
- if self._values['max_answers_returned'] is None:
- return None
- return int(self._values['max_answers_returned'])
-
- @property
- def members(self):
- result = []
- if self._values['members'] is None or 'items' not in self._values['members']:
- return result
- for item in self._values['members']['items']:
- self._remove_internal_keywords(item)
- if 'disabled' in item:
- item['disabled'] = flatten_boolean(item['disabled'])
- item['enabled'] = flatten_boolean(not item['disabled'])
- if 'enabled' in item:
- item['enabled'] = flatten_boolean(item['enabled'])
- item['disabled'] = flatten_boolean(not item['enabled'])
- if 'fullPath' in item:
- item['full_path'] = item.pop('fullPath')
- if 'memberOrder' in item:
- item['member_order'] = int(item.pop('memberOrder'))
- # Cast some attributes to integer
- for x in ['order', 'preference', 'ratio', 'service']:
- if x in item:
- item[x] = int(item[x])
- result.append(item)
- return result
-
- @property
- def qos_hit_ratio(self):
- if self._values['qos_hit_ratio'] is None:
- return None
- return int(self._values['qos_hit_ratio'])
-
- @property
- def qos_hops(self):
- if self._values['qos_hops'] is None:
- return None
- return int(self._values['qos_hops'])
-
- @property
- def qos_kilobytes_second(self):
- if self._values['qos_kilobytes_second'] is None:
- return None
- return int(self._values['qos_kilobytes_second'])
-
- @property
- def qos_lcs(self):
- if self._values['qos_lcs'] is None:
- return None
- return int(self._values['qos_lcs'])
-
- @property
- def qos_packet_rate(self):
- if self._values['qos_packet_rate'] is None:
- return None
- return int(self._values['qos_packet_rate'])
-
- @property
- def qos_rtt(self):
- if self._values['qos_rtt'] is None:
- return None
- return int(self._values['qos_rtt'])
-
- @property
- def qos_topology(self):
- if self._values['qos_topology'] is None:
- return None
- return int(self._values['qos_topology'])
-
- @property
- def qos_vs_capacity(self):
- if self._values['qos_vs_capacity'] is None:
- return None
- return int(self._values['qos_vs_capacity'])
-
- @property
- def qos_vs_score(self):
- if self._values['qos_vs_score'] is None:
- return None
- return int(self._values['qos_vs_score'])
-
- @property
- def availability_state(self):
- if self._values['stats'] is None:
- return None
- try:
- result = self._values['stats']['status']['availabilityState']
- return result['description']
- except AttributeError:
- return None
-
- @property
- def enabled_state(self):
- if self._values['stats'] is None:
- return None
- try:
- result = self._values['stats']['status']['enabledState']
- return result['description']
- except AttributeError:
- return None
-
- @property
- def availability_status(self):
- # This fact is a combination of the availability_state and enabled_state
- #
- # The purpose of the fact is to give a higher-level view of the availability
- # of the pool, that can be used in playbooks. If you need further detail,
- # consider using the following facts together.
- #
- # - availability_state
- # - enabled_state
- #
- if self.enabled_state == 'enabled':
- if self.availability_state == 'offline':
- return 'red'
- elif self.availability_state == 'available':
- return 'green'
- elif self.availability_state == 'unknown':
- return 'blue'
- else:
- return 'none'
- else:
- # disabled
- return 'black'
-
- @property
- def manual_resume(self):
- return flatten_boolean(self._values['manual_resume'])
-
-
-class GtmAPoolsFactManager(BaseManager):
- def __init__(self, *args, **kwargs):
- self.client = kwargs.get('client', None)
- self.module = kwargs.get('module', None)
- super(GtmAPoolsFactManager, self).__init__(**kwargs)
- self.want = GtmXPoolsParameters(params=self.module.params)
-
- def exec_module(self):
- facts = self._exec_module()
- result = dict(gtm_a_pools=facts)
- return result
-
- def _exec_module(self):
- if 'gtm' not in self.provisioned_modules:
- return []
- results = []
- facts = self.read_facts()
- for item in facts:
- attrs = item.to_return()
- results.append(attrs)
- results = sorted(results, key=lambda k: k['full_path'])
- return results
-
- def read_facts(self):
- results = []
- collection = self.read_collection_from_device()
- for resource in collection:
- params = GtmXPoolsParameters(params=resource)
- results.append(params)
- return results
-
- def read_collection_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/gtm/pool/a".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- query = "?expandSubcollections=true"
- resp = self.client.api.get(uri + query)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- if 'items' not in response:
- return []
- result = response['items']
- return result
-
-
-class GtmAaaaPoolsFactManager(BaseManager):
- def __init__(self, *args, **kwargs):
- self.client = kwargs.get('client', None)
- self.module = kwargs.get('module', None)
- super(GtmAaaaPoolsFactManager, self).__init__(**kwargs)
- self.want = GtmXPoolsParameters(params=self.module.params)
-
- def exec_module(self):
- facts = self._exec_module()
- result = dict(gtm_aaaa_pools=facts)
- return result
-
- def _exec_module(self):
- if 'gtm' not in self.provisioned_modules:
- return []
- results = []
- facts = self.read_facts()
- for item in facts:
- attrs = item.to_return()
- results.append(attrs)
- results = sorted(results, key=lambda k: k['full_path'])
- return results
-
- def read_facts(self):
- results = []
- collection = self.read_collection_from_device()
- for resource in collection:
- params = GtmXPoolsParameters(params=resource)
- results.append(params)
- return results
-
- def read_collection_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/gtm/pool/aaaa".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- query = "?expandSubcollections=true"
- resp = self.client.api.get(uri + query)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- if 'items' not in response:
- return []
- result = response['items']
- return result
-
-
-class GtmCnamePoolsFactManager(BaseManager):
- def __init__(self, *args, **kwargs):
- self.client = kwargs.get('client', None)
- self.module = kwargs.get('module', None)
- super(GtmCnamePoolsFactManager, self).__init__(**kwargs)
- self.want = GtmXPoolsParameters(params=self.module.params)
-
- def exec_module(self):
- facts = self._exec_module()
- result = dict(gtm_cname_pools=facts)
- return result
-
- def _exec_module(self):
- if 'gtm' not in self.provisioned_modules:
- return []
- results = []
- facts = self.read_facts()
- for item in facts:
- attrs = item.to_return()
- results.append(attrs)
- results = sorted(results, key=lambda k: k['full_path'])
- return results
-
- def read_facts(self):
- results = []
- collection = self.read_collection_from_device()
- for resource in collection:
- params = GtmXPoolsParameters(params=resource)
- results.append(params)
- return results
-
- def read_collection_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/gtm/pool/cname".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- query = "?expandSubcollections=true"
- resp = self.client.api.get(uri + query)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- if 'items' not in response:
- return []
- result = response['items']
- return result
-
-
-class GtmMxPoolsFactManager(BaseManager):
- def __init__(self, *args, **kwargs):
- self.client = kwargs.get('client', None)
- self.module = kwargs.get('module', None)
- super(GtmMxPoolsFactManager, self).__init__(**kwargs)
- self.want = GtmXPoolsParameters(params=self.module.params)
-
- def exec_module(self):
- facts = self._exec_module()
- result = dict(gtm_mx_pools=facts)
- return result
-
- def _exec_module(self):
- if 'gtm' not in self.provisioned_modules:
- return []
- results = []
- facts = self.read_facts()
- for item in facts:
- attrs = item.to_return()
- results.append(attrs)
- results = sorted(results, key=lambda k: k['full_path'])
- return results
-
- def read_facts(self):
- results = []
- collection = self.read_collection_from_device()
- for resource in collection:
- params = GtmXPoolsParameters(params=resource)
- results.append(params)
- return results
-
- def read_collection_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/gtm/pool/mx".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- query = "?expandSubcollections=true"
- resp = self.client.api.get(uri + query)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- if 'items' not in response:
- return []
- result = response['items']
- return result
-
-
-class GtmNaptrPoolsFactManager(BaseManager):
- def __init__(self, *args, **kwargs):
- self.client = kwargs.get('client', None)
- self.module = kwargs.get('module', None)
- super(GtmNaptrPoolsFactManager, self).__init__(**kwargs)
- self.want = GtmXPoolsParameters(params=self.module.params)
-
- def exec_module(self):
- facts = self._exec_module()
- result = dict(gtm_naptr_pools=facts)
- return result
-
- def _exec_module(self):
- if 'gtm' not in self.provisioned_modules:
- return []
- results = []
- facts = self.read_facts()
- for item in facts:
- attrs = item.to_return()
- results.append(attrs)
- results = sorted(results, key=lambda k: k['full_path'])
- return results
-
- def read_facts(self):
- results = []
- collection = self.read_collection_from_device()
- for resource in collection:
- params = GtmXPoolsParameters(params=resource)
- results.append(params)
- return results
-
- def read_collection_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/gtm/pool/naptr".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- query = "?expandSubcollections=true"
- resp = self.client.api.get(uri + query)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- if 'items' not in response:
- return []
- result = response['items']
- return result
-
-
-class GtmSrvPoolsFactManager(BaseManager):
- def __init__(self, *args, **kwargs):
- self.client = kwargs.get('client', None)
- self.module = kwargs.get('module', None)
- super(GtmSrvPoolsFactManager, self).__init__(**kwargs)
- self.want = GtmXPoolsParameters(params=self.module.params)
-
- def exec_module(self):
- facts = self._exec_module()
- result = dict(gtm_srv_pools=facts)
- return result
-
- def _exec_module(self):
- if 'gtm' not in self.provisioned_modules:
- return []
- results = []
- facts = self.read_facts()
- for item in facts:
- attrs = item.to_return()
- results.append(attrs)
- results = sorted(results, key=lambda k: k['full_path'])
- return results
-
- def read_facts(self):
- results = []
- collection = self.read_collection_from_device()
- for resource in collection:
- params = GtmXPoolsParameters(params=resource)
- results.append(params)
- return results
-
- def read_collection_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/gtm/pool/srv".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- query = "?expandSubcollections=true"
- resp = self.client.api.get(uri + query)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- if 'items' not in response:
- return []
- result = response['items']
- return result
-
-
-class GtmServersParameters(BaseParameters):
- api_map = {
- 'fullPath': 'full_path',
- 'exposeRouteDomains': 'expose_route_domains',
- 'iqAllowPath': 'iq_allow_path',
- 'iqAllowServiceCheck': 'iq_allow_service_check',
- 'iqAllowSnmp': 'iq_allow_snmp',
- 'limitCpuUsage': 'limit_cpu_usage',
- 'limitCpuUsageStatus': 'limit_cpu_usage_status',
- 'limitMaxBps': 'limit_max_bps',
- 'limitMaxBpsStatus': 'limit_max_bps_status',
- 'limitMaxConnections': 'limit_max_connections',
- 'limitMaxConnectionsStatus': 'limit_max_connections_status',
- 'limitMaxPps': 'limit_max_pps',
- 'limitMaxPpsStatus': 'limit_max_pps_status',
- 'limitMemAvail': 'limit_mem_available',
- 'limitMemAvailStatus': 'limit_mem_available_status',
- 'linkDiscovery': 'link_discovery',
- 'proberFallback': 'prober_fallback',
- 'proberPreference': 'prober_preference',
- 'virtualServerDiscovery': 'virtual_server_discovery',
- 'devicesReference': 'devices',
- 'virtualServersReference': 'virtual_servers',
- 'monitor': 'monitors',
- }
-
- returnables = [
- 'datacenter',
- 'enabled',
- 'disabled',
- 'expose_route_domains',
- 'iq_allow_path',
- 'full_path',
- 'iq_allow_service_check',
- 'iq_allow_snmp',
- 'limit_cpu_usage',
- 'limit_cpu_usage_status',
- 'limit_max_bps',
- 'limit_max_bps_status',
- 'limit_max_connections',
- 'limit_max_connections_status',
- 'limit_max_pps',
- 'limit_max_pps_status',
- 'limit_mem_available',
- 'limit_mem_available_status',
- 'link_discovery',
- 'monitors',
- 'monitor_type',
- 'name',
- 'product',
- 'prober_fallback',
- 'prober_preference',
- 'virtual_server_discovery',
- 'addresses',
- 'devices',
- 'virtual_servers',
- ]
-
- @property
- def monitors(self):
- if self._values['monitors'] is None:
- return []
- try:
- result = re.findall(r'/\w+/[^\s}]+', self._values['monitors'])
- return result
- except Exception:
- return [self._values['monitors']]
-
- @property
- def monitor_type(self):
- if self._values['monitors'] is None:
- return None
- pattern = r'min\s+\d+\s+of'
- matches = re.search(pattern, self._values['monitors'])
- if matches:
- return 'm_of_n'
- else:
- return 'and_list'
-
- @property
- def limit_mem_available_status(self):
- return flatten_boolean(self._values['limit_mem_available_status'])
-
- @property
- def limit_max_pps_status(self):
- return flatten_boolean(self._values['limit_max_pps_status'])
-
- @property
- def limit_max_connections_status(self):
- return flatten_boolean(self._values['limit_max_connections_status'])
-
- @property
- def limit_max_bps_status(self):
- return flatten_boolean(self._values['limit_max_bps_status'])
-
- @property
- def limit_cpu_usage_status(self):
- return flatten_boolean(self._values['limit_cpu_usage_status'])
-
- @property
- def iq_allow_service_check(self):
- return flatten_boolean(self._values['iq_allow_service_check'])
-
- @property
- def iq_allow_snmp(self):
- return flatten_boolean(self._values['iq_allow_snmp'])
-
- @property
- def expose_route_domains(self):
- return flatten_boolean(self._values['expose_route_domains'])
-
- @property
- def iq_allow_path(self):
- return flatten_boolean(self._values['iq_allow_path'])
-
- @property
- def product(self):
- if self._values['product'] is None:
- return None
- if self._values['product'] in ['single-bigip', 'redundant-bigip']:
- return 'bigip'
- return self._values['product']
-
- @property
- def devices(self):
- result = []
- if self._values['devices'] is None or 'items' not in self._values['devices']:
- return result
- for item in self._values['devices']['items']:
- self._remove_internal_keywords(item)
- if 'fullPath' in item:
- item['full_path'] = item.pop('fullPath')
- result.append(item)
- return result
-
- @property
- def virtual_servers(self):
- result = []
- if self._values['virtual_servers'] is None or 'items' not in self._values['virtual_servers']:
- return result
- for item in self._values['virtual_servers']['items']:
- self._remove_internal_keywords(item)
- if 'disabled' in item:
- if item['disabled'] in BOOLEANS_TRUE:
- item['disabled'] = flatten_boolean(item['disabled'])
- item['enabled'] = flatten_boolean(not item['disabled'])
- if 'enabled' in item:
- if item['enabled'] in BOOLEANS_TRUE:
- item['enabled'] = flatten_boolean(item['enabled'])
- item['disabled'] = flatten_boolean(not item['enabled'])
- if 'fullPath' in item:
- item['full_path'] = item.pop('fullPath')
- if 'limitMaxBps' in item:
- item['limit_max_bps'] = int(item.pop('limitMaxBps'))
- if 'limitMaxBpsStatus' in item:
- item['limit_max_bps_status'] = item.pop('limitMaxBpsStatus')
- if 'limitMaxConnections' in item:
- item['limit_max_connections'] = int(item.pop('limitMaxConnections'))
- if 'limitMaxConnectionsStatus' in item:
- item['limit_max_connections_status'] = item.pop('limitMaxConnectionsStatus')
- if 'limitMaxPps' in item:
- item['limit_max_pps'] = int(item.pop('limitMaxPps'))
- if 'limitMaxPpsStatus' in item:
- item['limit_max_pps_status'] = item.pop('limitMaxPpsStatus')
- if 'translationAddress' in item:
- item['translation_address'] = item.pop('translationAddress')
- if 'translationPort' in item:
- item['translation_port'] = int(item.pop('translationPort'))
- result.append(item)
- return result
-
- @property
- def limit_cpu_usage(self):
- if self._values['limit_cpu_usage'] is None:
- return None
- return int(self._values['limit_cpu_usage'])
-
- @property
- def limit_max_bps(self):
- if self._values['limit_max_bps'] is None:
- return None
- return int(self._values['limit_max_bps'])
-
- @property
- def limit_max_connections(self):
- if self._values['limit_max_connections'] is None:
- return None
- return int(self._values['limit_max_connections'])
-
- @property
- def limit_max_pps(self):
- if self._values['limit_max_pps'] is None:
- return None
- return int(self._values['limit_max_pps'])
-
- @property
- def limit_mem_available(self):
- if self._values['limit_mem_available'] is None:
- return None
- return int(self._values['limit_mem_available'])
-
-
-class GtmServersFactManager(BaseManager):
- def __init__(self, *args, **kwargs):
- self.client = kwargs.get('client', None)
- self.module = kwargs.get('module', None)
- super(GtmServersFactManager, self).__init__(**kwargs)
- self.want = GtmServersParameters(params=self.module.params)
-
- def exec_module(self):
- facts = self._exec_module()
- result = dict(gtm_servers=facts)
- return result
-
- def _exec_module(self):
- if 'gtm' not in self.provisioned_modules:
- return []
- results = []
- facts = self.read_facts()
- for item in facts:
- attrs = item.to_return()
- results.append(attrs)
- results = sorted(results, key=lambda k: k['full_path'])
- return results
-
- def read_facts(self):
- results = []
- collection = self.read_collection_from_device()
- for resource in collection:
- params = GtmServersParameters(params=resource)
- results.append(params)
- return results
-
- def read_collection_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/gtm/server".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- if 'items' not in response:
- return []
- result = response['items']
- return result
-
-
-class GtmXWideIpsParameters(BaseParameters):
- api_map = {
- 'fullPath': 'full_path',
- 'failureRcode': 'failure_rcode',
- 'failureRcodeResponse': 'failure_rcode_response',
- 'failureRcodeTtl': 'failure_rcode_ttl',
- 'lastResortPool': 'last_resort_pool',
- 'minimalResponse': 'minimal_response',
- 'persistCidrIpv4': 'persist_cidr_ipv4',
- 'persistCidrIpv6': 'persist_cidr_ipv6',
- 'poolLbMode': 'pool_lb_mode',
- 'ttlPersistence': 'ttl_persistence'
- }
-
- returnables = [
- 'full_path',
- 'description',
- 'enabled',
- 'disabled',
- 'failure_rcode',
- 'failure_rcode_response',
- 'failure_rcode_ttl',
- 'last_resort_pool',
- 'minimal_response',
- 'name',
- 'persist_cidr_ipv4',
- 'persist_cidr_ipv6',
- 'pool_lb_mode',
- 'ttl_persistence',
- 'pools',
- ]
-
- @property
- def pools(self):
- result = []
- if self._values['pools'] is None:
- return []
- for pool in self._values['pools']:
- del pool['nameReference']
- for x in ['order', 'ratio']:
- if x in pool:
- pool[x] = int(pool[x])
- result.append(pool)
- return result
-
- @property
- def failure_rcode_response(self):
- return flatten_boolean(self._values['failure_rcode_response'])
-
- @property
- def failure_rcode_ttl(self):
- if self._values['failure_rcode_ttl'] is None:
- return None
- return int(self._values['failure_rcode_ttl'])
-
- @property
- def persist_cidr_ipv4(self):
- if self._values['persist_cidr_ipv4'] is None:
- return None
- return int(self._values['persist_cidr_ipv4'])
-
- @property
- def persist_cidr_ipv6(self):
- if self._values['persist_cidr_ipv6'] is None:
- return None
- return int(self._values['persist_cidr_ipv6'])
-
- @property
- def ttl_persistence(self):
- if self._values['ttl_persistence'] is None:
- return None
- return int(self._values['ttl_persistence'])
-
-
-class GtmAWideIpsFactManager(BaseManager):
- def __init__(self, *args, **kwargs):
- self.client = kwargs.get('client', None)
- self.module = kwargs.get('module', None)
- super(GtmAWideIpsFactManager, self).__init__(**kwargs)
- self.want = GtmXWideIpsParameters(params=self.module.params)
-
- def exec_module(self):
- facts = self._exec_module()
- result = dict(gtm_a_wide_ips=facts)
- return result
-
- def _exec_module(self):
- if 'gtm' not in self.provisioned_modules:
- return []
- results = []
- facts = self.read_facts()
- for item in facts:
- attrs = item.to_return()
- results.append(attrs)
- results = sorted(results, key=lambda k: k['full_path'])
- return results
-
- def read_facts(self):
- results = []
- collection = self.read_collection_from_device()
- for resource in collection:
- params = GtmXWideIpsParameters(params=resource)
- results.append(params)
- return results
-
- def read_collection_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/gtm/wideip/a".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- if 'items' not in response:
- return []
- result = response['items']
- return result
-
-
-class GtmAaaaWideIpsFactManager(BaseManager):
- def __init__(self, *args, **kwargs):
- self.client = kwargs.get('client', None)
- self.module = kwargs.get('module', None)
- super(GtmAaaaWideIpsFactManager, self).__init__(**kwargs)
- self.want = GtmXWideIpsParameters(params=self.module.params)
-
- def exec_module(self):
- facts = self._exec_module()
- result = dict(gtm_aaaa_wide_ips=facts)
- return result
-
- def _exec_module(self):
- if 'gtm' not in self.provisioned_modules:
- return []
- results = []
- facts = self.read_facts()
- for item in facts:
- attrs = item.to_return()
- results.append(attrs)
- results = sorted(results, key=lambda k: k['full_path'])
- return results
-
- def read_facts(self):
- results = []
- collection = self.read_collection_from_device()
- for resource in collection:
- params = GtmXWideIpsParameters(params=resource)
- results.append(params)
- return results
-
- def read_collection_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/gtm/wideip/aaaa".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- if 'items' not in response:
- return []
- result = response['items']
- return result
-
-
-class GtmCnameWideIpsFactManager(BaseManager):
- def __init__(self, *args, **kwargs):
- self.client = kwargs.get('client', None)
- self.module = kwargs.get('module', None)
- super(GtmCnameWideIpsFactManager, self).__init__(**kwargs)
- self.want = GtmXWideIpsParameters(params=self.module.params)
-
- def exec_module(self):
- facts = self._exec_module()
- result = dict(gtm_cname_wide_ips=facts)
- return result
-
- def _exec_module(self):
- if 'gtm' not in self.provisioned_modules:
- return []
- results = []
- facts = self.read_facts()
- for item in facts:
- attrs = item.to_return()
- results.append(attrs)
- results = sorted(results, key=lambda k: k['full_path'])
- return results
-
- def read_facts(self):
- results = []
- collection = self.read_collection_from_device()
- for resource in collection:
- params = GtmXWideIpsParameters(params=resource)
- results.append(params)
- return results
-
- def read_collection_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/gtm/wideip/cname".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- if 'items' not in response:
- return []
- result = response['items']
- return result
-
-
-class GtmMxWideIpsFactManager(BaseManager):
- def __init__(self, *args, **kwargs):
- self.client = kwargs.get('client', None)
- self.module = kwargs.get('module', None)
- super(GtmMxWideIpsFactManager, self).__init__(**kwargs)
- self.want = GtmXWideIpsParameters(params=self.module.params)
-
- def exec_module(self):
- facts = self._exec_module()
- result = dict(gtm_mx_wide_ips=facts)
- return result
-
- def _exec_module(self):
- if 'gtm' not in self.provisioned_modules:
- return []
- results = []
- facts = self.read_facts()
- for item in facts:
- attrs = item.to_return()
- results.append(attrs)
- results = sorted(results, key=lambda k: k['full_path'])
- return results
-
- def read_facts(self):
- results = []
- collection = self.read_collection_from_device()
- for resource in collection:
- params = GtmXWideIpsParameters(params=resource)
- results.append(params)
- return results
-
- def read_collection_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/gtm/wideip/mx".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- if 'items' not in response:
- return []
- result = response['items']
- return result
-
-
-class GtmNaptrWideIpsFactManager(BaseManager):
- def __init__(self, *args, **kwargs):
- self.client = kwargs.get('client', None)
- self.module = kwargs.get('module', None)
- super(GtmNaptrWideIpsFactManager, self).__init__(**kwargs)
- self.want = GtmXWideIpsParameters(params=self.module.params)
-
- def exec_module(self):
- facts = self._exec_module()
- result = dict(gtm_naptr_wide_ips=facts)
- return result
-
- def _exec_module(self):
- results = []
- if 'gtm' not in self.provisioned_modules:
- return []
- facts = self.read_facts()
- for item in facts:
- attrs = item.to_return()
- results.append(attrs)
- results = sorted(results, key=lambda k: k['full_path'])
- return results
-
- def read_facts(self):
- results = []
- collection = self.read_collection_from_device()
- for resource in collection:
- params = GtmXWideIpsParameters(params=resource)
- results.append(params)
- return results
-
- def read_collection_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/gtm/wideip/naptr".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- if 'items' not in response:
- return []
- result = response['items']
- return result
-
-
-class GtmSrvWideIpsFactManager(BaseManager):
- def __init__(self, *args, **kwargs):
- self.client = kwargs.get('client', None)
- self.module = kwargs.get('module', None)
- super(GtmSrvWideIpsFactManager, self).__init__(**kwargs)
- self.want = GtmXWideIpsParameters(params=self.module.params)
-
- def exec_module(self):
- facts = self._exec_module()
- result = dict(gtm_srv_wide_ips=facts)
- return result
-
- def _exec_module(self):
- if 'gtm' not in self.provisioned_modules:
- return []
- results = []
- facts = self.read_facts()
- for item in facts:
- attrs = item.to_return()
- results.append(attrs)
- results = sorted(results, key=lambda k: k['full_path'])
- return results
-
- def read_facts(self):
- results = []
- collection = self.read_collection_from_device()
- for resource in collection:
- params = GtmXWideIpsParameters(params=resource)
- results.append(params)
- return results
-
- def read_collection_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/gtm/wideip/srv".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- if 'items' not in response:
- return []
- result = response['items']
- return result
-
-
-class HttpMonitorsParameters(BaseParameters):
- api_map = {
- 'fullPath': 'full_path',
- 'defaultsFrom': 'parent',
- 'adaptiveDivergenceType': 'adaptive_divergence_type',
- 'adaptiveDivergenceValue': 'adaptive_divergence_value',
- 'adaptiveLimit': 'adaptive_limit',
- 'adaptiveSamplingTimespan': 'adaptive_sampling_timespan',
- 'ipDscp': 'ip_dscp',
- 'manualResume': 'manual_resume',
- 'recv': 'receive_string',
- 'recvDisable': 'receive_disable_string',
- 'send': 'send_string',
- 'timeUntilUp': 'time_until_up',
- 'upInterval': 'up_interval',
- }
-
- returnables = [
- 'full_path',
- 'name',
- 'parent',
- 'description',
- 'adaptive',
- 'adaptive_divergence_type',
- 'adaptive_divergence_value',
- 'adaptive_limit',
- 'adaptive_sampling_timespan',
- 'destination',
- 'interval',
- 'ip_dscp',
- 'manual_resume',
- 'receive_string',
- 'receive_disable_string',
- 'reverse',
- 'send_string',
- 'time_until_up',
- 'timeout',
- 'transparent',
- 'up_interval',
- 'username',
- ]
-
- @property
- def description(self):
- if self._values['description'] in [None, 'none']:
- return None
- return self._values['description']
-
- @property
- def transparent(self):
- return flatten_boolean(self._values['transparent'])
-
- @property
- def reverse(self):
- return flatten_boolean(self._values['reverse'])
-
- @property
- def manual_resume(self):
- return flatten_boolean(self._values['manual_resume'])
-
- @property
- def adaptive(self):
- return flatten_boolean(self._values['adaptive'])
-
-
-class HttpMonitorsFactManager(BaseManager):
- def __init__(self, *args, **kwargs):
- self.client = kwargs.get('client', None)
- self.module = kwargs.get('module', None)
- super(HttpMonitorsFactManager, self).__init__(**kwargs)
- self.want = HttpMonitorsParameters(params=self.module.params)
-
- def exec_module(self):
- facts = self._exec_module()
- result = dict(http_monitors=facts)
- return result
-
- def _exec_module(self):
- results = []
- facts = self.read_facts()
- for item in facts:
- attrs = item.to_return()
- results.append(attrs)
- results = sorted(results, key=lambda k: k['full_path'])
- return results
-
- def read_facts(self):
- results = []
- collection = self.read_collection_from_device()
- for resource in collection:
- params = HttpMonitorsParameters(params=resource)
- results.append(params)
- return results
-
- def read_collection_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/monitor/http".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- result = response['items']
- return result
-
-
-class HttpsMonitorsParameters(BaseParameters):
- api_map = {
- 'fullPath': 'full_path',
- 'defaultsFrom': 'parent',
- 'adaptiveDivergenceType': 'adaptive_divergence_type',
- 'adaptiveDivergenceValue': 'adaptive_divergence_value',
- 'adaptiveLimit': 'adaptive_limit',
- 'adaptiveSamplingTimespan': 'adaptive_sampling_timespan',
- 'ipDscp': 'ip_dscp',
- 'manualResume': 'manual_resume',
- 'recv': 'receive_string',
- 'recvDisable': 'receive_disable_string',
- 'send': 'send_string',
- 'sslProfile': 'ssl_profile',
- 'timeUntilUp': 'time_until_up',
- 'upInterval': 'up_interval',
- }
-
- returnables = [
- 'full_path',
- 'name',
- 'parent',
- 'description',
- 'adaptive',
- 'adaptive_divergence_type',
- 'adaptive_divergence_value',
- 'adaptive_limit',
- 'adaptive_sampling_timespan',
- 'destination',
- 'interval',
- 'ip_dscp',
- 'manual_resume',
- 'receive_string',
- 'receive_disable_string',
- 'reverse',
- 'send_string',
- 'ssl_profile',
- 'time_until_up',
- 'timeout',
- 'transparent',
- 'up_interval',
- 'username',
- ]
-
- @property
- def description(self):
- if self._values['description'] in [None, 'none']:
- return None
- return self._values['description']
-
- @property
- def transparent(self):
- return flatten_boolean(self._values['transparent'])
-
- @property
- def reverse(self):
- return flatten_boolean(self._values['reverse'])
-
- @property
- def manual_resume(self):
- return flatten_boolean(self._values['manual_resume'])
-
- @property
- def adaptive(self):
- return flatten_boolean(self._values['adaptive'])
-
-
-class HttpsMonitorsFactManager(BaseManager):
- def __init__(self, *args, **kwargs):
- self.client = kwargs.get('client', None)
- self.module = kwargs.get('module', None)
- super(HttpsMonitorsFactManager, self).__init__(**kwargs)
- self.want = HttpsMonitorsParameters(params=self.module.params)
-
- def exec_module(self):
- facts = self._exec_module()
- result = dict(https_monitors=facts)
- return result
-
- def _exec_module(self):
- results = []
- facts = self.read_facts()
- for item in facts:
- attrs = item.to_return()
- results.append(attrs)
- results = sorted(results, key=lambda k: k['full_path'])
- return results
-
- def read_facts(self):
- results = []
- collection = self.read_collection_from_device()
- for resource in collection:
- params = HttpsMonitorsParameters(params=resource)
- results.append(params)
- return results
-
- def read_collection_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/monitor/https".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- result = response['items']
- return result
-
-
-class HttpProfilesParameters(BaseParameters):
- api_map = {
- 'fullPath': 'full_path',
- 'defaultsFrom': 'parent',
- 'acceptXff': 'accept_xff',
- 'explicitProxy': 'explicit_proxy',
- 'insertXforwardedFor': 'insert_x_forwarded_for',
- 'lwsWidth': 'lws_max_columns',
- 'oneconnectTransformations': 'onconnect_transformations',
- 'proxyType': 'proxy_mode',
- 'redirectRewrite': 'redirect_rewrite',
- 'requestChunking': 'request_chunking',
- 'responseChunking': 'response_chunking',
- 'serverAgentName': 'server_agent_name',
- 'viaRequest': 'via_request',
- 'viaResponse': 'via_response',
- 'pipeline': 'pipeline_action',
- }
-
- returnables = [
- 'full_path',
- 'name',
- 'parent',
- 'description',
- 'accept_xff',
- 'allow_truncated_redirects',
- 'excess_client_headers',
- 'excess_server_headers',
- 'known_methods',
- 'max_header_count',
- 'max_header_size',
- 'max_requests',
- 'oversize_client_headers',
- 'oversize_server_headers',
- 'pipeline_action',
- 'unknown_method',
- 'default_connect_handling',
- 'hsts_include_subdomains',
- 'hsts_enabled',
- 'insert_x_forwarded_for',
- 'lws_max_columns',
- 'onconnect_transformations',
- 'proxy_mode',
- 'redirect_rewrite',
- 'request_chunking',
- 'response_chunking',
- 'server_agent_name',
- 'sflow_poll_interval',
- 'sflow_sampling_rate',
- 'via_request',
- 'via_response',
- ]
-
- @property
- def description(self):
- if self._values['description'] in [None, 'none']:
- return None
- return self._values['description']
-
- @property
- def accept_xff(self):
- return flatten_boolean(self._values['accept_xff'])
-
- @property
- def excess_client_headers(self):
- if self._values['enforcement'] is None:
- return None
- if self._values['enforcement']['excessClientHeaders'] is None:
- return None
- return self._values['enforcement']['excessClientHeaders']
-
- @property
- def excess_server_headers(self):
- if self._values['enforcement'] is None:
- return None
- if self._values['enforcement']['excessServerHeaders'] is None:
- return None
- return self._values['enforcement']['excessServerHeaders']
-
- @property
- def known_methods(self):
- if self._values['enforcement'] is None:
- return None
- if self._values['enforcement']['knownMethods'] is None:
- return None
- return self._values['enforcement']['knownMethods']
-
- @property
- def max_header_count(self):
- if self._values['enforcement'] is None:
- return None
- if self._values['enforcement']['maxHeaderCount'] is None:
- return None
- return self._values['enforcement']['maxHeaderCount']
-
- @property
- def max_header_size(self):
- if self._values['enforcement'] is None:
- return None
- if self._values['enforcement']['maxHeaderSize'] is None:
- return None
- return self._values['enforcement']['maxHeaderSize']
-
- @property
- def max_requests(self):
- if self._values['enforcement'] is None:
- return None
- if self._values['enforcement']['maxRequests'] is None:
- return None
- return self._values['enforcement']['maxRequests']
-
- @property
- def oversize_client_headers(self):
- if self._values['enforcement'] is None:
- return None
- if self._values['enforcement']['oversizeClientHeaders'] is None:
- return None
- return self._values['enforcement']['oversizeClientHeaders']
-
- @property
- def oversize_server_headers(self):
- if self._values['enforcement'] is None:
- return None
- if self._values['enforcement']['oversizeServerHeaders'] is None:
- return None
- return self._values['enforcement']['oversizeServerHeaders']
-
- @property
- def allow_truncated_redirects(self):
- if self._values['enforcement'] is None:
- return None
- if self._values['enforcement']['truncatedRedirects'] is None:
- return None
- return flatten_boolean(self._values['enforcement']['truncatedRedirects'])
-
- @property
- def unknown_method(self):
- if self._values['enforcement'] is None:
- return None
- if self._values['enforcement']['unknownMethod'] is None:
- return None
- return self._values['enforcement']['unknownMethod']
-
- @property
- def default_connect_handling(self):
- if self._values['explicit_proxy'] is None:
- return None
- if self._values['explicit_proxy']['defaultConnectHandling'] is None:
- return None
- return self._values['explicit_proxy']['defaultConnectHandling']
-
- @property
- def hsts_include_subdomains(self):
- if self._values['hsts'] is None:
- return None
- if self._values['hsts']['includeSubdomains'] is None:
- return None
- return flatten_boolean(self._values['hsts']['includeSubdomains'])
-
- @property
- def hsts_enabled(self):
- if self._values['hsts'] is None:
- return None
- if self._values['hsts']['mode'] is None:
- return None
- return flatten_boolean(self._values['hsts']['mode'])
-
- @property
- def hsts_max_age(self):
- if self._values['hsts'] is None:
- return None
- if self._values['hsts']['mode'] is None:
- return None
- return self._values['hsts']['maximumAge']
-
- @property
- def insert_x_forwarded_for(self):
- if self._values['insert_x_forwarded_for'] is None:
- return None
- return flatten_boolean(self._values['insert_x_forwarded_for'])
-
- @property
- def onconnect_transformations(self):
- if self._values['onconnect_transformations'] is None:
- return None
- return flatten_boolean(self._values['onconnect_transformations'])
-
- @property
- def sflow_poll_interval(self):
- if self._values['sflow'] is None:
- return None
- if self._values['sflow']['pollInterval'] is None:
- return None
- return self._values['sflow']['pollInterval']
-
- @property
- def sflow_sampling_rate(self):
- if self._values['sflow'] is None:
- return None
- if self._values['sflow']['samplingRate'] is None:
- return None
- return self._values['sflow']['samplingRate']
-
-
-class HttpProfilesFactManager(BaseManager):
- def __init__(self, *args, **kwargs):
- self.client = kwargs.get('client', None)
- self.module = kwargs.get('module', None)
- super(HttpProfilesFactManager, self).__init__(**kwargs)
- self.want = HttpProfilesParameters(params=self.module.params)
-
- def exec_module(self):
- facts = self._exec_module()
- result = dict(http_profiles=facts)
- return result
-
- def _exec_module(self):
- results = []
- facts = self.read_facts()
- for item in facts:
- attrs = item.to_return()
- results.append(attrs)
- results = sorted(results, key=lambda k: k['full_path'])
- return results
-
- def read_facts(self):
- results = []
- collection = self.read_collection_from_device()
- for resource in collection:
- params = HttpProfilesParameters(params=resource)
- results.append(params)
- return results
-
- def read_collection_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/profile/http".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- if 'items' not in response:
- return []
- result = response['items']
- return result
-
-
-class IappServicesParameters(BaseParameters):
- api_map = {
- 'fullPath': 'full_path',
- 'deviceGroup': 'device_group',
- 'inheritedDevicegroup': 'inherited_device_group',
- 'inheritedTrafficGroup': 'inherited_traffic_group',
- 'strictUpdates': 'strict_updates',
- 'templateModified': 'template_modified',
- 'trafficGroup': 'traffic_group',
- }
-
- returnables = [
- 'full_path',
- 'name',
- 'device_group',
- 'inherited_device_group',
- 'inherited_traffic_group',
- 'strict_updates',
- 'template_modified',
- 'traffic_group',
- 'tables',
- 'variables',
- 'metadata',
- 'lists',
- 'description',
- ]
-
- @property
- def description(self):
- if self._values['description'] in [None, 'none']:
- return None
- return self._values['description']
-
- @property
- def inherited_device_group(self):
- return flatten_boolean(self._values['inherited_device_group'])
-
- @property
- def inherited_traffic_group(self):
- return flatten_boolean(self._values['inherited_traffic_group'])
-
- @property
- def strict_updates(self):
- return flatten_boolean(self._values['strict_updates'])
-
- @property
- def template_modified(self):
- return flatten_boolean(self._values['template_modified'])
-
-
-class IappServicesFactManager(BaseManager):
- def __init__(self, *args, **kwargs):
- self.client = kwargs.get('client', None)
- self.module = kwargs.get('module', None)
- super(IappServicesFactManager, self).__init__(**kwargs)
- self.want = IappServicesParameters(params=self.module.params)
-
- def exec_module(self):
- facts = self._exec_module()
- result = dict(iapp_services=facts)
- return result
-
- def _exec_module(self):
- results = []
- facts = self.read_facts()
- for item in facts:
- attrs = item.to_return()
- results.append(attrs)
- results = sorted(results, key=lambda k: k['full_path'])
- return results
-
- def read_facts(self):
- results = []
- collection = self.read_collection_from_device()
- for resource in collection:
- params = IappServicesParameters(params=resource)
- results.append(params)
- return results
-
- def read_collection_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/sys/application/service".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- if 'items' not in response:
- return []
- result = response['items']
- return result
-
-
-class IapplxPackagesParameters(BaseParameters):
- api_map = {
- 'packageName': 'package_name',
- }
-
- returnables = [
- 'name',
- 'version',
- 'release',
- 'arch',
- 'package_name',
- 'tags',
- ]
-
-
-class IapplxPackagesFactManager(BaseManager):
- def __init__(self, *args, **kwargs):
- self.client = kwargs.get('client', None)
- self.module = kwargs.get('module', None)
- super(IapplxPackagesFactManager, self).__init__(**kwargs)
- self.want = IapplxPackagesParameters(params=self.module.params)
-
- def exec_module(self):
- facts = self._exec_module()
- result = dict(iapplx_packages=facts)
- return result
-
- def _exec_module(self):
- results = []
- facts = self.read_facts()
- for item in facts:
- attrs = item.to_return()
- results.append(attrs)
- results = sorted(results, key=lambda k: k['name'])
- return results
-
- def read_facts(self):
- results = []
- collection = self.read_collection_from_device()
- for resource in collection:
- params = IapplxPackagesParameters(params=resource)
- results.append(params)
- return results
-
- def read_collection_from_device(self):
- params = dict(operation='QUERY')
- uri = "https://{0}:{1}/mgmt/shared/iapp/package-management-tasks".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- status = self.wait_for_task(response['id'])
- if status == 'FINISHED':
- uri = "https://{0}:{1}/mgmt/shared/iapp/package-management-tasks/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- response['id']
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- else:
- raise F5ModuleError(
- "An error occurred querying iAppLX packages."
- )
- result = response['queryResponse']
- return result
-
- def wait_for_task(self, task_id):
- uri = "https://{0}:{1}/mgmt/shared/iapp/package-management-tasks/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- task_id
- )
- for x in range(0, 60):
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- if response['status'] in ['FINISHED', 'FAILED']:
- return response['status']
- time.sleep(1)
- return response['status']
-
-
-class IcmpMonitorsParameters(BaseParameters):
- api_map = {
- 'fullPath': 'full_path',
- 'defaultsFrom': 'parent',
- 'adaptiveDivergenceType': 'adaptive_divergence_type',
- 'adaptiveDivergenceValue': 'adaptive_divergence_value',
- 'adaptiveLimit': 'adaptive_limit',
- 'adaptiveSamplingTimespan': 'adaptive_sampling_timespan',
- 'manualResume': 'manual_resume',
- 'timeUntilUp': 'time_until_up',
- 'upInterval': 'up_interval',
- }
-
- returnables = [
- 'full_path',
- 'name',
- 'parent',
- 'description',
- 'adaptive',
- 'adaptive_divergence_type',
- 'adaptive_divergence_value',
- 'adaptive_limit',
- 'adaptive_sampling_timespan',
- 'destination',
- 'interval',
- 'manual_resume',
- 'time_until_up',
- 'timeout',
- 'transparent',
- 'up_interval',
- ]
-
- @property
- def description(self):
- if self._values['description'] in [None, 'none']:
- return None
- return self._values['description']
-
- @property
- def transparent(self):
- return flatten_boolean(self._values['transparent'])
-
- @property
- def manual_resume(self):
- return flatten_boolean(self._values['manual_resume'])
-
- @property
- def adaptive(self):
- return flatten_boolean(self._values['adaptive'])
-
-
-class IcmpMonitorsFactManager(BaseManager):
- def __init__(self, *args, **kwargs):
- self.client = kwargs.get('client', None)
- self.module = kwargs.get('module', None)
- super(IcmpMonitorsFactManager, self).__init__(**kwargs)
- self.want = IcmpMonitorsParameters(params=self.module.params)
-
- def exec_module(self):
- facts = self._exec_module()
- result = dict(icmp_monitors=facts)
- return result
-
- def _exec_module(self):
- results = []
- facts = self.read_facts()
- for item in facts:
- attrs = item.to_return()
- results.append(attrs)
- results = sorted(results, key=lambda k: k['full_path'])
- return results
-
- def read_facts(self):
- results = []
- collection = self.read_collection_from_device()
- for resource in collection:
- params = IcmpMonitorsParameters(params=resource)
- results.append(params)
- return results
-
- def read_collection_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/monitor/icmp".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- if 'items' not in response:
- return []
- result = response['items']
- return result
-
-
-class InterfacesParameters(BaseParameters):
- api_map = {
- 'fullPath': 'full_path',
- 'mediaActive': 'active_media_type',
- 'flowControl': 'flow_control',
- 'bundleSpeed': 'bundle_speed',
- 'ifIndex': 'if_index',
- 'macAddress': 'mac_address',
- 'mediaSfp': 'media_sfp',
- 'lldpAdmin': 'lldp_admin',
- 'preferPort': 'prefer_port',
- 'stpAutoEdgePort': 'stp_auto_edge_port',
- 'stp': 'stp_enabled',
- 'stpLinkType': 'stp_link_type'
- }
-
- returnables = [
- 'full_path',
- 'name',
- 'active_media_type',
- 'flow_control',
- 'description',
- 'bundle',
- 'bundle_speed',
- 'enabled',
- 'if_index',
- 'mac_address',
- 'media_sfp',
- 'lldp_admin',
- 'mtu',
- 'prefer_port',
- 'sflow_poll_interval',
- 'sflow_poll_interval_global',
- 'stp_auto_edge_port',
- 'stp_enabled',
- 'stp_link_type'
- ]
-
- @property
- def stp_auto_edge_port(self):
- return flatten_boolean(self._values['stp_auto_edge_port'])
-
- @property
- def stp_enabled(self):
- return flatten_boolean(self._values['stp_enabled'])
-
- @property
- def sflow_poll_interval_global(self):
- if self._values['sflow'] is None:
- return None
- if 'pollIntervalGlobal' in self._values['sflow']:
- return self._values['sflow']['pollIntervalGlobal']
-
- @property
- def sflow_poll_interval(self):
- if self._values['sflow'] is None:
- return None
- if 'pollInterval' in self._values['sflow']:
- return self._values['sflow']['pollInterval']
-
- @property
- def mac_address(self):
- if self._values['mac_address'] in [None, 'none']:
- return None
- return self._values['mac_address']
-
- @property
- def enabled(self):
- return flatten_boolean(self._values['enabled'])
-
-
-class InterfacesFactManager(BaseManager):
- def __init__(self, *args, **kwargs):
- self.client = kwargs.get('client', None)
- self.module = kwargs.get('module', None)
- super(InterfacesFactManager, self).__init__(**kwargs)
- self.want = InterfacesParameters(params=self.module.params)
-
- def exec_module(self):
- facts = self._exec_module()
- result = dict(interfaces=facts)
- return result
-
- def _exec_module(self):
- results = []
- facts = self.read_facts()
- for item in facts:
- attrs = item.to_return()
- results.append(attrs)
- results = sorted(results, key=lambda k: k['full_path'])
- return results
-
- def read_facts(self):
- results = []
- collection = self.read_collection_from_device()
- for resource in collection:
- params = InterfacesParameters(params=resource)
- results.append(params)
- return results
-
- def read_collection_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/net/interface".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- if 'items' not in response:
- return []
- result = response['items']
- return result
-
-
-class InternalDataGroupsParameters(BaseParameters):
- api_map = {
- 'fullPath': 'full_path'
- }
-
- returnables = [
- 'full_path',
- 'name',
- 'type',
- 'records'
- ]
-
-
-class InternalDataGroupsFactManager(BaseManager):
- def __init__(self, *args, **kwargs):
- self.client = kwargs.get('client', None)
- self.module = kwargs.get('module', None)
- super(InternalDataGroupsFactManager, self).__init__(**kwargs)
- self.want = InternalDataGroupsParameters(params=self.module.params)
-
- def exec_module(self):
- facts = self._exec_module()
- result = dict(internal_data_groups=facts)
- return result
-
- def _exec_module(self):
- results = []
- facts = self.read_facts()
- for item in facts:
- attrs = item.to_return()
- results.append(attrs)
- results = sorted(results, key=lambda k: k['full_path'])
- return results
-
- def read_facts(self):
- results = []
- collection = self.read_collection_from_device()
- for resource in collection:
- params = InternalDataGroupsParameters(params=resource)
- results.append(params)
- return results
-
- def read_collection_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/data-group/internal".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- if 'items' not in response:
- return []
- result = response['items']
- return result
-
-
-class IrulesParameters(BaseParameters):
- api_map = {
- 'fullPath': 'full_path',
- 'ignoreVerification': 'ignore_verification',
- }
-
- returnables = [
- 'full_path',
- 'name',
- 'ignore_verification',
- 'checksum',
- 'definition',
- 'signature'
- ]
-
- @property
- def checksum(self):
- if self._values['apiAnonymous'] is None:
- return None
- pattern = r'definition-checksum\s(?P<checksum>\w+)'
- matches = re.search(pattern, self._values['apiAnonymous'])
- if matches:
- return matches.group('checksum')
-
- @property
- def definition(self):
- if self._values['apiAnonymous'] is None:
- return None
- pattern = r'(definition-(checksum|signature)\s[\w=\/+]+)'
- result = re.sub(pattern, '', self._values['apiAnonymous']).strip()
- if result:
- return result
-
- @property
- def signature(self):
- if self._values['apiAnonymous'] is None:
- return None
- pattern = r'definition-signature\s(?P<signature>[\w=\/+]+)'
- matches = re.search(pattern, self._values['apiAnonymous'])
- if matches:
- return matches.group('signature')
-
- @property
- def ignore_verification(self):
- if self._values['ignore_verification'] is None:
- return 'no'
- return 'yes'
-
-
-class IrulesFactManager(BaseManager):
- def __init__(self, *args, **kwargs):
- self.client = kwargs.get('client', None)
- self.module = kwargs.get('module', None)
- super(IrulesFactManager, self).__init__(**kwargs)
- self.want = IrulesParameters(params=self.module.params)
-
- def exec_module(self):
- facts = self._exec_module()
- result = dict(irules=facts)
- return result
-
- def _exec_module(self):
- results = []
- facts = self.read_facts()
- for item in facts:
- attrs = item.to_return()
- results.append(attrs)
- results = sorted(results, key=lambda k: k['full_path'])
- return results
-
- def read_facts(self):
- results = []
- collection = self.read_collection_from_device()
- for resource in collection:
- params = IrulesParameters(params=resource)
- results.append(params)
- return results
-
- def read_collection_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/rule".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- if 'items' not in response:
- return []
- result = response['items']
- return result
-
-
-class LtmPoolsParameters(BaseParameters):
- api_map = {
- 'fullPath': 'full_path',
- 'allowNat': 'allow_nat',
- 'allowSnat': 'allow_snat',
- 'ignorePersistedWeight': 'ignore_persisted_weight',
- 'ipTosToClient': 'client_ip_tos',
- 'ipTosToServer': 'server_ip_tos',
- 'linkQosToClient': 'client_link_qos',
- 'linkQosToServer': 'server_link_qos',
- 'loadBalancingMode': 'lb_method',
- 'minActiveMembers': 'minimum_active_members',
- 'minUpMembers': 'minimum_up_members',
- 'minUpMembersAction': 'minimum_up_members_action',
- 'minUpMembersChecking': 'minimum_up_members_checking',
- 'queueDepthLimit': 'queue_depth_limit',
- 'queueOnConnectionLimit': 'queue_on_connection_limit',
- 'queueTimeLimit': 'queue_time_limit',
- 'reselectTries': 'reselect_tries',
- 'serviceDownAction': 'service_down_action',
- 'slowRampTime': 'slow_ramp_time',
- 'monitor': 'monitors',
- }
-
- returnables = [
- 'full_path',
- 'name',
- 'allow_nat',
- 'allow_snat',
- 'description',
- 'ignore_persisted_weight',
- 'client_ip_tos',
- 'server_ip_tos',
- 'client_link_qos',
- 'server_link_qos',
- 'lb_method',
- 'minimum_active_members',
- 'minimum_up_members',
- 'minimum_up_members_action',
- 'minimum_up_members_checking',
- 'monitors',
- 'queue_depth_limit',
- 'queue_on_connection_limit',
- 'queue_time_limit',
- 'reselect_tries',
- 'service_down_action',
- 'slow_ramp_time',
- 'priority_group_activation',
- 'members',
- 'metadata',
- 'active_member_count',
- 'available_member_count',
- 'availability_status',
- 'enabled_status',
- 'status_reason',
- 'all_max_queue_entry_age_ever',
- 'all_avg_queue_entry_age',
- 'all_queue_head_entry_age',
- 'all_max_queue_entry_age_recently',
- 'all_num_connections_queued_now',
- 'all_num_connections_serviced',
- 'pool_max_queue_entry_age_ever',
- 'pool_avg_queue_entry_age',
- 'pool_queue_head_entry_age',
- 'pool_max_queue_entry_age_recently',
- 'pool_num_connections_queued_now',
- 'pool_num_connections_serviced',
- 'current_sessions',
- 'member_count',
- 'total_requests',
- 'server_side_bits_in',
- 'server_side_bits_out',
- 'server_side_current_connections',
- 'server_side_max_connections',
- 'server_side_pkts_in',
- 'server_side_pkts_out',
- 'server_side_total_connections',
- ]
-
- @property
- def active_member_count(self):
- if 'availableMemberCnt' in self._values['stats']:
- return int(self._values['stats']['activeMemberCnt'])
- return None
-
- @property
- def available_member_count(self):
- if 'availableMemberCnt' in self._values['stats']:
- return int(self._values['stats']['availableMemberCnt'])
- return None
-
- @property
- def all_max_queue_entry_age_ever(self):
- return self._values['stats']['connqAll']['ageEdm']
-
- @property
- def all_avg_queue_entry_age(self):
- return self._values['stats']['connqAll']['ageEma']
-
- @property
- def all_queue_head_entry_age(self):
- return self._values['stats']['connqAll']['ageHead']
-
- @property
- def all_max_queue_entry_age_recently(self):
- return self._values['stats']['connqAll']['ageMax']
-
- @property
- def all_num_connections_queued_now(self):
- return self._values['stats']['connqAll']['depth']
-
- @property
- def all_num_connections_serviced(self):
- return self._values['stats']['connqAll']['serviced']
-
- @property
- def availability_status(self):
- return self._values['stats']['status']['availabilityState']
-
- @property
- def enabled_status(self):
- return self._values['stats']['status']['enabledState']
-
- @property
- def status_reason(self):
- return self._values['stats']['status']['statusReason']
-
- @property
- def pool_max_queue_entry_age_ever(self):
- return self._values['stats']['connq']['ageEdm']
-
- @property
- def pool_avg_queue_entry_age(self):
- return self._values['stats']['connq']['ageEma']
-
- @property
- def pool_queue_head_entry_age(self):
- return self._values['stats']['connq']['ageHead']
-
- @property
- def pool_max_queue_entry_age_recently(self):
- return self._values['stats']['connq']['ageMax']
-
- @property
- def pool_num_connections_queued_now(self):
- return self._values['stats']['connq']['depth']
-
- @property
- def pool_num_connections_serviced(self):
- return self._values['stats']['connq']['serviced']
-
- @property
- def current_sessions(self):
- return self._values['stats']['curSessions']
-
- @property
- def member_count(self):
- if 'memberCnt' in self._values['stats']:
- return self._values['stats']['memberCnt']
- return None
-
- @property
- def total_requests(self):
- return self._values['stats']['totRequests']
-
- @property
- def server_side_bits_in(self):
- return self._values['stats']['serverside']['bitsIn']
-
- @property
- def server_side_bits_out(self):
- return self._values['stats']['serverside']['bitsOut']
-
- @property
- def server_side_current_connections(self):
- return self._values['stats']['serverside']['curConns']
-
- @property
- def server_side_max_connections(self):
- return self._values['stats']['serverside']['maxConns']
-
- @property
- def server_side_pkts_in(self):
- return self._values['stats']['serverside']['pktsIn']
-
- @property
- def server_side_pkts_out(self):
- return self._values['stats']['serverside']['pktsOut']
-
- @property
- def server_side_total_connections(self):
- return self._values['stats']['serverside']['totConns']
-
- @property
- def ignore_persisted_weight(self):
- return flatten_boolean(self._values['ignore_persisted_weight'])
-
- @property
- def minimum_up_members_checking(self):
- return flatten_boolean(self._values['minimum_up_members_checking'])
-
- @property
- def queue_on_connection_limit(self):
- return flatten_boolean(self._values['queue_on_connection_limit'])
-
- @property
- def priority_group_activation(self):
- """Returns the TMUI value for "Priority Group Activation"
-
- This value is identified as ``minActiveMembers`` in the REST API, so this
- is just a convenience key for users of Ansible (where the ``bigip_virtual_server``
- parameter is called ``priority_group_activation``.
-
- Returns:
- int: Priority number assigned to the pool members.
- """
- return self._values['minimum_active_members']
-
- @property
- def metadata(self):
- """Returns metadata associated with a pool
-
- An arbitrary amount of metadata may be associated with a pool. You typically
- see this used in situations where the user wants to annotate a resource, maybe
- in cases where an automation system is responsible for creating the resource.
-
- The metadata in the API is always stored as a list of dictionaries. We change
- this to be a simple dictionary before it is returned to the user.
-
- Returns:
- dict: A dictionary of key/value pairs where the key is the metadata name
- and the value is the metadata value.
- """
- if self._values['metadata'] is None:
- return None
- result = dict([(k['name'], k['value']) for k in self._values['metadata']])
- return result
-
- @property
- def members(self):
- if not self._values['members']:
- return None
- result = []
- for member in self._values['members']:
- member['connection_limit'] = member.pop('connectionLimit', None)
- member['dynamic_ratio'] = member.pop('dynamicRatio', None)
- member['full_path'] = member.pop('fullPath', None)
- member['inherit_profile'] = member.pop('inheritProfile', None)
- member['priority_group'] = member.pop('priorityGroup', None)
- member['rate_limit'] = member.pop('rateLimit', None)
-
- if 'fqdn' in member and 'autopopulate' in member['fqdn']:
- if member['fqdn']['autopopulate'] == 'enabled':
- member['fqdn_autopopulate'] = 'yes'
- elif member['fqdn']['autopopulate'] == 'disabled':
- member['fqdn_autopopulate'] = 'no'
- del member['fqdn']
-
- for key in ['ephemeral', 'inherit_profile', 'logging', 'rate_limit']:
- tmp = flatten_boolean(member[key])
- member[key] = tmp
-
- if 'profiles' in member:
- # Even though the ``profiles`` is a list, there is only ever 1
- member['encapsulation_profile'] = [x['name'] for x in member['profiles']][0]
- del member['profiles']
-
- if 'monitor' in member:
- monitors = member.pop('monitor')
- if monitors is not None:
- try:
- member['monitors'] = re.findall(r'/[\w-]+/[^\s}]+', monitors)
- except Exception:
- member['monitors'] = [monitors.strip()]
-
- session = member.pop('session')
- state = member.pop('state')
-
- member['real_session'] = session
- member['real_state'] = state
-
- if state in ['user-up', 'unchecked', 'fqdn-up-no-addr', 'fqdn-up'] and session in ['user-enabled']:
- member['state'] = 'present'
- elif state in ['user-down'] and session in ['user-disabled']:
- member['state'] = 'forced_offline'
- elif state in ['up', 'checking'] and session in ['monitor-enabled']:
- member['state'] = 'present'
- elif state in ['down'] and session in ['monitor-enabled']:
- member['state'] = 'offline'
- else:
- member['state'] = 'disabled'
- self._remove_internal_keywords(member)
- member = dict([(k, v) for k, v in iteritems(member) if v is not None])
- result.append(member)
- return result
-
- @property
- def monitors(self):
- if self._values['monitors'] is None:
- return None
- try:
- result = re.findall(r'/[\w-]+/[^\s}]+', self._values['monitors'])
- return result
- except Exception:
- return [self._values['monitors'].strip()]
-
-
-class LtmPoolsFactManager(BaseManager):
- def __init__(self, *args, **kwargs):
- self.client = kwargs.get('client', None)
- self.module = kwargs.get('module', None)
- super(LtmPoolsFactManager, self).__init__(**kwargs)
- self.want = LtmPoolsParameters(params=self.module.params)
-
- def exec_module(self):
- facts = self._exec_module()
- result = dict(ltm_pools=facts)
- return result
-
- def _exec_module(self):
- results = []
- facts = self.read_facts()
- for item in facts:
- attrs = item.to_return()
- results.append(attrs)
- results = sorted(results, key=lambda k: k['full_path'])
- return results
-
- def read_facts(self):
- results = []
- collection = self.read_collection_from_device()
- for resource in collection:
- attrs = resource
- members = self.read_member_from_device(attrs['fullPath'])
- attrs['members'] = members
- attrs['stats'] = self.read_stats_from_device(attrs['fullPath'])
- params = LtmPoolsParameters(params=attrs)
- results.append(params)
- return results
-
- def read_collection_from_device(self):
- """Read the LTM pools collection from the device
-
- Note that sub-collection expansion does not work with LTM pools. Therefore,
- one needs to query the ``members`` endpoint separately and add that to the
- list of ``attrs`` before the full set of attributes is sent to the ``Parameters``
- class.
-
- Returns:
- list: List of ``Pool`` objects
- """
- uri = "https://{0}:{1}/mgmt/tm/ltm/pool".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- if 'items' not in response:
- return []
- result = response['items']
- return result
-
- def read_member_from_device(self, full_path):
- uri = "https://{0}:{1}/mgmt/tm/ltm/pool/{2}/members".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(name=full_path)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- if 'items' not in response:
- return []
- result = response['items']
- return result
-
- def read_stats_from_device(self, full_path):
- uri = "https://{0}:{1}/mgmt/tm/ltm/pool/{2}/stats".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(name=full_path)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- result = parseStats(response)
- try:
- return result['stats']
- except KeyError:
- return {}
-
-
-class LtmPolicyParameters(BaseParameters):
- api_map = {
- 'fullPath': 'full_path',
- 'rulesReference': 'rules',
- }
-
- returnables = [
- 'full_path',
- 'name',
- 'status',
- 'description',
- 'strategy',
- 'rules',
- 'requires',
- 'controls',
- ]
-
- def _handle_conditions(self, conditions):
- result = []
- if conditions is None or 'items' not in conditions:
- return result
- for condition in conditions['items']:
- tmp = dict()
- tmp['case_insensitive'] = flatten_boolean(condition.pop('caseInsensitive', None))
- tmp['case_sensitive'] = flatten_boolean(condition.pop('caseSensitive', None))
- tmp['contains_string'] = flatten_boolean(condition.pop('contains', None))
- tmp['external'] = flatten_boolean(condition.pop('external', None))
- tmp['http_basic_auth'] = flatten_boolean(condition.pop('httpBasicAuth', None))
- tmp['http_host'] = flatten_boolean(condition.pop('httpHost', None))
- tmp['http_uri'] = flatten_boolean(condition.pop('httpUri', None))
- tmp['request'] = flatten_boolean(condition.pop('request', None))
- tmp['username'] = flatten_boolean(condition.pop('username', None))
- tmp['external'] = flatten_boolean(condition.pop('external', None))
- tmp['values'] = condition.pop('values', None)
- tmp['all'] = flatten_boolean(condition.pop('all', None))
- result.append(self._filter_params(tmp))
- return result
-
- def _handle_actions(self, actions):
- result = []
- if actions is None or 'items' not in actions:
- return result
- for action in actions['items']:
- tmp = dict()
- tmp['httpReply'] = flatten_boolean(action.pop('http_reply', None))
- tmp['redirect'] = flatten_boolean(action.pop('redirect', None))
- tmp['request'] = flatten_boolean(action.pop('request', None))
- tmp['location'] = action.pop('location', None)
- result.append(self._filter_params(tmp))
- return result
-
- @property
- def rules(self):
- result = []
- if self._values['rules'] is None or 'items' not in self._values['rules']:
- return result
- for item in self._values['rules']['items']:
- self._remove_internal_keywords(item)
- item['conditions'] = self._handle_conditions(item.pop('conditionsReference', None))
- item['actions'] = self._handle_actions(item.pop('actionsReference', None))
- result.append(item)
- return result
-
-
-class LtmPolicyFactManager(BaseManager):
- def __init__(self, *args, **kwargs):
- self.client = kwargs.get('client', None)
- self.module = kwargs.get('module', None)
- super(LtmPolicyFactManager, self).__init__(**kwargs)
- self.want = LtmPolicyParameters(params=self.module.params)
-
- def exec_module(self):
- facts = self._exec_module()
- result = dict(ltm_policies=facts)
- return result
-
- def _exec_module(self):
- results = []
- facts = self.read_facts()
- for item in facts:
- attrs = item.to_return()
- results.append(attrs)
- results = sorted(results, key=lambda k: k['full_path'])
- return results
-
- def read_facts(self):
- results = []
- collection = self.read_collection_from_device()
- for resource in collection:
- params = LtmPolicyParameters(params=resource)
- results.append(params)
- return results
-
- def read_collection_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/policy/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- query = "?expandSubcollections=true"
- resp = self.client.api.get(uri + query)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- if 'items' not in response:
- return []
- result = response['items']
- return result
-
-
-class NodesParameters(BaseParameters):
- api_map = {
- 'fullPath': 'full_path',
- 'connectionLimit': 'connection_limit',
- 'dynamicRatio': 'dynamic_ratio',
- 'rateLimit': 'rate_limit',
- 'monitor': 'monitors'
- }
-
- returnables = [
- 'full_path',
- 'name',
- 'ratio',
- 'description',
- 'connection_limit',
- 'address',
- 'dynamic_ratio',
- 'rate_limit',
- 'monitor_status',
- 'session_status',
- 'availability_status',
- 'enabled_status',
- 'status_reason',
- 'monitor_rule',
- 'monitors',
- 'monitor_type'
- ]
-
- @property
- def monitors(self):
- if self._values['monitors'] is None:
- return []
- try:
- result = re.findall(r'/\w+/[^\s}]+', self._values['monitors'])
- return result
- except Exception:
- return [self._values['monitors']]
-
- @property
- def monitor_type(self):
- if self._values['monitors'] is None:
- return None
- pattern = r'min\s+\d+\s+of'
- matches = re.search(pattern, self._values['monitors'])
- if matches:
- return 'm_of_n'
- else:
- return 'and_list'
-
- @property
- def rate_limit(self):
- if self._values['rate_limit'] is None:
- return None
- elif self._values['rate_limit'] == 'disabled':
- return 0
- else:
- return int(self._values['rate_limit'])
-
- @property
- def monitor_status(self):
- return self._values['stats']['monitorStatus']
-
- @property
- def session_status(self):
- return self._values['stats']['sessionStatus']
-
- @property
- def availability_status(self):
- return self._values['stats']['status']['availabilityState']
-
- @property
- def enabled_status(self):
- return self._values['stats']['status']['enabledState']
-
- @property
- def status_reason(self):
- return self._values['stats']['status']['statusReason']
-
- @property
- def monitor_rule(self):
- return self._values['stats']['monitorRule']
-
-
-class NodesFactManager(BaseManager):
- def __init__(self, *args, **kwargs):
- self.client = kwargs.get('client', None)
- self.module = kwargs.get('module', None)
- super(NodesFactManager, self).__init__(**kwargs)
- self.want = NodesParameters(params=self.module.params)
-
- def exec_module(self):
- facts = self._exec_module()
- result = dict(nodes=facts)
- return result
-
- def _exec_module(self):
- results = []
- facts = self.read_facts()
- for item in facts:
- attrs = item.to_return()
- results.append(attrs)
- results = sorted(results, key=lambda k: k['full_path'])
- return results
-
- def read_facts(self):
- results = []
- collection = self.read_collection_from_device()
- for resource in collection:
- attrs = resource
- attrs['stats'] = self.read_stats_from_device(attrs['fullPath'])
- params = NodesParameters(params=attrs)
- results.append(params)
- return results
-
- def read_collection_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/node".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- if 'items' not in response:
- return []
- result = response['items']
- return result
-
- def read_stats_from_device(self, full_path):
- uri = "https://{0}:{1}/mgmt/tm/ltm/node/{2}/stats".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(name=full_path)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- result = parseStats(response)
- try:
- return result['stats']
- except KeyError:
- return {}
-
-
-class OneConnectProfilesParameters(BaseParameters):
- api_map = {
- 'fullPath': 'full_path',
- 'clientTimeout': 'client_timeout',
- 'defaultsFrom': 'parent',
- 'idleTimeoutOverride': 'idle_timeout_override',
- 'limitType': 'limit_type',
- 'maxAge': 'max_age',
- 'maxReuse': 'max_reuse',
- 'maxSize': 'max_size',
- 'sharePools': 'share_pools',
- 'sourceMask': 'source_mask',
- }
-
- returnables = [
- 'full_path',
- 'name',
- 'parent',
- 'description',
- 'idle_timeout_override',
- 'limit_type',
- 'max_age',
- 'max_reuse',
- 'max_size',
- 'share_pools',
- 'source_mask',
- ]
-
- @property
- def description(self):
- if self._values['description'] in [None, 'none']:
- return None
- return self._values['description']
-
- @property
- def idle_timeout_override(self):
- if self._values['idle_timeout_override'] is None:
- return None
- elif self._values['idle_timeout_override'] == 'disabled':
- return 0
- elif self._values['idle_timeout_override'] == 'indefinite':
- return 4294967295
- return int(self._values['idle_timeout_override'])
-
- @property
- def share_pools(self):
- return flatten_boolean(self._values['share_pools'])
-
-
-class OneConnectProfilesFactManager(BaseManager):
- def __init__(self, *args, **kwargs):
- self.client = kwargs.get('client', None)
- self.module = kwargs.get('module', None)
- super(OneConnectProfilesFactManager, self).__init__(**kwargs)
- self.want = OneConnectProfilesParameters(params=self.module.params)
-
- def exec_module(self):
- facts = self._exec_module()
- result = dict(oneconnect_profiles=facts)
- return result
-
- def _exec_module(self):
- results = []
- facts = self.read_facts()
- for item in facts:
- attrs = item.to_return()
- results.append(attrs)
- results = sorted(results, key=lambda k: k['full_path'])
- return results
-
- def read_facts(self):
- results = []
- collection = self.read_collection_from_device()
- for resource in collection:
- params = OneConnectProfilesParameters(params=resource)
- results.append(params)
- return results
-
- def read_collection_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/profile/one-connect".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- if 'items' not in response:
- return []
- result = response['items']
- return result
-
-
-class PartitionParameters(BaseParameters):
- api_map = {
- 'defaultRouteDomain': 'default_route_domain',
- 'fullPath': 'full_path',
- }
-
- returnables = [
- 'name',
- 'full_path',
- 'description',
- 'default_route_domain'
- ]
-
-
-class PartitionFactManager(BaseManager):
- def __init__(self, *args, **kwargs):
- self.client = kwargs.get('client', None)
- self.module = kwargs.get('module', None)
- super(PartitionFactManager, self).__init__(**kwargs)
- self.want = PartitionParameters(params=self.module.params)
-
- def exec_module(self):
- facts = self._exec_module()
- result = dict(partitions=facts)
- return result
-
- def _exec_module(self):
- results = []
- facts = self.read_facts()
- for item in facts:
- attrs = item.to_return()
- results.append(attrs)
- results = sorted(results, key=lambda k: k['full_path'])
- return results
-
- def read_facts(self):
- results = []
- collection = self.read_collection_from_device()
- for resource in collection:
- params = PartitionParameters(params=resource)
- results.append(params)
- return results
-
- def read_collection_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/auth/partition".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- if 'items' not in response:
- return []
- result = response['items']
- return result
-
-
-class ProvisionInfoParameters(BaseParameters):
- api_map = {
- 'fullPath': 'full_path',
- 'cpuRatio': 'cpu_ratio',
- 'diskRatio': 'disk_ratio',
- 'memoryRatio': 'memory_ratio',
- }
-
- returnables = [
- 'full_path',
- 'name',
- 'cpu_ratio',
- 'disk_ratio',
- 'memory_ratio',
- 'level'
- ]
-
-
-class ProvisionInfoFactManager(BaseManager):
- def __init__(self, *args, **kwargs):
- self.client = kwargs.get('client', None)
- self.module = kwargs.get('module', None)
- super(ProvisionInfoFactManager, self).__init__(**kwargs)
- self.want = ProvisionInfoParameters(params=self.module.params)
-
- def exec_module(self):
- facts = self._exec_module()
- result = dict(provision_info=facts)
- return result
-
- def _exec_module(self):
- results = []
- facts = self.read_facts()
- for item in facts:
- attrs = item.to_return()
- results.append(attrs)
- results = sorted(results, key=lambda k: k['full_path'])
- return results
-
- def read_facts(self):
- results = []
- collection = self.read_collection_from_device()
- for resource in collection:
- params = ProvisionInfoParameters(params=resource)
- results.append(params)
- return results
-
- def read_collection_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/sys/provision".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- if 'items' not in response:
- return []
- result = response['items']
- return result
-
-
-class RouteDomainParameters(BaseParameters):
- api_map = {
- 'fullPath': 'full_path',
- 'bwcPolicy': 'bandwidth_controller_policy',
- 'connectionLimit': 'connection_limit',
- 'flowEvictionPolicy': 'flow_eviction_policy',
- 'servicePolicy': 'service_policy',
- 'routingProtocol': 'routing_protocol'
- }
-
- returnables = [
- 'name',
- 'id',
- 'full_path',
- 'parent',
- 'bandwidth_controller_policy',
- 'connection_limit',
- 'description',
- 'flow_eviction_policy',
- 'service_policy',
- 'strict',
- 'routing_protocol',
- 'vlans'
- ]
-
- @property
- def strict(self):
- return flatten_boolean(self._values['strict'])
-
- @property
- def connection_limit(self):
- if self._values['connection_limit'] is None:
- return None
- return int(self._values['connection_limit'])
-
-
-class RouteDomainFactManager(BaseManager):
- def __init__(self, *args, **kwargs):
- self.client = kwargs.get('client', None)
- self.module = kwargs.get('module', None)
- super(RouteDomainFactManager, self).__init__(**kwargs)
- self.want = RouteDomainParameters(params=self.module.params)
-
- def exec_module(self):
- facts = self._exec_module()
- result = dict(route_domains=facts)
- return result
-
- def _exec_module(self):
- results = []
- facts = self.read_facts()
- for item in facts:
- attrs = item.to_return()
- results.append(attrs)
- results = sorted(results, key=lambda k: k['full_path'])
- return results
-
- def read_facts(self):
- results = []
- collection = self.read_collection_from_device()
- for resource in collection:
- params = RouteDomainParameters(params=resource)
- results.append(params)
- return results
-
- def read_collection_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/net/route-domain".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- if 'items' not in response:
- return []
- result = response['items']
- return result
-
-
-class SelfIpsParameters(BaseParameters):
- api_map = {
- 'fullPath': 'full_path',
- 'trafficGroup': 'traffic_group',
- 'servicePolicy': 'service_policy',
- 'allowService': 'allow_access_list',
- 'inheritedTrafficGroup': 'traffic_group_inherited'
- }
-
- returnables = [
- 'full_path',
- 'name',
- 'address',
- 'description',
- 'netmask',
- 'netmask_cidr',
- 'floating',
- 'traffic_group',
- 'service_policy',
- 'vlan',
- 'allow_access_list',
- 'traffic_group_inherited'
- ]
-
- @property
- def address(self):
- parts = self._values['address'].split('/')
- return parts[0]
-
- @property
- def netmask(self):
- parts = self._values['address'].split('/')
- return to_netmask(parts[1])
-
- @property
- def netmask_cidr(self):
- parts = self._values['address'].split('/')
- return int(parts[1])
-
- @property
- def traffic_group_inherited(self):
- if self._values['traffic_group_inherited'] is None:
- return None
- elif self._values['traffic_group_inherited'] in [False, 'false']:
- # BIG-IP appears to store this as a string. This is a bug, so we handle both
- # cases here.
- return 'no'
- else:
- return 'yes'
-
- @property
- def floating(self):
- if self._values['floating'] is None:
- return None
- elif self._values['floating'] == 'disabled':
- return 'no'
- else:
- return 'yes'
-
-
-class SelfIpsFactManager(BaseManager):
- def __init__(self, *args, **kwargs):
- self.client = kwargs.get('client', None)
- self.module = kwargs.get('module', None)
- super(SelfIpsFactManager, self).__init__(**kwargs)
- self.want = SelfIpsParameters(params=self.module.params)
-
- def exec_module(self):
- facts = self._exec_module()
- result = dict(self_ips=facts)
- return result
-
- def _exec_module(self):
- results = []
- facts = self.read_facts()
- for item in facts:
- attrs = item.to_return()
- results.append(attrs)
- results = sorted(results, key=lambda k: k['full_path'])
- return results
-
- def read_facts(self):
- results = []
- collection = self.read_collection_from_device()
- for resource in collection:
- params = SelfIpsParameters(params=resource)
- results.append(params)
- return results
-
- def read_collection_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/net/self".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- if 'items' not in response:
- return []
- result = response['items']
- return result
-
-
-class ServerSslProfilesParameters(BaseParameters):
- api_map = {
- 'fullPath': 'full_path',
- 'alertTimeout': 'alert_timeout',
- 'allowExpiredCrl': 'allow_expired_crl',
- 'authenticate': 'authentication_frequency',
- 'authenticateDepth': 'authenticate_depth',
- 'authenticateName': 'authenticate_name',
- 'bypassOnClientCertFail': 'bypass_on_client_cert_fail',
- 'bypassOnHandshakeAlert': 'bypass_on_handshake_alert',
- 'c3dCaCert': 'c3d_ca_cert',
- 'c3dCaKey': 'c3d_ca_key',
- 'c3dCertExtensionIncludes': 'c3d_cert_extension_includes',
- 'c3dCertLifespan': 'c3d_cert_lifespan',
- 'caFile': 'ca_file',
- 'cacheSize': 'cache_size',
- 'cacheTimeout': 'cache_timeout',
- 'cipherGroup': 'cipher_group',
- 'crlFile': 'crl_file',
- 'expireCertResponseControl': 'expire_cert_response_control',
- 'genericAlert': 'generic_alert',
- 'handshakeTimeout': 'handshake_timeout',
- 'maxActiveHandshakes': 'max_active_handshakes',
- 'modSslMethods': 'mod_ssl_methods',
- 'tmOptions': 'options',
- 'peerCertMode': 'peer_cert_mode',
- 'proxySsl': 'proxy_ssl',
- 'proxySslPassthrough': 'proxy_ssl_passthrough',
- 'renegotiatePeriod': 'renegotiate_period',
- 'renegotiateSize': 'renegotiate_size',
- 'retainCertificate': 'retain_certificate',
- 'secureRenegotiation': 'secure_renegotiation',
- 'serverName': 'server_name',
- 'sessionMirroring': 'session_mirroring',
- 'sessionTicket': 'session_ticket',
- 'sniDefault': 'sni_default',
- 'sniRequire': 'sni_require',
- 'sslC3d': 'ssl_c3d',
- 'sslForwardProxy': 'ssl_forward_proxy_enabled',
- 'sslForwardProxyBypass': 'ssl_forward_proxy_bypass',
- 'sslSignHash': 'ssl_sign_hash',
- 'strictResume': 'strict_resume',
- 'uncleanShutdown': 'unclean_shutdown',
- 'untrustedCertResponseControl': 'untrusted_cert_response_control'
- }
-
- returnables = [
- 'full_path',
- 'name',
- 'parent',
- 'description',
- 'unclean_shutdown',
- 'strict_resume',
- 'ssl_forward_proxy_enabled',
- 'ssl_forward_proxy_bypass',
- 'sni_default',
- 'sni_require',
- 'ssl_c3d',
- 'session_mirroring',
- 'session_ticket',
- 'mod_ssl_methods',
- 'allow_expired_crl',
- 'retain_certificate',
- 'mode',
- 'bypass_on_client_cert_fail',
- 'bypass_on_handshake_alert',
- 'generic_alert',
- 'renegotiation',
- 'proxy_ssl',
- 'proxy_ssl_passthrough',
- 'peer_cert_mode',
- 'untrusted_cert_response_control',
- 'ssl_sign_hash',
- 'server_name',
- 'secure_renegotiation',
- 'renegotiate_size',
- 'renegotiate_period',
- 'options',
- 'ocsp',
- 'max_active_handshakes',
- 'key',
- 'handshake_timeout',
- 'expire_cert_response_control',
- 'cert',
- 'chain',
- 'authentication_frequency',
- 'ciphers',
- 'cipher_group',
- 'crl_file',
- 'cache_timeout',
- 'cache_size',
- 'ca_file',
- 'c3d_cert_lifespan',
- 'alert_timeout',
- 'c3d_ca_key',
- 'authenticate_depth',
- 'authenticate_name',
- 'c3d_ca_cert',
- 'c3d_cert_extension_includes',
- ]
-
- @property
- def c3d_cert_extension_includes(self):
- if self._values['c3d_cert_extension_includes'] is None:
- return None
- if len(self._values['c3d_cert_extension_includes']) == 0:
- return None
- self._values['c3d_cert_extension_includes'].sort()
- return self._values['c3d_cert_extension_includes']
-
- @property
- def options(self):
- if self._values['options'] is None:
- return None
- if len(self._values['options']) == 0:
- return None
- self._values['options'].sort()
- return self._values['options']
-
- @property
- def c3d_ca_cert(self):
- if self._values['c3d_ca_cert'] in [None, 'none']:
- return None
- return self._values['c3d_ca_cert']
-
- @property
- def ocsp(self):
- if self._values['ocsp'] in [None, 'none']:
- return None
- return self._values['ocsp']
-
- @property
- def server_name(self):
- if self._values['server_name'] in [None, 'none']:
- return None
- return self._values['server_name']
-
- @property
- def cipher_group(self):
- if self._values['cipher_group'] in [None, 'none']:
- return None
- return self._values['cipher_group']
-
- @property
- def authenticate_name(self):
- if self._values['authenticate_name'] in [None, 'none']:
- return None
- return self._values['authenticate_name']
-
- @property
- def c3d_ca_key(self):
- if self._values['c3d_ca_key'] in [None, 'none']:
- return None
- return self._values['c3d_ca_key']
-
- @property
- def ca_file(self):
- if self._values['ca_file'] in [None, 'none']:
- return None
- return self._values['ca_file']
-
- @property
- def crl_file(self):
- if self._values['crl_file'] in [None, 'none']:
- return None
- return self._values['crl_file']
-
- @property
- def authentication_frequency(self):
- if self._values['authentication_frequency'] in [None, 'none']:
- return None
- return self._values['authentication_frequency']
-
- @property
- def description(self):
- if self._values['description'] in [None, 'none']:
- return None
- return self._values['description']
-
- @property
- def proxy_ssl_passthrough(self):
- return flatten_boolean(self._values['proxy_ssl_passthrough'])
-
- @property
- def proxy_ssl(self):
- return flatten_boolean(self._values['proxy_ssl'])
-
- @property
- def generic_alert(self):
- return flatten_boolean(self._values['generic_alert'])
-
- @property
- def renegotiation(self):
- return flatten_boolean(self._values['renegotiation'])
-
- @property
- def bypass_on_handshake_alert(self):
- return flatten_boolean(self._values['bypass_on_handshake_alert'])
-
- @property
- def bypass_on_client_cert_fail(self):
- return flatten_boolean(self._values['bypass_on_client_cert_fail'])
-
- @property
- def mode(self):
- return flatten_boolean(self._values['mode'])
-
- @property
- def retain_certificate(self):
- return flatten_boolean(self._values['retain_certificate'])
-
- @property
- def allow_expired_crl(self):
- return flatten_boolean(self._values['allow_expired_crl'])
-
- @property
- def mod_ssl_methods(self):
- return flatten_boolean(self._values['mod_ssl_methods'])
-
- @property
- def session_ticket(self):
- return flatten_boolean(self._values['session_ticket'])
-
- @property
- def session_mirroring(self):
- return flatten_boolean(self._values['session_mirroring'])
-
- @property
- def unclean_shutdown(self):
- return flatten_boolean(self._values['unclean_shutdown'])
-
- @property
- def strict_resume(self):
- return flatten_boolean(self._values['strict_resume'])
-
- @property
- def ssl_forward_proxy_enabled(self):
- return flatten_boolean(self._values['ssl_forward_proxy_enabled'])
-
- @property
- def ssl_forward_proxy_bypass(self):
- return flatten_boolean(self._values['ssl_forward_proxy_bypass'])
-
- @property
- def sni_default(self):
- return flatten_boolean(self._values['sni_default'])
-
- @property
- def sni_require(self):
- return flatten_boolean(self._values['sni_require'])
-
- @property
- def ssl_c3d(self):
- return flatten_boolean(self._values['ssl_c3d'])
-
-
-class ServerSslProfilesFactManager(BaseManager):
- def __init__(self, *args, **kwargs):
- self.client = kwargs.get('client', None)
- self.module = kwargs.get('module', None)
- super(ServerSslProfilesFactManager, self).__init__(**kwargs)
- self.want = ServerSslProfilesParameters(params=self.module.params)
-
- def exec_module(self):
- facts = self._exec_module()
- result = dict(server_ssl_profiles=facts)
- return result
-
- def _exec_module(self):
- results = []
- facts = self.read_facts()
- for item in facts:
- attrs = item.to_return()
- results.append(attrs)
- results = sorted(results, key=lambda k: k['full_path'])
- return results
-
- def read_facts(self):
- results = []
- collection = self.read_collection_from_device()
- for resource in collection:
- params = ServerSslProfilesParameters(params=resource)
- results.append(params)
- return results
-
- def read_collection_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/profile/server-ssl".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- if 'items' not in response:
- return []
- result = response['items']
- return result
-
-
-class SoftwareVolumesParameters(BaseParameters):
- api_map = {
- 'fullPath': 'full_path',
- 'basebuild': 'base_build',
- }
-
- returnables = [
- 'full_path',
- 'name',
- 'active',
- 'base_build',
- 'build',
- 'product',
- 'status',
- 'version',
- 'install_volume',
- 'default_boot_location'
- ]
-
- @property
- def install_volume(self):
- if self._values['media'] is None:
- return None
- return self._values['media'].get('name', None)
-
- @property
- def default_boot_location(self):
- if self._values['media'] is None:
- return None
- return flatten_boolean(self._values['media'].get('defaultBootLocation', None))
-
- @property
- def active(self):
- if self._values['active'] is True:
- return 'yes'
- return 'no'
-
-
-class SoftwareVolumesFactManager(BaseManager):
- def __init__(self, *args, **kwargs):
- self.client = kwargs.get('client', None)
- self.module = kwargs.get('module', None)
- super(SoftwareVolumesFactManager, self).__init__(**kwargs)
- self.want = SoftwareVolumesParameters(params=self.module.params)
-
- def exec_module(self):
- facts = self._exec_module()
- result = dict(software_volumes=facts)
- return result
-
- def _exec_module(self):
- results = []
- facts = self.read_facts()
- for item in facts:
- attrs = item.to_return()
- results.append(attrs)
- results = sorted(results, key=lambda k: k['full_path'])
- return results
-
- def read_facts(self):
- results = []
- collection = self.read_collection_from_device()
- for resource in collection:
- params = SoftwareVolumesParameters(params=resource)
- results.append(params)
- return results
-
- def read_collection_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/sys/software/volume".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- if 'items' not in response:
- return []
- result = response['items']
- return result
-
-
-class SoftwareHotfixesParameters(BaseParameters):
- api_map = {
- 'fullPath': 'full_path',
- }
-
- returnables = [
- 'name',
- 'full_path',
- 'build',
- 'checksum',
- 'id',
- 'product',
- 'title',
- 'verified',
- 'version',
- ]
-
-
-class SoftwareHotfixesFactManager(BaseManager):
- def __init__(self, *args, **kwargs):
- self.client = kwargs.get('client', None)
- self.module = kwargs.get('module', None)
- super(SoftwareHotfixesFactManager, self).__init__(**kwargs)
- self.want = SoftwareHotfixesParameters(params=self.module.params)
-
- def exec_module(self):
- facts = self._exec_module()
- result = dict(software_hotfixes=facts)
- return result
-
- def _exec_module(self):
- results = []
- facts = self.read_facts()
- for item in facts:
- attrs = item.to_return()
- results.append(attrs)
- results = sorted(results, key=lambda k: k['full_path'])
- return results
-
- def read_facts(self):
- results = []
- collection = self.read_collection_from_device()
- for resource in collection:
- params = SoftwareHotfixesParameters(params=resource)
- results.append(params)
- return results
-
- def read_collection_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/sys/software/hotfix".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- if 'items' not in response:
- return []
- result = response['items']
- return result
-
-
-class SoftwareImagesParameters(BaseParameters):
- api_map = {
- 'fullPath': 'full_path',
- 'buildDate': 'build_date',
- 'fileSize': 'file_size',
- 'lastModified': 'last_modified',
- }
-
- returnables = [
- 'name',
- 'full_path',
- 'build',
- 'build_date',
- 'checksum',
- 'file_size',
- 'last_modified',
- 'product',
- 'verified',
- 'version',
- ]
-
- @property
- def file_size(self):
- if self._values['file_size'] is None:
- return None
- matches = re.match(r'\d+', self._values['file_size'])
- if matches:
- return int(matches.group(0))
-
- @property
- def build_date(self):
- """Normalizes the build_date string
-
- The ISOs usually ship with a broken format
-
- ex: Tue May 15 15 26 30 PDT 2018
-
- This will re-format that time so that it looks like ISO 8601 without
- microseconds
-
- ex: 2018-05-15T15:26:30
-
- :return:
- """
- if self._values['build_date'] is None:
- return None
-
- d = self._values['build_date'].split(' ')
-
- # This removes the timezone portion from the string. This is done
- # because Python has awfule tz parsing and strptime doesnt work with
- # all timezones in %Z; it only uses the timezones found in time.tzname
- d.pop(6)
-
- result = datetime.datetime.strptime(' '.join(d), '%a %b %d %H %M %S %Y').isoformat()
- return result
-
- @property
- def last_modified(self):
- """Normalizes the last_modified string
-
- The strings that the system reports look like the following
-
- ex: Tue May 15 15:26:30 2018
-
- This property normalizes this value to be isoformat
-
- ex: 2018-05-15T15:26:30
-
- :return:
- """
- if self._values['last_modified'] is None:
- return None
- result = datetime.datetime.strptime(self._values['last_modified'], '%a %b %d %H:%M:%S %Y').isoformat()
- return result
-
-
-class SoftwareImagesFactManager(BaseManager):
- def __init__(self, *args, **kwargs):
- self.client = kwargs.get('client', None)
- self.module = kwargs.get('module', None)
- super(SoftwareImagesFactManager, self).__init__(**kwargs)
- self.want = SoftwareImagesParameters(params=self.module.params)
-
- def exec_module(self):
- facts = self._exec_module()
- result = dict(software_images=facts)
- return result
-
- def _exec_module(self):
- results = []
- facts = self.read_facts()
- for item in facts:
- attrs = item.to_return()
- results.append(attrs)
- results = sorted(results, key=lambda k: k['full_path'])
- return results
-
- def read_facts(self):
- results = []
- collection = self.read_collection_from_device()
- for resource in collection:
- params = SoftwareImagesParameters(params=resource)
- results.append(params)
- return results
-
- def read_collection_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/sys/software/image".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- if 'items' not in response:
- return []
- result = response['items']
- return result
-
-
-class SslCertificatesParameters(BaseParameters):
- api_map = {
- 'fullPath': 'full_path',
- 'keyType': 'key_type',
- 'certificateKeySize': 'key_size',
- 'systemPath': 'system_path',
- 'checksum': 'sha1_checksum',
- 'lastUpdateTime': 'last_update_time',
- 'isBundle': 'is_bundle',
- 'expirationString': 'expiration_date',
- 'expirationDate': 'expiration_timestamp',
- 'createTime': 'create_time'
- }
-
- returnables = [
- 'full_path',
- 'name',
- 'key_type',
- 'key_size',
- 'system_path',
- 'sha1_checksum',
- 'subject',
- 'last_update_time',
- 'issuer',
- 'is_bundle',
- 'fingerprint',
- 'expiration_date',
- 'expiration_timestamp',
- 'create_time',
- ]
-
- @property
- def sha1_checksum(self):
- if self._values['sha1_checksum'] is None:
- return None
- parts = self._values['sha1_checksum'].split(':')
- return parts[2]
-
- @property
- def is_bundle(self):
- if self._values['sha1_checksum'] is None:
- return None
- if self._values['is_bundle'] in BOOLEANS_TRUE:
- return 'yes'
- return 'no'
-
-
-class SslCertificatesFactManager(BaseManager):
- def __init__(self, *args, **kwargs):
- self.client = kwargs.get('client', None)
- self.module = kwargs.get('module', None)
- super(SslCertificatesFactManager, self).__init__(**kwargs)
- self.want = SslCertificatesParameters(params=self.module.params)
-
- def exec_module(self):
- facts = self._exec_module()
- result = dict(ssl_certs=facts)
- return result
-
- def _exec_module(self):
- results = []
- facts = self.read_facts()
- for item in facts:
- attrs = item.to_return()
- results.append(attrs)
- results = sorted(results, key=lambda k: k['full_path'])
- return results
-
- def read_facts(self):
- results = []
- collection = self.read_collection_from_device()
- for resource in collection:
- params = SslCertificatesParameters(params=resource)
- results.append(params)
- return results
-
- def read_collection_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/sys/file/ssl-cert".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- if 'items' not in response:
- return []
- result = response['items']
- return result
-
-
-class SslKeysParameters(BaseParameters):
- api_map = {
- 'fullPath': 'full_path',
- 'keyType': 'key_type',
- 'keySize': 'key_size',
- 'securityType': 'security_type',
- 'systemPath': 'system_path',
- 'checksum': 'sha1_checksum'
- }
-
- returnables = [
- 'full_path',
- 'name',
- 'key_type',
- 'key_size',
- 'security_type',
- 'system_path',
- 'sha1_checksum'
- ]
-
- @property
- def sha1_checksum(self):
- if self._values['sha1_checksum'] is None:
- return None
- parts = self._values['sha1_checksum'].split(':')
- return parts[2]
-
-
-class SslKeysFactManager(BaseManager):
- def __init__(self, *args, **kwargs):
- self.client = kwargs.get('client', None)
- self.module = kwargs.get('module', None)
- super(SslKeysFactManager, self).__init__(**kwargs)
- self.want = SslKeysParameters(params=self.module.params)
-
- def exec_module(self):
- facts = self._exec_module()
- result = dict(ssl_keys=facts)
- return result
-
- def _exec_module(self):
- results = []
- facts = self.read_facts()
- for item in facts:
- attrs = item.to_return()
- results.append(attrs)
- results = sorted(results, key=lambda k: k['full_path'])
- return results
-
- def read_facts(self):
- results = []
- collection = self.read_collection_from_device()
- for resource in collection:
- params = SslKeysParameters(params=resource)
- results.append(params)
- return results
-
- def read_collection_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/sys/file/ssl-key".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- if 'items' not in response:
- return []
- result = response['items']
- return result
-
-
-class SystemDbParameters(BaseParameters):
- api_map = {
- 'fullPath': 'full_path',
- 'defaultValue': 'default',
- 'scfConfig': 'scf_config',
- 'valueRange': 'value_range'
- }
-
- returnables = [
- 'name',
- 'full_path',
- 'default',
- 'scf_config',
- 'value',
- 'value_range'
- ]
-
-
-class SystemDbFactManager(BaseManager):
- def __init__(self, *args, **kwargs):
- self.client = kwargs.get('client', None)
- self.module = kwargs.get('module', None)
- super(SystemDbFactManager, self).__init__(**kwargs)
- self.want = SystemInfoParameters(params=self.module.params)
-
- def exec_module(self):
- facts = self._exec_module()
- result = dict(system_db=facts)
- return result
-
- def _exec_module(self):
- results = []
- facts = self.read_facts()
- for item in facts:
- attrs = item.to_return()
- results.append(attrs)
- results = sorted(results, key=lambda k: k['full_path'])
- return results
-
- def read_facts(self):
- results = []
- collection = self.read_collection_from_device()
- for resource in collection:
- params = SystemDbParameters(params=resource)
- results.append(params)
- return results
-
- def read_collection_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/sys/db".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- if 'items' not in response:
- return []
- result = response['items']
- return result
-
-
-class SystemInfoParameters(BaseParameters):
- api_map = {
-
- }
-
- returnables = [
- 'base_mac_address',
- 'marketing_name',
- 'time',
- 'hardware_information',
- 'product_information',
- 'package_edition',
- 'package_version',
- 'product_code',
- 'product_build',
- 'product_built',
- 'product_build_date',
- 'product_changelist',
- 'product_jobid',
- 'product_version',
- 'uptime',
- 'chassis_serial',
- 'host_board_part_revision',
- 'host_board_serial',
- 'platform',
- 'switch_board_part_revision',
- 'switch_board_serial'
- ]
-
- @property
- def chassis_serial(self):
- if self._values['system-info'] is None:
- return None
- if 'bigipChassisSerialNum' not in self._values['system-info'][0]:
- return None
- return self._values['system-info'][0]['bigipChassisSerialNum']
-
- @property
- def switch_board_serial(self):
- if self._values['system-info'] is None:
- return None
- if 'switchBoardSerialNum' not in self._values['system-info'][0]:
- return None
- if self._values['system-info'][0]['switchBoardSerialNum'].strip() == '':
- return None
- return self._values['system-info'][0]['switchBoardSerialNum']
-
- @property
- def switch_board_part_revision(self):
- if self._values['system-info'] is None:
- return None
- if 'switchBoardPartRevNum' not in self._values['system-info'][0]:
- return None
- if self._values['system-info'][0]['switchBoardPartRevNum'].strip() == '':
- return None
- return self._values['system-info'][0]['switchBoardPartRevNum']
-
- @property
- def platform(self):
- if self._values['system-info'] is None:
- return None
- return self._values['system-info'][0]['platform']
-
- @property
- def host_board_serial(self):
- if self._values['system-info'] is None:
- return None
- if 'hostBoardSerialNum' not in self._values['system-info'][0]:
- return None
- if self._values['system-info'][0]['hostBoardSerialNum'].strip() == '':
- return None
- return self._values['system-info'][0]['hostBoardSerialNum']
-
- @property
- def host_board_part_revision(self):
- if self._values['system-info'] is None:
- return None
- if 'hostBoardPartRevNum' not in self._values['system-info'][0]:
- return None
- if self._values['system-info'][0]['hostBoardPartRevNum'].strip() == '':
- return None
- return self._values['system-info'][0]['hostBoardPartRevNum']
-
- @property
- def package_edition(self):
- return self._values['Edition']
-
- @property
- def package_version(self):
- return 'Build {0} - {1}'.format(self._values['Build'], self._values['Date'])
-
- @property
- def product_build(self):
- return self._values['Build']
-
- @property
- def product_build_date(self):
- return self._values['Date']
-
- @property
- def product_built(self):
- if 'Built' in self._values['version_info']:
- return int(self._values['version_info']['Built'])
-
- @property
- def product_changelist(self):
- if 'Changelist' in self._values['version_info']:
- return int(self._values['version_info']['Changelist'])
-
- @property
- def product_jobid(self):
- if 'JobID' in self._values['version_info']:
- return int(self._values['version_info']['JobID'])
-
- @property
- def product_code(self):
- return self._values['Product']
-
- @property
- def product_version(self):
- return self._values['Version']
-
- @property
- def hardware_information(self):
- if self._values['hardware-version'] is None:
- return None
- self._transform_name_attribute(self._values['hardware-version'])
- result = [v for k, v in iteritems(self._values['hardware-version'])]
- return result
-
- def _transform_name_attribute(self, entry):
- if isinstance(entry, dict):
- for k, v in iteritems(entry):
- if k == 'tmName':
- entry['name'] = entry.pop('tmName')
- self._transform_name_attribute(v)
- elif isinstance(entry, list):
- for k in entry:
- if k == 'tmName':
- entry['name'] = entry.pop('tmName')
- self._transform_name_attribute(k)
- else:
- return
-
- @property
- def time(self):
- if self._values['fullDate'] is None:
- return None
- date = datetime.datetime.strptime(self._values['fullDate'], "%Y-%m-%dT%H:%M:%SZ")
- result = dict(
- day=date.day,
- hour=date.hour,
- minute=date.minute,
- month=date.month,
- second=date.second,
- year=date.year
- )
- return result
-
- @property
- def marketing_name(self):
- if self._values['platform'] is None:
- return None
- return self._values['platform'][0]['marketingName']
-
- @property
- def base_mac_address(self):
- if self._values['platform'] is None:
- return None
- return self._values['platform'][0]['baseMac']
-
-
-class SystemInfoFactManager(BaseManager):
- def __init__(self, *args, **kwargs):
- self.client = kwargs.get('client', None)
- self.module = kwargs.get('module', None)
- super(SystemInfoFactManager, self).__init__(**kwargs)
- self.want = SystemInfoParameters(params=self.module.params)
-
- def exec_module(self):
- facts = self._exec_module()
- result = dict(system_info=facts)
- return result
-
- def _exec_module(self):
- facts = self.read_facts()
- results = facts.to_return()
- return results
-
- def read_facts(self):
- collection = self.read_collection_from_device()
- params = SystemInfoParameters(params=collection)
- return params
-
- def read_collection_from_device(self):
- result = dict()
- tmp = self.read_hardware_info_from_device()
- if tmp:
- result.update(tmp)
-
- tmp = self.read_clock_info_from_device()
- if tmp:
- result.update(tmp)
-
- tmp = self.read_version_info_from_device()
- if tmp:
- result.update(tmp)
-
- tmp = self.read_uptime_info_from_device()
- if tmp:
- result.update(tmp)
-
- tmp = self.read_version_file_info_from_device()
- if tmp:
- result.update(tmp)
-
- return result
-
- def read_version_file_info_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/util/bash".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- args = dict(
- command='run',
- utilCmdArgs='-c "cat /VERSION"'
- )
- resp = self.client.api.post(uri, json=args)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- try:
- pattern = r'^(?P<key>(Product|Build|Sequence|BaseBuild|Edition|Date|Built|Changelist|JobID))\:(?P<value>.*)'
- result = response['commandResult'].strip()
- except KeyError:
- return None
-
- if 'No such file or directory' in result:
- return None
-
- lines = response['commandResult'].split("\n")
- result = dict()
- for line in lines:
- if not line:
- continue
- matches = re.match(pattern, line)
- if matches:
- result[matches.group('key')] = matches.group('value').strip()
-
- if result:
- return dict(
- version_info=result
- )
-
- def read_uptime_info_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/util/bash".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- args = dict(
- command='run',
- utilCmdArgs='-c "cat /proc/uptime"'
- )
- resp = self.client.api.post(uri, json=args)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- try:
- parts = response['commandResult'].strip().split(' ')
- return dict(
- uptime=math.floor(float(parts[0]))
- )
- except KeyError:
- pass
-
- def read_hardware_info_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/sys/hardware".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- result = parseStats(response)
- return result
-
- def read_clock_info_from_device(self):
- """Parses clock info from the REST API
-
- The clock stat returned from the REST API (at the time of 13.1.0.7)
- is similar to the following.
-
- {
- "kind": "tm:sys:clock:clockstats",
- "selfLink": "https://localhost/mgmt/tm/sys/clock?ver=13.1.0.4",
- "entries": {
- "https://localhost/mgmt/tm/sys/clock/0": {
- "nestedStats": {
- "entries": {
- "fullDate": {
- "description": "2018-06-05T13:38:33Z"
- }
- }
- }
- }
- }
- }
-
- Parsing this data using the ``parseStats`` method, yields a list of
- the clock stats in a format resembling that below.
-
- [{'fullDate': '2018-06-05T13:41:05Z'}]
-
- Therefore, this method cherry-picks the first entry from this list
- and returns it. There can be no other items in this list.
-
- Returns:
- A dict mapping keys to the corresponding clock stats. For
- example:
-
- {'fullDate': '2018-06-05T13:41:05Z'}
-
- There should never not be a clock stat, unless by chance it
- is removed from the API in the future, or changed to a different
- API endpoint.
-
- Raises:
- F5ModuleError: A non-successful HTTP code was returned or a JSON
- response was not found.
- """
- uri = "https://{0}:{1}/mgmt/tm/sys/clock".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- result = parseStats(response)
- return result[0]
-
- def read_version_info_from_device(self):
- """Parses version info from the REST API
-
- The version stat returned from the REST API (at the time of 13.1.0.7)
- is similar to the following.
-
- {
- "kind": "tm:sys:version:versionstats",
- "selfLink": "https://localhost/mgmt/tm/sys/version?ver=13.1.0.4",
- "entries": {
- "https://localhost/mgmt/tm/sys/version/0": {
- "nestedStats": {
- "entries": {
- "Build": {
- "description": "0.0.6"
- },
- "Date": {
- "description": "Tue Mar 13 20:10:42 PDT 2018"
- },
- "Edition": {
- "description": "Point Release 4"
- },
- "Product": {
- "description": "BIG-IP"
- },
- "Title": {
- "description": "Main Package"
- },
- "Version": {
- "description": "13.1.0.4"
- }
- }
- }
- }
- }
- }
-
- Parsing this data using the ``parseStats`` method, yields a list of
- the clock stats in a format resembling that below.
-
- [{'Build': '0.0.6', 'Date': 'Tue Mar 13 20:10:42 PDT 2018',
- 'Edition': 'Point Release 4', 'Product': 'BIG-IP', 'Title': 'Main Package',
- 'Version': '13.1.0.4'}]
-
- Therefore, this method cherry-picks the first entry from this list
- and returns it. There can be no other items in this list.
-
- Returns:
- A dict mapping keys to the corresponding clock stats. For
- example:
-
- {'Build': '0.0.6', 'Date': 'Tue Mar 13 20:10:42 PDT 2018',
- 'Edition': 'Point Release 4', 'Product': 'BIG-IP', 'Title': 'Main Package',
- 'Version': '13.1.0.4'}
-
- There should never not be a version stat, unless by chance it
- is removed from the API in the future, or changed to a different
- API endpoint.
-
- Raises:
- F5ModuleError: A non-successful HTTP code was returned or a JSON
- response was not found.
- """
- uri = "https://{0}:{1}/mgmt/tm/sys/version".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- result = parseStats(response)
- return result[0]
-
-
-class TcpMonitorsParameters(BaseParameters):
- api_map = {
- 'fullPath': 'full_path',
- 'defaultsFrom': 'parent',
- 'adaptiveDivergenceType': 'adaptive_divergence_type',
- 'adaptiveDivergenceValue': 'adaptive_divergence_value',
- 'adaptiveLimit': 'adaptive_limit',
- 'adaptiveSamplingTimespan': 'adaptive_sampling_timespan',
- 'ipDscp': 'ip_dscp',
- 'manualResume': 'manual_resume',
- 'timeUntilUp': 'time_until_up',
- 'upInterval': 'up_interval',
- }
-
- returnables = [
- 'full_path',
- 'name',
- 'parent',
- 'description',
- 'adaptive',
- 'adaptive_divergence_type',
- 'adaptive_divergence_value',
- 'adaptive_limit',
- 'adaptive_sampling_timespan',
- 'destination',
- 'interval',
- 'ip_dscp',
- 'manual_resume',
- 'reverse',
- 'time_until_up',
- 'timeout',
- 'transparent',
- 'up_interval',
- ]
-
- @property
- def description(self):
- if self._values['description'] in [None, 'none']:
- return None
- return self._values['description']
-
- @property
- def transparent(self):
- return flatten_boolean(self._values['transparent'])
-
- @property
- def manual_resume(self):
- return flatten_boolean(self._values['manual_resume'])
-
- @property
- def adaptive(self):
- return flatten_boolean(self._values['adaptive'])
-
- @property
- def reverse(self):
- return flatten_boolean(self._values['reverse'])
-
-
-class TcpMonitorsFactManager(BaseManager):
- def __init__(self, *args, **kwargs):
- self.client = kwargs.get('client', None)
- self.module = kwargs.get('module', None)
- super(TcpMonitorsFactManager, self).__init__(**kwargs)
- self.want = TcpMonitorsParameters(params=self.module.params)
-
- def exec_module(self):
- facts = self._exec_module()
- result = dict(tcp_monitors=facts)
- return result
-
- def _exec_module(self):
- results = []
- facts = self.read_facts()
- for item in facts:
- attrs = item.to_return()
- results.append(attrs)
- results = sorted(results, key=lambda k: k['full_path'])
- return results
-
- def read_facts(self):
- results = []
- collection = self.read_collection_from_device()
- for resource in collection:
- params = TcpMonitorsParameters(params=resource)
- results.append(params)
- return results
-
- def read_collection_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/monitor/tcp".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- if 'items' not in response:
- return []
- result = response['items']
- return result
-
-
-class TcpHalfOpenMonitorsParameters(BaseParameters):
- api_map = {
- 'fullPath': 'full_path',
- 'defaultsFrom': 'parent',
- 'manualResume': 'manual_resume',
- 'timeUntilUp': 'time_until_up',
- 'upInterval': 'up_interval',
- }
-
- returnables = [
- 'full_path',
- 'name',
- 'parent',
- 'description',
- 'destination',
- 'interval',
- 'manual_resume',
- 'time_until_up',
- 'timeout',
- 'transparent',
- 'up_interval',
- ]
-
- @property
- def description(self):
- if self._values['description'] in [None, 'none']:
- return None
- return self._values['description']
-
- @property
- def transparent(self):
- return flatten_boolean(self._values['transparent'])
-
- @property
- def manual_resume(self):
- return flatten_boolean(self._values['manual_resume'])
-
-
-class TcpHalfOpenMonitorsFactManager(BaseManager):
- def __init__(self, *args, **kwargs):
- self.client = kwargs.get('client', None)
- self.module = kwargs.get('module', None)
- super(TcpHalfOpenMonitorsFactManager, self).__init__(**kwargs)
- self.want = TcpHalfOpenMonitorsParameters(params=self.module.params)
-
- def exec_module(self):
- facts = self._exec_module()
- result = dict(tcp_half_open_monitors=facts)
- return result
-
- def _exec_module(self):
- results = []
- facts = self.read_facts()
- for item in facts:
- attrs = item.to_return()
- results.append(attrs)
- results = sorted(results, key=lambda k: k['full_path'])
- return results
-
- def read_facts(self):
- results = []
- collection = self.read_collection_from_device()
- for resource in collection:
- params = TcpHalfOpenMonitorsParameters(params=resource)
- results.append(params)
- return results
-
- def read_collection_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/monitor/tcp-half-open".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- if 'items' not in response:
- return []
- result = response['items']
- return result
-
-
-class TcpProfilesParameters(BaseParameters):
- api_map = {
- 'fullPath': 'full_path',
- 'defaultsFrom': 'parent',
- 'ackOnPush': 'ack_on_push',
- 'autoProxyBufferSize': 'auto_proxy_buffer',
- 'autoReceiveWindowSize': 'auto_receive_window',
- 'autoSendBufferSize': 'auto_send_buffer',
- 'closeWaitTimeout': 'close_wait',
- 'cmetricsCache': 'congestion_metrics_cache',
- 'cmetricsCacheTimeout': 'congestion_metrics_cache_timeout',
- 'congestionControl': 'congestion_control',
- 'deferredAccept': 'deferred_accept',
- 'delayWindowControl': 'delay_window_control',
- 'delayedAcks': 'delayed_acks',
- 'earlyRetransmit': 'early_retransmit',
- 'ecn': 'explicit_congestion_notification',
- 'enhancedLossRecovery': 'enhanced_loss_recovery',
- 'fastOpen': 'fast_open',
- 'fastOpenCookieExpiration': 'fast_open_cookie_expiration',
- 'finWaitTimeout': 'fin_wait_1',
- 'finWait_2Timeout': 'fin_wait_2',
- 'idleTimeout': 'idle_timeout',
- 'initCwnd': 'initial_congestion_window_size',
- 'initRwnd': 'initial_receive_window_size',
- 'ipDfMode': 'dont_fragment_flag',
- 'ipTosToClient': 'ip_tos',
- 'ipTtlMode': 'time_to_live',
- 'ipTtlV4': 'time_to_live_v4',
- 'ipTtlV6': 'time_to_live_v6',
- 'keepAliveInterval': 'keep_alive_interval',
- 'limitedTransmit': 'limited_transmit_recovery',
- 'linkQosToClient': 'link_qos',
- 'maxRetrans': 'max_segment_retrans',
- 'synMaxRetrans': 'max_syn_retrans',
- 'rexmtThresh': 'retransmit_threshold',
- 'maxSegmentSize': 'max_segment_size',
- 'md5Signature': 'md5_signature',
- 'minimumRto': 'minimum_rto',
- 'mptcp': 'multipath_tcp',
- 'mptcpCsum': 'mptcp_checksum',
- 'mptcpCsumVerify': 'mptcp_checksum_verify',
- 'mptcpFallback': 'mptcp_fallback',
- 'mptcpFastjoin': 'mptcp_fast_join',
- 'mptcpIdleTimeout': 'mptcp_idle_timeout',
- 'mptcpJoinMax': 'mptcp_join_max',
- 'mptcpMakeafterbreak': 'mptcp_make_after_break',
- 'mptcpNojoindssack': 'mptcp_no_join_dss_ack',
- 'mptcpRtomax': 'mptcp_rto_max',
- 'mptcpRxmitmin': 'mptcp_retransmit_min',
- 'mptcpSubflowmax': 'mptcp_subflow_max',
- 'mptcpTimeout': 'mptcp_timeout',
- 'nagle': 'nagle_algorithm',
- 'pktLossIgnoreBurst': 'pkt_loss_ignore_burst',
- 'pktLossIgnoreRate': 'pkt_loss_ignore_rate',
- 'proxyBufferHigh': 'proxy_buffer_high',
- 'proxyBufferLow': 'proxy_buffer_low',
- 'proxyMss': 'proxy_max_segment',
- 'proxyOptions': 'proxy_options',
- 'pushFlag': 'push_flag',
- 'ratePace': 'rate_pace',
- 'ratePaceMaxRate': 'rate_pace_max_rate',
- 'receiveWindowSize': 'receive_window',
- 'resetOnTimeout': 'reset_on_timeout',
- 'selectiveAcks': 'selective_acks',
- 'selectiveNack': 'selective_nack',
- 'sendBufferSize': 'send_buffer',
- 'slowStart': 'slow_start',
- 'synCookieEnable': 'syn_cookie_enable',
- 'synCookieWhitelist': 'syn_cookie_white_list',
- 'synRtoBase': 'syn_retrans_to_base',
- 'tailLossProbe': 'tail_loss_probe',
- 'timeWaitRecycle': 'time_wait_recycle',
- 'timeWaitTimeout': 'time_wait',
- 'verifiedAccept': 'verified_accept',
- 'zeroWindowTimeout': 'zero_window_timeout',
- }
-
- returnables = [
- 'full_path',
- 'name',
- 'parent',
- 'description',
- 'abc',
- 'ack_on_push',
- 'auto_proxy_buffer',
- 'auto_receive_window',
- 'auto_send_buffer',
- 'close_wait',
- 'congestion_metrics_cache',
- 'congestion_metrics_cache_timeout',
- 'congestion_control',
- 'deferred_accept',
- 'delay_window_control',
- 'delayed_acks',
- 'dsack',
- 'early_retransmit',
- 'explicit_congestion_notification',
- 'enhanced_loss_recovery',
- 'fast_open',
- 'fast_open_cookie_expiration',
- 'fin_wait_1',
- 'fin_wait_2',
- 'idle_timeout',
- 'initial_congestion_window_size',
- 'initial_receive_window_size',
- 'dont_fragment_flag',
- 'ip_tos',
- 'time_to_live',
- 'time_to_live_v4',
- 'time_to_live_v6',
- 'keep_alive_interval',
- 'limited_transmit_recovery',
- 'link_qos',
- 'max_segment_retrans',
- 'max_syn_retrans',
- 'max_segment_size',
- 'md5_signature',
- 'minimum_rto',
- 'multipath_tcp',
- 'mptcp_checksum',
- 'mptcp_checksum_verify',
- 'mptcp_fallback',
- 'mptcp_fast_join',
- 'mptcp_idle_timeout',
- 'mptcp_join_max',
- 'mptcp_make_after_break',
- 'mptcp_no_join_dss_ack',
- 'mptcp_rto_max',
- 'mptcp_retransmit_min',
- 'mptcp_subflow_max',
- 'mptcp_timeout',
- 'nagle_algorithm',
- 'pkt_loss_ignore_burst',
- 'pkt_loss_ignore_rate',
- 'proxy_buffer_high',
- 'proxy_buffer_low',
- 'proxy_max_segment',
- 'proxy_options',
- 'push_flag',
- 'rate_pace',
- 'rate_pace_max_rate',
- 'receive_window',
- 'reset_on_timeout',
- 'retransmit_threshold',
- 'selective_acks',
- 'selective_nack',
- 'send_buffer',
- 'slow_start',
- 'syn_cookie_enable',
- 'syn_cookie_white_list',
- 'syn_retrans_to_base',
- 'tail_loss_probe',
- 'time_wait_recycle',
- 'time_wait',
- 'timestamps',
- 'verified_accept',
- 'zero_window_timeout',
- ]
-
- @property
- def description(self):
- if self._values['description'] in [None, 'none']:
- return None
- return self._values['description']
-
- @property
- def time_wait(self):
- if self._values['time_wait'] is None:
- return None
- if self._values['time_wait'] == 0:
- return "immediate"
- if self._values['time_wait'] == 4294967295:
- return 'indefinite'
- return self._values['time_wait']
-
- @property
- def close_wait(self):
- if self._values['close_wait'] is None:
- return None
- if self._values['close_wait'] == 0:
- return "immediate"
- if self._values['close_wait'] == 4294967295:
- return 'indefinite'
- return self._values['close_wait']
-
- @property
- def fin_wait_1(self):
- if self._values['fin_wait_1'] is None:
- return None
- if self._values['fin_wait_1'] == 0:
- return "immediate"
- if self._values['fin_wait_1'] == 4294967295:
- return 'indefinite'
- return self._values['fin_wait_1']
-
- @property
- def fin_wait_2(self):
- if self._values['fin_wait_2'] is None:
- return None
- if self._values['fin_wait_2'] == 0:
- return "immediate"
- if self._values['fin_wait_2'] == 4294967295:
- return 'indefinite'
- return self._values['fin_wait_2']
-
- @property
- def zero_window_timeout(self):
- if self._values['zero_window_timeout'] is None:
- return None
- if self._values['zero_window_timeout'] == 4294967295:
- return 'indefinite'
- return self._values['zero_window_timeout']
-
- @property
- def idle_timeout(self):
- if self._values['idle_timeout'] is None:
- return None
- if self._values['idle_timeout'] == 4294967295:
- return 'indefinite'
- return self._values['idle_timeout']
-
- @property
- def keep_alive_interval(self):
- if self._values['keep_alive_interval'] is None:
- return None
- if self._values['keep_alive_interval'] == 4294967295:
- return 'indefinite'
- return self._values['keep_alive_interval']
-
- @property
- def verified_accept(self):
- return flatten_boolean(self._values['verified_accept'])
-
- @property
- def timestamps(self):
- return flatten_boolean(self._values['timestamps'])
-
- @property
- def time_wait_recycle(self):
- return flatten_boolean(self._values['time_wait_recycle'])
-
- @property
- def tail_loss_probe(self):
- return flatten_boolean(self._values['tail_loss_probe'])
-
- @property
- def syn_cookie_white_list(self):
- return flatten_boolean(self._values['syn_cookie_white_list'])
-
- @property
- def syn_cookie_enable(self):
- return flatten_boolean(self._values['syn_cookie_enable'])
-
- @property
- def slow_start(self):
- return flatten_boolean(self._values['slow_start'])
-
- @property
- def selective_nack(self):
- return flatten_boolean(self._values['selective_nack'])
-
- @property
- def selective_acks(self):
- return flatten_boolean(self._values['selective_acks'])
-
- @property
- def reset_on_timeout(self):
- return flatten_boolean(self._values['reset_on_timeout'])
-
- @property
- def rate_pace(self):
- return flatten_boolean(self._values['rate_pace'])
-
- @property
- def proxy_options(self):
- return flatten_boolean(self._values['proxy_options'])
-
- @property
- def proxy_max_segment(self):
- return flatten_boolean(self._values['proxy_max_segment'])
-
- @property
- def nagle_algorithm(self):
- return flatten_boolean(self._values['nagle_algorithm'])
-
- @property
- def mptcp_no_join_dss_ack(self):
- return flatten_boolean(self._values['mptcp_no_join_dss_ack'])
-
- @property
- def mptcp_make_after_break(self):
- return flatten_boolean(self._values['mptcp_make_after_break'])
-
- @property
- def mptcp_fast_join(self):
- return flatten_boolean(self._values['mptcp_fast_join'])
-
- @property
- def mptcp_checksum_verify(self):
- return flatten_boolean(self._values['mptcp_checksum_verify'])
-
- @property
- def mptcp_checksum(self):
- return flatten_boolean(self._values['mptcp_checksum'])
-
- @property
- def multipath_tcp(self):
- return flatten_boolean(self._values['multipath_tcp'])
-
- @property
- def md5_signature(self):
- return flatten_boolean(self._values['md5_signature'])
-
- @property
- def limited_transmit_recovery(self):
- return flatten_boolean(self._values['limited_transmit_recovery'])
-
- @property
- def fast_open(self):
- return flatten_boolean(self._values['fast_open'])
-
- @property
- def enhanced_loss_recovery(self):
- return flatten_boolean(self._values['enhanced_loss_recovery'])
-
- @property
- def explicit_congestion_notification(self):
- return flatten_boolean(self._values['explicit_congestion_notification'])
-
- @property
- def early_retransmit(self):
- return flatten_boolean(self._values['early_retransmit'])
-
- @property
- def dsack(self):
- return flatten_boolean(self._values['dsack'])
-
- @property
- def delayed_acks(self):
- return flatten_boolean(self._values['delayed_acks'])
-
- @property
- def delay_window_control(self):
- return flatten_boolean(self._values['delay_window_control'])
-
- @property
- def deferred_accept(self):
- return flatten_boolean(self._values['deferred_accept'])
-
- @property
- def congestion_metrics_cache(self):
- return flatten_boolean(self._values['congestion_metrics_cache'])
-
- @property
- def auto_send_buffer(self):
- return flatten_boolean(self._values['auto_send_buffer'])
-
- @property
- def auto_receive_window(self):
- return flatten_boolean(self._values['auto_receive_window'])
-
- @property
- def auto_proxy_buffer(self):
- return flatten_boolean(self._values['auto_proxy_buffer'])
-
- @property
- def abc(self):
- return flatten_boolean(self._values['abc'])
-
- @property
- def ack_on_push(self):
- return flatten_boolean(self._values['ack_on_push'])
-
-
-class TcpProfilesFactManager(BaseManager):
- def __init__(self, *args, **kwargs):
- self.client = kwargs.get('client', None)
- self.module = kwargs.get('module', None)
- super(TcpProfilesFactManager, self).__init__(**kwargs)
- self.want = TcpProfilesParameters(params=self.module.params)
-
- def exec_module(self):
- facts = self._exec_module()
- result = dict(tcp_profiles=facts)
- return result
-
- def _exec_module(self):
- results = []
- facts = self.read_facts()
- for item in facts:
- attrs = item.to_return()
- results.append(attrs)
- results = sorted(results, key=lambda k: k['full_path'])
- return results
-
- def read_facts(self):
- results = []
- collection = self.read_collection_from_device()
- for resource in collection:
- params = TcpProfilesParameters(params=resource)
- results.append(params)
- return results
-
- def read_collection_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/profile/tcp".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- if 'items' not in response:
- return []
- result = response['items']
- return result
-
-
-class TrafficGroupsParameters(BaseParameters):
- api_map = {
- 'fullPath': 'full_path',
- 'autoFailbackEnabled': 'auto_failback_enabled',
- 'autoFailbackTime': 'auto_failback_time',
- 'haLoadFactor': 'ha_load_factor',
- 'haOrder': 'ha_order',
- 'isFloating': 'is_floating',
- 'mac': 'mac_masquerade_address'
- }
-
- returnables = [
- 'full_path',
- 'name',
- 'description',
- 'auto_failback_enabled',
- 'auto_failback_time',
- 'ha_load_factor',
- 'ha_order',
- 'is_floating',
- 'mac_masquerade_address'
- ]
-
- @property
- def auto_failback_time(self):
- if self._values['auto_failback_time'] is None:
- return None
- return int(self._values['auto_failback_time'])
-
- @property
- def auto_failback_enabled(self):
- if self._values['auto_failback_enabled'] is None:
- return None
- elif self._values['auto_failback_enabled'] == 'false':
- # Yes, the REST API stores this as a string
- return 'no'
- return 'yes'
-
- @property
- def is_floating(self):
- if self._values['is_floating'] is None:
- return None
- elif self._values['is_floating'] == 'true':
- # Yes, the REST API stores this as a string
- return 'yes'
- return 'no'
-
- @property
- def mac_masquerade_address(self):
- if self._values['mac_masquerade_address'] in [None, 'none']:
- return None
- return self._values['mac_masquerade_address']
-
-
-class TrafficGroupsFactManager(BaseManager):
- def __init__(self, *args, **kwargs):
- self.client = kwargs.get('client', None)
- self.module = kwargs.get('module', None)
- super(TrafficGroupsFactManager, self).__init__(**kwargs)
- self.want = TrafficGroupsParameters(params=self.module.params)
-
- def exec_module(self):
- facts = self._exec_module()
- result = dict(traffic_groups=facts)
- return result
-
- def _exec_module(self):
- results = []
- facts = self.read_facts()
- for item in facts:
- attrs = item.to_return()
- results.append(attrs)
- results = sorted(results, key=lambda k: k['full_path'])
- return results
-
- def read_facts(self):
- results = []
- collection = self.read_collection_from_device()
- for resource in collection:
- attrs = resource
- attrs['stats'] = self.read_stats_from_device(attrs['fullPath'])
- params = TrafficGroupsParameters(params=attrs)
- results.append(params)
- return results
-
- def read_collection_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/cm/traffic-group".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- if 'items' not in response:
- return []
- result = response['items']
- return result
-
- def read_stats_from_device(self, full_path):
- uri = "https://{0}:{1}/mgmt/tm/cm/traffic-group/{2}/stats".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(name=full_path)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- result = parseStats(response)
- try:
- return result['stats']
- except KeyError:
- return {}
-
-
-class TrunksParameters(BaseParameters):
- api_map = {
- 'fullPath': 'full_path',
- 'media': 'media_speed',
- 'lacpMode': 'lacp_mode',
- 'lacp': 'lacp_state',
- 'lacpTimeout': 'lacp_timeout',
- 'stp': 'stp_enabled',
- 'workingMbrCount': 'operational_member_count',
- 'linkSelectPolicy': 'link_selection_policy',
- 'distributionHash': 'distribution_hash',
- 'cfgMbrCount': 'configured_member_count'
- }
-
- returnables = [
- 'full_path',
- 'name',
- 'description',
- 'media_speed',
- 'lacp_mode', # 'active' or 'passive'
- 'lacp_enabled',
- 'stp_enabled',
- 'operational_member_count',
- 'media_status',
- 'link_selection_policy',
- 'lacp_timeout',
- 'interfaces',
- 'distribution_hash',
- 'configured_member_count'
- ]
-
- @property
- def lacp_enabled(self):
- if self._values['lacp_enabled'] is None:
- return None
- elif self._values['lacp_enabled'] == 'disabled':
- return 'no'
- return 'yes'
-
- @property
- def stp_enabled(self):
- if self._values['stp_enabled'] is None:
- return None
- elif self._values['stp_enabled'] == 'disabled':
- return 'no'
- return 'yes'
-
- @property
- def media_status(self):
- return self._values['stats']['status']
-
-
-class TrunksFactManager(BaseManager):
- def __init__(self, *args, **kwargs):
- self.client = kwargs.get('client', None)
- self.module = kwargs.get('module', None)
- super(TrunksFactManager, self).__init__(**kwargs)
- self.want = TrunksParameters(params=self.module.params)
-
- def exec_module(self):
- facts = self._exec_module()
- result = dict(trunks=facts)
- return result
-
- def _exec_module(self):
- results = []
- facts = self.read_facts()
- for item in facts:
- attrs = item.to_return()
- results.append(attrs)
- results = sorted(results, key=lambda k: k['full_path'])
- return results
-
- def read_facts(self):
- results = []
- collection = self.read_collection_from_device()
- for resource in collection:
- attrs = resource
- attrs['stats'] = self.read_stats_from_device(attrs['fullPath'])
- params = TrunksParameters(params=attrs)
- results.append(params)
- return results
-
- def read_collection_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/net/trunk".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- if 'items' not in response:
- return []
- result = response['items']
- return result
-
- def read_stats_from_device(self, full_path):
- uri = "https://{0}:{1}/mgmt/tm/net/trunk/{2}/stats".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(name=full_path)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- result = parseStats(response)
- try:
- return result['stats']
- except KeyError:
- return {}
-
-
-class UsersParameters(BaseParameters):
- api_map = {
- 'fullPath': 'full_path',
- 'partitionAccess': 'partition_access',
- }
-
- returnables = [
- 'full_path',
- 'name',
- 'description',
- 'partition_access',
- 'shell',
- ]
-
- @property
- def partition_access(self):
- result = []
- if self._values['partition_access'] is None:
- return []
- for partition in self._values['partition_access']:
- del partition['nameReference']
- result.append(partition)
- return result
-
- @property
- def shell(self):
- if self._values['shell'] in [None, 'none']:
- return None
- return self._values['shell']
-
-
-class UsersFactManager(BaseManager):
- def __init__(self, *args, **kwargs):
- self.client = kwargs.get('client', None)
- self.module = kwargs.get('module', None)
- super(UsersFactManager, self).__init__(**kwargs)
- self.want = UsersParameters(params=self.module.params)
-
- def exec_module(self):
- facts = self._exec_module()
- result = dict(users=facts)
- return result
-
- def _exec_module(self):
- results = []
- facts = self.read_facts()
- for item in facts:
- attrs = item.to_return()
- results.append(attrs)
- results = sorted(results, key=lambda k: k['full_path'])
- return results
-
- def read_facts(self):
- results = []
- collection = self.read_collection_from_device()
- for resource in collection:
- attrs = resource
- params = UsersParameters(params=attrs)
- results.append(params)
- return results
-
- def read_collection_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/auth/user".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- if 'items' not in response:
- return []
- result = response['items']
- return result
-
-
-class UdpProfilesParameters(BaseParameters):
- api_map = {
- 'fullPath': 'full_path',
- 'allowNoPayload': 'allow_no_payload',
- 'bufferMaxBytes': 'buffer_max_bytes',
- 'bufferMaxPackets': 'buffer_max_packets',
- 'datagramLoadBalancing': 'datagram_load_balancing',
- 'defaultsFrom': 'parent',
- 'idleTimeout': 'idle_timeout',
- 'ipDfMode': 'ip_df_mode',
- 'ipTosToClient': 'ip_tos_to_client',
- 'ipTtlMode': 'ip_ttl_mode',
- 'ipTtlV4': 'ip_ttl_v4',
- 'ipTtlV6': 'ip_ttl_v6',
- 'linkQosToClient': 'link_qos_to_client',
- 'noChecksum': 'no_checksum',
- 'proxyMss': 'proxy_mss',
- }
-
- returnables = [
- 'full_path',
- 'name',
- 'parent',
- 'description',
- 'allow_no_payload',
- 'buffer_max_bytes',
- 'buffer_max_packets',
- 'datagram_load_balancing',
- 'idle_timeout',
- 'ip_df_mode',
- 'ip_tos_to_client',
- 'ip_ttl_mode',
- 'ip_ttl_v4',
- 'ip_ttl_v6',
- 'link_qos_to_client',
- 'no_checksum',
- 'proxy_mss',
- ]
-
- @property
- def description(self):
- if self._values['description'] in [None, 'none']:
- return None
- return self._values['description']
-
- @property
- def allow_no_payload(self):
- return flatten_boolean(self._values['allow_no_payload'])
-
- @property
- def datagram_load_balancing(self):
- return flatten_boolean(self._values['datagram_load_balancing'])
-
- @property
- def proxy_mss(self):
- return flatten_boolean(self._values['proxy_mss'])
-
- @property
- def no_checksum(self):
- return flatten_boolean(self._values['no_checksum'])
-
-
-class UdpProfilesFactManager(BaseManager):
- def __init__(self, *args, **kwargs):
- self.client = kwargs.get('client', None)
- self.module = kwargs.get('module', None)
- super(UdpProfilesFactManager, self).__init__(**kwargs)
- self.want = UdpProfilesParameters(params=self.module.params)
-
- def exec_module(self):
- facts = self._exec_module()
- result = dict(udp_profiles=facts)
- return result
-
- def _exec_module(self):
- results = []
- facts = self.read_facts()
- for item in facts:
- attrs = item.to_return()
- results.append(attrs)
- results = sorted(results, key=lambda k: k['full_path'])
- return results
-
- def read_facts(self):
- results = []
- collection = self.read_collection_from_device()
- for resource in collection:
- params = UdpProfilesParameters(params=resource)
- results.append(params)
- return results
-
- def read_collection_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/profile/udp".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- if 'items' not in response:
- return []
- result = response['items']
- return result
-
-
-class VcmpGuestsParameters(BaseParameters):
- api_map = {
- 'fullPath': 'full_path',
- 'allowedSlots': 'allowed_slots',
- 'assignedSlots': 'assigned_slots',
- 'bootPriority': 'boot_priority',
- 'coresPerSlot': 'cores_per_slot',
- 'initialImage': 'initial_image',
- 'initialHotfix': 'hotfix_image',
- 'managementGw': 'mgmt_route',
- 'managementIp': 'mgmt_address',
- 'managementNetwork': 'mgmt_network',
- 'minSlots': 'min_number_of_slots',
- 'slots': 'number_of_slots',
- 'sslMode': 'ssl_mode',
- 'virtualDisk': 'virtual_disk'
- }
-
- returnables = [
- 'name',
- 'full_path',
- 'allowed_slots',
- 'assigned_slots',
- 'boot_priority',
- 'cores_per_slot',
- 'hostname',
- 'hotfix_image',
- 'initial_image',
- 'mgmt_route',
- 'mgmt_address',
- 'mgmt_network',
- 'vlans',
- 'min_number_of_slots',
- 'number_of_slots',
- 'ssl_mode',
- 'state',
- 'virtual_disk',
- ]
-
-
-class VcmpGuestsFactManager(BaseManager):
- def __init__(self, *args, **kwargs):
- self.client = kwargs.get('client', None)
- self.module = kwargs.get('module', None)
- super(VcmpGuestsFactManager, self).__init__(**kwargs)
- self.want = VcmpGuestsParameters(params=self.module.params)
-
- def exec_module(self):
- facts = self._exec_module()
- result = dict(vcmp_guests=facts)
- return result
-
- def _exec_module(self):
- if 'vcmp' not in self.provisioned_modules:
- return []
- results = []
- facts = self.read_facts()
- for item in facts:
- attrs = item.to_return()
- results.append(attrs)
- results = sorted(results, key=lambda k: k['full_path'])
- return results
-
- def read_facts(self):
- results = []
- collection = self.read_collection_from_device()
- for resource in collection:
- params = VcmpGuestsParameters(params=resource)
- results.append(params)
- return results
-
- def read_collection_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/vcmp/guest".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- if 'items' not in response:
- return []
- result = response['items']
- return result
-
-
-class VirtualAddressesParameters(BaseParameters):
- api_map = {
- 'fullPath': 'full_path',
- 'arp': 'arp_enabled',
- 'autoDelete': 'auto_delete_enabled',
- 'connectionLimit': 'connection_limit',
- 'icmpEcho': 'icmp_echo',
- 'mask': 'netmask',
- 'routeAdvertisement': 'route_advertisement',
- 'trafficGroup': 'traffic_group',
- 'inheritedTrafficGroup': 'inherited_traffic_group'
- }
-
- returnables = [
- 'full_path',
- 'name',
- 'address',
- 'arp_enabled',
- 'auto_delete_enabled',
- 'connection_limit',
- 'description',
- 'enabled',
- 'icmp_echo',
- 'floating',
- 'netmask',
- 'route_advertisement',
- 'traffic_group',
- 'spanning',
- 'inherited_traffic_group'
- ]
-
- @property
- def spanning(self):
- return flatten_boolean(self._values['spanning'])
-
- @property
- def arp_enabled(self):
- return flatten_boolean(self._values['arp_enabled'])
-
- @property
- def route_advertisement(self):
- return flatten_boolean(self._values['route_advertisement'])
-
- @property
- def auto_delete_enabled(self):
- return flatten_boolean(self._values['auto_delete_enabled'])
-
- @property
- def inherited_traffic_group(self):
- return flatten_boolean(self._values['inherited_traffic_group'])
-
- @property
- def icmp_echo(self):
- return flatten_boolean(self._values['icmp_echo'])
-
- @property
- def floating(self):
- return flatten_boolean(self._values['floating'])
-
- @property
- def enabled(self):
- return flatten_boolean(self._values['enabled'])
-
-
-class VirtualAddressesFactManager(BaseManager):
- def __init__(self, *args, **kwargs):
- self.client = kwargs.get('client', None)
- self.module = kwargs.get('module', None)
- super(VirtualAddressesFactManager, self).__init__(**kwargs)
- self.want = VirtualAddressesParameters(params=self.module.params)
-
- def exec_module(self):
- facts = self._exec_module()
- result = dict(virtual_addresses=facts)
- return result
-
- def _exec_module(self):
- results = []
- facts = self.read_facts()
- for item in facts:
- attrs = item.to_return()
- results.append(attrs)
- results = sorted(results, key=lambda k: k['full_path'])
- return results
-
- def read_facts(self):
- results = []
- collection = self.read_collection_from_device()
- for resource in collection:
- params = VirtualAddressesParameters(params=resource)
- results.append(params)
- return results
-
- def read_collection_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/virtual-address".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- if 'items' not in response:
- return []
- result = response['items']
- return result
-
-
-class VirtualServersParameters(BaseParameters):
- api_map = {
- 'fullPath': 'full_path',
- 'autoLasthop': 'auto_lasthop',
- 'bwcPolicy': 'bw_controller_policy',
- 'cmpEnabled': 'cmp_enabled',
- 'connectionLimit': 'connection_limit',
- 'fallbackPersistence': 'fallback_persistence_profile',
- 'persist': 'persistence_profile',
- 'translatePort': 'translate_port',
- 'translateAddress': 'translate_address',
- 'lastHopPool': 'last_hop_pool',
- 'nat64': 'nat64_enabled',
- 'sourcePort': 'source_port_behavior',
- 'ipIntelligencePolicy': 'ip_intelligence_policy',
- 'ipProtocol': 'protocol',
- 'pool': 'default_pool',
- 'rateLimitMode': 'rate_limit_mode',
- 'rateLimitSrcMask': 'rate_limit_source_mask',
- 'rateLimitDstMask': 'rate_limit_destination_mask',
- 'rateLimit': 'rate_limit',
- 'sourceAddressTranslation': 'snat_type',
- 'gtmScore': 'gtm_score',
- 'rateClass': 'rate_class',
- 'source': 'source_address',
- 'auth': 'authentication_profile',
- 'mirror': 'connection_mirror_enabled',
- 'rules': 'irules',
- 'securityLogProfiles': 'security_log_profiles',
- 'profilesReference': 'profiles'
- }
-
- returnables = [
- 'full_path',
- 'name',
- 'auto_lasthop',
- 'bw_controller_policy',
- 'cmp_enabled',
- 'connection_limit',
- 'description',
- 'enabled',
- 'fallback_persistence_profile',
- 'persistence_profile',
- 'translate_port',
- 'translate_address',
- 'vlans',
- 'destination',
- 'last_hop_pool',
- 'nat64_enabled',
- 'source_port_behavior',
- 'ip_intelligence_policy',
- 'protocol',
- 'default_pool',
- 'rate_limit_mode',
- 'rate_limit_source_mask',
- 'rate_limit',
- 'snat_type',
- 'snat_pool',
- 'gtm_score',
- 'rate_class',
- 'rate_limit_destination_mask',
- 'source_address',
- 'authentication_profile',
- 'connection_mirror_enabled',
- 'irules',
- 'security_log_profiles',
- 'type',
- 'profiles',
- 'destination_address',
- 'destination_port',
- 'availability_status',
- 'status_reason',
- 'total_requests',
- 'client_side_bits_in',
- 'client_side_bits_out',
- 'client_side_current_connections',
- 'client_side_evicted_connections',
- 'client_side_max_connections',
- 'client_side_pkts_in',
- 'client_side_pkts_out',
- 'client_side_slow_killed',
- 'client_side_total_connections',
- 'cmp_mode',
- 'ephemeral_bits_in',
- 'ephemeral_bits_out',
- 'ephemeral_current_connections',
- 'ephemeral_evicted_connections',
- 'ephemeral_max_connections',
- 'ephemeral_pkts_in',
- 'ephemeral_pkts_out',
- 'ephemeral_slow_killed',
- 'ephemeral_total_connections',
- 'total_software_accepted_syn_cookies',
- 'total_hardware_accepted_syn_cookies',
- 'total_hardware_syn_cookies',
- 'hardware_syn_cookie_instances',
- 'total_software_rejected_syn_cookies',
- 'software_syn_cookie_instances',
- 'current_syn_cache',
- 'syn_cache_overflow',
- 'total_software_syn_cookies',
- 'syn_cookies_status',
- 'max_conn_duration',
- 'mean_conn_duration',
- 'min_conn_duration',
- 'cpu_usage_ratio_last_5_min',
- 'cpu_usage_ratio_last_5_sec',
- 'cpu_usage_ratio_last_1_min',
- ]
-
- @property
- def max_conn_duration(self):
- return self._values['stats']['csMaxConnDur']
-
- @property
- def mean_conn_duration(self):
- return self._values['stats']['csMeanConnDur']
-
- @property
- def min_conn_duration(self):
- return self._values['stats']['csMinConnDur']
-
- @property
- def cpu_usage_ratio_last_5_min(self):
- return self._values['stats']['fiveMinAvgUsageRatio']
-
- @property
- def cpu_usage_ratio_last_5_sec(self):
- return self._values['stats']['fiveSecAvgUsageRatio']
-
- @property
- def cpu_usage_ratio_last_1_min(self):
- return self._values['stats']['oneMinAvgUsageRatio']
-
- @property
- def cmp_mode(self):
- return self._values['stats']['cmpEnableMode']
-
- @property
- def availability_status(self):
- return self._values['stats']['status']['availabilityState']
-
- @property
- def status_reason(self):
- return self._values['stats']['status']['statusReason']
-
- @property
- def total_requests(self):
- return self._values['stats']['totRequests']
-
- @property
- def ephemeral_bits_in(self):
- return self._values['stats']['ephemeral']['bitsIn']
-
- @property
- def ephemeral_bits_out(self):
- return self._values['stats']['ephemeral']['bitsOut']
-
- @property
- def ephemeral_current_connections(self):
- return self._values['stats']['ephemeral']['curConns']
-
- @property
- def ephemeral_evicted_connections(self):
- return self._values['stats']['ephemeral']['evictedConns']
-
- @property
- def ephemeral_max_connections(self):
- return self._values['stats']['ephemeral']['maxConns']
-
- @property
- def ephemeral_pkts_in(self):
- return self._values['stats']['ephemeral']['pktsIn']
-
- @property
- def ephemeral_pkts_out(self):
- return self._values['stats']['ephemeral']['pktsOut']
-
- @property
- def ephemeral_slow_killed(self):
- return self._values['stats']['ephemeral']['slowKilled']
-
- @property
- def ephemeral_total_connections(self):
- return self._values['stats']['ephemeral']['totConns']
-
- @property
- def client_side_bits_in(self):
- return self._values['stats']['clientside']['bitsIn']
-
- @property
- def client_side_bits_out(self):
- return self._values['stats']['clientside']['bitsOut']
-
- @property
- def client_side_current_connections(self):
- return self._values['stats']['clientside']['curConns']
-
- @property
- def client_side_evicted_connections(self):
- return self._values['stats']['clientside']['evictedConns']
-
- @property
- def client_side_max_connections(self):
- return self._values['stats']['clientside']['maxConns']
-
- @property
- def client_side_pkts_in(self):
- return self._values['stats']['clientside']['pktsIn']
-
- @property
- def client_side_pkts_out(self):
- return self._values['stats']['clientside']['pktsOut']
-
- @property
- def client_side_slow_killed(self):
- return self._values['stats']['clientside']['slowKilled']
-
- @property
- def client_side_total_connections(self):
- return self._values['stats']['clientside']['totConns']
-
- @property
- def total_software_accepted_syn_cookies(self):
- return self._values['stats']['syncookie']['accepts']
-
- @property
- def total_hardware_accepted_syn_cookies(self):
- return self._values['stats']['syncookie']['hwAccepts']
-
- @property
- def total_hardware_syn_cookies(self):
- return self._values['stats']['syncookie']['hwSyncookies']
-
- @property
- def hardware_syn_cookie_instances(self):
- return self._values['stats']['syncookie']['hwsyncookieInstance']
-
- @property
- def total_software_rejected_syn_cookies(self):
- return self._values['stats']['syncookie']['rejects']
-
- @property
- def software_syn_cookie_instances(self):
- return self._values['stats']['syncookie']['swsyncookieInstance']
-
- @property
- def current_syn_cache(self):
- return self._values['stats']['syncookie']['syncacheCurr']
-
- @property
- def syn_cache_overflow(self):
- return self._values['stats']['syncookie']['syncacheOver']
-
- @property
- def total_software_syn_cookies(self):
- return self._values['stats']['syncookie']['syncookies']
-
- @property
- def syn_cookies_status(self):
- return self._values['stats']['syncookieStatus']
-
- @property
- def destination_address(self):
- if self._values['destination'] is None:
- return None
- tup = self.destination_tuple
- return tup.ip
-
- @property
- def destination_port(self):
- if self._values['destination'] is None:
- return None
- tup = self.destination_tuple
- return tup.port
-
- @property
- def type(self):
- """Attempt to determine the current server type
-
- This check is very unscientific. It turns out that this information is not
- exactly available anywhere on a BIG-IP. Instead, we rely on a semi-reliable
- means for determining what the type of the virtual server is. Hopefully it
- always works.
-
- There are a handful of attributes that can be used to determine a specific
- type. There are some types though that can only be determined by looking at
- the profiles that are assigned to them. We follow that method for those
- complicated types; message-routing, fasthttp, and fastl4.
-
- Because type determination is an expensive operation, we cache the result
- from the operation.
-
- Returns:
- string: The server type.
- """
- if self._values['l2Forward'] is True:
- result = 'forwarding-l2'
- elif self._values['ipForward'] is True:
- result = 'forwarding-ip'
- elif self._values['stateless'] is True:
- result = 'stateless'
- elif self._values['reject'] is True:
- result = 'reject'
- elif self._values['dhcpRelay'] is True:
- result = 'dhcp'
- elif self._values['internal'] is True:
- result = 'internal'
- elif self.has_fasthttp_profiles:
- result = 'performance-http'
- elif self.has_fastl4_profiles:
- result = 'performance-l4'
- elif self.has_message_routing_profiles:
- result = 'message-routing'
- else:
- result = 'standard'
- return result
-
- @property
- def profiles(self):
- """Returns a list of profiles from the API
-
- The profiles are formatted so that they are usable in this module and
- are able to be compared by the Difference engine.
-
- Returns:
- list (:obj:`list` of :obj:`dict`): List of profiles.
-
- Each dictionary in the list contains the following three (3) keys.
-
- * name
- * context
- * fullPath
-
- Raises:
- F5ModuleError: If the specified context is a value other that
- ``all``, ``server-side``, or ``client-side``.
- """
- if 'items' not in self._values['profiles']:
- return None
- result = []
- for item in self._values['profiles']['items']:
- context = item['context']
- if context == 'serverside':
- context = 'server-side'
- elif context == 'clientside':
- context = 'client-side'
- name = item['name']
- if context in ['all', 'server-side', 'client-side']:
- result.append(dict(name=name, context=context, full_path=item['fullPath']))
- else:
- raise F5ModuleError(
- "Unknown profile context found: '{0}'".format(context)
- )
- return result
-
- @property
- def has_message_routing_profiles(self):
- if self.profiles is None:
- return None
- current = self._read_current_message_routing_profiles_from_device()
- result = [x['name'] for x in self.profiles if x['name'] in current]
- if len(result) > 0:
- return True
- return False
-
- @property
- def has_fastl4_profiles(self):
- if self.profiles is None:
- return None
- current = self._read_current_fastl4_profiles_from_device()
- result = [x['name'] for x in self.profiles if x['name'] in current]
- if len(result) > 0:
- return True
- return False
-
- @property
- def has_fasthttp_profiles(self):
- """Check if ``fasthttp`` profile is in API profiles
-
- This method is used to determine the server type when doing comparisons
- in the Difference class.
-
- Returns:
- bool: True if server has ``fasthttp`` profiles. False otherwise.
- """
- if self.profiles is None:
- return None
- current = self._read_current_fasthttp_profiles_from_device()
- result = [x['name'] for x in self.profiles if x['name'] in current]
- if len(result) > 0:
- return True
- return False
-
- def _read_current_message_routing_profiles_from_device(self):
- result = []
- result += self._read_diameter_profiles_from_device()
- result += self._read_sip_profiles_from_device()
- return result
-
- def _read_diameter_profiles_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/profile/diameter/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- result = [x['name'] for x in response['items']]
- return result
-
- def _read_sip_profiles_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/profile/sip/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- result = [x['name'] for x in response['items']]
- return result
-
- def _read_current_fastl4_profiles_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/profile/fastl4/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- result = [x['name'] for x in response['items']]
- return result
-
- def _read_current_fasthttp_profiles_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/profile/fasthttp/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- result = [x['name'] for x in response['items']]
- return result
-
- @property
- def security_log_profiles(self):
- if self._values['security_log_profiles'] is None:
- return None
- result = list(set([x.strip('"') for x in self._values['security_log_profiles']]))
- result.sort()
- return result
-
- @property
- def snat_type(self):
- if self._values['snat_type'] is None:
- return None
- if 'type' in self._values['snat_type']:
- if self._values['snat_type']['type'] == 'automap':
- return 'automap'
- elif self._values['snat_type']['type'] == 'none':
- return 'none'
- elif self._values['snat_type']['type'] == 'pool':
- return 'snat'
-
- @property
- def connection_mirror_enabled(self):
- if self._values['connection_mirror_enabled'] is None:
- return None
- elif self._values['connection_mirror_enabled'] == 'enabled':
- return 'yes'
- return 'no'
-
- @property
- def rate_limit(self):
- if self._values['rate_limit'] is None:
- return None
- elif self._values['rate_limit'] == 'disabled':
- return -1
- return int(self._values['rate_limit'])
-
- @property
- def nat64_enabled(self):
- if self._values['nat64_enabled'] is None:
- return None
- elif self._values['nat64_enabled'] == 'enabled':
- return 'yes'
- return 'no'
-
- @property
- def enabled(self):
- if self._values['enabled'] is None:
- return 'no'
- elif self._values['enabled'] is True:
- return 'yes'
- return 'no'
-
- @property
- def translate_port(self):
- if self._values['translate_port'] is None:
- return None
- elif self._values['translate_port'] == 'enabled':
- return 'yes'
- return 'no'
-
- @property
- def translate_address(self):
- if self._values['translate_address'] is None:
- return None
- elif self._values['translate_address'] == 'enabled':
- return 'yes'
- return 'no'
-
- @property
- def persistence_profile(self):
- """Return persistence profile in a consumable form
-
- I don't know why the persistence profile is stored this way, but below is the
- general format of it.
-
- "persist": [
- {
- "name": "msrdp",
- "partition": "Common",
- "tmDefault": "yes",
- "nameReference": {
- "link": "https://localhost/mgmt/tm/ltm/persistence/msrdp/~Common~msrdp?ver=13.1.0.4"
- }
- }
- ],
-
- As you can see, this is quite different from something like the fallback
- persistence profile which is just simply
-
- /Common/fallback1
-
- This method makes the persistence profile look like the fallback profile.
-
- Returns:
- string: The persistence profile configured on the virtual.
- """
- if self._values['persistence_profile'] is None:
- return None
- profile = self._values['persistence_profile'][0]
- result = fq_name(profile['partition'], profile['name'])
- return result
-
- @property
- def destination_tuple(self):
- Destination = namedtuple('Destination', ['ip', 'port', 'route_domain'])
-
- # Remove the partition
- if self._values['destination'] is None:
- result = Destination(ip=None, port=None, route_domain=None)
- return result
- destination = re.sub(r'^/[a-zA-Z0-9_.-]+/', '', self._values['destination'])
-
- if is_valid_ip(destination):
- result = Destination(
- ip=destination,
- port=None,
- route_domain=None
- )
- return result
-
- # Covers the following examples
- #
- # /Common/2700:bc00:1f10:101::6%2.80
- # 2700:bc00:1f10:101::6%2.80
- # 1.1.1.1%2:80
- # /Common/1.1.1.1%2:80
- # /Common/2700:bc00:1f10:101::6%2.any
- #
- pattern = r'(?P<ip>[^%]+)%(?P<route_domain>[0-9]+)[:.](?P<port>[0-9]+|any)'
- matches = re.search(pattern, destination)
- if matches:
- try:
- port = int(matches.group('port'))
- except ValueError:
- # Can be a port of "any". This only happens with IPv6
- port = matches.group('port')
- if port == 'any':
- port = 0
- ip = matches.group('ip')
- if not is_valid_ip(ip):
- raise F5ModuleError(
- "The provided destination is not a valid IP address"
- )
- result = Destination(
- ip=matches.group('ip'),
- port=port,
- route_domain=int(matches.group('route_domain'))
- )
- return result
-
- pattern = r'(?P<ip>[^%]+)%(?P<route_domain>[0-9]+)'
- matches = re.search(pattern, destination)
- if matches:
- ip = matches.group('ip')
- if not is_valid_ip(ip):
- raise F5ModuleError(
- "The provided destination is not a valid IP address"
- )
- result = Destination(
- ip=matches.group('ip'),
- port=None,
- route_domain=int(matches.group('route_domain'))
- )
- return result
-
- parts = destination.split('.')
- if len(parts) == 4:
- # IPv4
- ip, port = destination.split(':')
- if not is_valid_ip(ip):
- raise F5ModuleError(
- "The provided destination is not a valid IP address"
- )
- result = Destination(
- ip=ip,
- port=int(port),
- route_domain=None
- )
- return result
- elif len(parts) == 2:
- # IPv6
- ip, port = destination.split('.')
- try:
- port = int(port)
- except ValueError:
- # Can be a port of "any". This only happens with IPv6
- if port == 'any':
- port = 0
- if not is_valid_ip(ip):
- raise F5ModuleError(
- "The provided destination is not a valid IP address"
- )
- result = Destination(
- ip=ip,
- port=port,
- route_domain=None
- )
- return result
- else:
- result = Destination(ip=None, port=None, route_domain=None)
- return result
-
-
-class VirtualServersFactManager(BaseManager):
- def __init__(self, *args, **kwargs):
- self.client = kwargs.get('client', None)
- self.module = kwargs.get('module', None)
- super(VirtualServersFactManager, self).__init__(**kwargs)
- self.want = VirtualServersParameters(client=self.client, params=self.module.params)
-
- def exec_module(self):
- facts = self._exec_module()
- result = dict(virtual_servers=facts)
- return result
-
- def _exec_module(self):
- results = []
- facts = self.read_facts()
- for item in facts:
- attrs = item.to_return()
- results.append(attrs)
- results = sorted(results, key=lambda k: k['full_path'])
- return results
-
- def read_facts(self):
- results = []
- collection = self.read_collection_from_device()
- for resource in collection:
- attrs = resource
- attrs['stats'] = self.read_stats_from_device(attrs['fullPath'])
- params = VirtualServersParameters(params=attrs)
- results.append(params)
- return results
-
- def read_collection_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/virtual?expandSubcollections=true".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- if 'items' not in response:
- return []
- result = response['items']
- return result
-
- def read_stats_from_device(self, full_path):
- uri = "https://{0}:{1}/mgmt/tm/ltm/virtual/{2}/stats".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(name=full_path)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- result = parseStats(response)
- try:
- return result['stats']
- except KeyError:
- return {}
-
-
-class VlansParameters(BaseParameters):
- api_map = {
- 'autoLasthop': 'auto_lasthop',
- 'cmpHash': 'cmp_hash_algorithm',
- 'failsafeAction': 'failsafe_action',
- 'failsafe': 'failsafe_enabled',
- 'failsafeTimeout': 'failsafe_timeout',
- 'ifIndex': 'if_index',
- 'learning': 'learning_mode',
- 'interfacesReference': 'interfaces',
- 'sourceChecking': 'source_check_enabled',
- 'fullPath': 'full_path'
- }
-
- returnables = [
- 'full_path',
- 'name',
- 'auto_lasthop',
- 'cmp_hash_algorithm',
- 'description',
- 'failsafe_action',
- 'failsafe_enabled',
- 'failsafe_timeout',
- 'if_index',
- 'learning_mode',
- 'interfaces',
- 'mtu',
- 'sflow_poll_interval',
- 'sflow_poll_interval_global',
- 'sflow_sampling_rate',
- 'sflow_sampling_rate_global',
- 'source_check_enabled',
- 'true_mac_address',
- 'tag',
- ]
-
- @property
- def interfaces(self):
- if self._values['interfaces'] is None:
- return None
- if 'items' not in self._values['interfaces']:
- return None
- result = []
- for item in self._values['interfaces']['items']:
- tmp = dict(
- name=item['name'],
- full_path=item['fullPath']
- )
- if 'tagged' in item:
- tmp['tagged'] = 'yes'
- else:
- tmp['tagged'] = 'no'
- result.append(tmp)
- return result
-
- @property
- def sflow_poll_interval(self):
- return int(self._values['sflow']['pollInterval'])
-
- @property
- def sflow_poll_interval_global(self):
- return flatten_boolean(self._values['sflow']['pollIntervalGlobal'])
-
- @property
- def sflow_sampling_rate(self):
- return int(self._values['sflow']['samplingRate'])
-
- @property
- def sflow_sampling_rate_global(self):
- return flatten_boolean(self._values['sflow']['samplingRateGlobal'])
-
- @property
- def source_check_state(self):
- return flatten_boolean(self._values['source_check_state'])
-
- @property
- def true_mac_address(self):
- # Who made this field a "description"!?
- return self._values['stats']['macTrue']
-
- @property
- def tag(self):
- # We can't agree on field names...SMH
- return self._values['stats']['id']
-
- @property
- def failsafe_enabled(self):
- return flatten_boolean(self._values['failsafe_enabled'])
-
-
-class VlansFactManager(BaseManager):
- def __init__(self, *args, **kwargs):
- self.client = kwargs.get('client', None)
- self.module = kwargs.get('module', None)
- super(VlansFactManager, self).__init__(**kwargs)
- self.want = VlansParameters(params=self.module.params)
-
- def exec_module(self):
- facts = self._exec_module()
- result = dict(vlans=facts)
- return result
-
- def _exec_module(self):
- results = []
- facts = self.read_facts()
- for item in facts:
- attrs = item.to_return()
- results.append(attrs)
- results = sorted(results, key=lambda k: k['full_path'])
- return results
-
- def read_facts(self):
- results = []
- collection = self.read_collection_from_device()
- for resource in collection:
- attrs = resource
- attrs['stats'] = self.read_stats_from_device(attrs['fullPath'])
- params = VlansParameters(params=attrs)
- results.append(params)
- return results
-
- def read_collection_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/net/vlan?expandSubcollections=true".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- if 'items' not in response:
- return []
- result = response['items']
- return result
-
- def read_stats_from_device(self, full_path):
- uri = "https://{0}:{1}/mgmt/tm/net/vlan/{2}/stats".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(name=full_path)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- result = parseStats(response)
- try:
- return result['stats']
- except KeyError:
- return {}
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = kwargs.get('client', None)
- self.kwargs = kwargs
- self.want = Parameters(params=self.module.params)
- self.managers = {
- 'asm-policy-stats': AsmPolicyStatsFactManager,
- 'asm-policies': AsmPolicyFactManager,
- 'asm-server-technologies': AsmServerTechnologyFactManager,
- 'asm-signature-sets': AsmSignatureSetsFactManager,
- 'client-ssl-profiles': ClientSslProfilesFactManager,
- 'devices': DevicesFactManager,
- 'device-groups': DeviceGroupsFactManager,
- 'external-monitors': ExternalMonitorsFactManager,
- 'fasthttp-profiles': FastHttpProfilesFactManager,
- 'fastl4-profiles': FastL4ProfilesFactManager,
- 'gateway-icmp-monitors': GatewayIcmpMonitorsFactManager,
- 'gtm-a-pools': GtmAPoolsFactManager,
- 'gtm-servers': GtmServersFactManager,
- 'gtm-a-wide-ips': GtmAWideIpsFactManager,
- 'gtm-aaaa-pools': GtmAaaaPoolsFactManager,
- 'gtm-aaaa-wide-ips': GtmAaaaWideIpsFactManager,
- 'gtm-cname-pools': GtmCnamePoolsFactManager,
- 'gtm-cname-wide-ips': GtmCnameWideIpsFactManager,
- 'gtm-mx-pools': GtmMxPoolsFactManager,
- 'gtm-mx-wide-ips': GtmMxWideIpsFactManager,
- 'gtm-naptr-pools': GtmNaptrPoolsFactManager,
- 'gtm-naptr-wide-ips': GtmNaptrWideIpsFactManager,
- 'gtm-srv-pools': GtmSrvPoolsFactManager,
- 'gtm-srv-wide-ips': GtmSrvWideIpsFactManager,
- 'http-monitors': HttpMonitorsFactManager,
- 'https-monitors': HttpsMonitorsFactManager,
- 'http-profiles': HttpProfilesFactManager,
- 'iapp-services': IappServicesFactManager,
- 'iapplx-packages': IapplxPackagesFactManager,
- 'icmp-monitors': IcmpMonitorsFactManager,
- 'interfaces': InterfacesFactManager,
- 'internal-data-groups': InternalDataGroupsFactManager,
- 'irules': IrulesFactManager,
- 'ltm-pools': LtmPoolsFactManager,
- 'ltm-policies': LtmPolicyFactManager,
- 'nodes': NodesFactManager,
- 'oneconnect-profiles': OneConnectProfilesFactManager,
- 'partitions': PartitionFactManager,
- 'provision-info': ProvisionInfoFactManager,
- 'route-domains': RouteDomainFactManager,
- 'self-ips': SelfIpsFactManager,
- 'server-ssl-profiles': ServerSslProfilesFactManager,
- 'software-volumes': SoftwareVolumesFactManager,
- 'software-images': SoftwareImagesFactManager,
- 'software-hotfixes': SoftwareHotfixesFactManager,
- 'ssl-certs': SslCertificatesFactManager,
- 'ssl-keys': SslKeysFactManager,
- 'system-db': SystemDbFactManager,
- 'system-info': SystemInfoFactManager,
- 'tcp-monitors': TcpMonitorsFactManager,
- 'tcp-half-open-monitors': TcpHalfOpenMonitorsFactManager,
- 'tcp-profiles': TcpProfilesFactManager,
- 'traffic-groups': TrafficGroupsFactManager,
- 'trunks': TrunksFactManager,
- 'udp-profiles': UdpProfilesFactManager,
- 'users': UsersFactManager,
- 'vcmp-guests': VcmpGuestsFactManager,
- 'virtual-addresses': VirtualAddressesFactManager,
- 'virtual-servers': VirtualServersFactManager,
- 'vlans': VlansFactManager,
- }
-
- def exec_module(self):
- self.handle_all_keyword()
- self.handle_profiles_keyword()
- self.handle_monitors_keyword()
- self.handle_gtm_pools_keyword()
- self.handle_gtm_wide_ips_keyword()
- res = self.check_valid_gather_subset(self.want.gather_subset)
- if res:
- invalid = ','.join(res)
- raise F5ModuleError(
- "The specified 'gather_subset' options are invalid: {0}".format(invalid)
- )
- result = self.filter_excluded_facts()
-
- managers = []
- for name in result:
- manager = self.get_manager(name)
- if manager:
- managers.append(manager)
-
- if not managers:
- result = dict(
- queried=False
- )
- return result
-
- result = self.execute_managers(managers)
- if result:
- result['queried'] = True
- else:
- result['queried'] = False
- return result
-
- def filter_excluded_facts(self):
- # Remove the excluded entries from the list of possible facts
- exclude = [x[1:] for x in self.want.gather_subset if x[0] == '!']
- include = [x for x in self.want.gather_subset if x[0] != '!']
- result = [x for x in include if x not in exclude]
- return result
-
- def handle_all_keyword(self):
- if 'all' not in self.want.gather_subset:
- return
- managers = list(self.managers.keys()) + self.want.gather_subset
- managers.remove('all')
- self.want.update({'gather_subset': managers})
-
- def handle_profiles_keyword(self):
- if 'profiles' not in self.want.gather_subset:
- return
- managers = [x for x in self.managers.keys() if '-profiles' in x] + self.want.gather_subset
- managers.remove('profiles')
- self.want.update({'gather_subset': managers})
-
- def handle_monitors_keyword(self):
- if 'monitors' not in self.want.gather_subset:
- return
- managers = [x for x in self.managers.keys() if '-monitors' in x] + self.want.gather_subset
- managers.remove('monitors')
- self.want.update({'gather_subset': managers})
-
- def handle_gtm_pools_keyword(self):
- if 'gtm-pools' not in self.want.gather_subset:
- return
- keys = self.managers.keys()
- managers = [x for x in keys if x.startswith('gtm-') and x.endswith('-pools')]
- managers += self.want.gather_subset
- managers.remove('gtm-pools')
- self.want.update({'gather_subset': managers})
-
- def handle_gtm_wide_ips_keyword(self):
- if 'gtm-wide-ips' not in self.want.gather_subset:
- return
- keys = self.managers.keys()
- managers = [x for x in keys if x.startswith('gtm-') and x.endswith('-wide-ips')]
- managers += self.want.gather_subset
- managers.remove('gtm-wide-ips')
- self.want.update({'gather_subset': managers})
-
- def check_valid_gather_subset(self, includes):
- """Check that the specified subset is valid
-
- The ``gather_subset`` parameter is specified as a "raw" field which means that
- any Python type could technically be provided
-
- :param includes:
- :return:
- """
- keys = self.managers.keys()
- result = []
- for x in includes:
- if x not in keys:
- if x[0] == '!':
- if x[1:] not in keys:
- result.append(x)
- else:
- result.append(x)
- return result
-
- def execute_managers(self, managers):
- results = dict()
- client = F5RestClient(**self.module.params)
- prov = modules_provisioned(client)
- for manager in managers:
- manager.provisioned_modules = prov
- result = manager.exec_module()
- results.update(result)
- return results
-
- def get_manager(self, which):
- result = {}
- manager = self.managers.get(which, None)
- if not manager:
- return result
- kwargs = dict()
- kwargs.update(self.kwargs)
-
- kwargs['client'] = F5RestClient(**self.module.params)
- result = manager(**kwargs)
- return result
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = False
- argument_spec = dict(
- gather_subset=dict(
- type='list',
- required=True,
- aliases=['include'],
- choices=[
- # Meta choices
- 'all',
- 'monitors',
- 'profiles',
- 'gtm-pools',
- 'gtm-wide-ips',
-
- # Non-meta choices
- 'asm-policies',
- 'asm-policy-stats',
- 'asm-server-technologies',
- 'asm-signature-sets',
- 'client-ssl-profiles',
- 'devices',
- 'device-groups',
- 'external-monitors',
- 'fasthttp-profiles',
- 'fastl4-profiles',
- 'gateway-icmp-monitors',
- 'gtm-a-pools',
- 'gtm-servers',
- 'gtm-a-wide-ips',
- 'gtm-aaaa-pools',
- 'gtm-aaaa-wide-ips',
- 'gtm-cname-pools',
- 'gtm-cname-wide-ips',
- 'gtm-mx-pools',
- 'gtm-mx-wide-ips',
- 'gtm-naptr-pools',
- 'gtm-naptr-wide-ips',
- 'gtm-srv-pools',
- 'gtm-srv-wide-ips',
- 'http-profiles',
- 'http-monitors',
- 'https-monitors',
- 'iapp-services',
- 'iapplx-packages',
- 'icmp-monitors',
- 'interfaces',
- 'internal-data-groups',
- 'irules',
- 'ltm-pools',
- 'ltm-policies',
- 'nodes',
- 'oneconnect-profiles',
- 'partitions',
- 'provision-info',
- 'self-ips',
- 'server-ssl-profiles',
- 'software-volumes',
- 'software-images',
- 'software-hotfixes',
- 'ssl-certs',
- 'ssl-keys',
- 'system-db',
- 'system-info',
- 'tcp-monitors',
- 'tcp-half-open-monitors',
- 'tcp-profiles',
- 'traffic-groups',
- 'trunks',
- 'udp-profiles',
- 'users',
- 'vcmp-guests',
- 'virtual-addresses',
- 'virtual-servers',
- 'vlans',
-
- # Negations of meta choices
- '!all',
- "!monitors",
- '!profiles',
- '!gtm-pools',
- '!gtm-wide-ips',
-
- # Negations of non-meta-choices
- '!asm-policy-stats',
- '!asm-policies',
- '!asm-server-technologies',
- '!asm-signature-sets',
- '!client-ssl-profiles',
- '!devices',
- '!device-groups',
- '!external-monitors',
- '!fasthttp-profiles',
- '!fastl4-profiles',
- '!gateway-icmp-monitors',
- '!gtm-a-pools',
- '!gtm-servers',
- '!gtm-a-wide-ips',
- '!gtm-aaaa-pools',
- '!gtm-aaaa-wide-ips',
- '!gtm-cname-pools',
- '!gtm-cname-wide-ips',
- '!gtm-mx-pools',
- '!gtm-mx-wide-ips',
- '!gtm-naptr-pools',
- '!gtm-naptr-wide-ips',
- '!gtm-srv-pools',
- '!gtm-srv-wide-ips',
- '!http-profiles',
- '!http-monitors',
- '!https-monitors',
- '!iapp-services',
- '!iapplx-packages',
- '!icmp-monitors',
- '!interfaces',
- '!internal-data-groups',
- '!irules',
- '!ltm-pools',
- '!ltm-policies',
- '!nodes',
- '!oneconnect-profiles',
- '!partitions',
- '!provision-info',
- '!self-ips',
- '!server-ssl-profiles',
- '!software-volumes',
- '!software-images',
- '!software-hotfixes',
- '!ssl-certs',
- '!ssl-keys',
- '!system-db',
- '!system-info',
- '!tcp-monitors',
- '!tcp-half-open-monitors',
- '!tcp-profiles',
- '!traffic-groups',
- '!trunks',
- '!udp-profiles',
- '!users',
- '!vcmp-guests',
- '!virtual-addresses',
- '!virtual-servers',
- '!vlans',
- ]
- ),
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode
- )
- if module._name == 'bigip_device_facts':
- module.deprecate("The 'bigip_device_facts' module has been renamed to 'bigip_device_info'", version='2.13')
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_device_license.py b/lib/ansible/modules/network/f5/bigip_device_license.py
deleted file mode 100644
index f3c769e3b8..0000000000
--- a/lib/ansible/modules/network/f5/bigip_device_license.py
+++ /dev/null
@@ -1,889 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2016, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = '''
----
-module: bigip_device_license
-short_description: Manage license installation and activation on BIG-IP devices
-description:
- - Manage license installation and activation on a BIG-IP.
-version_added: 2.6
-options:
- license_key:
- description:
- - The registration key to use to license the BIG-IP.
- - This parameter is required if the C(state) is equal to C(present).
- - This parameter is not required when C(state) is C(absent) and will be
- ignored if it is provided.
- type: str
- license_server:
- description:
- - The F5 license server to use when getting a license and validating a dossier.
- - This parameter is required if the C(state) is equal to C(present).
- - This parameter is not required when C(state) is C(absent) and will be
- ignored if it is provided.
- type: str
- default: activate.f5.com
- state:
- description:
- - The state of the license on the system.
- - When C(present), only guarantees that a license is there.
- - When C(latest), ensures that the license is always valid.
- - When C(absent), removes the license on the system.
- - When C(revoked), removes the license on the system and revokes its future usage
- on the F5 license servers.
- type: str
- choices:
- - absent
- - present
- - revoked
- default: present
- accept_eula:
- description:
- - Declares whether you accept the BIG-IP EULA or not. By default, this
- value is C(no). You must specifically declare that you have viewed and
- accepted the license. This module will not present you with that EULA
- though, so it is incumbent on you to read it.
- - The EULA can be found here; https://support.f5.com/csp/article/K12902.
- - This parameter is not required when C(state) is C(absent) and will be
- ignored if it is provided.
- type: bool
- default: no
-extends_documentation_fragment: f5
-author:
- - Tim Rupp (@caphrim007)
-'''
-
-EXAMPLES = '''
-- name: License BIG-IP using a key
- bigip_device_license:
- license_key: "XXXXX-XXXXX-XXXXX-XXXXX-XXXXXXX"
- provider:
- server: "lb.mydomain.com"
- user: "admin"
- password: "secret"
- delegate_to: localhost
-
-- name: Remove the license from the system
- bigip_device_license:
- state: "absent"
- provider:
- server: "lb.mydomain.com"
- user: "admin"
- password: "secret"
- delegate_to: localhost
-'''
-
-RETURN = r'''
-# only common fields returned
-'''
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.six import iteritems
-
-import re
-import time
-import xml.etree.ElementTree
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import fq_name
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.icontrol import iControlRestSession
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import fq_name
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.icontrol import iControlRestSession
-
-
-class LicenseXmlParser(object):
- def __init__(self, content=None):
- self.raw_content = content
- try:
- self.content = xml.etree.ElementTree.fromstring(content)
- except xml.etree.ElementTree.ParseError as ex:
- raise F5ModuleError("Provided XML payload is invalid. Received '{0}'.".format(str(ex)))
-
- @property
- def namespaces(self):
- result = {
- 'xsi': 'http://www.w3.org/2001/XMLSchema-instance'
- }
- return result
-
- @property
- def eula(self):
- try:
- root = self.content.findall('.//eula', self.namespaces)
- return root[0].text
- except Exception:
- return None
-
- @property
- def license(self):
- try:
- root = self.content.findall('.//license', self.namespaces)
- return root[0].text
- except Exception:
- return None
-
- def find_element(self, value):
- root = self.content.findall('.//multiRef', self.namespaces)
- if len(root) == 0:
- return None
- for elem in root:
- for k, v in iteritems(elem.attrib):
- if value in v:
- return elem
-
- @property
- def state(self):
- elem = self.find_element('TransactionState')
- if elem is not None:
- return elem.text
-
- @property
- def fault_number(self):
- fault = self.get_fault()
- return fault.get('faultNumber', None)
-
- @property
- def fault_text(self):
- fault = self.get_fault()
- return fault.get('faultText', None)
-
- def get_fault(self):
- result = dict()
-
- self.set_result_for_license_fault(result)
- self.set_result_for_general_fault(result)
-
- if 'faultNumber' not in result:
- result['faultNumber'] = None
- return result
-
- def set_result_for_license_fault(self, result):
- root = self.find_element('LicensingFault')
- if root is None:
- return result
- for elem in root:
- if elem.tag == 'faultNumber':
- result['faultNumber'] = int(elem.text)
- elif elem.tag == 'faultText':
- tmp = elem.attrib.get('{http://www.w3.org/2001/XMLSchema-instance}nil', None)
- if tmp == 'true':
- result['faultText'] = None
- else:
- result['faultText'] = elem.text
-
- def set_result_for_general_fault(self, result):
- namespaces = {
- 'ns2': 'http://schemas.xmlsoap.org/soap/envelope/'
- }
- root = self.content.findall('.//ns2:Fault', namespaces)
- if len(root) == 0:
- return None
- for elem in root[0]:
- if elem.tag == 'faultstring':
- result['faultText'] = elem.text
-
- def json(self):
- result = dict(
- eula=self.eula or None,
- license=self.license or None,
- state=self.state or None,
- fault_number=self.fault_number,
- fault_text=self.fault_text or None
- )
- return result
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'licenseEndDateTime': 'license_end_date_time',
- }
-
- api_attributes = [
-
- ]
-
- returnables = [
-
- ]
-
- updatables = [
-
- ]
-
-
-class ApiParameters(Parameters):
- pass
-
-
-class ModuleParameters(Parameters):
- @property
- def license_options(self):
- result = dict(
- eula=self.eula or '',
- email=self.email or '',
- first_name=self.first_name or '',
- last_name=self.last_name or '',
- company=self.company or '',
- phone=self.phone or '',
- job_title=self.job_title or '',
- address=self.address or '',
- city=self.city or '',
- state=self.state or '',
- postal_code=self.postal_code or '',
- country=self.country or ''
- )
- return result
-
- @property
- def license_url(self):
- result = 'https://{0}/license/services/urn:com.f5.license.v5b.ActivationService'.format(self.license_server)
- return result
-
- @property
- def license_envelope(self):
- result = """<?xml version="1.0" encoding="UTF-8"?>
- <SOAP-ENV:Envelope xmlns:ns3="http://www.w3.org/2001/XMLSchema"
- xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
- xmlns:ns0="http://schemas.xmlsoap.org/soap/encoding/"
- xmlns:ns1="https://{0}/license/services/urn:com.f5.license.v5b.ActivationService"
- xmlns:ns2="http://schemas.xmlsoap.org/soap/envelope/"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
- SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
- <SOAP-ENV:Header/>
- <ns2:Body>
- <ns1:getLicense>
- <dossier xsi:type="ns3:string">{1}</dossier>
- <eula xsi:type="ns3:string">{eula}</eula>
- <email xsi:type="ns3:string">{email}</email>
- <firstName xsi:type="ns3:string">{first_name}</firstName>
- <lastName xsi:type="ns3:string">{last_name}</lastName>
- <companyName xsi:type="ns3:string">{company}</companyName>
- <phone xsi:type="ns3:string">{phone}</phone>
- <jobTitle xsi:type="ns3:string">{job_title}</jobTitle>
- <address xsi:type="ns3:string">{address}</address>
- <city xsi:type="ns3:string">{city}</city>
- <stateProvince xsi:type="ns3:string">{state}</stateProvince>
- <postalCode xsi:type="ns3:string">{postal_code}</postalCode>
- <country xsi:type="ns3:string">{country}</country>
- </ns1:getLicense>
- </ns2:Body>
- </SOAP-ENV:Envelope>"""
- result = result.format(self.license_server, self.dossier, **self.license_options)
- return result
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class UsableChanges(Changes):
- pass
-
-
-class ReportableChanges(Changes):
- pass
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(params=self.module.params, client=self.client)
- self.have = ApiParameters(client=self.client)
- self.changes = UsableChanges()
- self.escape_patterns = r'([$"' + "'])"
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = UsableChanges(params=changed)
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def exec_module(self):
- changed = False
- result = dict()
- state = self.want.state
-
- if state == "present":
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
- elif state == "revoked":
- changed = self.revoke()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.client.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def present(self):
- if self.exists() and not self.is_revoked():
- return False
- else:
- return self.create()
-
- def remove(self):
- if self.module.check_mode:
- return True
- self.remove_from_device()
- if self.exists():
- raise F5ModuleError("Failed to delete the resource.")
- return True
-
- def revoke(self):
- if self.is_revoked():
- return False
- else:
- # When revoking a license, it should be acceptable to auto-accept the
- # license since you accepted it the first time when you activated the
- # license you are now revoking.
- self.want.update({'accept_eula': True})
-
- # Revoking seems to just be another way of saying "get me a new license".
- # There appear to be revoke-specific wording in the license and I assume
- # some special revoke-like signing is happening, but the process is essentially
- # just another form of "create".
- return self.create()
-
- def revoke_from_device(self):
- if self.module.check_mode:
- return True
-
- dossier = self.read_dossier_from_device()
- if dossier:
- self.want.update({'dossier': dossier})
- else:
- raise F5ModuleError("Dossier not generated.")
-
- if self.is_revoked():
- return False
-
- def is_revoked(self):
- command = '-c "egrep Revoked /config/bigip.license"'
- params = dict(
- command='run',
- utilCmdArgs=command
- )
- uri = "https://{0}:{1}/mgmt/tm/util/bash".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- if 'commandResult' in response and 'Revoked' in response['commandResult']:
- return True
- return False
-
- def read_dossier_from_device(self):
- params = dict(
- command='run',
- utilCmdArgs='-b "{0}"'.format(self.want.license_key)
- )
- if self.want.state == 'revoked':
- params['utilCmdArgs'] = '-r ' + params['utilCmdArgs']
-
- uri = "https://{0}:{1}/mgmt/tm/util/get-dossier".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- try:
- if self.want.state == 'revoked':
- return response['commandResult'][8:]
- else:
- return response['commandResult']
- except Exception:
- return None
-
- def generate_license_from_remote(self):
- mgmt = iControlRestSession(
- validate_certs=False,
- headers={
- 'SOAPAction': '""',
- 'Content-Type': 'text/xml; charset=utf-8',
- }
- )
-
- for x in range(0, 10):
- try:
- resp = mgmt.post(
- self.want.license_url,
- data=self.want.license_envelope,
- )
- except Exception:
- continue
-
- try:
- resp = LicenseXmlParser(content=resp.content)
- result = resp.json()
- except F5ModuleError:
- # This error occurs when there is a problem with the license server and it
- # starts returning invalid XML (like if they upgraded something and the server
- # is redirecting improperly.
- #
- # There's no way to recover from this error except by notifying F5 that there
- # is an issue with the license server.
- raise
- except Exception:
- continue
-
- if result['state'] == 'EULA_REQUIRED':
- self.want.update({'eula': result['eula']})
- continue
- if result['state'] == 'LICENSE_RETURNED':
- return result
- elif result['state'] == 'EMAIL_REQUIRED':
- raise F5ModuleError("Email must be provided")
- elif result['state'] == 'CONTACT_INFO_REQUIRED':
- raise F5ModuleError("Contact info must be provided")
- else:
- raise F5ModuleError(result['fault_text'])
-
- def create(self):
- self._set_changed_options()
- if not self.want.accept_eula:
- raise F5ModuleError(
- "You must read and accept the product EULA to license the box."
- )
- if self.module.check_mode:
- return True
-
- dossier = self.read_dossier_from_device()
- if dossier:
- self.want.update({'dossier': dossier})
- else:
- raise F5ModuleError("Dossier not generated.")
-
- self.create_on_device()
- self.wait_for_mcpd()
- if not self.exists():
- raise F5ModuleError(
- "Failed to license the device."
- )
- return True
-
- def absent(self):
- if self.any_license_exists():
- self.remove()
- self.wait_for_mcpd()
- if self.exists():
- raise F5ModuleError(
- "Failed to remove the license from the device."
- )
- return True
- return False
-
- def exists(self):
- uri = "https://{0}:{1}/mgmt/tm/shared/licensing/registration".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- try:
- if response['registrationKey'] == self.want.license_key:
- return True
- except Exception:
- pass
- return False
-
- def wait_for_mcpd(self):
- nops = 0
-
- # Sleep a little to let mcpd settle and begin properly
- time.sleep(5)
-
- while nops < 4:
- try:
- if self._is_mcpd_ready_on_device():
- nops += 1
- else:
- nops = 0
- except Exception:
- pass
- time.sleep(5)
-
- def _is_mcpd_ready_on_device(self):
- try:
- command = "tmsh show sys mcp-state | grep running"
- params = dict(
- command='run',
- utilCmdArgs='-c "{0}"'.format(command)
- )
- uri = "https://{0}:{1}/mgmt/tm/util/bash".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- if 'commandResult' in response:
- return True
- except Exception:
- pass
- return False
-
- def any_license_exists(self):
- uri = "https://{0}:{1}/mgmt/tm/shared/licensing/registration".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- try:
- if response['registrationKey'] is not None:
- return True
- except Exception:
- pass
- return False
-
- def create_on_device(self):
- license = self.generate_license_from_remote()
- if license is None:
- raise F5ModuleError(
- "Failed to generate license from F5 activation servers."
- )
- result = self.upload_license_to_device(license)
- if not result:
- raise F5ModuleError(
- "Failed to install license on device."
- )
- result = self.upload_eula_to_device(license)
- if not result:
- raise F5ModuleError(
- "Failed to upload EULA file to device."
- )
- result = self.reload_license()
- if not result:
- raise F5ModuleError(
- "Failed to reload license configuration."
- )
-
- def upload_license_to_device(self, license):
- license_payload = re.sub(self.escape_patterns, r'\\\1', license['license'])
- command_arg = """cat > /config/bigip.license <<EOF\n{0}\nEOF""".format(license_payload)
- command = '-c "{0}"'.format(command_arg)
- params = dict(
- command='run',
- utilCmdArgs=command
- )
- uri = "https://{0}:{1}/mgmt/tm/util/bash".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return True
-
- def upload_eula_to_device(self, license):
- eula_payload = re.sub(self.escape_patterns, r'\\\1', license['eula'])
- command_arg = """cat > /LICENSE.F5 <<EOF\n{0}\nEOF""".format(eula_payload)
- command = '-c "{0}"'.format(command_arg)
- params = dict(
- command='run',
- utilCmdArgs=command
- )
- uri = "https://{0}:{1}/mgmt/tm/util/bash".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return True
-
- def reload_license(self):
- command = '-c "{0}"'.format("/usr/bin/reloadlic")
- params = dict(
- command='run',
- utilCmdArgs=command
- )
- uri = "https://{0}:{1}/mgmt/tm/util/bash".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return True
-
- def remove_from_device(self):
- result = self.remove_license_from_device()
- if not result:
- raise F5ModuleError(
- "Failed to remove license from device."
- )
- result = self.remove_eula_from_device()
- if not result:
- raise F5ModuleError(
- "Failed to remove EULA file from device."
- )
- result = self.reload_license()
- if not result:
- raise F5ModuleError(
- "Failed to reload the empty license configuration."
- )
-
- def remove_license_from_device(self):
- params = dict(
- command='run',
- utilCmdArgs='/config/bigip.license'
- )
- uri = "https://{0}:{1}/mgmt/tm/util/bash".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- resp = self.client.api.post(uri, json=params)
-
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- if 'commandResult' in response:
- if 'No such file or directory' in response['commandResult']:
- return True
- else:
- raise F5ModuleError(response['commandResult'])
- return True
-
- def remove_eula_from_device(self):
- params = dict(
- command='run',
- utilCmdArgs='/LICENSE.F5'
- )
- uri = "https://{0}:{1}/mgmt/tm/util/bash".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- resp = self.client.api.post(uri, json=params)
-
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- if 'commandResult' in response:
- if 'No such file or directory' in response['commandResult']:
- return True
- else:
- raise F5ModuleError(response['commandResult'])
- return True
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- license_key=dict(),
- license_server=dict(
- default='activate.f5.com'
- ),
- state=dict(
- choices=['absent', 'present', 'revoked'],
- default='present'
- ),
- accept_eula=dict(
- type='bool',
- default='no'
- )
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
- self.required_if = [
- ['state', 'present', ['accept_eula', 'license_key']]
- ]
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode,
- required_if=spec.required_if
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_device_ntp.py b/lib/ansible/modules/network/f5/bigip_device_ntp.py
deleted file mode 100644
index 1414f5bc26..0000000000
--- a/lib/ansible/modules/network/f5/bigip_device_ntp.py
+++ /dev/null
@@ -1,417 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['stableinterface'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_device_ntp
-short_description: Manage NTP servers on a BIG-IP
-description:
- - Manage NTP servers on a BIG-IP.
-version_added: 2.2
-options:
- ntp_servers:
- description:
- - A list of NTP servers to set on the device. At least one of C(ntp_servers)
- or C(timezone) is required.
- type: list
- state:
- description:
- - The state of the NTP servers on the system. When C(present), guarantees
- that the NTP servers are set on the system. When C(absent), removes the
- specified NTP servers from the device configuration.
- type: str
- choices:
- - absent
- - present
- default: present
- timezone:
- description:
- - The timezone to set for NTP lookups. At least one of C(ntp_servers) or
- C(timezone) is required.
- type: str
-extends_documentation_fragment: f5
-author:
- - Tim Rupp (@caphrim007)
- - Wojciech Wypior (@wojtek0806)
-'''
-
-EXAMPLES = r'''
-- name: Set NTP server
- bigip_device_ntp:
- ntp_servers:
- - 192.0.2.23
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-
-- name: Set timezone
- bigip_device_ntp:
- timezone: America/Los_Angeles
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-'''
-
-RETURN = r'''
-ntp_servers:
- description: The NTP servers that were set on the device
- returned: changed
- type: list
- sample: ["192.0.2.23", "192.0.2.42"]
-timezone:
- description: The timezone that was set on the device
- returned: changed
- type: str
- sample: true
-'''
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import fq_name
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.common import is_empty_list
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import fq_name
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.common import is_empty_list
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'servers': 'ntp_servers',
- }
-
- api_attributes = [
- 'servers', 'timezone',
- ]
-
- updatables = [
- 'ntp_servers', 'timezone',
- ]
-
- returnables = [
- 'ntp_servers', 'timezone',
- ]
-
- absentables = [
- 'ntp_servers',
- ]
-
-
-class ApiParameters(Parameters):
- pass
-
-
-class ModuleParameters(Parameters):
- @property
- def ntp_servers(self):
- ntp_servers = self._values['ntp_servers']
- if ntp_servers is None:
- return None
- if is_empty_list(ntp_servers):
- return []
- return ntp_servers
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- change = getattr(self, returnable)
- if isinstance(change, dict):
- result.update(change)
- else:
- result[returnable] = change
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class UsableChanges(Changes):
- pass
-
-
-class ReportableChanges(Changes):
- pass
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
- @property
- def ntp_servers(self):
- state = self.want.state
- if self.want.ntp_servers is None:
- return None
- if state == 'absent':
- if self.have.ntp_servers is None and self.want.ntp_servers:
- return None
- if set(self.want.ntp_servers) == set(self.have.ntp_servers):
- return []
- if set(self.want.ntp_servers) != set(self.have.ntp_servers):
- return list(set(self.want.ntp_servers).difference(self.have.ntp_servers))
- if not self.want.ntp_servers:
- if self.have.ntp_servers is None:
- return None
- if self.have.ntp_servers is not None:
- return self.want.ntp_servers
- if self.have.ntp_servers is None:
- return self.want.ntp_servers
- if set(self.want.ntp_servers) != set(self.have.ntp_servers):
- return self.want.ntp_servers
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.pop('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(params=self.module.params)
- self.have = ApiParameters()
- self.changes = UsableChanges()
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def _absent_changed_options(self):
- diff = Difference(self.want, self.have)
- absentables = Parameters.absentables
- changed = dict()
- for k in absentables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def exec_module(self):
- changed = False
- result = dict()
- state = self.want.state
-
- if state == "present":
- changed = self.update()
- elif state == "absent":
- changed = self.absent()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
-
- if self.module._diff and self.have:
- result['diff'] = self.make_diff()
-
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
-
- return result
-
- def _grab_attr(self, item):
- result = dict()
- updatables = Parameters.updatables
- for k in updatables:
- if getattr(item, k) is not None:
- result[k] = getattr(item, k)
- return result
-
- def make_diff(self):
- result = dict(before=self._grab_attr(self.have), after=self._grab_attr(self.want))
- return result
-
- def update(self):
- self.have = self.read_current_from_device()
- if not self.should_update():
- return False
- if self.module.check_mode:
- return True
- self.update_on_device()
- return True
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def should_absent(self):
- result = self._absent_changed_options()
- if result:
- return True
- return False
-
- def absent(self):
- self.have = self.read_current_from_device()
- if not self.should_absent():
- return False
- if self.module.check_mode:
- return True
- self.absent_on_device()
- return True
-
- def update_on_device(self):
- params = self.changes.api_params()
- uri = "https://{0}:{1}/mgmt/tm/sys/ntp/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/sys/ntp/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return ApiParameters(params=response)
-
- def absent_on_device(self):
- params = self.changes.api_params()
- uri = "https://{0}:{1}/mgmt/tm/sys/ntp/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- ntp_servers=dict(
- type='list',
- ),
- timezone=dict(),
- state=dict(
- default='present',
- choices=['present', 'absent']
- ),
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
-
- self.required_one_of = [
- ['ntp_servers', 'timezone']
- ]
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode,
- required_one_of=spec.required_one_of
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_device_sshd.py b/lib/ansible/modules/network/f5/bigip_device_sshd.py
deleted file mode 100644
index 1a4a98d860..0000000000
--- a/lib/ansible/modules/network/f5/bigip_device_sshd.py
+++ /dev/null
@@ -1,449 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['stableinterface'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_device_sshd
-short_description: Manage the SSHD settings of a BIG-IP
-description:
- - Manage the SSHD settings of a BIG-IP.
-version_added: 2.2
-options:
- allow:
- description:
- - Specifies, if you have enabled SSH access, the IP address or address
- range for other systems that can use SSH to communicate with this
- system.
- - To specify all addresses, use the value C(all).
- - IP address can be specified, such as 172.27.1.10.
- - IP rangees can be specified, such as 172.27.*.* or 172.27.0.0/255.255.0.0.
- - To remove SSH access specify an empty list or an empty string.
- type: list
- banner:
- description:
- - Whether to enable the banner or not.
- type: str
- choices:
- - enabled
- - disabled
- banner_text:
- description:
- - Specifies the text to include on the pre-login banner that displays
- when a user attempts to login to the system using SSH.
- type: str
- inactivity_timeout:
- description:
- - Specifies the number of seconds before inactivity causes an SSH
- session to log out.
- type: int
- log_level:
- description:
- - Specifies the minimum SSHD message level to include in the system log.
- type: str
- choices:
- - debug
- - debug1
- - debug2
- - debug3
- - error
- - fatal
- - info
- - quiet
- - verbose
- login:
- description:
- - Specifies, when checked C(enabled), that the system accepts SSH
- communications.
- type: str
- choices:
- - enabled
- - disabled
- port:
- description:
- - Port that you want the SSH daemon to run on.
- type: int
-notes:
- - Requires BIG-IP version 12.0.0 or greater
-extends_documentation_fragment: f5
-author:
- - Tim Rupp (@caphrim007)
- - Wojciech Wypior (@wojtek0806)
-'''
-
-EXAMPLES = r'''
-- name: Set the banner for the SSHD service from a string
- bigip_device_sshd:
- banner: enabled
- banner_text: banner text goes here
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-
-- name: Set the banner for the SSHD service from a file
- bigip_device_sshd:
- banner: enabled
- banner_text: "{{ lookup('file', '/path/to/file') }}"
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-
-- name: Set the SSHD service to run on port 2222
- bigip_device_sshd:
- port: 2222
- provider:
- user: admin
- password: secret
- server: lb.mydomain.com
- delegate_to: localhost
-'''
-
-RETURN = r'''
-allow:
- description:
- - Specifies, if you have enabled SSH access, the IP address or address
- range for other systems that can use SSH to communicate with this
- system.
- returned: changed
- type: list
- sample: 192.0.2.*
-banner:
- description: Whether the banner is enabled or not.
- returned: changed
- type: str
- sample: true
-banner_text:
- description:
- - Specifies the text included on the pre-login banner that
- displays when a user attempts to login to the system using SSH.
- returned: changed and success
- type: str
- sample: This is a corporate device. Connecting to it without...
-inactivity_timeout:
- description:
- - The number of seconds before inactivity causes an SSH
- session to log out.
- returned: changed
- type: int
- sample: 10
-log_level:
- description: The minimum SSHD message level to include in the system log.
- returned: changed
- type: str
- sample: debug
-login:
- description: Specifies that the system accepts SSH communications or not.
- returned: changed
- type: bool
- sample: true
-port:
- description: Port that you want the SSH daemon to run on.
- returned: changed
- type: int
- sample: 22
-'''
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import fq_name
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.common import is_empty_list
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import fq_name
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.common import is_empty_list
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'bannerText': 'banner_text',
- 'inactivityTimeout': 'inactivity_timeout',
- 'logLevel': 'log_level',
- }
-
- api_attributes = [
- 'allow', 'banner', 'bannerText', 'inactivityTimeout',
- 'logLevel', 'login', 'port',
- ]
-
- updatables = [
- 'allow', 'banner', 'banner_text', 'inactivity_timeout',
- 'log_level', 'login', 'port',
- ]
-
- returnables = [
- 'allow', 'banner', 'banner_text', 'inactivity_timeout',
- 'log_level', 'login', 'port',
- ]
-
-
-class ApiParameters(Parameters):
- pass
-
-
-class ModuleParameters(Parameters):
- @property
- def inactivity_timeout(self):
- if self._values['inactivity_timeout'] is None:
- return None
- return int(self._values['inactivity_timeout'])
-
- @property
- def port(self):
- if self._values['port'] is None:
- return None
- return int(self._values['port'])
-
- @property
- def allow(self):
- allow = self._values['allow']
- if allow is None:
- return None
- if is_empty_list(allow):
- return []
- return allow
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- change = getattr(self, returnable)
- if isinstance(change, dict):
- result.update(change)
- else:
- result[returnable] = change
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class UsableChanges(Changes):
- pass
-
-
-class ReportableChanges(Changes):
- pass
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
- @property
- def allow(self):
- if self.want.allow is None:
- return None
- if not self.want.allow:
- if self.have.allow is None:
- return None
- if self.have.allow is not None:
- return self.want.allow
- if self.have.allow is None:
- return self.want.allow
- if set(self.want.allow) != set(self.have.allow):
- return self.want.allow
-
- @property
- def banner_text(self):
- if self.want.banner_text is None:
- return None
- if self.want.banner_text == '' and self.have.banner_text is None:
- return None
- if self.want.banner_text != self.have.banner_text:
- return self.want.banner_text
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(params=self.module.params)
- self.have = ApiParameters()
- self.changes = UsableChanges()
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.client.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def exec_module(self):
- result = dict()
-
- changed = self.present()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def present(self):
- return self.update()
-
- def update(self):
- self.have = self.read_current_from_device()
- if not self.should_update():
- return False
- if self.module.check_mode:
- return True
- self.update_on_device()
- return True
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def update_on_device(self):
- params = self.changes.api_params()
- uri = "https://{0}:{1}/mgmt/tm/sys/sshd/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/sys/sshd/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return ApiParameters(params=response)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.choices = ['enabled', 'disabled']
- self.levels = [
- 'debug', 'debug1', 'debug2', 'debug3', 'error', 'fatal', 'info',
- 'quiet', 'verbose'
- ]
- self.supports_check_mode = True
- argument_spec = dict(
- allow=dict(
- type='list'
- ),
- banner=dict(
- choices=self.choices
- ),
- banner_text=dict(),
- inactivity_timeout=dict(
- type='int'
- ),
- log_level=dict(
- choices=self.levels
- ),
- login=dict(
- choices=self.choices
- ),
- port=dict(
- type='int'
- )
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_device_syslog.py b/lib/ansible/modules/network/f5/bigip_device_syslog.py
deleted file mode 100644
index 803ded9c1e..0000000000
--- a/lib/ansible/modules/network/f5/bigip_device_syslog.py
+++ /dev/null
@@ -1,735 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2018, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_device_syslog
-short_description: Manage system-level syslog settings on BIG-IP
-description:
- - Manage system-level syslog settings on BIG-IP.
-version_added: 2.8
-options:
- auth_priv_from:
- description:
- - Specifies the lowest level of messages about user authentication
- to include in the system log.
- type: str
- choices:
- - alert
- - crit
- - debug
- - emerg
- - err
- - info
- - notice
- - warning
- auth_priv_to:
- description:
- - Specifies the highest level of messages about user authentication
- to include in the system log.
- type: str
- choices:
- - alert
- - crit
- - debug
- - emerg
- - err
- - info
- - notice
- - warning
- console_log:
- description:
- - Enables or disables logging emergency syslog messages to the
- console.
- type: bool
- cron_from:
- description:
- - Specifies the lowest level of messages about time-based scheduling
- to include in the system log.
- type: str
- choices:
- - alert
- - crit
- - debug
- - emerg
- - err
- - info
- - notice
- - warning
- cron_to:
- description:
- - Specifies the highest level of messages about time-based
- scheduling to include in the system log.
- type: str
- choices:
- - alert
- - crit
- - debug
- - emerg
- - err
- - info
- - notice
- - warning
- daemon_from:
- description:
- - Specifies the lowest level of messages about daemon performance to
- include in the system log.
- type: str
- choices:
- - alert
- - crit
- - debug
- - emerg
- - err
- - info
- - notice
- - warning
- daemon_to:
- description:
- - Specifies the highest level of messages about daemon performance
- to include in the system log.
- type: str
- choices:
- - alert
- - crit
- - debug
- - emerg
- - err
- - info
- - notice
- - warning
- include:
- description:
- - Syslog-NG configuration to include in the device syslog config.
- type: str
- iso_date:
- description:
- - Enables or disables the ISO date format for messages in the log
- files.
- type: bool
- kern_from:
- description:
- - Specifies the lowest level of kernel messages to include in the
- system log.
- type: str
- choices:
- - alert
- - crit
- - debug
- - emerg
- - err
- - info
- - notice
- - warning
- kern_to:
- description:
- - Specifies the highest level of kernel messages to include in the
- system log.
- type: str
- choices:
- - alert
- - crit
- - debug
- - emerg
- - err
- - info
- - notice
- - warning
- local6_from:
- description:
- - Specifies the lowest error level for messages from the local6
- facility to include in the log.
- type: str
- choices:
- - alert
- - crit
- - debug
- - emerg
- - err
- - info
- - notice
- - warning
- local6_to:
- description:
- - Specifies the highest error level for messages from the local6
- facility to include in the log.
- type: str
- choices:
- - alert
- - crit
- - debug
- - emerg
- - err
- - info
- - notice
- - warning
- mail_from:
- description:
- - Specifies the lowest level of mail log messages to include in the
- system log.
- type: str
- choices:
- - alert
- - crit
- - debug
- - emerg
- - err
- - info
- - notice
- - warning
- mail_to:
- description:
- - Specifies the highest level of mail log messages to include in the
- system log.
- type: str
- choices:
- - alert
- - crit
- - debug
- - emerg
- - err
- - info
- - notice
- - warning
- messages_from:
- description:
- - Specifies the lowest level of system messages to include in the
- system log.
- type: str
- choices:
- - alert
- - crit
- - debug
- - emerg
- - err
- - info
- - notice
- - warning
- messages_to:
- description:
- - Specifies the highest level of system messages to include in the
- system log.
- type: str
- choices:
- - alert
- - crit
- - debug
- - emerg
- - err
- - info
- - notice
- - warning
- user_log_from:
- description:
- - Specifies the lowest level of user account messages to include in
- the system log.
- type: str
- choices:
- - alert
- - crit
- - debug
- - emerg
- - err
- - info
- - notice
- - warning
- user_log_to:
- description:
- - Specifies the highest level of user account messages to include in
- the system log.
- type: str
- choices:
- - alert
- - crit
- - debug
- - emerg
- - err
- - info
- - notice
- - warning
-extends_documentation_fragment: f5
-author:
- - Tim Rupp (@caphrim007)
-'''
-
-EXAMPLES = r'''
-- name: Create a syslog config
- bigip_device_syslog:
- name: foo
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-'''
-
-RETURN = r'''
-auth_priv_from:
- description: The new lowest user authentication logging level
- returned: changed
- type: str
- sample: alert
-auth_priv_to:
- description: The new highest user authentication logging level.
- returned: changed
- type: str
- sample: emerg
-console_log:
- description: Whether logging to console is enabled or not.
- returned: changed
- type: bool
- sample: yes
-iso_date:
- description: Whether ISO date format in logs is enabled or not
- returned: changed
- type: bool
- sample: no
-cron_from:
- description: The new lowest time-based scheduling logging level.
- returned: changed
- type: str
- sample: emerg
-cron_to:
- description: The new highest time-based scheduling logging level.
- returned: changed
- type: str
- sample: alert
-daemon_from:
- description: The new lowest daemon performance logging level.
- returned: changed
- type: str
- sample: alert
-daemon_to:
- description: The new highest daemon performance logging level.
- returned: changed
- type: str
- sample: alert
-include:
- description: The new extra syslog-ng configuration to include in syslog config.
- returned: changed
- type: str
- sample: "filter f_remote_syslog { not (facility(local6)) };"
-kern_from:
- description: The new lowest kernel messages logging level.
- returned: changed
- type: str
- sample: alert
-kern_to:
- description: The new highest kernel messages logging level.
- returned: changed
- type: str
- sample: alert
-local6_from:
- description: The new lowest local6 facility logging level.
- returned: changed
- type: str
- sample: alert
-local6_to:
- description: The new highest local6 facility logging level.
- returned: changed
- type: str
- sample: alert
-mail_from:
- description: The new lowest mail log logging level.
- returned: changed
- type: str
- sample: alert
-mail_to:
- description: The new highest mail log logging level.
- returned: changed
- type: str
- sample: alert
-messages_from:
- description: The new lowest system logging level.
- returned: changed
- type: str
- sample: alert
-messages_to:
- description: The new highest system logging level.
- returned: changed
- type: str
- sample: alert
-user_log_from:
- description: The new lowest user account logging level.
- returned: changed
- type: str
- sample: alert
-user_log_to:
- description: The new highest user account logging level.
- returned: changed
- type: str
- sample: alert
-'''
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import fq_name
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.common import flatten_boolean
- from library.module_utils.network.f5.compare import cmp_str_with_none
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import fq_name
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.common import flatten_boolean
- from ansible.module_utils.network.f5.compare import cmp_str_with_none
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'authPrivFrom': 'auth_priv_from',
- 'authPrivTo': 'auth_priv_to',
- 'consoleLog': 'console_log',
- 'cronFrom': 'cron_from',
- 'cronTo': 'cron_to',
- 'daemonFrom': 'daemon_from',
- 'daemonTo': 'daemon_to',
- 'isoDate': 'iso_date',
- 'kernFrom': 'kern_from',
- 'kernTo': 'kern_to',
- 'local6From': 'local6_from',
- 'local6To': 'local6_to',
- 'mailFrom': 'mail_from',
- 'mailTo': 'mail_to',
- 'messagesFrom': 'messages_from',
- 'messagesTo': 'messages_to',
- 'userLogFrom': 'user_log_from',
- 'userLogTo': 'user_log_to',
- }
-
- api_attributes = [
- 'include',
- 'authPrivFrom',
- 'authPrivTo',
- 'consoleLog',
- 'cronFrom',
- 'cronTo',
- 'daemonFrom',
- 'daemonTo',
- 'isoDate',
- 'kernFrom',
- 'kernTo',
- 'local6From',
- 'local6To',
- 'mailFrom',
- 'mailTo',
- 'messagesFrom',
- 'messagesTo',
- 'userLogFrom',
- 'userLogTo',
- ]
-
- returnables = [
- 'include',
- 'auth_priv_from',
- 'auth_priv_to',
- 'console_log',
- 'cron_from',
- 'cron_to',
- 'daemon_from',
- 'daemon_to',
- 'iso_date',
- 'kern_from',
- 'kern_to',
- 'local6_from',
- 'local6_to',
- 'mail_from',
- 'mail_to',
- 'messages_from',
- 'messages_to',
- 'user_log_from',
- 'user_log_to',
- ]
-
- updatables = [
- 'include',
- 'auth_priv_from',
- 'auth_priv_to',
- 'console_log',
- 'cron_from',
- 'cron_to',
- 'daemon_from',
- 'daemon_to',
- 'iso_date',
- 'kern_from',
- 'kern_to',
- 'local6_from',
- 'local6_to',
- 'mail_from',
- 'mail_to',
- 'messages_from',
- 'messages_to',
- 'user_log_from',
- 'user_log_to',
- ]
-
- @property
- def console_log(self):
- return flatten_boolean(self._values['console_log'])
-
- @property
- def iso_date(self):
- return flatten_boolean(self._values['iso_date'])
-
-
-class ApiParameters(Parameters):
- @property
- def include(self):
- if self._values['include'] in [None, 'none']:
- return None
- return self._values['include']
-
-
-class ModuleParameters(Parameters):
- @property
- def include(self):
- if self._values['include'] is None:
- return None
- if self._values['include'] in ['', 'none']:
- return ''
- return self._values['include'].replace('"', "'")
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class UsableChanges(Changes):
- @property
- def console_log(self):
- if self._values['console_log'] is None:
- return None
- elif self._values['console_log'] == 'yes':
- return 'enabled'
- return 'disabled'
-
- @property
- def iso_date(self):
- if self._values['iso_date'] is None:
- return None
- elif self._values['iso_date'] == 'yes':
- return 'enabled'
- return 'disabled'
-
-
-class ReportableChanges(Changes):
- @property
- def console_log(self):
- return flatten_boolean(self._values['console_log'])
-
- @property
- def iso_date(self):
- return flatten_boolean(self._values['iso_date'])
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
- @property
- def include(self):
- return cmp_str_with_none(self.want.include, self.have.include)
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(params=self.module.params)
- self.have = ApiParameters()
- self.changes = UsableChanges()
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = UsableChanges(params=changed)
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def exec_module(self):
- result = dict()
-
- changed = self.present()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.client.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def present(self):
- return self.update()
-
- def update(self):
- self.have = self.read_current_from_device()
- if not self.should_update():
- return False
- if self.module.check_mode:
- return True
- self.update_on_device()
- return True
-
- def update_on_device(self):
- params = self.changes.api_params()
- uri = "https://{0}:{1}/mgmt/tm/sys/syslog".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/sys/syslog".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return ApiParameters(params=response)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- levels = [
- 'alert', 'crit', 'debug', 'emerg', 'err', 'info', 'notice', 'warning'
- ]
-
- argument_spec = dict(
- auth_priv_from=dict(choices=levels),
- auth_priv_to=dict(choices=levels),
- console_log=dict(type='bool'),
- cron_from=dict(choices=levels),
- cron_to=dict(choices=levels),
- daemon_from=dict(choices=levels),
- daemon_to=dict(choices=levels),
- include=dict(),
- iso_date=dict(type='bool'),
- kern_from=dict(choices=levels),
- kern_to=dict(choices=levels),
- local6_from=dict(choices=levels),
- local6_to=dict(choices=levels),
- mail_from=dict(choices=levels),
- mail_to=dict(choices=levels),
- messages_from=dict(choices=levels),
- messages_to=dict(choices=levels),
- user_log_from=dict(choices=levels),
- user_log_to=dict(choices=levels),
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode,
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_device_traffic_group.py b/lib/ansible/modules/network/f5/bigip_device_traffic_group.py
deleted file mode 100644
index 5354a74efd..0000000000
--- a/lib/ansible/modules/network/f5/bigip_device_traffic_group.py
+++ /dev/null
@@ -1,672 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_device_traffic_group
-short_description: Manages traffic groups on BIG-IP
-description:
- - Supports managing traffic groups and their attributes on a BIG-IP.
-version_added: 2.5
-options:
- name:
- description:
- - The name of the traffic group.
- type: str
- required: True
- mac_address:
- description:
- - Specifies the floating Media Access Control (MAC) address associated with the floating IP addresses
- defined for a traffic group.
- - Primarily, a MAC masquerade address minimizes ARP communications or dropped packets as a result of failover.
- - A MAC masquerade address ensures that any traffic destined for a specific traffic group reaches an available
- device after failover, which happens because along with the traffic group, the MAC masquerade address floats
- to the available device.
- - Without a MAC masquerade address, the sending host must learn the MAC address for a newly-active device,
- either by sending an ARP request or by relying on the gratuitous ARP from the newly-active device.
- - To unset the MAC address, specify an empty value (C("")) to this parameter.
- type: str
- version_added: 2.6
- ha_order:
- description:
- - Specifies order in which you would like to assign devices for failover.
- - If you configure this setting, you must configure the setting on every traffic group in the device group.
- - The values should be device names of the devices that belong to the failover group configured beforehand.
- - The order in which the devices are placed as arguments to this parameter, determines their HA order
- on the device, in other words changing the order of the same elements will cause a change on the unit.
- - To disable an HA order failover method , specify an empty string value (C("")) to this parameter.
- - Disabling HA order will revert the device back to using Load Aware method as it is the default,
- unless C(ha_group) setting is also configured.
- - Device names will be prepended by a partition by the module, so you can provide either the full path format
- name C(/Common/bigip1) or just the name string C(bigip1).
- type: list
- version_added: 2.8
- ha_group:
- description:
- - Specifies a configured C(HA group) to be associated with the traffic group.
- - Once you create an HA group on a device and associate the HA group with a traffic group,
- you must create an HA group and associate it with that same traffic group on every device in the device group.
- - To disable an HA group failover method , specify an empty string value (C("")) to this parameter.
- - Disabling HA group will revert the device back to using C(Load Aware) method as it is the default,
- unless C(ha_order) setting is also configured.
- - The C(auto_failback) and C(auto_failback_time) are not compatible with C(ha_group).
- type: str
- version_added: 2.8
- ha_load_factor:
- description:
- - The value of the load the traffic-group presents the system relative to other traffic groups.
- - This parameter only takes effect when C(Load Aware) failover method is in use.
- - The correct value range is C(1 - 1000) inclusive.
- type: int
- version_added: 2.8
- auto_failback:
- description:
- - Specifies whether the traffic group fails back to the initial device specified in C(ha_order).
- type: bool
- version_added: 2.8
- auto_failback_time:
- description:
- - Specifies the number of seconds the system delays before failing back to the initial device
- specified in C(ha_order).
- - The correct value range is C(0 - 300) inclusive.
- type: int
- version_added: 2.8
- partition:
- description:
- - Device partition to manage resources on.
- type: str
- default: Common
- state:
- description:
- - When C(present), ensures that the traffic group exists.
- - When C(absent), ensures the traffic group is removed.
- type: str
- choices:
- - present
- - absent
- default: present
-extends_documentation_fragment: f5
-author:
- - Tim Rupp (@caphrim007)
- - Wojciech Wypior (@wojtek0806)
-'''
-
-EXAMPLES = r'''
-- name: Create a traffic group
- bigip_device_traffic_group:
- name: foo1
- state: present
- provider:
- user: admin
- password: secret
- server: lb.mydomain.com
- delegate_to: localhost
-
-- name: Create a traffic group with ha_group failover
- bigip_device_traffic_group:
- name: foo2
- state: present
- ha_group: foo_HA_grp
- provider:
- user: admin
- password: secret
- server: lb.mydomain.com
- delegate_to: localhost
-
-- name: Create a traffic group with ha_order failover
- bigip_device_traffic_group:
- name: foo3
- state: present
- ha_order:
- - /Common/bigip1.lab.local
- - /Common/bigip2.lab.local
- auto_failback: yes
- auto_failback_time: 40
- provider:
- user: admin
- password: secret
- server: lb.mydomain.com
- delegate_to: localhost
-
-- name: Change traffic group ha_order to ha_group
- bigip_device_traffic_group:
- name: foo3
- state: present
- ha_group: foo_HA_grp
- ha_order: ""
- auto_failback: no
- provider:
- user: admin
- password: secret
- server: lb.mydomain.com
- delegate_to: localhost
-
-- name: Remove traffic group
- bigip_device_traffic_group:
- name: foo
- state: absent
- provider:
- user: admin
- password: secret
- server: lb.mydomain.com
- delegate_to: localhost
-'''
-
-RETURN = r'''
-mac_address:
- description: The MAC masquerade address
- returned: changed
- type: str
- sample: "02:01:d7:93:35:08"
-ha_group:
- description: The configured HA group associated with traffic group
- returned: changed
- type: str
- sample: foo_HA_grp
-ha_order:
- description: Specifies the order in which the devices will failover
- returned: changed
- type: list
- sample: ['/Common/bigip1', '/Common/bigip2']
-ha_load_factor:
- description: The value of the load the traffic-group presents the system relative to other traffic groups
- returned: changed
- type: int
- sample: 20
-auto_failback:
- description: Specifies whether the traffic group fails back to the initial device specified in ha_order
- returned: changed
- type: bool
- sample: yes
-auto_failback_time:
- description: Specifies the number of seconds the system delays before failing back
- returned: changed
- type: int
- sample: 60
-'''
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.basic import env_fallback
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.common import fq_name
- from library.module_utils.network.f5.common import transform_name
- from library.module_utils.network.f5.common import flatten_boolean
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.common import fq_name
- from ansible.module_utils.network.f5.common import transform_name
- from ansible.module_utils.network.f5.common import flatten_boolean
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'mac': 'mac_address',
- 'haGroup': 'ha_group',
- 'haOrder': 'ha_order',
- 'haLoadFactor': 'ha_load_factor',
- 'autoFailbackTime': 'auto_failback_time',
- 'autoFailbackEnabled': 'auto_failback',
- }
-
- api_attributes = [
- 'mac',
- 'haGroup',
- 'haOrder',
- 'haLoadFactor',
- 'autoFailbackTime',
- 'autoFailbackEnabled',
-
- ]
-
- returnables = [
- 'mac_address',
- 'ha_group',
- 'ha_order',
- 'ha_load_factor',
- 'auto_failback_time',
- 'auto_failback',
- ]
-
- updatables = [
- 'mac_address',
- 'ha_group',
- 'ha_order',
- 'ha_load_factor',
- 'auto_failback_time',
- 'auto_failback',
- ]
-
-
-class ApiParameters(Parameters):
- pass
-
-
-class ModuleParameters(Parameters):
- @property
- def mac_address(self):
- if self._values['mac_address'] is None:
- return None
- if self._values['mac_address'] == '':
- return 'none'
- return self._values['mac_address']
-
- @property
- def ha_group(self):
- if self._values['ha_group'] is None:
- return None
- if self._values['ha_group'] == '':
- return 'none'
- if self.auto_failback == 'true':
- raise F5ModuleError(
- "The auto_failback cannot be enabled when ha_group is specified."
- )
- return self._values['ha_group']
-
- @property
- def ha_load_factor(self):
- if self._values['ha_load_factor'] is None:
- return None
- value = self._values['ha_load_factor']
- if value < 1 or value > 1000:
- raise F5ModuleError(
- "Invalid ha_load_factor value, correct range is 1 - 1000, specified value: {0}.".format(value))
- return value
-
- @property
- def auto_failback_time(self):
- if self._values['auto_failback_time'] is None:
- return None
- value = self._values['auto_failback_time']
- if value < 0 or value > 300:
- raise F5ModuleError(
- "Invalid auto_failback_time value, correct range is 0 - 300, specified value: {0}.".format(value))
- return value
-
- @property
- def auto_failback(self):
- result = flatten_boolean(self._values['auto_failback'])
- if result == 'yes':
- return 'true'
- if result == 'no':
- return 'false'
- return None
-
- @property
- def ha_order(self):
- if self._values['ha_order'] is None:
- return None
- if len(self._values['ha_order']) == 1 and self._values['ha_order'][0] == '':
- if self.auto_failback == 'true':
- raise F5ModuleError(
- 'Cannot enable auto failback when HA order list is empty, at least one device must be specified.'
- )
- return 'none'
- result = [fq_name(self.partition, value) for value in self._values['ha_order']]
- return result
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- return result
-
-
-class UsableChanges(Changes):
- pass
-
-
-class ReportableChanges(Changes):
-
- @property
- def mac_address(self):
- if self._values['mac_address'] is None:
- return None
- if self._values['mac_address'] == 'none':
- return ''
- return self._values['mac_address']
-
- @property
- def ha_group(self):
- if self._values['ha_group'] is None:
- return None
- if self._values['ha_group'] == 'none':
- return ''
- return self._values['ha_group']
-
- @property
- def auto_failback(self):
- result = self._values['auto_failback']
- if result == 'true':
- return 'yes'
- if result == 'false':
- return 'no'
- return None
-
- @property
- def ha_order(self):
- if self._values['ha_order'] is None:
- return None
- if self._values['ha_order'] == 'none':
- return ''
- return self._values['ha_order']
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
- @property
- def ha_group(self):
- if self.want.ha_group is None:
- return None
- if self.have.ha_group is None and self.want.ha_group == 'none':
- return None
- if self.want.ha_group != self.have.ha_group:
- if self.have.auto_failback == 'true' and self.want.auto_failback != 'false':
- raise F5ModuleError(
- "The auto_failback parameter on the device must disabled to use ha_group failover method."
- )
- return self.want.ha_group
-
- @property
- def ha_order(self):
- # Device order is literally derived from the order in the array,
- # hence lists with the same elements but in different order cannot be equal, so cmp_simple_list
- # function will not work here.
- if self.want.ha_order is None:
- return None
- if self.have.ha_order is None and self.want.ha_order == 'none':
- return None
- if self.want.ha_order != self.have.ha_order:
- return self.want.ha_order
-
- @property
- def partition(self):
- raise F5ModuleError(
- "Partition cannot be changed for a traffic group. Only /Common is allowed."
- )
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.have = None
- self.want = ModuleParameters(params=self.module.params)
- self.changes = UsableChanges()
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = UsableChanges(params=changed)
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def exec_module(self):
- changed = False
- result = dict()
- state = self.want.state
-
- if state == "present":
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def present(self):
- if self.exists():
- return self.update()
- else:
- return self.create()
-
- def absent(self):
- if self.exists():
- return self.remove()
- return False
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def update(self):
- self.have = self.read_current_from_device()
- if not self.should_update():
- return False
- if self.module.check_mode:
- return True
- self.update_on_device()
- return True
-
- def remove(self):
- if self.module.check_mode:
- return True
- self.remove_from_device()
- if self.exists():
- raise F5ModuleError("Failed to delete the resource.")
- return True
-
- def create(self):
- self._set_changed_options()
- if self.want.partition.lower().strip('/') != 'common':
- raise F5ModuleError(
- "Traffic groups can only be created in the /Common partition"
- )
- if self.module.check_mode:
- return True
- self.create_on_device()
- return True
-
- def exists(self):
- uri = "https://{0}:{1}/mgmt/tm/cm/traffic-group/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def create_on_device(self):
- params = self.changes.api_params()
- params['name'] = self.want.name
- params['partition'] = self.want.partition
- uri = "https://{0}:{1}/mgmt/tm/cm/traffic-group/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return response['selfLink']
-
- def update_on_device(self):
- params = self.changes.api_params()
- uri = "https://{0}:{1}/mgmt/tm/cm/traffic-group/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/cm/traffic-group/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
-
- resp = self.client.api.get(uri)
-
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return ApiParameters(params=response)
-
- def remove_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/cm/traffic-group/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- response = self.client.api.delete(uri)
- if response.status == 200:
- return True
- raise F5ModuleError(response.content)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- name=dict(required=True),
- mac_address=dict(),
- ha_order=dict(
- type='list'
- ),
- ha_group=dict(),
- ha_load_factor=dict(
- type='int'
- ),
- auto_failback=dict(
- type='bool',
- ),
- auto_failback_time=dict(
- type='int'
- ),
- state=dict(
- default='present',
- choices=['absent', 'present']
- ),
- partition=dict(
- default='Common',
- fallback=(env_fallback, ['F5_PARTITION'])
- ),
-
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode,
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_device_trust.py b/lib/ansible/modules/network/f5/bigip_device_trust.py
deleted file mode 100644
index bb324ce40e..0000000000
--- a/lib/ansible/modules/network/f5/bigip_device_trust.py
+++ /dev/null
@@ -1,380 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['stableinterface'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_device_trust
-short_description: Manage the trust relationships between BIG-IPs
-description:
- - Manage the trust relationships between BIG-IPs. Devices, once peered, cannot
- be updated. If updating is needed, the peer must first be removed before it
- can be re-added to the trust.
-version_added: 2.5
-options:
- peer_server:
- description:
- - The peer address to connect to and trust for synchronizing configuration.
- This is typically the management address of the remote device, but may
- also be a Self IP.
- type: str
- required: True
- peer_hostname:
- description:
- - The hostname that you want to associate with the device. This value will
- be used to easily distinguish this device in BIG-IP configuration.
- - When trusting a new device, if this parameter is not specified, the value
- of C(peer_server) will be used as a default.
- type: str
- peer_user:
- description:
- - The API username of the remote peer device that you are trusting. Note
- that the CLI user cannot be used unless it too has an API account. If this
- value is not specified, then the value of C(user), or the environment
- variable C(F5_USER) will be used.
- type: str
- peer_password:
- description:
- - The password of the API username of the remote peer device that you are
- trusting. If this value is not specified, then the value of C(password),
- or the environment variable C(F5_PASSWORD) will be used.
- type: str
- type:
- description:
- - Specifies whether the device you are adding is a Peer or a Subordinate.
- The default is C(peer).
- - The difference between the two is a matter of mitigating risk of
- compromise.
- - A subordinate device cannot sign a certificate for another device.
- - In the case where the security of an authority device in a trust domain
- is compromised, the risk of compromise is minimized for any subordinate
- device.
- - Designating devices as subordinate devices is recommended for device
- groups with a large number of member devices, where the risk of compromise
- is high.
- type: str
- choices:
- - peer
- - subordinate
- default: peer
- state:
- description:
- - When C(present), ensures the specified devices are trusted.
- - When C(absent), removes the device trusts.
- type: str
- choices:
- - absent
- - present
- default: present
-extends_documentation_fragment: f5
-author:
- - Tim Rupp (@caphrim007)
-'''
-
-EXAMPLES = r'''
-- name: Add trusts for all peer devices to Active device
- bigip_device_trust:
- peer_server: "{{ item.ansible_host }}"
- peer_hostname: "{{ item.inventory_hostname }}"
- peer_user: "{{ item.bigip_username }}"
- peer_password: "{{ item.bigip_password }}"
- provider:
- server: lb.mydomain.com
- user: admin
- password: secret
- loop: hostvars
- when: inventory_hostname in groups['master']
- delegate_to: localhost
-'''
-
-RETURN = r'''
-peer_server:
- description: The remote IP address of the trusted peer.
- returned: changed
- type: str
- sample: 10.0.2.15
-peer_hostname:
- description: The remote hostname used to identify the trusted peer.
- returned: changed
- type: str
- sample: test-bigip-02.localhost.localdomain
-'''
-
-import re
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.ipaddress import is_valid_ip
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.ipaddress import is_valid_ip
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'deviceName': 'peer_hostname',
- 'caDevice': 'type',
- 'device': 'peer_server',
- 'username': 'peer_user',
- 'password': 'peer_password'
- }
-
- api_attributes = [
- 'name',
- 'caDevice',
- 'device',
- 'deviceName',
- 'username',
- 'password'
- ]
-
- returnables = [
- 'peer_server', 'peer_hostname'
- ]
-
- updatables = []
-
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- return result
- except Exception:
- return result
-
- @property
- def peer_server(self):
- if self._values['peer_server'] is None:
- return None
- if is_valid_ip(self._values['peer_server']):
- return self._values['peer_server']
- raise F5ModuleError(
- "The provided 'peer_server' parameter is not an IP address."
- )
-
- @property
- def peer_hostname(self):
- if self._values['peer_hostname'] is None:
- return self.peer_server
- regex = re.compile(r'[^a-zA-Z0-9.\-_]')
- result = regex.sub('_', self._values['peer_hostname'])
- return result
-
- @property
- def type(self):
- if self._values['type'] == 'peer':
- return True
- return False
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.have = None
- self.want = Parameters(params=self.module.params)
- self.changes = Parameters()
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = Parameters(params=changed)
-
- def exec_module(self):
- changed = False
- result = dict()
- state = self.want.state
-
- if state == "present":
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
-
- changes = self.changes.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- return result
-
- def provided_password(self):
- if self.want.password:
- return self.password
- if self.want.provider.get('password', None):
- return self.want.provider.get('password')
- if self.module.params.get('password', None):
- return self.module.params.get('password')
-
- def provided_username(self):
- if self.want.username:
- return self.username
- if self.want.provider.get('user', None):
- return self.provider.get('user')
- if self.module.params.get('user', None):
- return self.module.params.get('user')
-
- def present(self):
- if self.exists():
- return False
- else:
- return self.create()
-
- def create(self):
- self._set_changed_options()
- if self.want.peer_user is None:
- self.want.update({'peer_user': self.provided_username()})
- if self.want.peer_password is None:
- self.want.update({'peer_password': self.provided_password()})
- if self.want.peer_hostname is None:
- self.want.update({'peer_hostname': self.want.peer_server})
- if self.module.check_mode:
- return True
-
- self.create_on_device()
- return True
-
- def absent(self):
- if self.exists():
- return self.remove()
- return False
-
- def remove(self):
- if self.module.check_mode:
- return True
- if self.want.peer_hostname is None:
- self.want.update({'peer_hostname': self.want.peer_server})
- self.remove_from_device()
- if self.exists():
- raise F5ModuleError("Failed to remove the trusted peer.")
- return True
-
- def exists(self):
- uri = "https://{0}:{1}/mgmt/tm/cm/device".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- for device in response['items']:
- try:
- if device['managementIp'] == self.want.peer_server:
- return True
- except KeyError:
- pass
- return False
-
- def create_on_device(self):
- params = self.want.api_params()
- params.update({
- "command": "run",
- "name": 'Root',
- })
- uri = "https://{0}:{1}/mgmt/tm/cm/add-to-trust/".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def remove_from_device(self):
- params = self.want.api_params()
- params.update({
- "command": "run",
- "deviceName": self.want.peer_hostname,
- "name": self.want.peer_hostname,
- })
- uri = "https://{0}:{1}/mgmt/tm/cm/remove-from-trust/".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- peer_server=dict(required=True),
- peer_hostname=dict(),
- peer_user=dict(),
- peer_password=dict(no_log=True),
- type=dict(
- choices=['peer', 'subordinate'],
- default='peer'
- ),
- state=dict(
- default='present',
- choices=['present', 'absent']
- )
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_dns_cache_resolver.py b/lib/ansible/modules/network/f5/bigip_dns_cache_resolver.py
deleted file mode 100644
index 2b7305e7b0..0000000000
--- a/lib/ansible/modules/network/f5/bigip_dns_cache_resolver.py
+++ /dev/null
@@ -1,547 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2018, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-
-DOCUMENTATION = r'''
----
-module: bigip_dns_cache_resolver
-short_description: Manage DNS resolver cache configurations on BIG-IP
-description:
- - Manage DNS resolver cache configurations on BIG-IP.
-version_added: 2.8
-options:
- name:
- description:
- - Specifies the name of the cache.
- type: str
- required: True
- answer_default_zones:
- description:
- - Specifies whether the system answers DNS queries for the default
- zones localhost, reverse 127.0.0.1 and ::1, and AS112.
- - When creating a new cache resolver, if this parameter is not specified, the
- default is C(no).
- type: bool
- forward_zones:
- description:
- - Forward zones associated with the cache.
- - To remove all forward zones, specify a value of C(none).
- suboptions:
- name:
- description:
- - Specifies a FQDN for the forward zone.
- type: str
- required: True
- nameservers:
- description:
- - Specifies the IP address and service port of a recursive
- nameserver that answers DNS queries for the zone when the
- response cannot be found in the DNS cache.
- suboptions:
- address:
- description:
- - Address of recursive nameserver.
- type: str
- port:
- description:
- - Port of recursive nameserver.
- - When specifying new nameservers, if this value is not provided, the
- default is C(53).
- type: int
- type: list
- type: raw
- route_domain:
- description:
- - Specifies the route domain the resolver uses for outbound traffic.
- type: str
- state:
- description:
- - When C(present), ensures that the resource exists.
- - When C(absent), ensures the resource is removed.
- type: str
- choices:
- - present
- - absent
- default: present
- partition:
- description:
- - Device partition to manage resources on.
- type: str
- default: Common
-extends_documentation_fragment: f5
-author:
- - Tim Rupp (@caphrim007)
-'''
-
-EXAMPLES = r'''
-- name: Create a DNS resolver cache
- bigip_dns_cache:
- name: foo
- answer_default_zones: yes
- forward_zones:
- - name: foo.bar.com
- nameservers:
- - address: 1.2.3.4
- port: 53
- - address: 5.6.7.8
- route_domain: 0
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-'''
-
-RETURN = r'''
-param1:
- description: The new param1 value of the resource.
- returned: changed
- type: bool
- sample: true
-param2:
- description: The new param2 value of the resource.
- returned: changed
- type: str
- sample: Foo is bar
-'''
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.basic import env_fallback
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import fq_name
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.common import flatten_boolean
- from library.module_utils.network.f5.common import transform_name
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import fq_name
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.common import flatten_boolean
- from ansible.module_utils.network.f5.common import transform_name
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'routeDomain': 'route_domain',
- 'answerDefaultZones': 'answer_default_zones',
- 'forwardZones': 'forward_zones',
- }
-
- api_attributes = [
- 'routeDomain',
- 'answerDefaultZones',
- 'forwardZones',
- ]
-
- returnables = [
- 'route_domain',
- 'answer_default_zones',
- 'forward_zones',
- ]
-
- updatables = [
- 'route_domain',
- 'answer_default_zones',
- 'forward_zones',
- ]
-
- @property
- def route_domain(self):
- if self._values['route_domain'] is None:
- return None
- return fq_name(self.partition, self._values['route_domain'])
-
- @property
- def answer_default_zones(self):
- return flatten_boolean(self._values['answer_default_zones'])
-
-
-class ApiParameters(Parameters):
- @property
- def forward_zones(self):
- if self._values['forward_zones'] is None:
- return None
- result = []
- for x in self._values['forward_zones']:
- tmp = dict(
- name=x['name'],
- nameservers=[]
- )
- if 'nameservers' in x:
- tmp['nameservers'] = [y['name'] for y in x['nameservers']]
- tmp['nameservers'].sort()
- result.append(tmp)
- return result
-
-
-class ModuleParameters(Parameters):
- @property
- def forward_zones(self):
- if self._values['forward_zones'] is None:
- return None
- elif self._values['forward_zones'] in ['', 'none']:
- return ''
- result = []
- for x in self._values['forward_zones']:
- if 'name' not in x:
- raise F5ModuleError(
- "A 'name' key must be provided when specifying a list of forward zones."
- )
- tmp = dict(
- name=x['name'],
- nameservers=[]
- )
- if 'nameservers' in x:
- for ns in x['nameservers']:
- if 'address' not in ns:
- raise F5ModuleError(
- "An 'address' key must be provided when specifying a list of forward zone nameservers."
- )
- item = '{0}:{1}'.format(ns['address'], ns.get('port', 53))
- tmp['nameservers'].append(item)
- tmp['nameservers'].sort()
- result.append(tmp)
- return result
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class UsableChanges(Changes):
- @property
- def forward_zones(self):
- if self._values['forward_zones'] is None:
- return None
- result = []
- for x in self._values['forward_zones']:
- tmp = {'name': x['name']}
- if 'nameservers' in x:
- tmp['nameservers'] = []
- for y in x['nameservers']:
- tmp['nameservers'].append(dict(name=y))
- result.append(tmp)
- return result
-
-
-class ReportableChanges(Changes):
- pass
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
- @property
- def forward_zones(self):
- if self.want.forward_zones is None:
- return None
- if self.have.forward_zones is None and self.want.forward_zones in ['', 'none']:
- return None
- if self.have.forward_zones is not None and self.want.forward_zones in ['', 'none']:
- return []
- if self.have.forward_zones is None:
- return dict(
- forward_zones=self.want.forward_zones
- )
-
- want = sorted(self.want.forward_zones, key=lambda x: x['name'])
- have = sorted(self.have.forward_zones, key=lambda x: x['name'])
-
- wnames = [x['name'] for x in want]
- hnames = [x['name'] for x in have]
-
- if set(wnames) != set(hnames):
- return dict(
- forward_zones=self.want.forward_zones
- )
-
- for idx, x in enumerate(want):
- wns = x.get('nameservers', [])
- hns = have[idx].get('nameservers', [])
- if set(wns) != set(hns):
- return dict(
- forward_zones=self.want.forward_zones
- )
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(params=self.module.params)
- self.have = ApiParameters()
- self.changes = UsableChanges()
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = UsableChanges(params=changed)
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def exec_module(self):
- changed = False
- result = dict()
- state = self.want.state
-
- if state == "present":
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.client.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def present(self):
- if self.exists():
- return self.update()
- else:
- return self.create()
-
- def exists(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/dns/cache/resolver/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def update(self):
- self.have = self.read_current_from_device()
- if not self.should_update():
- return False
- if self.module.check_mode:
- return True
- self.update_on_device()
- return True
-
- def remove(self):
- if self.module.check_mode:
- return True
- self.remove_from_device()
- if self.exists():
- raise F5ModuleError("Failed to delete the resource.")
- return True
-
- def create(self):
- self._set_changed_options()
- if self.module.check_mode:
- return True
- self.create_on_device()
- return True
-
- def create_on_device(self):
- params = self.changes.api_params()
- params['name'] = self.want.name
- params['partition'] = self.want.partition
- uri = "https://{0}:{1}/mgmt/tm/ltm/dns/cache/resolver/".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def update_on_device(self):
- params = self.changes.api_params()
- uri = "https://{0}:{1}/mgmt/tm/ltm/dns/cache/resolver/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def absent(self):
- if self.exists():
- return self.remove()
- return False
-
- def remove_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/dns/cache/resolver/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- response = self.client.api.delete(uri)
- if response.status == 200:
- return True
- raise F5ModuleError(response.content)
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/dns/cache/resolver/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return ApiParameters(params=response)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- name=dict(required=True),
- route_domain=dict(),
- answer_default_zones=dict(type='bool'),
- forward_zones=dict(
- type='raw',
- options=dict(
- name=dict(),
- nameservers=dict(
- type='list',
- elements='dict',
- options=dict(
- address=dict(),
- port=dict(type='int')
- )
- )
- )
- ),
- state=dict(
- default='present',
- choices=['present', 'absent']
- ),
- partition=dict(
- default='Common',
- fallback=(env_fallback, ['F5_PARTITION'])
- )
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode,
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_dns_nameserver.py b/lib/ansible/modules/network/f5/bigip_dns_nameserver.py
deleted file mode 100644
index 9d92bb0278..0000000000
--- a/lib/ansible/modules/network/f5/bigip_dns_nameserver.py
+++ /dev/null
@@ -1,468 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2018, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_dns_nameserver
-short_description: Manage LTM DNS nameservers on a BIG-IP
-description:
- - Manages LTM DNS nameservers on a BIG-IP. These nameservers form part of what is
- known as DNS Express on a BIG-IP. This module does not configure GTM related
- functionality, nor does it configure system-level name servers that affect the
- base system's ability to resolve DNS names.
-version_added: 2.8
-options:
- name:
- description:
- - Specifies the name of the nameserver.
- type: str
- required: True
- address:
- description:
- - Specifies the IP address on which the DNS nameserver (client) or back-end DNS
- authoritative server (DNS Express server) listens for DNS messages.
- - When creating a new nameserver, if this value is not specified, the default
- is C(127.0.0.1).
- type: str
- service_port:
- description:
- - Specifies the service port on which the DNS nameserver (client) or back-end DNS
- authoritative server (DNS Express server) listens for DNS messages.
- - When creating a new nameserver, if this value is not specified, the default
- is C(53).
- type: str
- route_domain:
- description:
- - Specifies the local route domain that the DNS nameserver (client) or back-end
- DNS authoritative server (DNS Express server) uses for outbound traffic.
- - When creating a new nameserver, if this value is not specified, the default
- is C(0).
- type: str
- tsig_key:
- description:
- - Specifies the TSIG key the system uses to communicate with this DNS nameserver
- (client) or back-end DNS authoritative server (DNS Express server) for AXFR zone
- transfers.
- - If the nameserver is a client, then the system uses this TSIG key to verify the
- request and sign the response.
- - If this nameserver is a DNS Express server, then this TSIG key must match the
- TSIG key for the zone on the back-end DNS authoritative server.
- type: str
- state:
- description:
- - When C(present), ensures that the resource exists.
- - When C(absent), ensures the resource is removed.
- type: str
- choices:
- - present
- - absent
- default: present
- partition:
- description:
- - Device partition to manage resources on.
- type: str
- default: Common
-extends_documentation_fragment: f5
-author:
- - Tim Rupp (@caphrim007)
-'''
-
-EXAMPLES = r'''
-- name: Create a nameserver
- bigip_dns_nameserver:
- name: foo
- address: 10.10.10.10
- service_port: 53
- state: present
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-'''
-
-RETURN = r'''
-address:
- description: Address which the nameserver listens for DNS messages.
- returned: changed
- type: str
- sample: 127.0.0.1
-service_port:
- description: Service port on which the nameserver listens for DNS messages.
- returned: changed
- type: int
- sample: 53
-'''
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.basic import env_fallback
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import fq_name
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.common import transform_name
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import fq_name
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.common import transform_name
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'routeDomain': 'route_domain',
- 'port': 'service_port',
- 'tsigKey': 'tsig_key'
- }
-
- api_attributes = [
- 'address',
- 'routeDomain',
- 'port',
- 'tsigKey'
- ]
-
- returnables = [
- 'address',
- 'service_port',
- 'route_domain',
- 'tsig_key',
- ]
-
- updatables = [
- 'address',
- 'service_port',
- 'route_domain',
- 'tsig_key',
- ]
-
-
-class ApiParameters(Parameters):
- pass
-
-
-class ModuleParameters(Parameters):
- @property
- def tsig_key(self):
- if self._values['tsig_key'] in [None, '']:
- return self._values['tsig_key']
- return fq_name(self.partition, self._values['tsig_key'])
-
- @property
- def route_domain(self):
- if self._values['route_domain'] is None:
- return None
- return fq_name(self.partition, self._values['route_domain'])
-
- @property
- def service_port(self):
- if self._values['service_port'] is None:
- return None
- try:
- return int(self._values['service_port'])
- except ValueError:
- # Reserving the right to add well-known ports
- raise F5ModuleError(
- "The 'service_port' must be in numeric form."
- )
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class UsableChanges(Changes):
- pass
-
-
-class ReportableChanges(Changes):
- pass
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
- @property
- def tsig_key(self):
- if self.want.tsig_key is None:
- return None
- if self.have.tsig_key is None and self.want.tsig_key == '':
- return None
- if self.want.tsig_key != self.have.tsig_key:
- return self.want.tsig_key
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(params=self.module.params)
- self.have = ApiParameters()
- self.changes = UsableChanges()
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = UsableChanges(params=changed)
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def exec_module(self):
- changed = False
- result = dict()
- state = self.want.state
-
- if state == "present":
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.client.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def present(self):
- if self.exists():
- return self.update()
- else:
- return self.create()
-
- def exists(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/dns/nameserver/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def update(self):
- self.have = self.read_current_from_device()
- if not self.should_update():
- return False
- if self.module.check_mode:
- return True
- self.update_on_device()
- return True
-
- def remove(self):
- if self.module.check_mode:
- return True
- self.remove_from_device()
- if self.exists():
- raise F5ModuleError("Failed to delete the resource.")
- return True
-
- def create(self):
- if self.want.address is None:
- self.want.update({'address': '127.0.0.1'})
- if self.want.service_port is None:
- self.want.update({'service_port': '53'})
- if self.want.route_domain is None:
- self.want.update({'route_domain': '/Common/0'})
- self._set_changed_options()
- if self.module.check_mode:
- return True
- self.create_on_device()
- return True
-
- def create_on_device(self):
- params = self.changes.api_params()
- params['name'] = self.want.name
- params['partition'] = self.want.partition
- uri = "https://{0}:{1}/mgmt/tm/ltm/dns/nameserver/".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def update_on_device(self):
- params = self.changes.api_params()
- uri = "https://{0}:{1}/mgmt/tm/ltm/dns/nameserver/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def absent(self):
- if self.exists():
- return self.remove()
- return False
-
- def remove_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/dns/nameserver/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- response = self.client.api.delete(uri)
- if response.status == 200:
- return True
- raise F5ModuleError(response.content)
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/dns/nameserver/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return ApiParameters(params=response)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- name=dict(required=True),
- address=dict(),
- service_port=dict(),
- route_domain=dict(),
- tsig_key=dict(),
- state=dict(
- default='present',
- choices=['present', 'absent']
- ),
- partition=dict(
- default='Common',
- fallback=(env_fallback, ['F5_PARTITION'])
- )
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode,
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_dns_resolver.py b/lib/ansible/modules/network/f5/bigip_dns_resolver.py
deleted file mode 100644
index 5a95d4da3f..0000000000
--- a/lib/ansible/modules/network/f5/bigip_dns_resolver.py
+++ /dev/null
@@ -1,536 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2018, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_dns_resolver
-short_description: Manage DNS resolvers on a BIG-IP
-description:
- - Manage DNS resolver on a BIG-IP.
-version_added: 2.8
-options:
- name:
- description:
- - Specifies the name of the DNS resolver.
- type: str
- required: True
- route_domain:
- description:
- - Specifies the route domain the resolver uses for outbound traffic.
- type: int
- cache_size:
- description:
- - Specifies the size of the internal DNS resolver cache.
- - When creating a new resolver, if this parameter is not specified, the default
- is 5767168 bytes.
- - After the cache reaches this size, when new or refreshed content arrives, the
- system removes expired and older content and caches the new or updated content.
- type: int
- answer_default_zones:
- description:
- - Specifies whether the system answers DNS queries for the default zones localhost,
- reverse 127.0.0.1 and ::1, and AS112.
- - When creating a new resolver, if this parameter is not specified, the default
- is C(no), meaning that the system passes along the DNS queries for the default zones.
- type: bool
- randomize_query_case:
- description:
- - When C(yes), specifies that the internal DNS resolver randomizes character case
- in domain name queries issued to the root DNS servers.
- - When creating a new resolver, if this parameter is not specified, the default
- is C(yes).
- type: bool
- use_ipv4:
- description:
- - Specifies whether the system can use IPv4 to query backend nameservers.
- - An IPv4 Self IP and default route must be available for these queries to work
- successfully.
- - When creating a new resolver, if this parameter is not specified, the default
- is C(yes).
- type: bool
- use_ipv6:
- description:
- - Specifies whether the system can use IPv6 to query backend nameservers.
- - An IPv6 Self IP and default route must be available for these queries to work
- successfully.
- - When creating a new resolver, if this parameter is not specified, the default
- is C(yes).
- type: bool
- use_udp:
- description:
- - Specifies whether the system answers and issues UDP-formatted queries.
- - When creating a new resolver, if this parameter is not specified, the default
- is C(yes).
- type: bool
- use_tcp:
- description:
- - Specifies whether the system answers and issues TCP-formatted queries.
- - When creating a new resolver, if this parameter is not specified, the default
- is C(yes).
- type: bool
- state:
- description:
- - When C(present), ensures that the resource exists.
- - When C(absent), ensures the resource is removed.
- type: str
- choices:
- - present
- - absent
- default: present
- partition:
- description:
- - Device partition to manage resources on.
- type: str
- default: Common
-extends_documentation_fragment: f5
-author:
- - Tim Rupp (@caphrim007)
-'''
-
-EXAMPLES = r'''
-- name: Create a simple DNS responder for OCSP stapling
- bigip_dns_resolver:
- name: resolver1
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-'''
-
-RETURN = r'''
-route_domain:
- description: The new route domain of the resource.
- returned: changed
- type: str
- sample: /Common/0
-cache_size:
- description: The new cache size of the resource.
- returned: changed
- type: int
- sample: 50000
-answer_default_zones:
- description: The new Answer Default Zones setting.
- returned: changed
- type: bool
- sample: yes
-randomize_query_case:
- description: The new Randomize Query Character Case setting.
- returned: changed
- type: bool
- sample: no
-use_ipv4:
- description: The new Use IPv4 setting.
- returned: changed
- type: bool
- sample: yes
-use_ipv6:
- description: The new Use IPv6 setting.
- returned: changed
- type: bool
- sample: no
-use_udp:
- description: The new Use UDP setting.
- returned: changed
- type: bool
- sample: yes
-use_tcp:
- description: The new Use TCP setting.
- returned: changed
- type: bool
- sample: no
-'''
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.basic import env_fallback
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import fq_name
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.common import transform_name
- from library.module_utils.network.f5.common import flatten_boolean
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import fq_name
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.common import transform_name
- from ansible.module_utils.network.f5.common import flatten_boolean
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'answerDefaultZones': 'answer_default_zones',
- 'cacheSize': 'cache_size',
- 'randomizeQueryNameCase': 'randomize_query_case',
- 'routeDomain': 'route_domain',
- 'useIpv4': 'use_ipv4',
- 'useIpv6': 'use_ipv6',
- 'useTcp': 'use_tcp',
- 'useUdp': 'use_udp',
- }
-
- api_attributes = [
- 'answerDefaultZones',
- 'cacheSize',
- 'randomizeQueryNameCase',
- 'routeDomain',
- 'useIpv4',
- 'useIpv6',
- 'useTcp',
- 'useUdp',
- ]
-
- returnables = [
- 'answer_default_zones',
- 'cache_size',
- 'randomize_query_case',
- 'route_domain',
- 'use_ipv4',
- 'use_ipv6',
- 'use_tcp',
- 'use_udp',
- ]
-
- updatables = [
- 'answer_default_zones',
- 'cache_size',
- 'randomize_query_case',
- 'route_domain',
- 'use_ipv4',
- 'use_ipv6',
- 'use_tcp',
- 'use_udp',
- ]
-
- @property
- def answer_default_zones(self):
- result = flatten_boolean(self._values['answer_default_zones'])
- return result
-
- @property
- def randomize_query_case(self):
- result = flatten_boolean(self._values['randomize_query_case'])
- return result
-
- @property
- def use_ipv4(self):
- result = flatten_boolean(self._values['use_ipv4'])
- return result
-
- @property
- def use_ipv6(self):
- result = flatten_boolean(self._values['use_ipv6'])
- return result
-
- @property
- def use_tcp(self):
- result = flatten_boolean(self._values['use_tcp'])
- return result
-
- @property
- def use_udp(self):
- result = flatten_boolean(self._values['use_udp'])
- return result
-
-
-class ApiParameters(Parameters):
- pass
-
-
-class ModuleParameters(Parameters):
- @property
- def route_domain(self):
- if self._values['route_domain'] is None:
- return None
- result = fq_name(self.partition, self._values['route_domain'])
- return result
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class UsableChanges(Changes):
- pass
-
-
-class ReportableChanges(Changes):
- pass
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(params=self.module.params)
- self.have = ApiParameters()
- self.changes = UsableChanges()
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = UsableChanges(params=changed)
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def exec_module(self):
- changed = False
- result = dict()
- state = self.want.state
-
- if state == "present":
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.client.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def present(self):
- if self.exists():
- return self.update()
- else:
- return self.create()
-
- def exists(self):
- uri = "https://{0}:{1}/mgmt/tm/net/dns-resolver/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def update(self):
- self.have = self.read_current_from_device()
- if not self.should_update():
- return False
- if self.module.check_mode:
- return True
- self.update_on_device()
- return True
-
- def remove(self):
- if self.module.check_mode:
- return True
- self.remove_from_device()
- if self.exists():
- raise F5ModuleError("Failed to delete the resource.")
- return True
-
- def create(self):
- self._set_changed_options()
- if self.module.check_mode:
- return True
- self.create_on_device()
- return True
-
- def create_on_device(self):
- params = self.changes.api_params()
- params['name'] = self.want.name
- params['partition'] = self.want.partition
- uri = "https://{0}:{1}/mgmt/tm/net/dns-resolver/".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def update_on_device(self):
- params = self.changes.api_params()
- uri = "https://{0}:{1}/mgmt/tm/net/dns-resolver/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def absent(self):
- if self.exists():
- return self.remove()
- return False
-
- def remove_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/net/dns-resolver/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- response = self.client.api.delete(uri)
- if response.status == 200:
- return True
- raise F5ModuleError(response.content)
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/net/dns-resolver/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return ApiParameters(params=response)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- name=dict(required=True),
- route_domain=dict(type='int'),
- cache_size=dict(type='int'),
- answer_default_zones=dict(type='bool'),
- randomize_query_case=dict(type='bool'),
- use_ipv4=dict(type='bool'),
- use_ipv6=dict(type='bool'),
- use_udp=dict(type='bool'),
- use_tcp=dict(type='bool'),
- state=dict(
- default='present',
- choices=['present', 'absent']
- ),
- partition=dict(
- default='Common',
- fallback=(env_fallback, ['F5_PARTITION'])
- )
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode,
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_dns_zone.py b/lib/ansible/modules/network/f5/bigip_dns_zone.py
deleted file mode 100644
index 73496a1e58..0000000000
--- a/lib/ansible/modules/network/f5/bigip_dns_zone.py
+++ /dev/null
@@ -1,698 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2018, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_dns_zone
-short_description: Manage DNS zones on BIG-IP
-description:
- - Manage DNS zones on BIG-IP. The zones managed here are primarily used
- for configuring DNS Express on BIG-IP. This module does not configure
- zones that are found in BIG-IP ZoneRunner.
-version_added: 2.8
-options:
- name:
- description:
- - Specifies the name of the DNS zone.
- - The name must begin with a letter and contain only letters, numbers,
- and the underscore character.
- type: str
- required: True
- dns_express:
- description:
- - DNS express related settings.
- type: dict
- suboptions:
- server:
- description:
- - Specifies the back-end authoritative DNS server from which the BIG-IP
- system receives AXFR zone transfers for the DNS Express zone.
- type: str
- enabled:
- description:
- - Specifies the current status of the DNS Express zone.
- type: bool
- notify_action:
- description:
- - Specifies the action the system takes when a NOTIFY message is received
- for this DNS Express zone.
- - If a TSIG key is configured for the zone, the signature is only validated
- for C(consume) and C(repeat) actions.
- - When C(consume), the NOTIFY message is seen only by DNS Express.
- - When C(bypass), the NOTIFY message does not go to DNS Express, but
- instead goes to a back-end DNS server (subject to the value of the
- Unhandled Query Action configured in the DNS profile applied to the
- listener that handles the DNS request).
- - When C(repeat), the NOTIFY message goes to both DNS Express and any
- back-end DNS server.
- type: str
- choices:
- - consume
- - bypass
- - repeat
- allow_notify_from:
- description:
- - Specifies the IP addresses from which the system accepts NOTIFY messages
- for this DNS Express zone.
- type: list
- verify_tsig:
- description:
- - Specifies whether the system verifies the identity of the authoritative
- nameserver that sends updated information for this DNS Express zone.
- type: bool
- response_policy:
- description:
- - Specifies whether this DNS Express zone is a DNS response policy zone (RPZ).
- type: bool
- nameservers:
- description:
- - Specifies the DNS nameservers to which the system sends NOTIFY messages.
- type: list
- tsig_server_key:
- description:
- - Specifies the TSIG key the system uses to authenticate the back-end DNS
- authoritative server that sends AXFR zone transfers to the BIG-IP system.
- type: str
- state:
- description:
- - When C(present), ensures that the resource exists.
- - When C(absent), ensures the resource is removed.
- type: str
- choices:
- - present
- - absent
- default: present
- partition:
- description:
- - Device partition to manage resources on.
- type: str
- default: Common
-extends_documentation_fragment: f5
-author:
- - Tim Rupp (@caphrim007)
- - Greg Crosby (@crosbygw)
-'''
-
-EXAMPLES = r'''
-- name: Create a DNS zone for DNS express
- bigip_dns_zone:
- name: zone.foo.com
- dns_express:
- enabled: yes
- server: dns-lab
- allow_notify_from:
- - 192.168.39.10
- notify_action: consume
- verify_tsig: no
- response_policy: no
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-
-- name: Disable DNS express zone, change server, and modify notify_action to bypass
- bigip_dns_zone:
- name: zone.foo.com
- dns_express:
- enabled: no
- server: foo1.server.com
- allow_notify_from:
- - 192.168.39.10
- notify_action: bypass
- verify_tsig: no
- response_policy: no
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-
-- name: Add nameservers
- bigip_dns_zone:
- name: zone.foo.com
- nameservers:
- - foo1.nameserver.com
- - foo2.nameserver.com
- - foo3.nameserver.com
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-
-- name: Remove nameserver
- bigip_dns_zone:
- name: zone.foo.com
- nameservers:
- - foo1.nameserver.com
- - foo2.nameserver.com
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-
-- name: Remove all nameservers
- bigip_dns_zone:
- name: zone.foo.com
- nameservers: none
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-
-- name: Add tsig_server_key
- bigip_dns_zone:
- name: zone.foo.com
- tsig_server_key: key1
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-
-- name: Remove tsig_server_key
- bigip_dns_zone:
- name: zone.foo.com
- tsig_server_key: none
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-
-- name: Remove zone
- bigip_dns_zone:
- name: zone.foo.com
- state: absent
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-
-'''
-
-RETURN = r'''
-enabled:
- description: Whether the zone is enabled or not.
- returned: changed
- type: bool
- sample: yes
-allow_notify_from:
- description: The new DNS Express Allow NOTIFY From value.
- returned: changed
- type: list
- sample: ['1.1.1.1', '2.2.2.2']
-notify_action:
- description: The new DNS Express Notify Action value.
- returned: changed
- type: str
- sample: consume
-verify_tsig:
- description: The new DNS Express Verify Notify TSIG value.
- returned: changed
- type: bool
- sample: yes
-express_server:
- description: The new DNS Express Server value.
- returned: changed
- type: str
- sample: server1
-response_policy:
- description: The new DNS Express Response Policy value.
- returned: changed
- type: bool
- sample: no
-nameservers:
- description: The new Zone Transfer Clients Nameservers value.
- returned: changed
- type: list
- sample: ['/Common/server1', '/Common/server2']
-tsig_server_key:
- description: The new TSIG Server Key value.
- returned: changed
- type: str
- sample: /Common/key1
-'''
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.basic import env_fallback
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import fq_name
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.common import transform_name
- from library.module_utils.network.f5.common import flatten_boolean
- from library.module_utils.network.f5.compare import cmp_simple_list
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import fq_name
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.common import transform_name
- from ansible.module_utils.network.f5.common import flatten_boolean
- from ansible.module_utils.network.f5.compare import cmp_simple_list
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'dnsExpressEnabled': 'enabled',
- 'dnsExpressAllowNotify': 'allow_notify_from',
- 'dnsExpressNotifyAction': 'notify_action',
- 'dnsExpressNotifyTsigVerify': 'verify_tsig',
- 'dnsExpressServer': 'express_server',
- 'responsePolicy': 'response_policy',
- 'transferClients': 'nameservers',
- 'serverTsigKey': 'tsig_server_key',
- }
-
- api_attributes = [
- 'dnsExpressEnabled',
- 'dnsExpressAllowNotify',
- 'dnsExpressNotifyAction',
- 'dnsExpressNotifyTsigVerify',
- 'dnsExpressServer',
- 'responsePolicy',
- 'transferClients',
- 'serverTsigKey',
- ]
-
- returnables = [
- 'enabled',
- 'allow_notify_from',
- 'notify_action',
- 'verify_tsig',
- 'express_server',
- 'response_policy',
- 'nameservers',
- 'tsig_server_key',
- ]
-
- updatables = [
- 'enabled',
- 'allow_notify_from',
- 'notify_action',
- 'verify_tsig',
- 'express_server',
- 'response_policy',
- 'nameservers',
- 'tsig_server_key',
- ]
-
-
-class ApiParameters(Parameters):
- pass
-
-
-class ModuleParameters(Parameters):
- @property
- def express_server(self):
- try:
- if self._values['dns_express']['server'] is None:
- return None
- if self._values['dns_express']['server'] in ['', 'none']:
- return ''
- return fq_name(self.partition, self._values['dns_express']['server'])
- except (TypeError, KeyError):
- return None
-
- @property
- def nameservers(self):
- if self._values['nameservers'] is None:
- return None
- elif len(self._values['nameservers']) == 1 and self._values['nameservers'][0] in ['', 'none']:
- return ''
- return [fq_name(self.partition, x) for x in self._values['nameservers']]
-
- @property
- def tsig_server_key(self):
- if self._values['tsig_server_key'] is None:
- return None
- if self._values['tsig_server_key'] in ['', 'none']:
- return ''
- return fq_name(self.partition, self._values['tsig_server_key'])
-
- @property
- def enabled(self):
- try:
- return flatten_boolean(self._values['dns_express']['enabled'])
- except (TypeError, KeyError):
- return None
-
- @property
- def verify_tsig(self):
- try:
- return flatten_boolean(self._values['dns_express']['verify_tsig'])
- except (TypeError, KeyError):
- return None
-
- @property
- def notify_action(self):
- try:
- return self._values['dns_express']['notify_action']
- except (TypeError, KeyError):
- return None
-
- @property
- def response_policy(self):
- try:
- return flatten_boolean(self._values['dns_express']['response_policy'])
- except (TypeError, KeyError):
- return None
-
- @property
- def allow_notify_from(self):
- try:
- v = self._values['dns_express']['allow_notify_from']
- if v is None:
- return None
- elif len(v) == 1 and v[0] in ['', 'none']:
- return ''
- return v
- except (TypeError, KeyError):
- return None
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class UsableChanges(Changes):
- pass
-
-
-class ReportableChanges(Changes):
- pass
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- @property
- def allow_notify_from(self):
- return cmp_simple_list(self.want.allow_notify_from, self.have.allow_notify_from)
-
- @property
- def nameservers(self):
- return cmp_simple_list(self.want.nameservers, self.have.nameservers)
-
- @property
- def express_server(self):
- if self.want.express_server is None:
- return None
- if self.want.express_server == '' and self.have.express_server is None:
- return None
- if self.want.express_server != self.have.express_server:
- return self.want.express_server
-
- @property
- def tsig_server_key(self):
- if self.want.tsig_server_key is None:
- return None
- if self.want.tsig_server_key == '' and self.have.tsig_server_key is None:
- return None
- if self.want.tsig_server_key != self.have.tsig_server_key:
- return self.want.tsig_server_key
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(params=self.module.params)
- self.have = ApiParameters()
- self.changes = UsableChanges()
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = UsableChanges(params=changed)
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def exec_module(self):
- changed = False
- result = dict()
- state = self.want.state
-
- if state == "present":
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.client.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def present(self):
- if self.exists():
- return self.update()
- else:
- return self.create()
-
- def exists(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/dns/zone/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def update(self):
- self.have = self.read_current_from_device()
- if not self.should_update():
- return False
- if self.module.check_mode:
- return True
- self.update_on_device()
- return True
-
- def remove(self):
- if self.module.check_mode:
- return True
- self.remove_from_device()
- if self.exists():
- raise F5ModuleError("Failed to delete the resource.")
- return True
-
- def create(self):
- self._set_changed_options()
- if self.module.check_mode:
- return True
- self.create_on_device()
- return True
-
- def create_on_device(self):
- params = self.changes.api_params()
- params['name'] = self.want.name
- params['partition'] = self.want.partition
- uri = "https://{0}:{1}/mgmt/tm/ltm/dns/zone/".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def update_on_device(self):
- params = self.changes.api_params()
- uri = "https://{0}:{1}/mgmt/tm/ltm/dns/zone/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def absent(self):
- if self.exists():
- return self.remove()
- return False
-
- def remove_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/dns/zone/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- response = self.client.api.delete(uri)
- if response.status == 200:
- return True
- raise F5ModuleError(response.content)
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/dns/zone/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return ApiParameters(params=response)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- name=dict(required=True),
- dns_express=dict(
- type='dict',
- options=dict(
- server=dict(),
- enabled=dict(type='bool'),
- notify_action=dict(
- choices=['consume', 'bypass', 'repeat']
- ),
- allow_notify_from=dict(type='list'),
- verify_tsig=dict(type='bool'),
- response_policy=dict(type='bool')
- )
- ),
- nameservers=dict(type='list'),
- tsig_server_key=dict(),
- partition=dict(
- default='Common',
- fallback=(env_fallback, ['F5_PARTITION'])
- ),
- state=dict(
- default='present',
- choices=['present', 'absent']
- )
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode,
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_file_copy.py b/lib/ansible/modules/network/f5/bigip_file_copy.py
deleted file mode 100644
index 28599a527e..0000000000
--- a/lib/ansible/modules/network/f5/bigip_file_copy.py
+++ /dev/null
@@ -1,684 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2018, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_file_copy
-short_description: Manage files in datastores on a BIG-IP
-description:
- - Manages files on a variety of datastores on a BIG-IP.
-version_added: 2.8
-options:
- name:
- description:
- - The name of the file as it should reside on the BIG-IP.
- - If this is not specified, then the filename provided in the C(source)
- parameter is used instead.
- type: str
- source:
- description:
- - Specifies the path of the file to upload.
- - This parameter is required if C(state) is C(present).
- type: path
- aliases:
- - src
- datastore:
- description:
- - Specifies the datastore to put the file in.
- - There are several different datastores and each of them allows files
- to be exposed in different ways.
- - When C(external-monitor), the specified file will be stored as
- an external monitor file and be available for use in external monitors
- - When C(ifile), the specified file will be stored as an iFile.
- - When C(lw4o6-table), the specified file will be store as an Lightweight 4
- over 6 (lw4o6) tunnel binding table, which include an IPv6 address for the
- lwB4, public IPv4 address, and restricted port set.
- type: str
- choices:
- - external-monitor
- - ifile
- - lw4o6-table
- default: ifile
- force:
- description:
- - Force overwrite a file.
- - By default, files will only be overwritten if the SHA of the file is different
- for the given filename. This parameter can be used to force overwrite the file
- even if it already exists and its SHA matches.
- - The C(lw4o6-table) datastore does not keep checksums of its file. Therefore, you
- would need to provide this argument to update any of these files.
- type: bool
- partition:
- description:
- - Device partition to manage resources on.
- type: str
- default: Common
- state:
- description:
- - When C(present), ensures that the resource exists.
- - When C(absent), ensures the resource is removed.
- type: str
- choices:
- - present
- - absent
- default: present
-extends_documentation_fragment: f5
-author:
- - Tim Rupp (@caphrim007)
-'''
-
-EXAMPLES = r'''
-- name: Upload a file as an iFile
- bigip_file_copy:
- name: foo
- source: /path/to/file.txt
- datastore: ifile
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-
-# Upload a directory of files
-- name: Recursively upload web related files in /var/tmp/project
- find:
- paths: /var/tmp/project
- patterns: "^.*?\\.(?:html|?:css|?:js)$"
- use_regex: yes
- register: f
-
-- name: Upload a directory of files as a set of iFiles
- bigip_file_copy:
- source: "{{ item.path }}"
- datastore: ifile
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- loop: f
- delegate_to: localhost
-# End upload a directory of files
-
-- name: Upload a file to use in an external monitor
- bigip_file_copy:
- source: /path/to/files/external.sh
- datastore: external-monitor
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-'''
-
-RETURN = r'''
-# only common fields returned
-'''
-
-import hashlib
-import os
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.basic import env_fallback
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import fq_name
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.common import transform_name
- from library.module_utils.network.f5.icontrol import upload_file
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import fq_name
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.common import transform_name
- from ansible.module_utils.network.f5.icontrol import upload_file
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
-
- }
-
- api_attributes = [
-
- ]
-
- returnables = [
-
- ]
-
- updatables = [
- 'checksum',
- ]
-
-
-class ApiParameters(Parameters):
- @property
- def checksum(self):
- """Returns a plain checksum value without the leading extra characters
-
- Values are stored in the REST as the following.
-
- ``"checksum": "SHA1:77002:b84015799949ac4acad87b81691455242a31e894"``
-
- Returns:
- string: The parsed SHA1 checksum.
- """
- if self._values['checksum'] is None:
- return None
- return str(self._values['checksum'].split(':')[2])
-
-
-class ModuleParameters(Parameters):
- @property
- def checksum(self):
- """Return SHA1 checksum of the file on disk
-
- Returns:
- string: The SHA1 checksum of the file.
-
- References:
- - https://stackoverflow.com/a/22058673/661215
- """
- if self._values['datastore'] == 'lw4o6-table':
- return None
-
- sha1 = hashlib.sha1()
- with open(self._values['source'], 'rb') as f:
- while True:
- data = f.read(4096)
- if not data:
- break
- sha1.update(data)
- return sha1.hexdigest()
-
- @property
- def name(self):
- if self._values['name'] is not None:
- return self._values['name']
- if self._values['source'] is None:
- return None
- return os.path.basename(self._values['source'])
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class UsableChanges(Changes):
- pass
-
-
-class ReportableChanges(Changes):
- pass
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
-
-class BaseManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(params=self.module.params)
- self.have = ApiParameters()
- self.changes = UsableChanges()
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = UsableChanges(params=changed)
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def exec_module(self):
- changed = False
- result = dict()
- state = self.want.state
-
- if state == "present":
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.client.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def present(self):
- if self.exists():
- return self.update()
- else:
- return self.create()
-
- def update(self):
- self.have = self.read_current_from_device()
- if not self.should_update() and not self.want.force:
- return False
- if self.module.check_mode:
- return True
- self.remove_from_device()
- self.upload_to_device()
- self.create_on_device()
- self.remove_uploaded_file_from_device(self.want.name)
- return True
-
- def remove(self):
- if self.module.check_mode:
- return True
- self.remove_from_device()
- if self.exists():
- raise F5ModuleError("Failed to delete the resource.")
- return True
-
- def create(self):
- if self.module.check_mode:
- return True
- self.upload_to_device()
- self.create_on_device()
- self.remove_uploaded_file_from_device(self.want.name)
- return True
-
- def absent(self):
- if self.exists():
- return self.remove()
- return False
-
- def upload_to_device(self):
- url = 'https://{0}:{1}/mgmt/shared/file-transfer/uploads'.format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- try:
- upload_file(self.client, url, self.want.source, self.want.name)
- except F5ModuleError:
- raise F5ModuleError(
- "Failed to upload the file."
- )
-
- def remove_uploaded_file_from_device(self, name):
- filepath = '/var/config/rest/downloads/{0}'.format(name)
- params = {
- "command": "run",
- "utilCmdArgs": filepath
- }
- uri = "https://{0}:{1}/mgmt/tm/util/unix-rm".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
-
-class IFileManager(BaseManager):
- def create_on_device(self):
- params = self.changes.api_params()
- params['name'] = self.want.name
- params['source-path'] = 'file:/var/config/rest/downloads/{0}'.format(self.want.name)
- params['partition'] = self.want.partition
- uri = "https://{0}:{1}/mgmt/tm/sys/file/ifile/".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def exists(self):
- uri = "https://{0}:{1}/mgmt/tm/sys/file/ifile/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/sys/file/ifile/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return ApiParameters(params=response)
-
- def remove_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/sys/file/ifile/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- response = self.client.api.delete(uri)
- if response.status == 200:
- return True
- raise F5ModuleError(response.content)
-
-
-class ExternalMonitorManager(BaseManager):
- def create_on_device(self):
- params = self.changes.api_params()
- params['name'] = self.want.name
- params['source-path'] = 'file:/var/config/rest/downloads/{0}'.format(self.want.name)
- params['partition'] = self.want.partition
- uri = "https://{0}:{1}/mgmt/tm/sys/file/external-monitor/".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def exists(self):
- uri = "https://{0}:{1}/mgmt/tm/sys/file/external-monitor/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/sys/file/external-monitor/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return ApiParameters(params=response)
-
- def remove_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/sys/file/external-monitor/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- response = self.client.api.delete(uri)
- if response.status == 200:
- return True
- raise F5ModuleError(response.content)
-
-
-class Lw4o6Manager(BaseManager):
- def create_on_device(self):
- params = self.changes.api_params()
- params['name'] = self.want.name
- params['source-path'] = 'file:/var/config/rest/downloads/{0}'.format(self.want.name)
- params['partition'] = self.want.partition
- uri = "https://{0}:{1}/mgmt/tm/sys/file/lwtunneltbl/".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def exists(self):
- uri = "https://{0}:{1}/mgmt/tm/sys/file/lwtunneltbl/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/sys/file/lwtunneltbl/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return ApiParameters(params=response)
-
- def remove_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/sys/file/lwtunneltbl/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- response = self.client.api.delete(uri)
- if response.status == 200:
- return True
- raise F5ModuleError(response.content)
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = kwargs.get('client', None)
- self.kwargs = kwargs
-
- def exec_module(self):
- if self.module.params['datastore'] == 'ifile':
- manager = self.get_manager('v1')
- elif self.module.params['datastore'] == 'external-monitor':
- manager = self.get_manager('v2')
- elif self.module.params['datastore'] == 'lw4o6-table':
- manager = self.get_manager('v3')
- else:
- raise F5ModuleError(
- "Unknown datastore specified."
- )
- return manager.exec_module()
-
- def get_manager(self, type):
- if type == 'v1':
- return IFileManager(**self.kwargs)
- elif type == 'v2':
- return ExternalMonitorManager(**self.kwargs)
- elif type == 'v3':
- return Lw4o6Manager(**self.kwargs)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- name=dict(),
- source=dict(
- type='path',
- aliases=['src'],
- ),
- datastore=dict(
- choices=[
- 'external-monitor',
- 'ifile',
- 'lw4o6-table',
- ],
- default='ifile'
- ),
- force=dict(type='bool', default='no'),
- state=dict(
- default='present',
- choices=['present', 'absent']
- ),
- partition=dict(
- default='Common',
- fallback=(env_fallback, ['F5_PARTITION'])
- )
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
- self.required_if = [
- ['state', 'present', ['source']]
- ]
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode,
- required_if=spec.required_if,
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_firewall_address_list.py b/lib/ansible/modules/network/f5/bigip_firewall_address_list.py
deleted file mode 100644
index 4a9de329f1..0000000000
--- a/lib/ansible/modules/network/f5/bigip_firewall_address_list.py
+++ /dev/null
@@ -1,978 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_firewall_address_list
-short_description: Manage address lists on BIG-IP AFM
-description:
- - Manages the AFM address lists on a BIG-IP. This module can be used to add
- and remove address list entries.
-version_added: 2.5
-options:
- name:
- description:
- - Specifies the name of the address list.
- type: str
- required: True
- partition:
- description:
- - Device partition to manage resources on.
- type: str
- default: Common
- description:
- description:
- - Description of the address list
- type: str
- geo_locations:
- description:
- - List of geolocations specified by their C(country) and C(region).
- suboptions:
- country:
- description:
- - The country name, or code, of the geolocation to use.
- - In addition to the country full names, you may also specify their abbreviated
- form, such as C(US) instead of C(United States).
- - Valid country codes can be found here https://countrycode.org/.
- type: str
- required: True
- choices:
- - Any valid 2 character ISO country code.
- - Any valid country name.
- region:
- description:
- - Region name of the country to use.
- type: str
- type: list
- addresses:
- description:
- - Individual addresses that you want to add to the list. These addresses differ
- from ranges, and lists of lists such as what can be used in C(address_ranges)
- and C(address_lists) respectively.
- - This list can also include networks that have CIDR notation.
- type: list
- address_ranges:
- description:
- - A list of address ranges where the range starts with a port number, is followed
- by a dash (-) and then a second number.
- - If the first address is greater than the second number, the numbers will be
- reversed so-as to be properly formatted. ie, C(2.2.2.2-1.1.1). would become
- C(1.1.1.1-2.2.2.2).
- type: list
- address_lists:
- description:
- - Simple list of existing address lists to add to this list. Address lists can be
- specified in either their fully qualified name (/Common/foo) or their short
- name (foo). If a short name is used, the C(partition) argument will automatically
- be prepended to the short name.
- type: list
- fqdns:
- description:
- - A list of fully qualified domain names (FQDNs).
- - An FQDN has at least one decimal point in it, separating the host from the domain.
- - To add FQDNs to a list requires that a global FQDN resolver be configured.
- At the moment, this must either be done via C(bigip_command), or, in the GUI
- of BIG-IP. If using C(bigip_command), this can be done with C(tmsh modify security
- firewall global-fqdn-policy FOO) where C(FOO) is a DNS resolver configured
- at C(tmsh create net dns-resolver FOO).
- type: list
- state:
- description:
- - When C(present), ensures that the address list and entries exists.
- - When C(absent), ensures the address list is removed.
- type: str
- choices:
- - present
- - absent
- default: present
-extends_documentation_fragment: f5
-author:
- - Tim Rupp (@caphrim007)
- - Wojciech Wypior (@wojtek0806)
-'''
-
-EXAMPLES = r'''
-- name: Create an address list
- bigip_firewall_address_list:
- name: foo
- addresses:
- - 3.3.3.3
- - 4.4.4.4
- - 5.5.5.5
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-'''
-
-RETURN = r'''
-description:
- description: The new description of the address list.
- returned: changed
- type: str
- sample: My address list
-addresses:
- description: The new list of addresses applied to the address list.
- returned: changed
- type: list
- sample: [1.1.1.1, 2.2.2.2]
-address_ranges:
- description: The new list of address ranges applied to the address list.
- returned: changed
- type: list
- sample: [1.1.1.1-2.2.2.2, 3.3.3.3-4.4.4.4]
-address_lists:
- description: The new list of address list names applied to the address list.
- returned: changed
- type: list
- sample: [/Common/list1, /Common/list2]
-fqdns:
- description: The new list of FQDN names applied to the address list.
- returned: changed
- type: list
- sample: [google.com, mit.edu]
-geo_locations:
- description: The new list of geo locations applied to the address list.
- returned: changed
- type: complex
- contains:
- country:
- description: Country of the geo location.
- returned: changed
- type: str
- sample: US
- region:
- description: Region of the geo location.
- returned: changed
- type: str
- sample: California
-'''
-
-import re
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.basic import env_fallback
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import fq_name
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.common import transform_name
- from library.module_utils.compat.ipaddress import ip_address
- from library.module_utils.compat.ipaddress import ip_interface
- from library.module_utils.network.f5.ipaddress import is_valid_ip
- from library.module_utils.network.f5.ipaddress import is_valid_ip_interface
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import fq_name
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.common import transform_name
- from ansible.module_utils.compat.ipaddress import ip_address
- from ansible.module_utils.compat.ipaddress import ip_interface
- from ansible.module_utils.network.f5.ipaddress import is_valid_ip
- from ansible.module_utils.network.f5.ipaddress import is_valid_ip_interface
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'addressLists': 'address_lists',
- 'geo': 'geo_locations',
- }
-
- api_attributes = [
- 'addressLists',
- 'addresses',
- 'description',
- 'fqdns',
- 'geo',
- ]
-
- returnables = [
- 'addresses',
- 'address_ranges',
- 'address_lists',
- 'description',
- 'fqdns',
- 'geo_locations',
- ]
-
- updatables = [
- 'addresses',
- 'address_ranges',
- 'address_lists',
- 'description',
- 'fqdns',
- 'geo_locations',
- ]
-
-
-class ApiParameters(Parameters):
- @property
- def address_ranges(self):
- if self._values['addresses'] is None:
- return None
- result = []
- for address_range in self._values['addresses']:
- if '-' not in address_range['name']:
- continue
- result.append(address_range['name'].strip())
- result = sorted(result)
- return result
-
- @property
- def address_lists(self):
- if self._values['address_lists'] is None:
- return None
- result = []
- for x in self._values['address_lists']:
- item = '/{0}/{1}'.format(x['partition'], x['name'])
- result.append(item)
- result = sorted(result)
- return result
-
- @property
- def addresses(self):
- if self._values['addresses'] is None:
- return None
- result = [x['name'] for x in self._values['addresses'] if '-' not in x['name']]
- result = sorted(result)
- return result
-
- @property
- def fqdns(self):
- if self._values['fqdns'] is None:
- return None
- result = [str(x['name']) for x in self._values['fqdns']]
- result = sorted(result)
- return result
-
- @property
- def geo_locations(self):
- if self._values['geo_locations'] is None:
- return None
- result = [str(x['name']) for x in self._values['geo_locations']]
- result = sorted(result)
- return result
-
-
-class ModuleParameters(Parameters):
- def __init__(self, params=None):
- super(ModuleParameters, self).__init__(params=params)
- self.country_iso_map = {
- 'Afghanistan': 'AF',
- 'Albania': 'AL',
- 'Algeria': 'DZ',
- 'American Samoa': 'AS',
- 'Andorra': 'AD',
- 'Angola': 'AO',
- 'Anguilla': 'AI',
- 'Antarctica': 'AQ',
- 'Antigua and Barbuda': 'AG',
- 'Argentina': 'AR',
- 'Armenia': 'AM',
- 'Aruba': 'AW',
- 'Australia': 'AU',
- 'Austria': 'AT',
- 'Azerbaijan': 'AZ',
- 'Bahamas': 'BS',
- 'Bahrain': 'BH',
- 'Bangladesh': 'BD',
- 'Barbados': 'BB',
- 'Belarus': 'BY',
- 'Belgium': 'BE',
- 'Belize': 'BZ',
- 'Benin': 'BJ',
- 'Bermuda': 'BM',
- 'Bhutan': 'BT',
- 'Bolivia': 'BO',
- 'Bosnia and Herzegovina': 'BA',
- 'Botswana': 'BW',
- 'Brazil': 'BR',
- 'Brunei': 'BN',
- 'Bulgaria': 'BG',
- 'Burkina Faso': 'BF',
- 'Burundi': 'BI',
- 'Cameroon': 'CM',
- 'Canada': 'CA',
- 'Cape Verde': 'CV',
- 'Central African Republic': 'CF',
- 'Chile': 'CL',
- 'China': 'CN',
- 'Christmas Island': 'CX',
- 'Cocos Islands': 'CC',
- 'Colombia': 'CO',
- 'Cook Islands': 'CK',
- 'Costa Rica': 'CR',
- 'Cuba': 'CU',
- 'Curacao': 'CW',
- 'Cyprus': 'CY',
- 'Czech Republic': 'CZ',
- 'Democratic Republic of the Congo': 'CD',
- 'Denmark': 'DK',
- 'Djibouti': 'DJ',
- 'Dominica': 'DM',
- 'Dominican Republic': 'DO',
- 'Ecuador': 'EC',
- 'Egypt': 'EG',
- 'Eritrea': 'ER',
- 'Estonia': 'EE',
- 'Ethiopia': 'ET',
- 'Falkland Islands': 'FK',
- 'Faroe Islands': 'FO',
- 'Fiji': 'FJ',
- 'Finland': 'FI',
- 'France': 'FR',
- 'French Polynesia': 'PF',
- 'Gabon': 'GA',
- 'Gambia': 'GM',
- 'Georgia': 'GE',
- 'Germany': 'DE',
- 'Ghana': 'GH',
- 'Gilbraltar': 'GI',
- 'Greece': 'GR',
- 'Greenland': 'GL',
- 'Grenada': 'GD',
- 'Guam': 'GU',
- 'Guatemala': 'GT',
- 'Guernsey': 'GG',
- 'Guinea': 'GN',
- 'Guinea-Bissau': 'GW',
- 'Guyana': 'GY',
- 'Haiti': 'HT',
- 'Honduras': 'HN',
- 'Hong Kong': 'HK',
- 'Hungary': 'HU',
- 'Iceland': 'IS',
- 'India': 'IN',
- 'Indonesia': 'ID',
- 'Iran': 'IR',
- 'Iraq': 'IQ',
- 'Ireland': 'IE',
- 'Isle of Man': 'IM',
- 'Israel': 'IL',
- 'Italy': 'IT',
- 'Ivory Coast': 'CI',
- 'Jamaica': 'JM',
- 'Japan': 'JP',
- 'Jersey': 'JE',
- 'Jordan': 'JO',
- 'Kazakhstan': 'KZ',
- 'Laos': 'LA',
- 'Latvia': 'LV',
- 'Lebanon': 'LB',
- 'Lesotho': 'LS',
- 'Liberia': 'LR',
- 'Libya': 'LY',
- 'Liechtenstein': 'LI',
- 'Lithuania': 'LT',
- 'Luxembourg': 'LU',
- 'Macau': 'MO',
- 'Macedonia': 'MK',
- 'Madagascar': 'MG',
- 'Malawi': 'MW',
- 'Malaysia': 'MY',
- 'Maldives': 'MV',
- 'Mali': 'ML',
- 'Malta': 'MT',
- 'Marshall Islands': 'MH',
- 'Mauritania': 'MR',
- 'Mauritius': 'MU',
- 'Mayotte': 'YT',
- 'Mexico': 'MX',
- 'Micronesia': 'FM',
- 'Moldova': 'MD',
- 'Monaco': 'MC',
- 'Mongolia': 'MN',
- 'Montenegro': 'ME',
- 'Montserrat': 'MS',
- 'Morocco': 'MA',
- 'Mozambique': 'MZ',
- 'Myanmar': 'MM',
- 'Namibia': 'NA',
- 'Nauru': 'NR',
- 'Nepal': 'NP',
- 'Netherlands': 'NL',
- 'Netherlands Antilles': 'AN',
- 'New Caledonia': 'NC',
- 'New Zealand': 'NZ',
- 'Nicaragua': 'NI',
- 'Niger': 'NE',
- 'Nigeria': 'NG',
- 'Niue': 'NU',
- 'North Korea': 'KP',
- 'Northern Mariana Islands': 'MP',
- 'Norway': 'NO',
- 'Oman': 'OM',
- 'Pakistan': 'PK',
- 'Palau': 'PW',
- 'Palestine': 'PS',
- 'Panama': 'PA',
- 'Papua New Guinea': 'PG',
- 'Paraguay': 'PY',
- 'Peru': 'PE',
- 'Philippines': 'PH',
- 'Pitcairn': 'PN',
- 'Poland': 'PL',
- 'Portugal': 'PT',
- 'Puerto Rico': 'PR',
- 'Qatar': 'QA',
- 'Republic of the Congo': 'CG',
- 'Reunion': 'RE',
- 'Romania': 'RO',
- 'Russia': 'RU',
- 'Rwanda': 'RW',
- 'Saint Barthelemy': 'BL',
- 'Saint Helena': 'SH',
- 'Saint Kitts and Nevis': 'KN',
- 'Saint Lucia': 'LC',
- 'Saint Martin': 'MF',
- 'Saint Pierre and Miquelon': 'PM',
- 'Saint Vincent and the Grenadines': 'VC',
- 'Samoa': 'WS',
- 'San Marino': 'SM',
- 'Sao Tome and Principe': 'ST',
- 'Saudi Arabia': 'SA',
- 'Senegal': 'SN',
- 'Serbia': 'RS',
- 'Seychelles': 'SC',
- 'Sierra Leone': 'SL',
- 'Singapore': 'SG',
- 'Sint Maarten': 'SX',
- 'Slovakia': 'SK',
- 'Slovenia': 'SI',
- 'Solomon Islands': 'SB',
- 'Somalia': 'SO',
- 'South Africa': 'ZA',
- 'South Korea': 'KR',
- 'South Sudan': 'SS',
- 'Spain': 'ES',
- 'Sri Lanka': 'LK',
- 'Sudan': 'SD',
- 'Suriname': 'SR',
- 'Svalbard and Jan Mayen': 'SJ',
- 'Swaziland': 'SZ',
- 'Sweden': 'SE',
- 'Switzerland': 'CH',
- 'Syria': 'SY',
- 'Taiwan': 'TW',
- 'Tajikstan': 'TJ',
- 'Tanzania': 'TZ',
- 'Thailand': 'TH',
- 'Togo': 'TG',
- 'Tokelau': 'TK',
- 'Tonga': 'TO',
- 'Trinidad and Tobago': 'TT',
- 'Tunisia': 'TN',
- 'Turkey': 'TR',
- 'Turkmenistan': 'TM',
- 'Turks and Caicos Islands': 'TC',
- 'Tuvalu': 'TV',
- 'U.S. Virgin Islands': 'VI',
- 'Uganda': 'UG',
- 'Ukraine': 'UA',
- 'United Arab Emirates': 'AE',
- 'United Kingdom': 'GB',
- 'United States': 'US',
- 'Uruguay': 'UY',
- 'Uzbekistan': 'UZ',
- 'Vanuatu': 'VU',
- 'Vatican': 'VA',
- 'Venezuela': 'VE',
- 'Vietnam': 'VN',
- 'Wallis and Futuna': 'WF',
- 'Western Sahara': 'EH',
- 'Yemen': 'YE',
- 'Zambia': 'ZM',
- 'Zimbabwe': 'ZW'
- }
- self.choices_iso_codes = self.country_iso_map.values()
-
- def is_valid_hostname(self, host):
- """Reasonable attempt at validating a hostname
-
- Compiled from various paragraphs outlined here
- https://tools.ietf.org/html/rfc3696#section-2
- https://tools.ietf.org/html/rfc1123
-
- Notably,
- * Host software MUST handle host names of up to 63 characters and
- SHOULD handle host names of up to 255 characters.
- * The "LDH rule", after the characters that it permits. (letters, digits, hyphen)
- * If the hyphen is used, it is not permitted to appear at
- either the beginning or end of a label
-
- :param host:
- :return:
- """
- if len(host) > 255:
- return False
- host = host.rstrip(".")
- allowed = re.compile(r'(?!-)[A-Z0-9-]{1,63}(?<!-)$', re.IGNORECASE)
- return all(allowed.match(x) for x in host.split("."))
-
- @property
- def addresses(self):
- if self._values['addresses'] is None:
- return None
- result = []
- for x in self._values['addresses']:
- if is_valid_ip(x):
- result.append(str(ip_address(u'{0}'.format(x))))
- elif is_valid_ip_interface(x):
- result.append(str(ip_interface(u'{0}'.format(x))))
- else:
- raise F5ModuleError(
- "Address {0} must be either an IPv4 or IPv6 address or network.".format(x)
- )
- result = sorted(result)
- return result
-
- @property
- def address_ranges(self):
- if self._values['address_ranges'] is None:
- return None
- result = []
- for address_range in self._values['address_ranges']:
- start, stop = address_range.split('-')
- start = start.strip()
- stop = stop.strip()
-
- start = ip_address(u'{0}'.format(start))
- stop = ip_address(u'{0}'.format(stop))
- if start.version != stop.version:
- raise F5ModuleError(
- "When specifying a range, IP addresses must be of the same type; IPv4 or IPv6."
- )
- if int(start) > int(stop):
- stop, start = start, stop
- item = '{0}-{1}'.format(str(start), str(stop))
- result.append(item)
- result = sorted(result)
- return result
-
- @property
- def address_lists(self):
- if self._values['address_lists'] is None:
- return None
- result = []
- for x in self._values['address_lists']:
- item = fq_name(self.partition, x)
- result.append(item)
- result = sorted(result)
- return result
-
- @property
- def fqdns(self):
- if self._values['fqdns'] is None:
- return None
- result = []
- for x in self._values['fqdns']:
- if self.is_valid_hostname(x):
- result.append(x)
- else:
- raise F5ModuleError(
- "The hostname '{0}' looks invalid.".format(x)
- )
- result = sorted(result)
- return result
-
- @property
- def geo_locations(self):
- if self._values['geo_locations'] is None:
- return None
- result = []
- for x in self._values['geo_locations']:
- if x['region'] is not None and x['region'].strip() != '':
- tmp = '{0}:{1}'.format(x['country'], x['region'])
- else:
- tmp = x['country']
- result.append(tmp)
- result = sorted(result)
- return result
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class ReportableChanges(Changes):
- @property
- def addresses(self):
- result = []
- for item in self._values['addresses']:
- if '-' in item['name']:
- continue
- result.append(item['name'])
- return result
-
- @property
- def address_ranges(self):
- result = []
- for item in self._values['addresses']:
- if '-' not in item['name']:
- continue
- start, stop = item['name'].split('-')
- start = start.strip()
- stop = stop.strip()
-
- start = ip_address(u'{0}'.format(start))
- stop = ip_address(u'{0}'.format(stop))
- if start.version != stop.version:
- raise F5ModuleError(
- "When specifying a range, IP addresses must be of the same type; IPv4 or IPv6."
- )
- if int(start) > int(stop):
- stop, start = start, stop
- item = '{0}-{1}'.format(str(start), str(stop))
- result.append(item)
- result = sorted(result)
- return result
-
- @property
- def address_lists(self):
- result = []
- for x in self._values['address_lists']:
- item = '/{0}/{1}'.format(x['partition'], x['name'])
- result.append(item)
- result = sorted(result)
- return result
-
-
-class UsableChanges(Changes):
- @property
- def addresses(self):
- if self._values['addresses'] is None and self._values['address_ranges'] is None:
- return None
- result = []
- if self._values['addresses']:
- result += [dict(name=str(x)) for x in self._values['addresses']]
- if self._values['address_ranges']:
- result += [dict(name=str(x)) for x in self._values['address_ranges']]
- return result
-
- @property
- def address_lists(self):
- if self._values['address_lists'] is None:
- return None
- result = []
- for x in self._values['address_lists']:
- partition, name = x.split('/')[1:]
- result.append(dict(
- name=name,
- partition=partition
- ))
- return result
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
- @property
- def addresses(self):
- if self.want.addresses is None:
- return None
- elif self.have.addresses is None:
- return self.want.addresses
- if sorted(self.want.addresses) != sorted(self.have.addresses):
- return self.want.addresses
-
- @property
- def address_lists(self):
- if self.want.address_lists is None:
- return None
- elif self.have.address_lists is None:
- return self.want.address_lists
- if sorted(self.want.address_lists) != sorted(self.have.address_lists):
- return self.want.address_lists
-
- @property
- def address_ranges(self):
- if self.want.address_ranges is None:
- return None
- elif self.have.address_ranges is None:
- return self.want.address_ranges
- if sorted(self.want.address_ranges) != sorted(self.have.address_ranges):
- return self.want.address_ranges
-
- @property
- def fqdns(self):
- if self.want.fqdns is None:
- return None
- elif self.have.fqdns is None:
- return self.want.fqdns
- if sorted(self.want.fqdns) != sorted(self.have.fqdns):
- return self.want.fqdns
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(params=self.module.params)
- self.have = ApiParameters()
- self.changes = UsableChanges()
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def exec_module(self):
- changed = False
- result = dict()
- state = self.want.state
-
- if state == "present":
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def present(self):
- if self.exists():
- return self.update()
- else:
- return self.create()
-
- def absent(self):
- if self.exists():
- return self.remove()
- return False
-
- def update(self):
- self.have = self.read_current_from_device()
- if not self.should_update():
- return False
- if self.module.check_mode:
- return True
- self.update_on_device()
- return True
-
- def remove(self):
- if self.module.check_mode:
- return True
- self.remove_from_device()
- if self.exists():
- raise F5ModuleError("Failed to delete the resource.")
- return True
-
- def create(self):
- self.have = ApiParameters()
- self._update_changed_options()
- if self.module.check_mode:
- return True
- self.create_on_device()
- return True
-
- def exists(self):
- uri = "https://{0}:{1}/mgmt/tm/security/firewall/address-list/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def create_on_device(self):
- params = self.changes.api_params()
- params['name'] = self.want.name
- params['partition'] = self.want.partition
- uri = "https://{0}:{1}/mgmt/tm/security/firewall/address-list/".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def update_on_device(self):
- params = self.changes.api_params()
- uri = "https://{0}:{1}/mgmt/tm/security/firewall/address-list/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def remove_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/security/firewall/address-list/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.delete(uri)
- if resp.status == 200:
- return True
- raise F5ModuleError(resp.content)
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/security/firewall/address-list/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return ApiParameters(params=response)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- description=dict(),
- name=dict(required=True),
- addresses=dict(type='list'),
- address_ranges=dict(type='list'),
- address_lists=dict(type='list'),
- geo_locations=dict(
- type='list',
- elements='dict',
- options=dict(
- country=dict(
- required=True,
- ),
- region=dict()
- )
- ),
- fqdns=dict(type='list'),
- partition=dict(
- default='Common',
- fallback=(env_fallback, ['F5_PARTITION'])
- ),
- state=dict(
- default='present',
- choices=['present', 'absent']
- )
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_firewall_dos_profile.py b/lib/ansible/modules/network/f5/bigip_firewall_dos_profile.py
deleted file mode 100644
index 2648a7acf6..0000000000
--- a/lib/ansible/modules/network/f5/bigip_firewall_dos_profile.py
+++ /dev/null
@@ -1,426 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2018, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_firewall_dos_profile
-short_description: Manage AFM DoS profiles on a BIG-IP
-description:
- - Manages AFM Denial of Service (DoS) profiles on a BIG-IP. To manage the vectors
- associated with a DoS profile, refer to the C(bigip_firewall_dos_vector) module.
-version_added: 2.7
-options:
- name:
- description:
- - Specifies the name of the profile.
- type: str
- required: True
- description:
- description:
- - The description of the DoS profile.
- type: str
- default_whitelist:
- description:
- - The default whitelist address list for the system to use to determine which
- IP addresses are legitimate.
- - The system does not examine traffic from the IP addresses in the list when
- performing DoS prevention.
- - To define a new whitelist, use the C(bigip_firewall_address_list) module.
- type: str
- threshold_sensitivity:
- description:
- - Specifies the threshold sensitivity for the DoS profile.
- - Thresholds for detecting attacks are higher when sensitivity is C(low), and
- lower when sensitivity is C(high).
- - When creating a new profile, if this parameter is not specified, the default
- is C(medium).
- type: str
- choices:
- - low
- - medium
- - high
- partition:
- description:
- - Device partition to manage resources on.
- type: str
- default: Common
- state:
- description:
- - When C(present), ensures that the resource exists.
- - When C(absent), ensures the resource is removed.
- type: str
- choices:
- - present
- - absent
- default: present
-extends_documentation_fragment: f5
-author:
- - Tim Rupp (@caphrim007)
-'''
-
-EXAMPLES = r'''
-- name: Create a new DoS profile
- bigip_firewall_dos_profile:
- name: profile1
- description: DoS profile 1
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-'''
-
-RETURN = r'''
-threshold_sensitivity:
- description: The new threshold sensitivity of the profile.
- returned: changed
- type: str
- sample: low
-default_whitelist:
- description: The new whitelist attached to the profile.
- returned: changed
- type: str
- sample: /Common/whitelist1
-description:
- description: The description of the profile.
- returned: changed
- type: str
- sample: New description
-'''
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.basic import env_fallback
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import fq_name
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.common import transform_name
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import fq_name
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.common import transform_name
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'thresholdSensitivity': 'threshold_sensitivity',
- 'whitelist': 'default_whitelist',
- }
-
- api_attributes = [
- 'thresholdSensitivity',
- 'whitelist',
- 'description',
- ]
-
- returnables = [
- 'threshold_sensitivity',
- 'default_whitelist',
- 'description',
- ]
-
- updatables = [
- 'threshold_sensitivity',
- 'default_whitelist',
- 'description',
- ]
-
-
-class ApiParameters(Parameters):
- pass
-
-
-class ModuleParameters(Parameters):
- @property
- def default_whitelist(self):
- if self._values['default_whitelist'] is None:
- return None
- return fq_name(self.partition, self._values['default_whitelist'])
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class UsableChanges(Changes):
- pass
-
-
-class ReportableChanges(Changes):
- pass
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(params=self.module.params)
- self.have = ApiParameters()
- self.changes = UsableChanges()
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = UsableChanges(params=changed)
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def exec_module(self):
- changed = False
- result = dict()
- state = self.want.state
-
- if state == "present":
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.client.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def present(self):
- if self.exists():
- return self.update()
- else:
- return self.create()
-
- def exists(self):
- uri = "https://{0}:{1}/mgmt/tm/security/dos/profile/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def update(self):
- self.have = self.read_current_from_device()
- if not self.should_update():
- return False
- if self.module.check_mode:
- return True
- self.update_on_device()
- return True
-
- def remove(self):
- if self.module.check_mode:
- return True
- self.remove_from_device()
- if self.exists():
- raise F5ModuleError("Failed to delete the resource.")
- return True
-
- def create(self):
- self._set_changed_options()
- if self.module.check_mode:
- return True
- self.create_on_device()
- return True
-
- def create_on_device(self):
- params = self.changes.api_params()
- params['name'] = self.want.name
- params['partition'] = self.want.partition
- uri = "https://{0}:{1}/mgmt/tm/security/dos/profile/".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def update_on_device(self):
- params = self.changes.api_params()
- uri = "https://{0}:{1}/mgmt/tm/security/dos/profile/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def absent(self):
- if self.exists():
- return self.remove()
- return False
-
- def remove_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/security/dos/profile/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.delete(uri)
- if resp.status == 200:
- return True
- raise F5ModuleError(resp.content)
-
- def read_current_from_device(self): # lgtm [py/similar-function]
- uri = "https://{0}:{1}/mgmt/tm/security/dos/profile/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return ApiParameters(params=response)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- name=dict(required=True),
- description=dict(),
- threshold_sensitivity=dict(
- choices=['low', 'medium', 'high']
- ),
- default_whitelist=dict(),
- state=dict(
- default='present',
- choices=['present', 'absent']
- ),
- partition=dict(
- default='Common',
- fallback=(env_fallback, ['F5_PARTITION'])
- )
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode,
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_firewall_dos_vector.py b/lib/ansible/modules/network/f5/bigip_firewall_dos_vector.py
deleted file mode 100644
index eb3ca94dbc..0000000000
--- a/lib/ansible/modules/network/f5/bigip_firewall_dos_vector.py
+++ /dev/null
@@ -1,1307 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2018, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_firewall_dos_vector
-short_description: Manage attack vector configuration in an AFM DoS profile
-description:
- - Manage attack vector configuration in an AFM DoS profile. In addition to the normal
- AFM DoS profile vectors, this module can manage the device-configuration vectors.
- See the module documentation for details about this method.
-version_added: 2.8
-options:
- name:
- description:
- - Specifies the name of the vector to modify.
- - Vectors that ship with the device are "hard-coded" so-to-speak in that the list
- of vectors is known to the system and users cannot add new vectors. Users only
- manipulate the existing vectors; all of which are disabled by default.
- - When C(ext-hdr-too-large), configures the "IPv6 extension header too large"
- Network Security vector.
- - When C(hop-cnt-low), configures the "IPv6 hop count <= <tunable>" Network
- Security vector.
- - When C(host-unreachable), configures the "Host Unreachable" Network Security
- vector.
- - When C(icmp-frag), configures the "ICMP Fragment" Network Security vector.
- - When C(icmpv4-flood), configures the "ICMPv4 flood" Network Security vector.
- - When C(icmpv6-flood), configures the "ICMPv6 flood" Network Security vector.
- - When C(ip-frag-flood), configures the "IP Fragment Flood" Network Security vector.
- - When C(ip-low-ttl), configures the "TTL <= <tunable>" Network Security vector.
- - When C(ip-opt-frames), configures the "IP Option Frames" Network Security vector.
- - When C(ipv6-ext-hdr-frames), configures the "IPv6 Extended Header Frames"
- Network Security vector.
- - When C(ipv6-frag-flood), configures the "IPv6 Fragment Flood" Network Security
- vector.
- - When C(opt-present-with-illegal-len), configures the "Option Present With Illegal
- Length" Network Security vector.
- - When C(sweep), configures the "Sweep" Network Security vector.
- - When C(tcp-bad-urg), configures the "TCP Flags-Bad URG" Network Security vector.
- - When C(tcp-half-open), configures the "TCP Half Open" Network Security vector.
- - When C(tcp-opt-overruns-tcp-hdr), configures the "TCP Option Overruns TCP Header"
- Network Security vector.
- - When C(tcp-psh-flood), configures the "TCP PUSH Flood" Network Security vector.
- - When C(tcp-rst-flood), configures the "TCP RST Flood" Network Security vector.
- - When C(tcp-syn-flood), configures the "TCP SYN Flood" Network Security vector.
- - When C(tcp-syn-oversize), configures the "TCP SYN Oversize" Network Security
- vector.
- - When C(tcp-synack-flood), configures the "TCP SYN ACK Flood" Network Security
- vector.
- - When C(tcp-window-size), configures the "TCP Window Size" Network Security
- vector.
- - When C(tidcmp), configures the "TIDCMP" Network Security vector.
- - When C(too-many-ext-hdrs), configures the "Too Many Extension Headers" Network
- Security vector.
- - When C(udp-flood), configures the "UDP Flood" Network Security vector.
- - When C(unk-tcp-opt-type), configures the "Unknown TCP Option Type" Network
- Security vector.
- - When C(a), configures the "DNS A Query" DNS Protocol Security vector.
- - When C(aaaa), configures the "DNS AAAA Query" DNS Protocol Security vector.
- - When C(any), configures the "DNS ANY Query" DNS Protocol Security vector.
- - When C(axfr), configures the "DNS AXFR Query" DNS Protocol Security vector.
- - When C(cname), configures the "DNS CNAME Query" DNS Protocol Security vector.
- - When C(dns-malformed), configures the "dns-malformed" DNS Protocol Security vector.
- - When C(ixfr), configures the "DNS IXFR Query" DNS Protocol Security vector.
- - When C(mx), configures the "DNS MX Query" DNS Protocol Security vector.
- - When C(ns), configures the "DNS NS Query" DNS Protocol Security vector.
- - When C(other), configures the "DNS OTHER Query" DNS Protocol Security vector.
- - When C(ptr), configures the "DNS PTR Query" DNS Protocol Security vector.
- - When C(qdcount), configures the "DNS QDCOUNT Query" DNS Protocol Security vector.
- - When C(soa), configures the "DNS SOA Query" DNS Protocol Security vector.
- - When C(srv), configures the "DNS SRV Query" DNS Protocol Security vector.
- - When C(txt), configures the "DNS TXT Query" DNS Protocol Security vector.
- - When C(ack), configures the "SIP ACK Method" SIP Protocol Security vector.
- - When C(bye), configures the "SIP BYE Method" SIP Protocol Security vector.
- - When C(cancel), configures the "SIP CANCEL Method" SIP Protocol Security vector.
- - When C(invite), configures the "SIP INVITE Method" SIP Protocol Security vector.
- - When C(message), configures the "SIP MESSAGE Method" SIP Protocol Security vector.
- - When C(notify), configures the "SIP NOTIFY Method" SIP Protocol Security vector.
- - When C(options), configures the "SIP OPTIONS Method" SIP Protocol Security vector.
- - When C(other), configures the "SIP OTHER Method" SIP Protocol Security vector.
- - When C(prack), configures the "SIP PRACK Method" SIP Protocol Security vector.
- - When C(publish), configures the "SIP PUBLISH Method" SIP Protocol Security vector.
- - When C(register), configures the "SIP REGISTER Method" SIP Protocol Security vector.
- - When C(sip-malformed), configures the "sip-malformed" SIP Protocol Security vector.
- - When C(subscribe), configures the "SIP SUBSCRIBE Method" SIP Protocol Security vector.
- - When C(uri-limit), configures the "uri-limit" SIP Protocol Security vector.
- type: str
- choices:
- - ext-hdr-too-large
- - hop-cnt-low
- - host-unreachable
- - icmp-frag
- - icmpv4-flood
- - icmpv6-flood
- - ip-frag-flood
- - ip-low-ttl
- - ip-opt-frames
- - ipv6-frag-flood
- - opt-present-with-illegal-len
- - sweep
- - tcp-bad-urg
- - tcp-half-open
- - tcp-opt-overruns-tcp-hdr
- - tcp-psh-flood
- - tcp-rst-flood
- - tcp-syn-flood
- - tcp-syn-oversize
- - tcp-synack-flood
- - tcp-window-size
- - tidcmp
- - too-many-ext-hdrs
- - udp-flood
- - unk-tcp-opt-type
- - a
- - aaaa
- - any
- - axfr
- - cname
- - dns-malformed
- - ixfr
- - mx
- - ns
- - other
- - ptr
- - qdcount
- - soa
- - srv
- - txt
- - ack
- - bye
- - cancel
- - invite
- - message
- - notify
- - options
- - other
- - prack
- - publish
- - register
- - sip-malformed
- - subscribe
- - uri-limit
- profile:
- description:
- - Specifies the name of the profile to manage vectors in.
- - The name C(device-config) is reserved for use by this module.
- - Vectors can be managed in either DoS Profiles, or Device Configuration. By
- specifying a profile of 'device-config', this module will specifically tailor
- configuration of the provided vectors to the Device Configuration.
- type: str
- required: True
- auto_blacklist:
- description:
- - Automatically blacklists detected bad actors.
- - To enable this parameter, the C(bad_actor_detection) must also be enabled.
- - This parameter is not supported by the C(dns-malformed) vector.
- - This parameter is not supported by the C(qdcount) vector.
- type: bool
- bad_actor_detection:
- description:
- - Whether Bad Actor detection is enabled or disabled for a vector, if available.
- - This parameter must be enabled to enable the C(auto_blacklist) parameter.
- - This parameter is not supported by the C(dns-malformed) vector.
- - This parameter is not supported by the C(qdcount) vector.
- type: bool
- attack_ceiling:
- description:
- - Specifies the absolute maximum allowable for packets of this type.
- - This setting rate limits packets to the packets per second setting, when
- specified.
- - To set no hard limit and allow automatic thresholds to manage all rate limiting,
- set this to C(infinite).
- type: str
- attack_floor:
- description:
- - Specifies packets per second to identify an attack.
- - These settings provide an absolute minimum of packets to allow before the attack
- is identified.
- - As the automatic detection thresholds adjust to traffic and CPU usage on the
- system over time, this attack floor becomes less relevant.
- - This value may not exceed the value in C(attack_floor).
- type: str
- allow_advertisement:
- description:
- - Specifies that addresses that are identified for blacklisting are advertised to
- BGP routers
- type: bool
- simulate_auto_threshold:
- description:
- - Specifies that results of the current automatic thresholds are logged, though
- manual thresholds are enforced, and no action is taken on automatic thresholds.
- - The C(sweep) vector does not support this parameter.
- type: bool
- blacklist_detection_seconds:
- description:
- - Detection, in seconds, before blacklisting occurs.
- type: int
- blacklist_duration:
- description:
- - Duration, in seconds, that the blacklist will last.
- type: int
- per_source_ip_detection_threshold:
- description:
- - Specifies the number of packets per second to identify an IP address as a bad
- actor.
- type: str
- per_source_ip_mitigation_threshold:
- description:
- - Specifies the rate limit applied to a source IP that is identified as a bad
- actor.
- type: str
- detection_threshold_percent:
- description:
- - Lists the threshold percent increase over time that the system must detect in
- traffic in order to detect this attack.
- - The C(tcp-half-open) vector does not support this parameter.
- type: str
- aliases:
- - rate_increase
- detection_threshold_eps:
- description:
- - Lists how many packets per second the system must discover in traffic in order
- to detect this attack.
- type: str
- aliases:
- - rate_threshold
- mitigation_threshold_eps:
- description:
- - Specify the maximum number of this type of packet per second the system allows
- for a vector.
- - The system drops packets once the traffic level exceeds the rate limit.
- type: str
- aliases:
- - rate_limit
- threshold_mode:
- description:
- - The C(dns-malformed) vector does not support C(fully-automatic), or C(stress-based-mitigation)
- for this parameter.
- - The C(qdcount) vector does not support C(fully-automatic), or C(stress-based-mitigation)
- for this parameter.
- - The C(sip-malformed) vector does not support C(fully-automatic), or C(stress-based-mitigation)
- for this parameter.
- type: str
- choices:
- - manual
- - stress-based-mitigation
- - fully-automatic
- state:
- description:
- - When C(state) is C(mitigate), ensures that the vector enforces limits and
- thresholds.
- - When C(state) is C(detect-only), ensures that the vector does not enforce limits
- and thresholds (rate limiting, dopping, etc), but is still tracked in logs and statistics.
- - When C(state) is C(disabled), ensures that the vector does not enforce limits
- and thresholds, but is still tracked in logs and statistics.
- - When C(state) is C(learn-only), ensures that the vector does not "detect" any attacks.
- Only learning and stat collecting is performed.
- type: str
- choices:
- - mitigate
- - detect-only
- - learn-only
- - disabled
- required: True
- partition:
- description:
- - Device partition to manage resources on.
- type: str
- default: Common
-extends_documentation_fragment: f5
-requirements:
- - BIG-IP >= v13.0.0
-author:
- - Tim Rupp (@caphrim007)
-'''
-
-EXAMPLES = r'''
-- name: Enable DNS AAAA vector mitigation
- bigip_firewall_dos_vector:
- name: aaaa
- state: mitigate
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-'''
-
-RETURN = r'''
-allow_advertisement:
- description: The new Allow External Advertisement setting.
- returned: changed
- type: bool
- sample: yes
-auto_blacklist:
- description: The new Auto Blacklist setting.
- returned: changed
- type: bool
- sample: no
-bad_actor_detection:
- description: The new Bad Actor Detection setting.
- returned: changed
- type: bool
- sample: no
-blacklist_detection_seconds:
- description: The new Sustained Attack Detection Time setting.
- returned: changed
- type: int
- sample: 60
-blacklist_duration:
- description: The new Category Duration Time setting.
- returned: changed
- type: int
- sample: 14400
-attack_ceiling:
- description: The new Attack Ceiling EPS setting.
- returned: changed
- type: str
- sample: infinite
-attack_floor:
- description: The new Attack Floor EPS setting.
- returned: changed
- type: str
- sample: infinite
-blacklist_category:
- description: The new Category Name setting.
- returned: changed
- type: str
- sample: /Common/cloud_provider_networks
-per_source_ip_detection_threshold:
- description: The new Per Source IP Detection Threshold EPS setting.
- returned: changed
- type: str
- sample: 23
-per_source_ip_mitigation_threshold:
- description: The new Per Source IP Mitigation Threshold EPS setting.
- returned: changed
- type: str
- sample: infinite
-detection_threshold_percent:
- description: The new Detection Threshold Percent setting.
- returned: changed
- type: str
- sample: infinite
-detection_threshold_eps:
- description: The new Detection Threshold EPS setting.
- returned: changed
- type: str
- sample: infinite
-mitigation_threshold_eps:
- description: The new Mitigation Threshold EPS setting.
- returned: changed
- type: str
- sample: infinite
-threshold_mode:
- description: The new Mitigation Threshold EPS setting.
- returned: changed
- type: str
- sample: infinite
-simulate_auto_threshold:
- description: The new Simulate Auto Threshold setting.
- returned: changed
- type: bool
- sample: no
-state:
- description: The new state of the vector.
- returned: changed
- type: str
- sample: mitigate
-'''
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.basic import env_fallback
-from ansible.module_utils.six import iteritems
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import fq_name
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.common import transform_name
- from library.module_utils.network.f5.common import flatten_boolean
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import fq_name
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.common import transform_name
- from ansible.module_utils.network.f5.common import flatten_boolean
-
-
-NETWORK_SECURITY_VECTORS = [
- 'ext-hdr-too-large', # IPv6 extension header too large
- 'hop-cnt-low', # IPv6 hop count <= <tunable>
- 'host-unreachable', # Host Unreachable
- 'icmp-frag', # ICMP Fragment
- 'icmpv4-flood', # ICMPv4 flood
- 'icmpv6-flood', # ICMPv6 flood
- 'ip-frag-flood', # IP Fragment Flood
- 'ip-low-ttl', # TTL <= <tunable>
- 'ip-opt-frames', # IP Option Frames
- 'ipv6-ext-hdr-frames', # IPv6 Extended Header Frames
- 'ipv6-frag-flood', # IPv6 Fragment Flood
- 'opt-present-with-illegal-len', # Option Present With Illegal Length
- 'sweep', # Sweep
- 'tcp-bad-urg', # TCP Flags-Bad URG
- 'tcp-half-open', # TCP Half Open
- 'tcp-opt-overruns-tcp-hdr', # TCP Option Overruns TCP Header
- 'tcp-psh-flood', # TCP PUSH Flood
- 'tcp-rst-flood', # TCP RST Flood
- 'tcp-syn-flood', # TCP SYN Flood
- 'tcp-syn-oversize', # TCP SYN Oversize
- 'tcp-synack-flood', # TCP SYN ACK Flood
- 'tcp-window-size', # TCP Window Size
- 'tidcmp', # TIDCMP
- 'too-many-ext-hdrs', # Too Many Extension Headers
- 'udp-flood', # UDP Flood
- 'unk-tcp-opt-type', # Unknown TCP Option Type
-]
-
-PROTOCOL_SIP_VECTORS = [
- 'ack', # SIP ACK Method
- 'bye', # SIP BYE Method
- 'cancel', # SIP CANCEL Method
- 'invite', # SIP INVITE Method
- 'message', # SIP MESSAGE Method
- 'notify', # SIP NOTIFY Method
- 'options', # SIP OPTIONS Method
- 'other', # SIP OTHER Method
- 'prack', # SIP PRACK Method
- 'publish', # SIP PUBLISH Method
- 'register', # SIP REGISTER Method
- 'sip-malformed', # sip-malformed
- 'subscribe', # SIP SUBSCRIBE Method
- 'uri-limit', # uri-limit
-]
-
-PROTOCOL_DNS_VECTORS = [
- 'a', # DNS A Query
- 'aaaa', # DNS AAAA Query
- 'any', # DNS ANY Query
- 'axfr', # DNS AXFR Query
- 'cname', # DNS CNAME Query
- 'dns-malformed', # dns-malformed
- 'ixfr', # DNS IXFR Query
- 'mx', # DNS MX Query
- 'ns', # DNS NS Query
- 'other', # DNS OTHER Query
- 'ptr', # DNS PTR Query
- 'qdcount', # DNS QDCOUNT LIMIT
- 'soa', # DNS SOA Query
- 'srv', # DNS SRV Query
- 'txt', # DNS TXT Query
-]
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'allowAdvertisement': 'allow_advertisement',
- 'autoBlacklisting': 'auto_blacklist',
-
- # "autoThreshold": "disabled",
- # This is a deprecated parameter in 13.1.0. Use threshold_mode instead
-
- 'badActor': 'bad_actor_detection',
- 'blacklistCategory': 'blacklist_category',
- 'blacklistDetectionSeconds': 'blacklist_detection_seconds',
- 'blacklistDuration': 'blacklist_duration',
- 'ceiling': 'attack_ceiling',
- # "enforce": "enabled",
- 'floor': 'attack_floor',
- 'perSourceIpDetectionPps': 'per_source_ip_detection_threshold',
- 'perSourceIpLimitPps': 'per_source_ip_mitigation_threshold',
- 'rateIncrease': 'detection_threshold_percent',
- 'rateLimit': 'mitigation_threshold_eps',
- 'rateThreshold': 'detection_threshold_eps',
- 'simulateAutoThreshold': 'simulate_auto_threshold',
- 'thresholdMode': 'threshold_mode',
-
- # device-config specific settings
- 'scrubbingDetectionSeconds': 'sustained_attack_detection_time',
- 'scrubbingDuration': 'category_detection_time',
- 'perDstIpDetectionPps': 'per_dest_ip_detection_threshold',
- 'perDstIpLimitPps': 'per_dest_ip_mitigation_threshold',
-
- # The following are not enabled for device-config because I
- # do not know what parameters in TMUI they map to. Additionally,
- # they do not appear to have any "help" documentation available
- # in ``tmsh help security dos device-config``.
- #
- # "allowUpstreamScrubbing": "disabled",
- # "attackedDst": "disabled",
- # "autoScrubbing": "disabled",
- 'defaultInternalRateLimit': 'mitigation_threshold_eps',
- 'detectionThresholdPercent': 'detection_threshold_percent',
- 'detectionThresholdPps': 'detection_threshold_eps',
- }
-
- api_attributes = [
- 'allowAdvertisement',
- 'autoBlacklisting',
- 'autoThreshold',
- 'badActor',
- 'blacklistCategory',
- 'blacklistDetectionSeconds',
- 'blacklistDuration',
- 'ceiling',
- 'enforce',
- 'floor',
- 'perSourceIpDetectionPps',
- 'perSourceIpLimitPps',
- 'rateIncrease',
- 'rateLimit',
- 'rateThreshold',
- 'simulateAutoThreshold',
- 'state',
- 'thresholdMode',
-
- # device-config specific
- 'scrubbingDetectionSeconds',
- 'scrubbingDuration',
- 'perDstIpDetectionPps',
- 'perDstIpLimitPps',
- 'defaultInternalRateLimit',
- 'detectionThresholdPercent',
- 'detectionThresholdPps',
-
- # Attributes on the DoS profiles that hold the different vectors
- #
- # Each of these attributes is a list of dictionaries. Each dictionary
- # contains the settings that affect the way the vector works.
- #
- # The vectors appear to all have the same attributes even if those
- # attributes are not used. There may be cases where this is not true,
- # however, and for those vectors we should either include specific
- # error detection, or pass the unfiltered values through to mcpd and
- # handle any unintuitive error messages that mcpd returns.
- 'dosDeviceVector',
- 'dnsQueryVector',
- 'networkAttackVector',
- 'sipAttackVector',
- ]
-
- returnables = [
- 'allow_advertisement',
- 'auto_blacklist',
- 'bad_actor_detection',
- 'blacklist_detection_seconds',
- 'blacklist_duration',
- 'attack_ceiling',
- 'attack_floor',
- 'blacklist_category',
- 'per_source_ip_detection_threshold',
- 'per_source_ip_mitigation_threshold',
- 'detection_threshold_percent',
- 'detection_threshold_eps',
- 'mitigation_threshold_eps',
- 'threshold_mode',
- 'simulate_auto_threshold',
- 'state',
- ]
-
- updatables = [
- 'allow_advertisement',
- 'auto_blacklist',
- 'bad_actor_detection',
- 'blacklist_detection_seconds',
- 'blacklist_duration',
- 'attack_ceiling',
- 'attack_floor',
- 'blacklist_category',
- 'per_source_ip_detection_threshold',
- 'per_source_ip_mitigation_threshold',
- 'detection_threshold_percent',
- 'detection_threshold_eps',
- 'mitigation_threshold_eps',
- 'threshold_mode',
- 'simulate_auto_threshold',
- 'state',
- ]
-
- @property
- def allow_advertisement(self):
- return flatten_boolean(self._values['allow_advertisement'])
-
- @property
- def auto_blacklist(self):
- return flatten_boolean(self._values['auto_blacklist'])
-
- @property
- def simulate_auto_threshold(self):
- return flatten_boolean(self._values['simulate_auto_threshold'])
-
- @property
- def bad_actor_detection(self):
- return flatten_boolean(self._values['bad_actor_detection'])
-
- @property
- def detection_threshold_percent(self):
- if self._values['detection_threshold_percent'] in [None, "infinite"]:
- return self._values['detection_threshold_percent']
- return int(self._values['detection_threshold_percent'])
-
- @property
- def per_source_ip_mitigation_threshold(self):
- if self._values['per_source_ip_mitigation_threshold'] in [None, "infinite"]:
- return self._values['per_source_ip_mitigation_threshold']
- return int(self._values['per_source_ip_mitigation_threshold'])
-
- @property
- def per_dest_ip_mitigation_threshold(self):
- if self._values['per_dest_ip_mitigation_threshold'] in [None, "infinite"]:
- return self._values['per_dest_ip_mitigation_threshold']
- return int(self._values['per_dest_ip_mitigation_threshold'])
-
- @property
- def mitigation_threshold_eps(self):
- if self._values['mitigation_threshold_eps'] in [None, "infinite"]:
- return self._values['mitigation_threshold_eps']
- return int(self._values['mitigation_threshold_eps'])
-
- @property
- def detection_threshold_eps(self):
- if self._values['detection_threshold_eps'] in [None, "infinite"]:
- return self._values['detection_threshold_eps']
- return int(self._values['detection_threshold_eps'])
-
- @property
- def attack_ceiling(self):
- if self._values['attack_ceiling'] in [None, "infinite"]:
- return self._values['attack_ceiling']
- return int(self._values['attack_ceiling'])
-
- @property
- def blacklist_category(self):
- if self._values['blacklist_category'] is None:
- return None
- return fq_name(self.partition, self._values['blacklist_category'])
-
-
-class ApiParameters(Parameters):
- pass
-
-
-class ModuleParameters(Parameters):
- pass
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class UsableChanges(Changes):
- @property
- def allow_advertisement(self):
- if self._values['allow_advertisement'] is None:
- return None
- if self._values['allow_advertisement'] == 'yes':
- return 'enabled'
- return 'disabled'
-
- @property
- def auto_blacklist(self):
- if self._values['auto_blacklist'] is None:
- return None
- if self._values['auto_blacklist'] == 'yes':
- return 'enabled'
- return 'disabled'
-
- @property
- def simulate_auto_threshold(self):
- if self._values['simulate_auto_threshold'] is None:
- return None
- if self._values['simulate_auto_threshold'] == 'yes':
- return 'enabled'
- return 'disabled'
-
- @property
- def bad_actor_detection(self):
- if self._values['bad_actor_detection'] is None:
- return None
- if self._values['bad_actor_detection'] == 'yes':
- return 'enabled'
- return 'disabled'
-
-
-class ReportableChanges(Changes):
- @property
- def allow_advertisement(self):
- return flatten_boolean(self._values['allow_advertisement'])
-
- @property
- def auto_blacklist(self):
- return flatten_boolean(self._values['auto_blacklist'])
-
- @property
- def simulate_auto_threshold(self):
- return flatten_boolean(self._values['simulate_auto_threshold'])
-
- @property
- def bad_actor_detection(self):
- return flatten_boolean(self._values['bad_actor_detection'])
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- def __default(self, param):
- want = getattr(self.want, param)
- try:
- have = getattr(self.have, param)
- if want != have:
- return want
- except AttributeError:
- return want
-
-
-class BaseManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
-
- # A list of all the vectors queried from the API when reading current info
- # from the device. This is used when updating the API as the value that needs
- # to be updated is a list of vectors and PATCHing a list would override any
- # default settings.
- self.vectors = dict()
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def exec_module(self):
- result = dict()
-
- changed = self.present()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def present(self):
- return self.update()
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def format_vectors(self, vectors):
- result = None
- for x in vectors:
- vector = ApiParameters(params=x)
- self.vectors[vector.name] = x
- if vector.name == self.want.name:
- result = vector
- if not result:
- return ApiParameters()
- return result
-
- def _update(self, vtype):
- self.have = self.format_vectors(self.read_current_from_device())
- if not self.should_update():
- return False
- if self.module.check_mode:
- return True
-
- # A disabled vector does not appear in the list of existing vectors
- if self.want.state == 'disabled':
- if self.want.profile == 'device-config' and self.have.state == 'disabled':
- return False
- # For non-device-config
- if self.want.name not in self.vectors:
- return False
-
- # At this point we know the existing vector is not disabled, so we need
- # to change it in some way.
- #
- # First, if we see that the vector is in the current list of vectors,
- # we are going to update it
- changes = dict(self.changes.api_params())
- if self.want.name in self.vectors:
- self.vectors[self.want.name].update(changes)
- else:
- # else, we are going to add it to the list of vectors
- self.vectors[self.want.name] = changes
-
- # Since the name attribute is not a parameter tracked in the Parameter
- # classes, we will add the name to the list of attributes so that when
- # we update the API, it creates the correct vector
- self.vectors[self.want.name].update({'name': self.want.name})
-
- # Finally, the disabled state forces us to remove the vector from the
- # list. However, items are only removed from the list if the profile
- # being configured is not a device-config
- if self.want.state == 'disabled':
- if self.want.profile != 'device-config':
- del self.vectors[self.want.name]
-
- # All of the vectors must be re-assembled into a list of dictionaries
- # so that when we PATCH the API endpoint, the vectors list is filled
- # correctly.
- #
- # There are **not** individual API endpoints for the individual vectors.
- # Instead, the endpoint includes a list of vectors that is part of the
- # DoS profile
- result = [v for k, v in iteritems(self.vectors)]
-
- self.changes = Changes(params={vtype: result})
- self.update_on_device()
- return True
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = kwargs.get('client', None)
- self.kwargs = kwargs
-
- def exec_module(self):
- if self.module.params['profile'] == 'device-config':
- manager = self.get_manager('v1')
- elif self.module.params['name'] in NETWORK_SECURITY_VECTORS:
- manager = self.get_manager('v2')
- elif self.module.params['name'] in PROTOCOL_DNS_VECTORS:
- manager = self.get_manager('v3')
- elif self.module.params['name'] in PROTOCOL_SIP_VECTORS:
- manager = self.get_manager('v4')
- else:
- raise F5ModuleError(
- "Unknown vector type specified."
- )
- return manager.exec_module()
-
- def get_manager(self, type):
- if type == 'v1':
- return DeviceConfigManager(**self.kwargs)
- elif type == 'v2':
- return NetworkSecurityManager(**self.kwargs)
- elif type == 'v3':
- return ProtocolDnsManager(**self.kwargs)
- elif type == 'v4':
- return ProtocolSipManager(**self.kwargs)
-
-
-class DeviceConfigManager(BaseManager):
- """Manages AFM DoS Device Configuration settings.
-
- DeviceConfiguration is a special type of profile that is specific to the
- BIG-IP device's management interface; not the data plane interfaces.
-
- There are many similar vectors that can be managed here. This configuration
- is a super-set of the base DoS profile vector configuration and includes
- several attributes per-vector that are not found in the DoS profile configuration.
- These include,
-
- * allowUpstreamScrubbing
- * attackedDst
- * autoScrubbing
- * defaultInternalRateLimit
- * detectionThresholdPercent
- * detectionThresholdPps
- * perDstIpDetectionPps
- * perDstIpLimitPps
- * scrubbingDetectionSeconds
- * scrubbingDuration
- """
- def __init__(self, *args, **kwargs):
- super(DeviceConfigManager, self).__init__(**kwargs)
- self.want = ModuleParameters(params=self.module.params)
- self.have = ApiParameters()
- self.changes = UsableChanges()
-
- def update(self):
- name = self.normalize_names_in_device_config(self.want.name)
-
- self.want.update({'name': name})
-
- return self._update('dosDeviceVector')
-
- def normalize_names_in_device_config(self, name):
- # Overwrite specific names because they do not align with DoS Profile names
- #
- # The following names (on the right) differ from the functionally equivalent
- # names (on the left) found in DoS Profiles. This seems like a bug to me,
- # but I do not expect it to be fixed, so this works around it in the meantime.
- name_map = {
- 'hop-cnt-low': 'hop-cnt-leq-one',
- 'ip-low-ttl': 'ttl-leq-one',
- }
-
- # Attempt to normalize, else just return the name. This handles the default
- # case where the name is actually correct and would not be found in the
- # ``name_map`` above.
- result = name_map.get(name, name)
- return result
-
- def update_on_device(self):
- params = self.changes.api_params()
- uri = "https://{0}:{1}/mgmt/tm/security/dos/device-config/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name('Common', 'dos-device-config')
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/security/dos/device-config/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name('Common', 'dos-device-config')
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- result = response.get('dosDeviceVector', [])
- return result
-
-
-class NetworkSecurityManager(BaseManager):
- """Manages AFM DoS Profile Network Security settings.
-
- Network Security settings are a sub-collection attached to each profile.
-
- There are many similar vectors that can be managed here. This configuration
- is a sub-set of the device-config DoS vector configuration and excludes
- several attributes per-vector that are found in the device-config configuration.
- These include,
-
- * rateIncrease
- * rateLimit
- * rateThreshold
- """
- def __init__(self, *args, **kwargs):
- super(NetworkSecurityManager, self).__init__(**kwargs)
- self.want = ModuleParameters(params=self.module.params)
- self.have = ApiParameters()
- self.changes = UsableChanges()
-
- def update(self):
- return self._update('networkAttackVector')
-
- def update_on_device(self):
- params = self.changes.api_params()
- uri = "https://{0}:{1}/mgmt/tm/security/dos/profile/{2}/dos-network/{3}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.profile),
- self.want.profile
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/security/dos/profile/{2}/dos-network/{3}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.profile),
- self.want.profile
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return response.get('networkAttackVector', [])
-
-
-class ProtocolDnsManager(BaseManager):
- """Manages AFM DoS Profile Protocol DNS settings.
-
- Protocol DNS settings are a sub-collection attached to each profile.
-
- There are many similar vectors that can be managed here. This configuration
- is a sub-set of the device-config DoS vector configuration and excludes
- several attributes per-vector that are found in the device-config configuration.
- These include,
-
- * rateIncrease
- * rateLimit
- * rateThreshold
- """
- def __init__(self, *args, **kwargs):
- super(ProtocolDnsManager, self).__init__(**kwargs)
- self.want = ModuleParameters(params=self.module.params)
- self.have = ApiParameters()
- self.changes = UsableChanges()
-
- def update(self):
- return self._update('dnsQueryVector')
-
- def update_on_device(self):
- params = self.changes.api_params()
- uri = "https://{0}:{1}/mgmt/tm/security/dos/profile/{2}/protocol-dns/{3}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.profile),
- self.want.profile
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/security/dos/profile/{2}/protocol-dns/{3}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.profile),
- self.want.profile
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return response.get('dnsQueryVector', [])
-
-
-class ProtocolSipManager(BaseManager):
- """Manages AFM DoS Profile Protocol SIP settings.
-
- Protocol SIP settings are a sub-collection attached to each profile.
-
- There are many similar vectors that can be managed here. This configuration
- is a sub-set of the device-config DoS vector configuration and excludes
- several attributes per-vector that are found in the device-config configuration.
- These include,
-
- * rateIncrease
- * rateLimit
- * rateThreshold
- """
- def __init__(self, *args, **kwargs):
- super(ProtocolSipManager, self).__init__(**kwargs)
- self.want = ModuleParameters(params=self.module.params)
- self.have = ApiParameters()
- self.changes = UsableChanges()
-
- def update(self):
- return self._update('sipAttackVector')
-
- def update_on_device(self):
- params = self.changes.api_params()
- uri = "https://{0}:{1}/mgmt/tm/security/dos/profile/{2}/protocol-sip/{3}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.profile),
- self.want.profile
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/security/dos/profile/{2}/protocol-sip/{3}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.profile),
- self.want.profile
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return response.get('sipAttackVector', [])
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- name=dict(
- required=True,
- choices=[
- 'ext-hdr-too-large',
- 'hop-cnt-low',
- 'host-unreachable',
- 'icmp-frag',
- 'icmpv4-flood',
- 'icmpv6-flood',
- 'ip-frag-flood',
- 'ip-low-ttl',
- 'ip-opt-frames',
- 'ipv6-frag-flood',
- 'opt-present-with-illegal-len',
- 'sweep',
- 'tcp-bad-urg',
- 'tcp-half-open',
- 'tcp-opt-overruns-tcp-hdr',
- 'tcp-psh-flood',
- 'tcp-rst-flood',
- 'tcp-syn-flood',
- 'tcp-syn-oversize',
- 'tcp-synack-flood',
- 'tcp-window-size',
- 'tidcmp',
- 'too-many-ext-hdrs',
- 'udp-flood',
- 'unk-tcp-opt-type',
- 'a',
- 'aaaa',
- 'any',
- 'axfr',
- 'cname',
- 'dns-malformed',
- 'ixfr',
- 'mx',
- 'ns',
- 'other',
- 'ptr',
- 'qdcount',
- 'soa',
- 'srv',
- 'txt',
- 'ack',
- 'bye',
- 'cancel',
- 'invite',
- 'message',
- 'notify',
- 'options',
- 'other',
- 'prack',
- 'publish',
- 'register',
- 'sip-malformed',
- 'subscribe',
- 'uri-limit',
- ]
- ),
- profile=dict(required=True),
- allow_advertisement=dict(type='bool'),
- auto_blacklist=dict(type='bool'),
- simulate_auto_threshold=dict(type='bool'),
- bad_actor_detection=dict(type='bool'),
- blacklist_detection_seconds=dict(type='int'),
- blacklist_duration=dict(type='int'),
- attack_ceiling=dict(),
- attack_floor=dict(),
- per_source_ip_detection_threshold=dict(),
- per_source_ip_mitigation_threshold=dict(),
- # sustained_attack_detection_time=dict(),
- # category_detection_time=dict(),
- # per_dest_ip_detection_threshold=dict(),
- # per_dest_ip_mitigation_threshold=dict(),
-
- detection_threshold_percent=dict(
- aliases=['rate_increase']
- ),
- detection_threshold_eps=dict(
- aliases=['rate_threshold']
- ),
- mitigation_threshold_eps=dict(
- aliases=['rate_limit']
- ),
- threshold_mode=dict(
- choices=['manual', 'stress-based-mitigation', 'fully-automatic']
- ),
- state=dict(
- choices=['mitigate', 'detect-only', 'learn-only', 'disabled'],
- ),
- partition=dict(
- default='Common',
- fallback=(env_fallback, ['F5_PARTITION'])
- )
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode,
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_firewall_global_rules.py b/lib/ansible/modules/network/f5/bigip_firewall_global_rules.py
deleted file mode 100644
index f0e036b2e7..0000000000
--- a/lib/ansible/modules/network/f5/bigip_firewall_global_rules.py
+++ /dev/null
@@ -1,381 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2018, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_firewall_global_rules
-short_description: Manage AFM global rule settings on BIG-IP
-description:
- - Configures the global network firewall rules. These firewall rules are
- applied to all packets except those going through the management
- interface. They are applied first, before any firewall rules for the
- packet's virtual server, route domain, and/or self IP.
-version_added: 2.8
-options:
- enforced_policy:
- description:
- - Specifies an enforced firewall policy.
- - C(enforced_policy) rules are enforced globally.
- type: str
- service_policy:
- description:
- - Specifies a service policy that would apply to traffic globally.
- - The service policy is applied to all flows, provided if there are
- no other context specific service policy configuration that
- overrides the global service policy. For example, when a service
- policy is configured both at a global level, as well as on a
- firewall rule, and a flow matches the rule, the more specific
- service policy configuration in the rule will override the service
- policy setting at the global level.
- - The service policy associated here can be created using the
- C(bigip_service_policy) module.
- type: str
- staged_policy:
- description:
- - Specifies a staged firewall policy.
- - C(staged_policy) rules are not enforced while all the visibility
- aspects namely statistics, reporting and logging function as if
- the staged-policy rules were enforced globally.
- type: str
- description:
- description:
- - Description for the global list of firewall rules.
- type: str
-extends_documentation_fragment: f5
-author:
- - Tim Rupp (@caphrim007)
-'''
-
-EXAMPLES = r'''
-- name: Change enforced policy in AFM global rules
- bigip_firewall_global_rules:
- enforced_policy: enforcing1
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-'''
-
-RETURN = r'''
-enforced_policy:
- description: The new global Enforced Policy.
- returned: changed
- type: str
- sample: /Common/enforced1
-service_policy:
- description: The new global Service Policy.
- returned: changed
- type: str
- sample: /Common/service1
-staged_policy:
- description: The new global Staged Policy.
- returned: changed
- type: str
- sample: /Common/staged1
-description:
- description: The new description.
- returned: changed
- type: str
- sample: My description
-'''
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import fq_name
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.compare import cmp_str_with_none
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import fq_name
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.compare import cmp_str_with_none
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'enforcedPolicy': 'enforced_policy',
- 'servicePolicy': 'service_policy',
- 'stagedPolicy': 'staged_policy',
- }
-
- api_attributes = [
- 'enforcedPolicy',
- 'servicePolicy',
- 'stagedPolicy',
- 'description',
- ]
-
- returnables = [
- 'enforced_policy',
- 'service_policy',
- 'staged_policy',
- 'description',
- ]
-
- updatables = [
- 'enforced_policy',
- 'service_policy',
- 'staged_policy',
- 'description',
- ]
-
-
-class ApiParameters(Parameters):
- @property
- def description(self):
- if self._values['description'] in [None, 'none']:
- return None
- return self._values['description']
-
-
-class ModuleParameters(Parameters):
- @property
- def enforced_policy(self):
- if self._values['enforced_policy'] is None:
- return None
- if self._values['enforced_policy'] in ['', 'none']:
- return ''
- return fq_name(self.partition, self._values['enforced_policy'])
-
- @property
- def service_policy(self):
- if self._values['service_policy'] is None:
- return None
- if self._values['service_policy'] in ['', 'none']:
- return ''
- return fq_name(self.partition, self._values['service_policy'])
-
- @property
- def staged_policy(self):
- if self._values['staged_policy'] is None:
- return None
- if self._values['staged_policy'] in ['', 'none']:
- return ''
- return fq_name(self.partition, self._values['staged_policy'])
-
- @property
- def description(self):
- if self._values['description'] is None:
- return None
- elif self._values['description'] in ['none', '']:
- return ''
- return self._values['description']
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class UsableChanges(Changes):
- pass
-
-
-class ReportableChanges(Changes):
- pass
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
- @property
- def description(self):
- return cmp_str_with_none(self.want.description, self.have.description)
-
- @property
- def enforced_policy(self):
- return cmp_str_with_none(self.want.enforced_policy, self.have.enforced_policy)
-
- @property
- def staged_policy(self):
- return cmp_str_with_none(self.want.staged_policy, self.have.staged_policy)
-
- @property
- def service_policy(self):
- return cmp_str_with_none(self.want.service_policy, self.have.service_policy)
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(params=self.module.params)
- self.have = ApiParameters()
- self.changes = UsableChanges()
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = UsableChanges(params=changed)
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def exec_module(self):
- result = dict()
-
- changed = self.present()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.client.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def present(self):
- return self.update()
-
- def update(self):
- self.have = self.read_current_from_device()
- if not self.should_update():
- return False
- if self.module.check_mode:
- return True
- self.update_on_device()
- return True
-
- def update_on_device(self):
- params = self.changes.api_params()
- uri = "https://{0}:{1}/mgmt/tm/security/firewall/global-rules".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/security/firewall/global-rules".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return ApiParameters(params=response)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- enforced_policy=dict(),
- service_policy=dict(),
- staged_policy=dict(),
- description=dict(),
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode,
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_firewall_log_profile.py b/lib/ansible/modules/network/f5/bigip_firewall_log_profile.py
deleted file mode 100644
index 7732004173..0000000000
--- a/lib/ansible/modules/network/f5/bigip_firewall_log_profile.py
+++ /dev/null
@@ -1,880 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2019, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_firewall_log_profile
-short_description: Manages AFM logging profiles configured in the system
-description:
- - Manages AFM logging profiles configured in the system along with basic information about each profile.
-version_added: 2.9
-options:
- name:
- description:
- - Specifies the name of the log profile.
- type: str
- required: True
- description:
- description:
- - Description of the log profile.
- type: str
- dos_protection:
- description:
- - Configures DoS related settings of the log profile.
- suboptions:
- dns_publisher:
- description:
- - Specifies the name of the log publisher used for DNS DoS events.
- - To specify the log_publisher on a different partition from the AFM log profile, specify the name in fullpath
- format, e.g. C(/Foobar/log-publisher), otherwise the partition for log publisher
- is inferred from C(partition) module parameter.
- type: str
- sip_publisher:
- description:
- - Specifies the name of the log publisher used for SIP DoS events.
- - To specify the log_publisher on a different partition from the AFM log profile, specify the name in fullpath
- format, e.g. C(/Foobar/log-publisher), otherwise the partition for log publisher
- is inferred from C(partition) module parameter.
- type: str
- network_publisher:
- description:
- - Specifies the name of the log publisher used for DoS Network events.
- - To specify the log_publisher on a different partition from the AFM log profile, specify the name in fullpath
- format, e.g. C(/Foobar/log-publisher), otherwise the partition for log publisher
- is inferred from C(partition) module parameter.
- type: str
- type: dict
- ip_intelligence:
- description:
- - Configures IP Intelligence related settings of the log profile.
- suboptions:
- log_publisher:
- description:
- - Specifies the name of the log publisher used for IP Intelligence events.
- - To specify the log_publisher on a different partition from the AFM log profile, specify the name in fullpath
- format, e.g. C(/Foobar/log-publisher), otherwise the partition for log publisher
- is inferred from C(partition) module parameter.
- type: str
- rate_limit:
- description:
- - Defines a rate limit for all combined IP intelligence log messages per second. Beyond this rate limit,
- log messages are not logged until the threshold drops below the specified rate.
- - To specify an indefinite rate, use the value C(indefinite).
- - If specifying a numeric rate, the value must be between C(1) and C(4294967295).
- type: str
- log_rtbh:
- description:
- - Specifies, when C(yes), that remotely triggered blackholing events are logged.
- type: bool
- log_shun:
- description:
- - Specifies, when C(yes), that IP Intelligence shun list events are logged.
- - This option can only be set on C(global-network) built-in profile
- type: bool
- log_translation_fields:
- description:
- - This option is used to enable or disable the logging of translated (i.e server side) fields in IP
- Intelligence log messages.
- - Translated fields include (but are not limited to) source address/port, destination address/port,
- IP protocol, route domain, and VLAN.
- type: bool
- type: dict
- port_misuse:
- description:
- - Port Misuse log configuration.
- suboptions:
- log_publisher:
- description:
- - Specifies the name of the log publisher used for Port Misuse events.
- - To specify the log_publisher on a different partition from the AFM log profile, specify the name in fullpath
- format, e.g. C(/Foobar/log-publisher), otherwise the partition for log publisher
- is inferred from C(partition) module parameter.
- type: str
- rate_limit:
- description:
- - Defines a rate limit for all combined port misuse log messages per second. Beyond this rate limit,
- log messages are not logged until the threshold drops below the specified rate.
- - To specify an indefinite rate, use the value C(indefinite).
- - If specifying a numeric rate, the value must be between C(1) and C(4294967295).
- type: str
- type: dict
- partition:
- description:
- - Device partition to create log profile on.
- - Parameter also used when specifying names for log publishers, unless log publisher names are in fullpath format.
- type: str
- default: Common
- state:
- description:
- - When C(state) is C(present), ensures the resource exists.
- - When C(state) is C(absent), ensures that resource is removed. Attempts to remove built-in system profiles are
- ignored and no change is returned.
- type: str
- choices:
- - present
- - absent
- default: present
-extends_documentation_fragment: f5
-author:
- - Wojciech Wypior (@wojtek0806)
-'''
-
-EXAMPLES = r'''
-- name: Create a basic log profile with port misuse
- bigip_firewall_log_profile:
- name: barbaz
- port_misuse:
- rate_limit: 30000
- log_publisher: local-db-pub
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-
-- name: Change ip_intelligence settings, publisher on different partition, remove port misuse
- bigip_firewall_log_profile:
- name: barbaz
- ip_intelligence:
- rate_limit: 400000
- log_translation_fields: yes
- log_rtbh: yes
- log_publisher: "/foobar/non-local-db"
- port_misuse:
- log_publisher: ""
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-
-- name: Create a log profile with dos protection, different partition
- bigip_firewall_log_profile:
- name: foobar
- partition: foobar
- dos_protection:
- dns_publisher: "/Common/local-db-pub"
- sip_publisher: "non-local-db"
- network_publisher: "/Common/local-db-pub"
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-
-- name: Remove log profile
- bigip_firewall_log_profile:
- name: barbaz
- partition: Common
- state: absent
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-'''
-
-RETURN = r'''
-description:
- description: New description of the AFM log profile.
- returned: changed
- type: str
- sample: This is my description
-dos_protection:
- description: Log publishers used in DoS related settings of the log profile.
- type: complex
- returned: changed
- contains:
- dns_publisher:
- description: The name of the log publisher used for DNS DoS events.
- returned: changed
- type: str
- sample: "/Common/local-db-publisher"
- sip_publisher:
- description: The name of the log publisher used for SIP DoS events.
- returned: changed
- type: str
- sample: "/Common/local-db-publisher"
- network_publisher:
- description: The name of the log publisher used for DoS Network events.
- returned: changed
- type: str
- sample: "/Common/local-db-publisher"
- sample: hash/dictionary of values
-ip_intelligence:
- description: IP Intelligence related settings of the log profile.
- type: complex
- returned: changed
- contains:
- log_publisher:
- description: The name of the log publisher used for IP Intelligence events.
- returned: changed
- type: str
- sample: "/Common/local-db-publisher"
- rate_limit:
- description: The rate limit for all combined IP intelligence log messages per second.
- returned: changed
- type: str
- sample: "indefinite"
- log_rtbh:
- description: Logging of remotely triggered blackholing events.
- returned: changed
- type: bool
- sample: yes
- log_shun:
- description: Logging of IP Intelligence shun list events.
- returned: changed
- type: bool
- sample: no
- log_translation_fields:
- description: Logging of translated fields in IP Intelligence log messages.
- returned: changed
- type: bool
- sample: no
- sample: hash/dictionary of values
-port_misuse:
- description: Port Misuse related settings of the log profile.
- type: complex
- returned: changed
- contains:
- log_publisher:
- description: The name of the log publisher used for Port Misuse events.
- returned: changed
- type: str
- sample: "/Common/local-db-publisher"
- rate_limit:
- description: The rate limit for all combined Port Misuse log messages per second.
- returned: changed
- type: str
- sample: "indefinite"
- sample: hash/dictionary of values
-'''
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.basic import env_fallback
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import fq_name
- from library.module_utils.network.f5.common import transform_name
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.common import flatten_boolean
- from library.module_utils.network.f5.compare import compare_dictionary
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import fq_name
- from ansible.module_utils.network.f5.common import transform_name
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.common import flatten_boolean
- from ansible.module_utils.network.f5.compare import compare_dictionary
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'ipIntelligence': 'ip_intelligence',
- 'portMisuse': 'port_misuse',
- 'protocolDnsDosPublisher': 'dns_publisher',
- 'protocolSipDosPublisher': 'sip_publisher',
- 'dosNetworkPublisher': 'network_publisher',
- }
-
- api_attributes = [
- 'description',
- 'ipIntelligence',
- 'portMisuse',
- 'dosNetworkPublisher',
- 'protocolDnsDosPublisher',
- 'protocolSipDosPublisher',
- ]
-
- returnables = [
- 'ip_intelligence',
- 'dns_publisher',
- 'sip_publisher',
- 'network_publisher',
- 'port_misuse',
- 'description',
- 'ip_log_publisher',
- 'ip_rate_limit',
- 'ip_log_rthb',
- 'ip_log_shun',
- 'ip_log_translation_fields',
- 'port_rate_limit',
- 'port_log_publisher',
- ]
-
- updatables = [
- 'dns_publisher',
- 'sip_publisher',
- 'network_publisher',
- 'description',
- 'ip_log_publisher',
- 'ip_rate_limit',
- 'ip_log_rthb',
- 'ip_log_shun',
- 'ip_log_translation_fields',
- 'port_rate_limit',
- 'port_log_publisher',
- ]
-
-
-class ApiParameters(Parameters):
- @property
- def ip_log_publisher(self):
- result = self._values['ip_intelligence'].get('logPublisher', None)
- return result
-
- @property
- def ip_rate_limit(self):
- return self._values['ip_intelligence']['aggregateRate']
-
- @property
- def port_rate_limit(self):
- return self._values['port_misuse']['aggregateRate']
-
- @property
- def port_log_publisher(self):
- result = self._values['port_misuse'].get('logPublisher', None)
- return result
-
- @property
- def ip_log_rtbh(self):
- return self._values['ip_intelligence']['logRtbh']
-
- @property
- def ip_log_shun(self):
- if self._values['name'] != 'global-network':
- return None
- return self._values['ip_intelligence']['logShun']
-
- @property
- def ip_log_translation_fields(self):
- return self._values['ip_intelligence']['logTranslationFields']
-
-
-class ModuleParameters(Parameters):
- def _transform_log_publisher(self, log_publisher):
- if log_publisher is None:
- return None
- if log_publisher in ['', 'none']:
- return {}
- return fq_name(self.partition, log_publisher)
-
- def _validate_rate_limit(self, rate_limit):
- if rate_limit is None:
- return None
- if rate_limit == 'indefinite':
- return 4294967295
- if 0 <= int(rate_limit) <= 4294967295:
- return int(rate_limit)
- raise F5ModuleError(
- "Valid 'maximum_age' must be in range 0 - 4294967295, or 'indefinite'."
- )
-
- @property
- def ip_log_rtbh(self):
- if self._values['ip_intelligence'] is None:
- return None
- result = flatten_boolean(self._values['ip_intelligence']['log_rtbh'])
- if result == 'yes':
- return 'enabled'
- if result == 'no':
- return 'disabled'
- return result
-
- @property
- def ip_log_shun(self):
- if self._values['ip_intelligence'] is None:
- return None
- if 'global-network' not in self._values['name']:
- return None
- result = flatten_boolean(self._values['ip_intelligence']['log_shun'])
- if result == 'yes':
- return 'enabled'
- if result == 'no':
- return 'disabled'
- return result
-
- @property
- def ip_log_translation_fields(self):
- if self._values['ip_intelligence'] is None:
- return None
- result = flatten_boolean(self._values['ip_intelligence']['log_translation_fields'])
- if result == 'yes':
- return 'enabled'
- if result == 'no':
- return 'disabled'
- return result
-
- @property
- def ip_log_publisher(self):
- if self._values['ip_intelligence'] is None:
- return None
- result = self._transform_log_publisher(self._values['ip_intelligence']['log_publisher'])
- return result
-
- @property
- def ip_rate_limit(self):
- if self._values['ip_intelligence'] is None:
- return None
- return self._validate_rate_limit(self._values['ip_intelligence']['rate_limit'])
-
- @property
- def port_rate_limit(self):
- if self._values['port_misuse'] is None:
- return None
- return self._validate_rate_limit(self._values['port_misuse']['rate_limit'])
-
- @property
- def port_log_publisher(self):
- if self._values['port_misuse'] is None:
- return None
- result = self._transform_log_publisher(self._values['port_misuse']['log_publisher'])
- return result
-
- @property
- def dns_publisher(self):
- if self._values['dos_protection'] is None:
- return None
- result = self._transform_log_publisher(self._values['dos_protection']['dns_publisher'])
- return result
-
- @property
- def sip_publisher(self):
- if self._values['dos_protection'] is None:
- return None
- result = self._transform_log_publisher(self._values['dos_protection']['sip_publisher'])
- return result
-
- @property
- def network_publisher(self):
- if self._values['dos_protection'] is None:
- return None
- result = self._transform_log_publisher(self._values['dos_protection']['network_publisher'])
- return result
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class UsableChanges(Changes):
- @property
- def ip_intelligence(self):
- to_filter = dict(
- logPublisher=self._values['ip_log_publisher'],
- aggregateRate=self._values['ip_rate_limit'],
- logRtbh=self._values['ip_log_rtbh'],
- logShun=self._values['ip_log_shun'],
- logTranslationFields=self._values['ip_log_translation_fields']
- )
- result = self._filter_params(to_filter)
- if result:
- return result
-
- @property
- def port_misuse(self):
- to_filter = dict(
- logPublisher=self._values['port_log_publisher'],
- aggregateRate=self._values['port_rate_limit']
- )
- result = self._filter_params(to_filter)
- if result:
- return result
-
-
-class ReportableChanges(Changes):
- returnables = [
- 'ip_intelligence',
- 'port_misuse',
- 'description',
- 'dos_protection',
- ]
-
- def _change_rate_limit_value(self, value):
- if value == 4294967295:
- return 'indefinite'
- else:
- return value
-
- @property
- def ip_log_rthb(self):
- result = flatten_boolean(self._values['ip_log_rtbh'])
- return result
-
- @property
- def ip_log_shun(self):
- result = flatten_boolean(self._values['ip_log_shun'])
- return result
-
- @property
- def ip_log_translation_fields(self):
- result = flatten_boolean(self._values['ip_log_translation_fields'])
- return result
-
- @property
- def ip_intelligence(self):
- if self._values['ip_intelligence'] is None:
- return None
- to_filter = dict(
- log_publisher=self._values['ip_log_publisher'],
- rate_limit=self._change_rate_limit_value(self._values['ip_rate_limit']),
- log_rtbh=self.ip_log_rtbh,
- log_shun=self.ip_log_shun,
- log_translation_fields=self.ip_log_translation_fields
- )
- result = self._filter_params(to_filter)
- if result:
- return result
-
- @property
- def port_misuse(self):
- if self._values['port_misuse'] is None:
- return None
- to_filter = dict(
- log_publisher=self._values['port_log_publisher'],
- rate_limit=self._change_rate_limit_value(self._values['port_rate_limit']),
- )
- result = self._filter_params(to_filter)
- if result:
- return result
-
- @property
- def dos_protection(self):
- to_filter = dict(
- dns_publisher=self._values['dns_publisher'],
- sip_publisher=self._values['sip_publisher'],
- network_publisher=self._values['network_publisher'],
- )
- result = self._filter_params(to_filter)
- return result
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
- @property
- def ip_log_publisher(self):
- result = compare_dictionary(self.want.ip_log_publisher, self.have.ip_log_publisher)
- return result
-
- @property
- def port_log_publisher(self):
- result = compare_dictionary(self.want.port_log_publisher, self.have.port_log_publisher)
- return result
-
- @property
- def dns_publisher(self):
- result = compare_dictionary(self.want.dns_publisher, self.have.dns_publisher)
- return result
-
- @property
- def sip_publisher(self):
- result = compare_dictionary(self.want.sip_publisher, self.have.sip_publisher)
- return result
-
- @property
- def network_publisher(self):
- result = compare_dictionary(self.want.network_publisher, self.have.network_publisher)
- return result
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(params=self.module.params)
- self.have = ApiParameters()
- self.changes = UsableChanges()
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = UsableChanges(params=changed)
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.client.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def exec_module(self):
- changed = False
- result = dict()
- state = self.want.state
-
- if state == "present":
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def present(self):
- if self.exists():
- return self.update()
- else:
- return self.create()
-
- def absent(self):
- # Built-in profiles cannot be removed
- built_ins = [
- 'Log all requests', 'Log illegal requests',
- 'global-network', 'local-dos'
- ]
- if self.want.name in built_ins:
- return False
- if self.exists():
- return self.remove()
- return False
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def update(self):
- self.have = self.read_current_from_device()
- if not self.should_update():
- return False
- if self.module.check_mode:
- return True
- self.update_on_device()
- return True
-
- def remove(self):
- if self.module.check_mode:
- return True
- self.remove_from_device()
- if self.exists():
- raise F5ModuleError("Failed to delete the resource.")
- return True
-
- def create(self):
- self._set_changed_options()
- if self.module.check_mode:
- return True
- self.create_on_device()
- return True
-
- def exists(self):
- uri = "https://{0}:{1}/mgmt/tm/security/log/profile/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def create_on_device(self):
- params = self.changes.api_params()
- params['name'] = self.want.name
- params['partition'] = self.want.partition
- uri = "https://{0}:{1}/mgmt/tm/security/log/profile/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 404, 409]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return True
-
- def update_on_device(self):
- params = self.changes.api_params()
- uri = "https://{0}:{1}/mgmt/tm/security/log/profile/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 404, 409]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def remove_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/security/log/profile/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- response = self.client.api.delete(uri)
- if response.status == 200:
- return True
- raise F5ModuleError(response.content)
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/security/log/profile/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 404, 409]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return ApiParameters(params=response)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- name=dict(
- required=True
- ),
- description=dict(),
- dos_protection=dict(
- type='dict',
- options=dict(
- dns_publisher=dict(),
- sip_publisher=dict(),
- network_publisher=dict()
- )
- ),
- ip_intelligence=dict(
- type='dict',
- options=dict(
- log_publisher=dict(),
- log_translation_fields=dict(type='bool'),
- rate_limit=dict(),
- log_rtbh=dict(type='bool'),
- log_shun=dict(type='bool')
- )
- ),
- port_misuse=dict(
- type='dict',
- options=dict(
- log_publisher=dict(),
- rate_limit=dict()
- )
- ),
- partition=dict(
- default='Common',
- fallback=(env_fallback, ['F5_PARTITION'])
- ),
- state=dict(
- default='present',
- choices=['present', 'absent']
- )
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode,
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_firewall_log_profile_network.py b/lib/ansible/modules/network/f5/bigip_firewall_log_profile_network.py
deleted file mode 100644
index 44d036cf59..0000000000
--- a/lib/ansible/modules/network/f5/bigip_firewall_log_profile_network.py
+++ /dev/null
@@ -1,1269 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2019, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_firewall_log_profile_network
-short_description: Configures Network Firewall related settings of the log profile
-description:
- - Configures Network Firewall related settings of the log profile.
-version_added: 2.9
-options:
- profile_name:
- description:
- - Specifies the name of the AFM log profile to be updated.
- type: str
- required: True
- log_publisher:
- description:
- - Specifies the name of the log publisher used for Network events.
- - To specify the log_publisher on a different partition from the AFM log profile, specify the name in fullpath
- format, e.g. C(/Foobar/log-publisher), otherwise the partition for log publisher is inferred from C(partition)
- module parameter.
- type: str
- rate_limit:
- description:
- - Defines a rate limit for all combined network firewall log messages per second. Beyond this rate limit,
- log messages are not logged.
- - To specify an indefinite rate, use the value C(indefinite).
- - If specifying a numeric rate, the value must be between C(1) and C(4294967295).
- type: str
- log_matches_accept_rule:
- description:
- - Modify log settings for ACL rules configured with an "accept" or "accept decisively" action.
- suboptions:
- enabled:
- description:
- - This option is used to enable or disable the logging of packets that match ACL rules configured with
- an "accept" or "accept decisively" action.
- type: bool
- rate_limit:
- description:
- - This option is used to set rate limits for the logging of packets that match ACL rules
- configured with an "accept" or "accept decisively" action.
- - This option is effective only if logging of this message type is enabled.
- type: int
- type: dict
- log_matches_drop_rule:
- description:
- - Modify log settings for ACL rules configured with a drop action.
- suboptions:
- enabled:
- description:
- - This option is used to enable or disable the logging of packets that match ACL rules
- configured with a drop action.
- type: bool
- rate_limit:
- description:
- - This option is used to set rate limits for the logging of packets that match ACL rules
- configured with a drop action.
- - This option is effective only if logging of this message type is enabled.
- type: int
- type: dict
- log_matches_reject_rule:
- description:
- - Modify log settings for ACL rules configured with a reject action.
- suboptions:
- enabled:
- description:
- - This option is used to enable or disable the logging of packets that match ACL rules
- configured with a reject action.
- type: bool
- rate_limit:
- description:
- - This option is used to set rate limits for the logging of packets that match ACL rules
- configured with a reject action.
- - This option is effective only if logging of this message type is enabled.
- type: int
- type: dict
- log_ip_errors:
- description:
- - Modify log settings for logging of IP error packets.
- suboptions:
- enabled:
- description:
- - This option is used to enable or disable the logging of IP error packets.
- type: bool
- rate_limit:
- description:
- - This option is used to set rate limits for the logging of IP error packets.
- - This option is effective only if logging of this message type is enabled.
- type: int
- type: dict
- log_tcp_errors:
- description:
- - Modify log settings for logging of TCP error packets.
- suboptions:
- enabled:
- description:
- - This option is used to enable or disable the logging of TCP error packets.
- type: bool
- rate_limit:
- description:
- - This option is used to set rate limits for the logging of TCP error packets.
- - This option is effective only if logging of this message type is enabled.
- type: int
- type: dict
- log_tcp_events:
- description:
- - Modify log settings for logging of TCP events on the client side.
- suboptions:
- enabled:
- description:
- - This option is used to enable or disable the logging of TCP events on the client side.
- - Only 'Established' and 'Closed' states of a TCP session are logged if this option is enabled.
- type: bool
- rate_limit:
- description:
- - This option is used to set rate limits for the logging of TCP events on the client side.
- - This option is effective only if logging of this message type is enabled.
- type: int
- type: dict
- log_translation_fields:
- description:
- - This option is used to enable or disable the logging of translated (i.e server side) fields in ACL
- match and TCP events.
- - Translated fields include (but are not limited to) source address/port, destination address/port,
- IP protocol, route domain, and VLAN.
- type: bool
- log_storage_format:
- description:
- - Specifies the type of the storage format.
- - When creating a new log profile, if this parameter is not specified, the default is C(none).
- - When C(field-list), specifies that the log displays only the items you specify in the C(log_message_fields) list
- with C(log_format_delimiter) as the delimiter between the items.
- - When C(none), the messages will be logged in the default format, which is C("management_ip_address",
- "bigip_hostname","context_type", "context_name","src_geo","src_ip", "dest_geo","dest_ip","src_port",
- "dest_port","vlan","protocol","route_domain", "translated_src_ip", "translated_dest_ip",
- "translated_src_port","translated_dest_port", "translated_vlan","translated_ip_protocol",
- "translated_route_domain", "acl_policy_type", "acl_policy_name","acl_rule_name","action",
- "drop_reason","sa_translation_type", "sa_translation_pool","flow_id", "source_user",
- "source_fqdn","dest_fqdn").
- choices:
- - field-list
- - none
- type: str
- log_format_delimiter:
- description:
- - Specifies the delimiter string when using a C(log_storage_format) of C(field-list).
- - When creating a new profile, if this parameter is not specified, the default value of C(,)
- (the comma character) will be used.
- - This option is valid when the C(log_storage_format) is set to C(field-list). It will be ignored otherwise.
- - Depending on the delimiter used, it may be necessary to wrap the delimiter
- in quotes to prevent YAML errors from occurring.
- - The special character C($) should not be used, and will raise an error if used,
- as it is reserved for internal use.
- - The maximum length allowed for this parameter is C(31) characters.
- type: str
- log_message_fields:
- description:
- - Specifies a set of fields to be logged.
- - This option is valid when the C(log_storage_format) is set to C(field-list). It will be ignored otherwise.
- - The order of the list is important as the server displays the selected traffic items in the log
- sequentially according to it.
- type: list
- choices:
- - acl_policy_name
- - acl_policy_type
- - acl_rule_name
- - action
- - bigip_hostname
- - context_name
- - context_type
- - date_time
- - dest_fqdn
- - dest_geo
- - dest_ip
- - dest_port
- - drop_reason
- - management_ip_address
- - protocol
- - route_domain
- - sa_translation_pool
- - sa_translation_type
- - source_fqdn
- - source_user
- - src_geo
- - src_ip
- - src_port
- - translated_dest_ip
- - translated_dest_port
- - translated_ip_protocol
- - translated_route_domain
- - translated_src_ip
- - translated_src_port
- - translated_vlan
- - vlan
- partition:
- description:
- - Device partition to create log profile on.
- - Parameter also used when specifying names for log publishers, unless log publisher names are in fullpath format.
- type: str
- default: Common
- state:
- description:
- - When C(state) is C(present), ensures the resource exists.
- - Only built-in profile that allows updating network log settings is global-network, attempts to do so on other
- built-in profiles will be ignored.
- - When C(state) is C(absent), ensures that resource is removed.
- - The C(absent) state is ignored for global-network log profile.
- type: str
- choices:
- - present
- - absent
- default: present
-extends_documentation_fragment: f5
-author:
- - Wojciech Wypior (@wojtek0806)
-'''
-
-EXAMPLES = r'''
-- name: Add network settings to log profile
- bigip_firewall_log_profile_network:
- profile_name: barbaz
- rate_limit: 150000
- log_publisher: local-db-pub
- log_tcp_errors:
- enabled: yes
- rate_limit: 10000
- log_tcp_events:
- enabled: yes
- rate_limit: 40000
- log_storage_format: "field-list"
- log_message_fields:
- - vlan
- - translated_vlan
- - src_ip
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-
-- name: Change delimiter and log fields
- bigip_firewall_log_profile_network:
- profile_name: barbaz
- log_format_delimiter: '.'
- log_message_fields:
- - translated_dest_ip
- - translated_dest_port
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-
-- name: Modify built-in profile
- bigip_firewall_log_profile_network:
- profile_name: "global-network"
- log_publisher: "/foobar/log1"
- log_ip_errors:
- enabled: yes
- rate_limit: 60000
- log_matches_reject_rule:
- enabled: yes
- rate_limit: 2000
- log_translation_fields: yes
- log_storage_format: "field-list"
- log_format_delimiter: '.'
- log_message_fields:
- - protocol
- - dest_ip
- - dest_port
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-
-- name: Remove custom log profile network log settings
- bigip_firewall_log_profile_network:
- profile_name: "{{ log_profile }}"
- state: absent
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-'''
-
-RETURN = r'''
-log_publisher:
- description: The name of the log publisher used for Network events.
- returned: changed
- type: str
- sample: /Common/log-publisher
-rate_limit:
- description: The rate limit for all combined network firewall log messages per second.
- returned: changed
- type: str
- sample: "indefinite"
-log_matches_accept_rule:
- description: Log settings for ACL rules configured with an "accept" or "accept decisively" action.
- type: complex
- returned: changed
- contains:
- enabled:
- description: Enable or disable the logging of packets that match ACL rules.
- returned: changed
- type: bool
- sample: yes
- rate_limit:
- description: The rate limit for the logging of packets that match ACL rules.
- returned: changed
- type: str
- sample: "indefinite"
- sample: hash/dictionary of values
-log_matches_drop_rule:
- description: Log settings for ACL rules configured with a drop action.
- type: complex
- returned: changed
- contains:
- enabled:
- description: Enable or disable the logging of packets that match ACL rules.
- returned: changed
- type: bool
- sample: yes
- rate_limit:
- description: The rate limit for the logging of packets that match ACL rules.
- returned: changed
- type: str
- sample: "indefinite"
- sample: hash/dictionary of values
-log_matches_reject_rule:
- description: Log settings for ACL rules configured with a reject action.
- type: complex
- returned: changed
- contains:
- enabled:
- description: Enable or disable the logging of packets that match ACL rules.
- returned: changed
- type: bool
- sample: yes
- rate_limit:
- description: The rate limit for the logging of packets that match ACL rules.
- returned: changed
- type: str
- sample: "indefinite"
- sample: hash/dictionary of values
-log_ip_errors:
- description: Log settings for logging of IP error packets.
- type: complex
- returned: changed
- contains:
- enabled:
- description: Enable or disable the logging of IP error packets.
- returned: changed
- type: bool
- sample: yes
- rate_limit:
- description: The rate limit for the logging of IP error packets.
- returned: changed
- type: str
- sample: "indefinite"
- sample: hash/dictionary of values
-log_tcp_errors:
- description: Log settings for logging of TCP error packets.
- type: complex
- returned: changed
- contains:
- enabled:
- description: Enable or disable the logging of TCP error packets.
- returned: changed
- type: bool
- sample: yes
- rate_limit:
- description: The rate limit for the logging of TCP error packets.
- returned: changed
- type: str
- sample: "indefinite"
- sample: hash/dictionary of values
-log_tcp_events:
- description: Log settings for logging of TCP events on the client side.
- type: complex
- returned: changed
- contains:
- enabled:
- description: Enable or disable the logging of TCP events on the client side.
- returned: changed
- type: bool
- sample: yes
- rate_limit:
- description: The rate limit for the logging of TCP events on the client side.
- returned: changed
- type: str
- sample: "indefinite"
- sample: hash/dictionary of values
-log_translation_fields:
- description: Enable or disable the logging of translated (i.e server side) fields in ACL match and TCP events.
- returned: changed
- type: bool
- sample: yes
-log_storage_format:
- description: The type of the storage format.
- returned: changed
- type: str
- sample: "field-list"
-log_format_delimiter:
- description: The delimiter string when using a log_storage_format of field-list.
- returned: changed
- type: str
- sample: "."
-log_message_fields:
- description: The delimiter string when using a log_storage_format of field-list.
- returned: changed
- type: list
- sample: ["acl_policy_name", "acl_policy_type"]
-'''
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.basic import env_fallback
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import fq_name
- from library.module_utils.network.f5.common import transform_name
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.common import flatten_boolean
- from library.module_utils.network.f5.compare import cmp_str_with_none
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import fq_name
- from ansible.module_utils.network.f5.common import transform_name
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.common import flatten_boolean
- from ansible.module_utils.network.f5.compare import cmp_str_with_none
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'publisher': 'log_publisher',
- 'rateLimit': 'rate_limits',
- }
-
- api_attributes = [
- 'publisher',
- 'format',
- 'rateLimit',
- 'filter',
- ]
-
- returnables = [
- 'rate_acl_match_accept',
- 'rate_acl_match_drop',
- 'rate_acl_match_reject',
- 'rate_tcp_errors',
- 'rate_tcp_events',
- 'rate_ip_errors',
- 'rate_limit',
- 'log_acl_match_accept',
- 'log_acl_match_drop',
- 'log_acl_match_reject',
- 'log_tcp_errors',
- 'log_tcp_events',
- 'log_ip_errors',
- 'log_translation_fields',
- 'log_publisher',
- 'log_format_delimiter',
- 'log_storage_format',
- 'log_message_fields',
- 'log_matches_accept_rule',
- 'log_matches_drop_rule',
- 'log_matches_reject_rule',
- ]
-
- updatables = [
- 'rate_acl_match_accept',
- 'rate_acl_match_drop',
- 'rate_acl_match_reject',
- 'rate_tcp_errors',
- 'rate_tcp_events',
- 'rate_ip_errors',
- 'rate_limit',
- 'log_acl_match_accept',
- 'log_acl_match_drop',
- 'log_acl_match_reject',
- 'log_tcp_errors',
- 'log_tcp_events',
- 'log_ip_errors',
- 'log_translation_fields',
- 'log_publisher',
- 'log_format_delimiter',
- 'log_storage_format',
- 'log_message_fields',
- ]
-
-
-class ApiParameters(Parameters):
- @property
- def rate_acl_match_accept(self):
- if self._values['rate_limits'] is None:
- return None
- return self._values['rate_limits']['aclMatchAccept']
-
- @property
- def log_acl_match_accept(self):
- if self._values['filter'] is None:
- return None
- return self._values['filter']['logAclMatchAccept']
-
- @property
- def rate_acl_match_drop(self):
- if self._values['rate_limits'] is None:
- return None
- return self._values['rate_limits']['aclMatchDrop']
-
- @property
- def log_acl_match_drop(self):
- if self._values['filter'] is None:
- return None
- return self._values['filter']['logAclMatchDrop']
-
- @property
- def rate_acl_match_reject(self):
- if self._values['rate_limits'] is None:
- return None
- return self._values['rate_limits']['aclMatchReject']
-
- @property
- def log_acl_match_reject(self):
- if self._values['filter'] is None:
- return None
- return self._values['filter']['logAclMatchReject']
-
- @property
- def rate_tcp_errors(self):
- if self._values['rate_limits'] is None:
- return None
- return self._values['rate_limits']['tcpErrors']
-
- @property
- def log_tcp_errors(self):
- if self._values['filter'] is None:
- return None
- return self._values['filter']['logTcpErrors']
-
- @property
- def rate_tcp_events(self):
- if self._values['rate_limits'] is None:
- return None
- return self._values['rate_limits']['tcpEvents']
-
- @property
- def log_tcp_events(self):
- if self._values['filter'] is None:
- return None
- return self._values['filter']['logTcpEvents']
-
- @property
- def rate_ip_errors(self):
- if self._values['rate_limits'] is None:
- return None
- return self._values['rate_limits']['ipErrors']
-
- @property
- def log_ip_errors(self):
- if self._values['filter'] is None:
- return None
- return self._values['filter']['logIpErrors']
-
- @property
- def log_translation_fields(self):
- if self._values['filter'] is None:
- return None
- return self._values['filter']['logTranslationFields']
-
- @property
- def rate_limit(self):
- if self._values['rate_limits'] is None:
- return None
- return self._values['rate_limits']['aggregateRate']
-
- @property
- def log_format_delimiter(self):
- if self._values['format'] is None:
- return None
- return self._values['format']['fieldListDelimiter']
-
- @property
- def log_storage_format(self):
- if self._values['format'] is None:
- return None
- return self._values['format']['type']
-
- @property
- def log_message_fields(self):
- if self._values['format'] is None:
- return None
- if 'fieldList' in self._values['format']:
- return self._values['format']['fieldList']
-
-
-class ModuleParameters(Parameters):
- def _validate_aggregate_rate(self, aggregate_rate):
- if aggregate_rate is None:
- return None
- if aggregate_rate == 'indefinite':
- return 4294967295
- if 0 <= int(aggregate_rate) <= 4294967295:
- return int(aggregate_rate)
- raise F5ModuleError(
- "Valid 'maximum_age' must be in range 0 - 4294967295, or 'indefinite'."
- )
-
- @property
- def rate_acl_match_accept(self):
- if self._values['log_matches_accept_rule'] is None:
- return None
- return self._validate_aggregate_rate(self._values['log_matches_accept_rule']['rate_limit'])
-
- @property
- def log_acl_match_accept(self):
- if self._values['log_matches_accept_rule'] is None:
- return None
- result = flatten_boolean(self._values['log_matches_accept_rule']['enabled'])
- if result == 'yes':
- return 'enabled'
- if result == 'no':
- return 'disabled'
- return result
-
- @property
- def rate_acl_match_drop(self):
- if self._values['log_matches_drop_rule'] is None:
- return None
- return self._validate_aggregate_rate(self._values['log_matches_drop_rule']['rate_limit'])
-
- @property
- def log_acl_match_drop(self):
- if self._values['log_matches_drop_rule'] is None:
- return None
- result = flatten_boolean(self._values['log_matches_drop_rule']['enabled'])
- if result == 'yes':
- return 'enabled'
- if result == 'no':
- return 'disabled'
- return result
-
- @property
- def rate_acl_match_reject(self):
- if self._values['log_matches_reject_rule'] is None:
- return None
- return self._validate_aggregate_rate(self._values['log_matches_reject_rule']['rate_limit'])
-
- @property
- def log_acl_match_reject(self):
- if self._values['log_matches_reject_rule'] is None:
- return None
- result = flatten_boolean(self._values['log_matches_reject_rule']['enabled'])
- if result == 'yes':
- return 'enabled'
- if result == 'no':
- return 'disabled'
- return result
-
- @property
- def rate_tcp_errors(self):
- if self._values['log_tcp_errors'] is None:
- return None
- return self._validate_aggregate_rate(self._values['log_tcp_errors']['rate_limit'])
-
- @property
- def log_tcp_errors(self):
- if self._values['log_tcp_errors'] is None:
- return None
- result = flatten_boolean(self._values['log_tcp_errors']['enabled'])
- if result == 'yes':
- return 'enabled'
- if result == 'no':
- return 'disabled'
- return result
-
- @property
- def rate_tcp_events(self):
- if self._values['log_tcp_events'] is None:
- return None
- return self._validate_aggregate_rate(self._values['log_tcp_events']['rate_limit'])
-
- @property
- def log_tcp_events(self):
- if self._values['log_tcp_events'] is None:
- return None
- result = flatten_boolean(self._values['log_tcp_events']['enabled'])
- if result == 'yes':
- return 'enabled'
- if result == 'no':
- return 'disabled'
- return result
-
- @property
- def rate_ip_errors(self):
- if self._values['log_ip_errors'] is None:
- return None
- return self._validate_aggregate_rate(self._values['log_ip_errors']['rate_limit'])
-
- @property
- def log_ip_errors(self):
- if self._values['log_ip_errors'] is None:
- return None
- result = flatten_boolean(self._values['log_ip_errors']['enabled'])
- if result == 'yes':
- return 'enabled'
- if result == 'no':
- return 'disabled'
- return result
-
- @property
- def log_translation_fields(self):
- result = flatten_boolean(self._values['log_translation_fields'])
- if result == 'yes':
- return 'enabled'
- if result == 'no':
- return 'disabled'
- return result
-
- @property
- def log_publisher(self):
- log_publisher = self._values['log_publisher']
- if log_publisher is None:
- return None
- if log_publisher in ['', 'none']:
- return log_publisher
- return fq_name(self.partition, log_publisher)
-
- @property
- def rate_limit(self):
- return self._validate_aggregate_rate(self._values['rate_limit'])
-
- @property
- def log_format_delimiter(self):
- if self._values['log_format_delimiter'] is None:
- return None
- if len(self._values['log_format_delimiter']) > 31:
- raise F5ModuleError('The maximum length of delimiter is 31 characters.')
- if "$" in self._values['log_format_delimiter']:
- raise F5ModuleError("Cannot use '$' character as a part of delimiter.")
- return self._values['log_format_delimiter']
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class UsableChanges(Changes):
- @property
- def rate_limits(self):
- to_filter = dict(
- aclMatchAccept=self._values['rate_acl_match_accept'],
- aclMatchDrop=self._values['rate_acl_match_drop'],
- aclMatchReject=self._values['rate_acl_match_reject'],
- ipErrors=self._values['rate_ip_errors'],
- tcpErrors=self._values['rate_tcp_errors'],
- tcpEvents=self._values['rate_tcp_events'],
- aggregateRate=self._values['rate_limit'],
- )
- result = self._filter_params(to_filter)
- return result
-
- @property
- def format(self):
- to_filter = dict(
- fieldListDelimiter=self._values['log_format_delimiter'],
- type=self._values['log_storage_format'],
- fieldList=self._values['log_message_fields']
- )
- result = self._filter_params(to_filter)
- return result
-
- @property
- def filter(self):
- to_filter = dict(
- logAclMatchAccept=self._values['log_acl_match_accept'],
- logAclMatchDrop=self._values['log_acl_match_drop'],
- logAclMatchReject=self._values['log_acl_match_reject'],
- logIpErrors=self._values['log_ip_errors'],
- logTcpErrors=self._values['log_tcp_errors'],
- logTcpEvents=self._values['log_tcp_events'],
- logTranslationFields=self._values['log_translation_fields'],
- )
- result = self._filter_params(to_filter)
- return result
-
-
-class ReportableChanges(Changes):
- def _change_aggregate_rate_value(self, value):
- if value == 4294967295:
- return 'indefinite'
- else:
- return value
-
- def _rebuild_params(self, enabled, rate_limit):
- to_filter = dict(
- enabled=flatten_boolean(self._values[enabled]),
- rate_limit=self._change_aggregate_rate_value(self._values[rate_limit])
- )
- result = self._filter_params(to_filter)
- return result
-
- @property
- def log_matches_accept_rule(self):
- result = self._rebuild_params('log_acl_match_accept', 'rate_acl_match_accept')
- if result:
- return result
-
- @property
- def log_acl_match_accept(self):
- return None
-
- @property
- def rate_acl_match_accept(self):
- return None
-
- @property
- def log_matches_drop_rule(self):
- result = self._rebuild_params('log_acl_match_drop', 'rate_acl_match_drop')
- if result:
- return result
-
- @property
- def log_acl_match_drop(self):
- return None
-
- @property
- def rate_acl_match_drop(self):
- return None
-
- @property
- def log_matches_reject_rule(self):
- result = self._rebuild_params('log_acl_match_reject', 'rate_acl_match_reject')
- if result:
- return result
-
- @property
- def log_acl_match_reject(self):
- return None
-
- @property
- def rate_acl_match_reject(self):
- return None
-
- @property
- def log_ip_errors(self):
- result = self._rebuild_params('log_ip_errors', 'rate_ip_errors')
- if result:
- return result
-
- @property
- def rate_ip_errors(self):
- return None
-
- @property
- def log_tcp_errors(self):
- result = self._rebuild_params('log_tcp_errors', 'rate_tcp_errors')
- if result:
- return result
-
- @property
- def rate_tcp_errors(self):
- return None
-
- @property
- def log_tcp_events(self):
- result = self._rebuild_params('log_tcp_events', 'rate_tcp_events')
- if result:
- return result
-
- @property
- def rate_tcp_events(self):
- return None
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
- @property
- def log_message_fields(self):
- if self.want.log_message_fields is None:
- return None
- if len(self.want.log_message_fields) == 1:
- if self.have.log_message_fields is None and self.want.log_message_fields[0] in ['', 'none']:
- return None
- if self.have.log_message_fields is not None and self.want.log_message_fields[0] in ['', 'none']:
- return []
- if self.have.log_message_fields is None:
- return self.want.log_message_fields
- if set(self.want.log_message_fields) != set(self.have.log_message_fields):
- return self.want.log_message_fields
- return None
-
- @property
- def log_publisher(self):
- return cmp_str_with_none(self.want.log_publisher, self.have.log_publisher)
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(params=self.module.params)
- self.have = ApiParameters()
- self.changes = UsableChanges()
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = UsableChanges(params=changed)
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.client.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def exec_module(self):
- changed = False
- result = dict()
- state = self.want.state
-
- if state == "present":
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def present(self):
- built_ins = ['Log all requests', 'Log illegal requests', 'local-dos']
- if self.want.profile_name in built_ins:
- return False
- if self.exists():
- return self.update()
- else:
- return self.create()
-
- def absent(self):
- # Built-in profile global-network cannot disable network log profile
- if 'global-network' in self.want.profile_name:
- return False
- if self.exists():
- return self.remove()
- return False
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def update(self):
- self.have = self.read_current_from_device()
- if not self.should_update():
- return False
- if self.module.check_mode:
- return True
- self.update_on_device()
- return True
-
- def remove(self):
- if self.module.check_mode:
- return True
- self.remove_from_device()
- if self.exists():
- raise F5ModuleError("Failed to delete the resource.")
- return True
-
- def create(self):
- self._set_changed_options()
- if self.module.check_mode:
- return True
- self.create_on_device()
- return True
-
- def _internal_name(self):
- name = self.want.profile_name
- partition = self.want.partition
- if 'global-network' in name:
- return 'global-network'
- return transform_name(partition, name)
-
- def _profile_exists(self):
- uri = "https://{0}:{1}/mgmt/tm/security/log/profile/{2}/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.profile_name),
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def exists(self):
- if not self._profile_exists():
- raise F5ModuleError(
- "Specified AFM log profile: {0} does not exist".format(self.want.profile_name)
- )
- uri = "https://{0}:{1}/mgmt/tm/security/log/profile/{2}/network/{3}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.profile_name),
- self._internal_name()
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def create_on_device(self):
- params = self.changes.api_params()
- params['name'] = self.want.profile_name
- params['partition'] = self.want.partition
- uri = "https://{0}:{1}/mgmt/tm/security/log/profile/{2}/network/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.profile_name)
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 409]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return True
-
- def update_on_device(self):
- params = self.changes.api_params()
- uri = "https://{0}:{1}/mgmt/tm/security/log/profile/{2}/network/{3}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.profile_name),
- self._internal_name()
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def remove_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/security/log/profile/{2}/network/{3}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.profile_name),
- self._internal_name()
- )
- response = self.client.api.delete(uri)
- if response.status == 200:
- return True
- raise F5ModuleError(response.content)
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/security/log/profile/{2}/network/{3}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.profile_name),
- self._internal_name()
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return ApiParameters(params=response)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- self.choices = [
- 'acl_policy_name', 'acl_policy_type', 'acl_rule_name', 'action',
- 'bigip_hostname', 'context_name', 'context_type', 'date_time',
- 'dest_fqdn', 'dest_geo', 'dest_ip', 'dest_port', 'drop_reason',
- 'management_ip_address', 'protocol', 'route_domain', 'sa_translation_pool',
- 'sa_translation_type', 'source_fqdn', 'source_user', 'src_geo', 'src_ip',
- 'src_port', 'translated_dest_ip', 'translated_dest_port', 'translated_ip_protocol',
- 'translated_route_domain', 'translated_src_ip', 'translated_src_port', 'translated_vlan',
- 'vlan'
- ]
- argument_spec = dict(
- profile_name=dict(
- required=True
- ),
- rate_limit=dict(),
- log_publisher=dict(),
- log_matches_accept_rule=dict(
- type='dict',
- options=dict(
- enabled=dict(type='bool'),
- rate_limit=dict()
- )
- ),
- log_matches_drop_rule=dict(
- type='dict',
- options=dict(
- enabled=dict(type='bool'),
- rate_limit=dict()
- )
- ),
- log_matches_reject_rule=dict(
- type='dict',
- options=dict(
- enabled=dict(type='bool'),
- rate_limit=dict()
- )
- ),
- log_tcp_errors=dict(
- type='dict',
- options=dict(
- enabled=dict(type='bool'),
- rate_limit=dict()
- )
- ),
- log_tcp_events=dict(
- type='dict',
- options=dict(
- enabled=dict(type='bool'),
- rate_limit=dict()
- )
- ),
- log_ip_errors=dict(
- type='dict',
- options=dict(
- enabled=dict(type='bool'),
- rate_limit=dict()
- )
- ),
- log_translation_fields=dict(type='bool'),
- log_storage_format=dict(
- choices=['none', 'field-list']
- ),
- log_format_delimiter=dict(),
- log_message_fields=dict(
- type='list',
- choices=self.choices
- ),
- partition=dict(
- default='Common',
- fallback=(env_fallback, ['F5_PARTITION'])
- ),
- state=dict(
- default='present',
- choices=['present', 'absent']
- )
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode,
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_firewall_policy.py b/lib/ansible/modules/network/f5/bigip_firewall_policy.py
deleted file mode 100644
index 84ba30ff09..0000000000
--- a/lib/ansible/modules/network/f5/bigip_firewall_policy.py
+++ /dev/null
@@ -1,532 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_firewall_policy
-short_description: Manage AFM security firewall policies on a BIG-IP
-description:
- - Manages AFM security firewall policies on a BIG-IP.
-version_added: 2.7
-options:
- name:
- description:
- - The name of the policy to create.
- type: str
- required: True
- description:
- description:
- - The description to attach to the policy.
- - This parameter is only supported on versions of BIG-IP >= 12.1.0. On earlier
- versions it will simply be ignored.
- type: str
- state:
- description:
- - When C(state) is C(present), ensures that the policy exists.
- - When C(state) is C(absent), ensures that the policy is removed.
- type: str
- choices:
- - present
- - absent
- default: present
- rules:
- description:
- - Specifies a list of rules that you want associated with this policy.
- The order of this list is the order they will be evaluated by BIG-IP.
- If the specified rules do not exist (for example when creating a new
- policy) then they will be created.
- - Rules specified here, if they do not exist, will be created with "default deny"
- behavior. It is expected that you follow-up this module with the actual
- configuration for these rules.
- - The C(bigip_firewall_rule) module can be used to also create, as well as
- edit, existing and new rules.
- type: list
- partition:
- description:
- - Device partition to manage resources on.
- type: str
- default: Common
-extends_documentation_fragment: f5
-author:
- - Tim Rupp (@caphrim007)
-'''
-
-EXAMPLES = r'''
-- name: Create a basic policy with some rule stubs
- bigip_firewall_policy:
- name: foo
- rules:
- - rule1
- - rule2
- - rule3
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-'''
-
-RETURN = r'''
-description:
- description: The new description of the policy.
- returned: changed
- type: str
- sample: My firewall policy
-rules:
- description: The list of rules, in the order that they are evaluated, on the device.
- returned: changed
- type: list
- sample: ['rule1', 'rule2', 'rule3']
-'''
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.basic import env_fallback
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.common import transform_name
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.common import transform_name
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'rulesReference': 'rules'
- }
-
- api_attributes = [
- 'description'
- ]
-
- returnables = [
- 'description',
- 'rules',
- ]
-
- updatables = [
- 'description',
- 'rules'
- ]
-
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class ModuleParameters(Parameters):
- @property
- def rules(self):
- if self._values['rules'] is None:
- return None
- # In case rule values are unicode (as they may be coming from the API
- result = [str(x) for x in self._values['rules']]
- return result
-
-
-class ApiParameters(Parameters):
- @property
- def rules(self):
- result = []
- if self._values['rules'] is None or 'items' not in self._values['rules']:
- return []
- for idx, item in enumerate(self._values['rules']['items']):
- result.append(dict(item=item['fullPath'], order=idx))
- result = [x['item'] for x in sorted(result, key=lambda k: k['order'])]
- return result
-
-
-class Changes(Parameters):
- pass
-
-
-class UsableChanges(Changes):
- pass
-
-
-class ReportableChanges(Changes):
- pass
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
- @property
- def rules(self):
- if self.want.rules is None:
- return None
- if self.have.rules is None:
- return self.want.rules
- if set(self.want.rules) != set(self.have.rules):
- return self.want.rules
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(params=self.module.params)
- self.have = ApiParameters()
- self.changes = UsableChanges()
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = Changes(params=changed)
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = Changes(params=changed)
- return True
- return False
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def exec_module(self):
- changed = False
- result = dict()
- state = self.want.state
-
- if state == "present":
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
-
- changes = self.changes.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def present(self):
- if self.exists():
- return self.update()
- else:
- return self.create()
-
- def exists(self):
- uri = "https://{0}:{1}/mgmt/tm/security/firewall/policy/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def update(self):
- self.have = self.read_current_from_device()
- if not self.should_update():
- return False
- if self.module.check_mode:
- return True
- self.update_on_device()
- return True
-
- def remove(self):
- if self.module.check_mode:
- return True
- self.remove_from_device()
- if self.exists():
- raise F5ModuleError("Failed to delete the resource.")
- return True
-
- def create(self):
- self._set_changed_options()
- if self.module.check_mode:
- return True
- self.create_on_device()
- return True
-
- def create_on_device(self):
- params = self.changes.api_params()
- params['name'] = self.want.name
- params['partition'] = self.want.partition
- uri = "https://{0}:{1}/mgmt/tm/security/firewall/policy/".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- if self.want.rules:
- self._upsert_policy_rules_on_device()
- return response['selfLink']
-
- def update_on_device(self):
- params = self.changes.api_params()
- uri = "https://{0}:{1}/mgmt/tm/security/firewall/policy/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- if params:
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return response['selfLink']
- if self.changes.rules is not None:
- self._upsert_policy_rules_on_device()
-
- def absent(self):
- if self.exists():
- return self.remove()
- return False
-
- def remove_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/security/firewall/policy/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- response = self.client.api.delete(uri)
- if response.status == 200:
- return True
- raise F5ModuleError(response.content)
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/security/firewall/policy/{2}/?expandSubcollections=true".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return ApiParameters(params=response)
-
- def rule_exists(self, rule):
- uri = "https://{0}:{1}/mgmt/tm/security/firewall/policy/{2}/rules/{3}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name),
- rule.replace('/', '_')
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def create_default_rule_on_device(self, rule):
- params = dict(
- name=rule.replace('/', '_'),
- action='reject',
- # Adding items to the end of the list causes the list of rules to match
- # what the user specified in the original list.
- placeAfter='last',
- )
- uri = "https://{0}:{1}/mgmt/tm/security/firewall/policy/{2}/rules/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name),
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return response['selfLink']
-
- def remove_rule_from_device(self, rule):
- uri = "https://{0}:{1}/mgmt/tm/security/firewall/policy/{2}/rules/{3}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name),
- rule.replace('/', '_'),
- )
- # this response returns no payload
- resp = self.client.api.delete(uri)
- if resp.status in [400, 403]:
- raise F5ModuleError(resp.content)
-
- def move_rule_to_front(self, rule):
- params = dict(
- placeAfter='last'
- )
- uri = "https://{0}:{1}/mgmt/tm/security/firewall/policy/{2}/rules/{3}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name),
- rule.replace('/', '_')
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return response['selfLink']
-
- def _upsert_policy_rules_on_device(self):
- rules = self.changes.rules
- if rules is None:
- rules = []
- self._remove_rule_difference(rules)
-
- for idx, rule in enumerate(rules):
- if not self.rule_exists(rule):
- self.create_default_rule_on_device(rule)
- for idx, rule in enumerate(rules):
- self.move_rule_to_front(rule)
-
- def _remove_rule_difference(self, rules):
- if rules is None or self.have.rules is None:
- return
- have_rules = set(self.have.rules)
- want_rules = set(rules)
- removable = have_rules.difference(want_rules)
- for remove in removable:
- self.remove_rule_from_device(remove)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- name=dict(required=True),
- description=dict(),
- rules=dict(type='list'),
- partition=dict(
- default='Common',
- fallback=(env_fallback, ['F5_PARTITION'])
- ),
- state=dict(
- default='present',
- choices=['present', 'absent']
- )
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode,
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_firewall_port_list.py b/lib/ansible/modules/network/f5/bigip_firewall_port_list.py
deleted file mode 100644
index c63b248c36..0000000000
--- a/lib/ansible/modules/network/f5/bigip_firewall_port_list.py
+++ /dev/null
@@ -1,645 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_firewall_port_list
-short_description: Manage port lists on BIG-IP AFM
-description:
- - Manages the AFM port lists on a BIG-IP. This module can be used to add
- and remove port list entries.
-version_added: 2.5
-options:
- name:
- description:
- - Specifies the name of the port list.
- type: str
- required: True
- partition:
- description:
- - Device partition to manage resources on.
- type: str
- default: Common
- description:
- description:
- - Description of the port list
- type: str
- ports:
- description:
- - Simple list of port values to add to the list
- type: list
- port_ranges:
- description:
- - A list of port ranges where the range starts with a port number, is followed
- by a dash (-) and then a second number.
- - If the first number is greater than the second number, the numbers will be
- reversed so-as to be properly formatted. ie, 90-78 would become 78-90.
- type: list
- port_lists:
- description:
- - Simple list of existing port lists to add to this list. Port lists can be
- specified in either their fully qualified name (/Common/foo) or their short
- name (foo). If a short name is used, the C(partition) argument will automatically
- be prepended to the short name.
- type: list
- state:
- description:
- - When C(present), ensures that the address list and entries exists.
- - When C(absent), ensures the address list is removed.
- type: str
- choices:
- - present
- - absent
- default: present
-extends_documentation_fragment: f5
-author:
- - Tim Rupp (@caphrim007)
- - Wojciech Wypior (@wojtek0806)
-'''
-
-EXAMPLES = r'''
-- name: Create a simple port list
- bigip_firewall_port_list:
- name: foo
- ports:
- - 80
- - 443
- state: present
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-
-- name: Override the above list of ports with a new list
- bigip_firewall_port_list:
- name: foo
- ports:
- - 3389
- - 8080
- - 25
- state: present
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-
-- name: Create port list with series of ranges
- bigip_firewall_port_list:
- name: foo
- port_ranges:
- - 25-30
- - 80-500
- - 50-78
- state: present
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-
-- name: Use multiple types of port arguments
- bigip_firewall_port_list:
- name: foo
- port_ranges:
- - 25-30
- - 80-500
- - 50-78
- ports:
- - 8080
- - 443
- state: present
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-
-- name: Remove port list
- bigip_firewall_port_list:
- name: foo
- state: absent
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-
-- name: Create port list from a file with one port per line
- bigip_firewall_port_list:
- name: lot-of-ports
- ports: "{{ lookup('file', 'my-large-port-list.txt').split('\n') }}"
- state: present
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-'''
-
-RETURN = r'''
-description:
- description: The new description of the port list.
- returned: changed
- type: str
- sample: My port list
-ports:
- description: The new list of ports applied to the port list.
- returned: changed
- type: list
- sample: [80, 443]
-port_ranges:
- description: The new list of port ranges applied to the port list.
- returned: changed
- type: list
- sample: [80-100, 200-8080]
-port_lists:
- description: The new list of port list names applied to the port list.
- returned: changed
- type: list
- sample: [/Common/list1, /Common/list2]
-'''
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.basic import env_fallback
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import fq_name
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.common import transform_name
- from library.module_utils.network.f5.icontrol import module_provisioned
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import fq_name
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.common import transform_name
- from ansible.module_utils.network.f5.icontrol import module_provisioned
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'portLists': 'port_lists',
- }
-
- api_attributes = [
- 'portLists', 'ports', 'description',
- ]
-
- returnables = [
- 'ports', 'port_ranges', 'port_lists', 'description',
- ]
-
- updatables = [
- 'description', 'ports', 'port_ranges', 'port_lists',
- ]
-
-
-class ApiParameters(Parameters):
- @property
- def port_ranges(self):
- if self._values['ports'] is None:
- return None
- result = []
- for port_range in self._values['ports']:
- if '-' not in port_range['name']:
- continue
- start, stop = port_range['name'].split('-')
- start = int(start.strip())
- stop = int(stop.strip())
- if start > stop:
- stop, start = start, stop
- item = '{0}-{1}'.format(start, stop)
- result.append(item)
- return result
-
- @property
- def port_lists(self):
- if self._values['port_lists'] is None:
- return None
- result = []
- for x in self._values['port_lists']:
- item = '/{0}/{1}'.format(x['partition'], x['name'])
- result.append(item)
- return result
-
- @property
- def ports(self):
- if self._values['ports'] is None:
- return None
- result = [int(x['name']) for x in self._values['ports'] if '-' not in x['name']]
- return result
-
-
-class ModuleParameters(Parameters):
- @property
- def ports(self):
- if self._values['ports'] is None:
- return None
- if any(x for x in self._values['ports'] if '-' in str(x)):
- raise F5ModuleError(
- "Ports must be whole numbers between 0 and 65,535"
- )
- if any(x for x in self._values['ports'] if 0 < int(x) > 65535):
- raise F5ModuleError(
- "Ports must be whole numbers between 0 and 65,535"
- )
- result = [int(x) for x in self._values['ports']]
- return result
-
- @property
- def port_ranges(self):
- if self._values['port_ranges'] is None:
- return None
- result = []
- for port_range in self._values['port_ranges']:
- if '-' not in port_range:
- continue
- start, stop = port_range.split('-')
- start = int(start.strip())
- stop = int(stop.strip())
- if start > stop:
- stop, start = start, stop
- if 0 < start > 65535 or 0 < stop > 65535:
- raise F5ModuleError(
- "Ports must be whole numbers between 0 and 65,535"
- )
- item = '{0}-{1}'.format(start, stop)
- result.append(item)
- return result
-
- @property
- def port_lists(self):
- if self._values['port_lists'] is None:
- return None
- result = []
- for x in self._values['port_lists']:
- item = fq_name(self.partition, x)
- result.append(item)
- return result
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class ReportableChanges(Changes):
- @property
- def ports(self):
- result = []
- for item in self._values['ports']:
- if '-' in item['name']:
- continue
- result.append(item['name'])
- return result
-
- @property
- def port_ranges(self):
- result = []
- for item in self._values['ports']:
- if '-' not in item['name']:
- continue
- result.append(item['name'])
- return result
-
-
-class UsableChanges(Changes):
- @property
- def ports(self):
- if self._values['ports'] is None and self._values['port_ranges'] is None:
- return None
- result = []
- if self._values['ports']:
- # The values of the 'key' index literally need to be string values.
- # If they are not, on BIG-IP 12.1.0 they will raise this REST exception.
- #
- # {
- # "code": 400,
- # "message": "one or more configuration identifiers must be provided",
- # "errorStack": [],
- # "apiError": 26214401
- # }
- result += [dict(name=str(x)) for x in self._values['ports']]
- if self._values['port_ranges']:
- result += [dict(name=str(x)) for x in self._values['port_ranges']]
- return result
-
- @property
- def port_lists(self):
- if self._values['port_lists'] is None:
- return None
- result = []
- for x in self._values['port_lists']:
- partition, name = x.split('/')[1:]
- result.append(dict(
- name=name,
- partition=partition
- ))
- return result
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
- @property
- def ports(self):
- if self.want.ports is None:
- return None
- elif self.have.ports is None:
- return self.want.ports
- if sorted(self.want.ports) != sorted(self.have.ports):
- return self.want.ports
-
- @property
- def port_lists(self):
- if self.want.port_lists is None:
- return None
- elif self.have.port_lists is None:
- return self.want.port_lists
- if sorted(self.want.port_lists) != sorted(self.have.port_lists):
- return self.want.port_lists
-
- @property
- def port_ranges(self):
- if self.want.port_ranges is None:
- return None
- elif self.have.port_ranges is None:
- return self.want.port_ranges
- if sorted(self.want.port_ranges) != sorted(self.have.port_ranges):
- return self.want.port_ranges
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(params=self.module.params)
- self.have = ApiParameters()
- self.changes = UsableChanges()
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = UsableChanges(params=changed)
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def exec_module(self):
- if not module_provisioned(self.client, 'afm'):
- raise F5ModuleError(
- "AFM must be provisioned to use this module."
- )
- changed = False
- result = dict()
- state = self.want.state
-
- if state == "present":
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def present(self):
- if self.exists():
- return self.update()
- else:
- return self.create()
-
- def absent(self):
- if self.exists():
- return self.remove()
- return False
-
- def update(self):
- self.have = self.read_current_from_device()
- if not self.should_update():
- return False
- if self.module.check_mode:
- return True
- self.update_on_device()
- return True
-
- def remove(self):
- if self.module.check_mode:
- return True
- self.remove_from_device()
- if self.exists():
- raise F5ModuleError("Failed to delete the resource.")
- return True
-
- def create(self):
- self._set_changed_options()
- if self.module.check_mode:
- return True
- self.create_on_device()
- return True
-
- def exists(self):
- uri = "https://{0}:{1}/mgmt/tm/security/firewall/port-list/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def update_on_device(self):
- params = self.changes.api_params()
- uri = "https://{0}:{1}/mgmt/tm/security/firewall/port-list/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/security/firewall/port-list/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
-
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return ApiParameters(params=response)
-
- def create_on_device(self):
- params = self.changes.api_params()
- params['name'] = self.want.name
- params['partition'] = self.want.partition
- uri = "https://{0}:{1}/mgmt/tm/security/firewall/port-list/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return response['selfLink']
-
- def remove_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/security/firewall/port-list/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- response = self.client.api.delete(uri)
- if response.status == 200:
- return True
- raise F5ModuleError(response.content)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- name=dict(required=True),
- description=dict(),
- ports=dict(type='list'),
- port_ranges=dict(type='list'),
- port_lists=dict(type='list'),
- partition=dict(
- default='Common',
- fallback=(env_fallback, ['F5_PARTITION'])
- ),
- state=dict(
- default='present',
- choices=['present', 'absent']
- )
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_firewall_rule.py b/lib/ansible/modules/network/f5/bigip_firewall_rule.py
deleted file mode 100644
index e711b7a0b4..0000000000
--- a/lib/ansible/modules/network/f5/bigip_firewall_rule.py
+++ /dev/null
@@ -1,1319 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2018, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_firewall_rule
-short_description: Manage AFM Firewall rules
-description:
- - Manages firewall rules in an AFM firewall policy. New rules will always be added to the
- end of the policy. Rules can be re-ordered using the C(bigip_security_policy) module.
- Rules can also be pre-ordered using the C(bigip_security_policy) module and then later
- updated using the C(bigip_firewall_rule) module.
-version_added: 2.7
-options:
- name:
- description:
- - Specifies the name of the rule.
- type: str
- required: True
- parent_policy:
- description:
- - The policy which contains the rule to be managed.
- - One of either C(parent_policy) or C(parent_rule_list) is required.
- type: str
- parent_rule_list:
- description:
- - The rule list which contains the rule to be managed.
- - One of either C(parent_policy) or C(parent_rule_list) is required.
- type: str
- action:
- description:
- - Specifies the action for the firewall rule.
- - When C(accept), allows packets with the specified source, destination,
- and protocol to pass through the firewall. Packets that match the rule,
- and are accepted, traverse the system as if the firewall is not present.
- - When C(drop), drops packets with the specified source, destination, and
- protocol. Dropping a packet is a silent action with no notification to
- the source or destination systems. Dropping the packet causes the connection
- to be retried until the retry threshold is reached.
- - When C(reject), rejects packets with the specified source, destination,
- and protocol. When a packet is rejected the firewall sends a destination
- unreachable message to the sender.
- - When C(accept-decisively), allows packets with the specified source,
- destination, and protocol to pass through the firewall, and does not require
- any further processing by any of the further firewalls. Packets that match
- the rule, and are accepted, traverse the system as if the firewall is not
- present. If the Rule List is applied to a virtual server, management IP,
- or self IP firewall rule, then Accept Decisively is equivalent to Accept.
- - When creating a new rule, if this parameter is not provided, the default is
- C(reject).
- type: str
- choices:
- - accept
- - drop
- - reject
- - accept-decisively
- status:
- description:
- - Indicates the activity state of the rule or rule list.
- - When C(disabled), specifies that the rule or rule list does not apply at all.
- - When C(enabled), specifies that the system applies the firewall rule or rule
- list to the given context and addresses.
- - When C(scheduled), specifies that the system applies the rule or rule list
- according to the specified schedule.
- - When creating a new rule, if this parameter is not provided, the default
- is C(enabled).
- type: str
- choices:
- - enabled
- - disabled
- - scheduled
- schedule:
- description:
- - Specifies a schedule for the firewall rule.
- - You configure schedules to define days and times when the firewall rule is
- made active.
- type: str
- description:
- description:
- - The rule description.
- type: str
- irule:
- description:
- - Specifies an iRule that is applied to the firewall rule.
- - An iRule can be started when the firewall rule matches traffic.
- type: str
- protocol:
- description:
- - Specifies the protocol to which the rule applies.
- - Protocols may be specified by either their name or numeric value.
- - A special protocol value C(any) can be specified to match any protocol. The
- numeric equivalent of this protocol is C(255).
- type: str
- source:
- description:
- - Specifies packet sources to which the rule applies.
- - Leaving this field blank applies the rule to all addresses and all ports.
- - You can specify the following source items. An IPv4 or IPv6 address, an IPv4
- or IPv6 address range, geographic location, VLAN, address list, port,
- port range, port list or address list.
- - You can specify a mix of different types of items for the source address.
- suboptions:
- address:
- description:
- - Specifies a specific IP address.
- type: str
- address_list:
- description:
- - Specifies an existing address list.
- type: str
- address_range:
- description:
- - Specifies an address range.
- type: str
- country:
- description:
- - Specifies a country code.
- type: str
- port:
- description:
- - Specifies a single numeric port.
- - This option is only valid when C(protocol) is C(tcp)(6) or C(udp)(17).
- type: int
- port_list:
- description:
- - Specifes an existing port list.
- - This option is only valid when C(protocol) is C(tcp)(6) or C(udp)(17).
- type: str
- port_range:
- description:
- - Specifies a range of ports, which is two port values separated by
- a hyphen. The port to the left of the hyphen should be less than the
- port to the right.
- - This option is only valid when C(protocol) is C(tcp)(6) or C(udp)(17).
- type: str
- vlan:
- description:
- - Specifies VLANs to which the rule applies.
- - The VLAN source refers to the packet's source.
- type: str
- type: list
- destination:
- description:
- - Specifies packet destinations to which the rule applies.
- - Leaving this field blank applies the rule to all addresses and all ports.
- - You can specify the following destination items. An IPv4 or IPv6 address,
- an IPv4 or IPv6 address range, geographic location, VLAN, address list, port,
- port range, port list or address list.
- - You can specify a mix of different types of items for the source address.
- suboptions:
- address:
- description:
- - Specifies a specific IP address.
- type: str
- address_list:
- description:
- - Specifies an existing address list.
- type: str
- address_range:
- description:
- - Specifies an address range.
- type: str
- country:
- description:
- - Specifies a country code.
- type: str
- port:
- description:
- - Specifies a single numeric port.
- - This option is only valid when C(protocol) is C(tcp)(6) or C(udp)(17).
- type: int
- port_list:
- description:
- - Specifes an existing port list.
- - This option is only valid when C(protocol) is C(tcp)(6) or C(udp)(17).
- type: str
- port_range:
- description:
- - Specifies a range of ports, which is two port values separated by
- a hyphen. The port to the left of the hyphen should be less than the
- port to the right.
- - This option is only valid when C(protocol) is C(tcp)(6) or C(udp)(17).
- type: str
- type: list
- logging:
- description:
- - Specifies whether logging is enabled or disabled for the firewall rule.
- - When creating a new rule, if this parameter is not specified, the default
- if C(no).
- type: bool
- rule_list:
- description:
- - Specifies an existing rule list to use in the rule.
- - This parameter is mutually exclusive with many of the other individual-rule
- specific settings. This includes C(logging), C(action), C(source),
- C(destination), C(irule'), C(protocol) and C(logging).
- - This parameter is only used when C(parent_policy) is specified, otherwise it is ignored.
- type: str
- icmp_message:
- description:
- - Specifies the Internet Control Message Protocol (ICMP) or ICMPv6 message
- C(type) and C(code) that the rule uses.
- - This parameter is only relevant when C(protocol) is either C(icmp)(1) or
- C(icmpv6)(58).
- suboptions:
- type:
- description:
- - Specifies the type of ICMP message.
- - You can specify control messages, such as Echo Reply (0) and Destination
- Unreachable (3), or you can specify C(any) to indicate that the system
- applies the rule for all ICMP messages.
- - You can also specify an arbitrary ICMP message.
- - The ICMP protocol contains definitions for the existing message type and
- number pairs.
- type: str
- code:
- description:
- - Specifies the code returned in response to the specified ICMP message type.
- - You can specify codes, each set appropriate to the associated type, such
- as No Code (0) (associated with Echo Reply (0)) and Host Unreachable (1)
- (associated with Destination Unreachable (3)), or you can specify C(any)
- to indicate that the system applies the rule for all codes in response to
- that specific ICMP message.
- - You can also specify an arbitrary code.
- - The ICMP protocol contains definitions for the existing message code and
- number pairs.
- type: str
- type: list
- partition:
- description:
- - Device partition to manage resources on.
- type: str
- default: Common
- state:
- description:
- - When C(state) is C(present), ensures that the rule exists.
- - When C(state) is C(absent), ensures that the rule is removed.
- type: str
- choices:
- - present
- - absent
- default: present
-extends_documentation_fragment: f5
-author:
- - Tim Rupp (@caphrim007)
- - Wojciech Wypior (@wojtek0806)
-'''
-
-EXAMPLES = r'''
-- name: Create a new rule in the foo firewall policy
- bigip_firewall_rule:
- name: foo
- parent_policy: policy1
- protocol: tcp
- source:
- - address: 1.2.3.4
- - address: "::1"
- - address_list: foo-list1
- - address_range: 1.1.1.1-2.2.2.2
- - vlan: vlan1
- - country: US
- - port: 22
- - port_list: port-list1
- - port_range: 80-443
- destination:
- - address: 1.2.3.4
- - address: "::1"
- - address_list: foo-list1
- - address_range: 1.1.1.1-2.2.2.2
- - country: US
- - port: 22
- - port_list: port-list1
- - port_range: 80-443
- irule: irule1
- action: accept
- logging: yes
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-
-- name: Create an ICMP specific rule
- bigip_firewall_rule:
- name: foo
- protocol: icmp
- icmp_message:
- type: 0
- source:
- - country: US
- action: drop
- logging: yes
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-
-- name: Add a new policy rule that uses an existing rule list
- bigip_firewall_rule:
- name: foo
- parent_policy: foo_policy
- rule_list: rule-list1
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-'''
-
-RETURN = r'''
-name:
- description: Name of the rule.
- returned: changed
- type: str
- sample: FooRule
-parent_policy:
- description: The policy which contains the rule to be managed.
- returned: changed
- type: str
- sample: FooPolicy
-parent_rule_list:
- description: The rule list which contains the rule to be managed.
- returned: changed
- type: str
- sample: FooRuleList
-action:
- description: The action for the firewall rule.
- returned: changed
- type: str
- sample: drop
-status:
- description: The activity state of the rule or rule list.
- returned: changed
- type: str
- sample: scheduled
-schedule:
- description: The schedule for the firewall rule.
- returned: changed
- type: str
- sample: Foo_schedule
-description:
- description: The rule description.
- returned: changed
- type: str
- sample: MyRule
-irule:
- description: The iRule that is applied to the firewall rule.
- returned: changed
- type: str
- sample: _sys_auth_radius
-protocol:
- description: The protocol to which the rule applies.
- returned: changed
- type: str
- sample: any
-source:
- description: The packet sources to which the rule applies
- returned: changed
- type: complex
- contains:
- address:
- description: A specific IP address.
- returned: changed
- type: str
- sample: 192.168.1.1
- address_list:
- description: An existing address list.
- returned: changed
- type: str
- sample: foo-list1
- address_range:
- description: The address range.
- returned: changed
- type: str
- sample: 1.1.1.1-2.2.2.2
- country:
- description: A country code.
- returned: changed
- type: str
- sample: US
- port:
- description: Single numeric port.
- returned: changed
- type: int
- sample: 8080
- port_list:
- description: An existing port list.
- returned: changed
- type: str
- sample: port-list1
- port_range:
- description: The port range.
- returned: changed
- type: str
- sample: 80-443
- vlan:
- description: Source VLANs for the packets.
- returned: changed
- type: str
- sample: vlan1
- sample: hash/dictionary of values
-destination:
- description: The packet destinations to which the rule applies.
- returned: changed
- type: complex
- contains:
- address:
- description: A specific IP address.
- returned: changed
- type: str
- sample: 192.168.1.1
- address_list:
- description: An existing address list.
- returned: changed
- type: str
- sample: foo-list1
- address_range:
- description: The address range.
- returned: changed
- type: str
- sample: 1.1.1.1-2.2.2.2
- country:
- description: A country code.
- returned: changed
- type: str
- sample: US
- port:
- description: Single numeric port.
- returned: changed
- type: int
- sample: 8080
- port_list:
- description: An existing port list.
- returned: changed
- type: str
- sample: port-list1
- port_range:
- description: The port range.
- returned: changed
- type: str
- sample: 80-443
- sample: hash/dictionary of values
-logging:
- description: Enable or Disable logging for the firewall rule.
- returned: changed
- type: bool
- sample: yes
-rule_list:
- description: An existing rule list to use in the parent policy.
- returned: changed
- type: str
- sample: rule-list-1
-icmp_message:
- description: The (ICMP) or ICMPv6 message C(type) and C(code) that the rule uses.
- returned: changed
- type: complex
- contains:
- type:
- description: The type of ICMP message.
- returned: changed
- type: str
- sample: 0
- code:
- description: The code returned in response to the specified ICMP message type.
- returned: changed
- type: str
- sample: 1
- sample: hash/dictionary of values
-'''
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.basic import env_fallback
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import fq_name
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.common import transform_name
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import fq_name
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.common import transform_name
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'ipProtocol': 'protocol',
- 'log': 'logging',
- 'icmp': 'icmp_message',
- 'ruleList': 'rule_list'
- }
-
- api_attributes = [
- 'irule',
- 'ipProtocol',
- 'log',
- 'schedule',
- 'status',
- 'destination',
- 'source',
- 'icmp',
- 'action',
- 'description',
- 'ruleList',
- ]
-
- returnables = [
- 'logging',
- 'protocol',
- 'irule',
- 'source',
- 'destination',
- 'action',
- 'status',
- 'schedule',
- 'description',
- 'icmp_message',
- 'rule_list',
- ]
-
- updatables = [
- 'logging',
- 'protocol',
- 'irule',
- 'source',
- 'destination',
- 'action',
- 'status',
- 'schedule',
- 'description',
- 'icmp_message',
- 'rule_list',
- ]
-
- protocol_map = {
- '1': 'icmp',
- '6': 'tcp',
- '17': 'udp',
- '58': 'icmpv6',
- '255': 'any',
- }
-
-
-class ApiParameters(Parameters):
- @property
- def logging(self):
- if self._values['logging'] is None:
- return None
- if self._values['logging'] == 'yes':
- return True
- return False
-
- @property
- def protocol(self):
- if self._values['protocol'] is None:
- return None
- if self._values['protocol'] in self.protocol_map:
- return self.protocol_map[self._values['protocol']]
- return self._values['protocol']
-
- @property
- def source(self):
- result = []
- if self._values['source'] is None:
- return None
- v = self._values['source']
- if 'addressLists' in v:
- result += [('address_list', x) for x in v['addressLists']]
- if 'vlans' in v:
- result += [('vlan', x) for x in v['vlans']]
- if 'geo' in v:
- result += [('geo', x['name']) for x in v['geo']]
- if 'addresses' in v:
- result += [('address', x['name']) for x in v['addresses']]
- if 'ports' in v:
- result += [('port', str(x['name'])) for x in v['ports']]
- if 'portLists' in v:
- result += [('port_list', x) for x in v['portLists']]
- if result:
- return result
- return None
-
- @property
- def destination(self):
- result = []
- if self._values['destination'] is None:
- return None
- v = self._values['destination']
- if 'addressLists' in v:
- result += [('address_list', x) for x in v['addressLists']]
- if 'geo' in v:
- result += [('geo', x['name']) for x in v['geo']]
- if 'addresses' in v:
- result += [('address', x['name']) for x in v['addresses']]
- if 'ports' in v:
- result += [('port', x['name']) for x in v['ports']]
- if 'portLists' in v:
- result += [('port_list', x) for x in v['portLists']]
- if result:
- return result
- return None
-
- @property
- def icmp_message(self):
- if self._values['icmp_message'] is None:
- return None
- result = [x['name'] for x in self._values['icmp_message']]
- return result
-
-
-class ModuleParameters(Parameters):
- @property
- def irule(self):
- if self._values['irule'] is None:
- return None
- if self._values['irule'] == '':
- return ''
- return fq_name(self.partition, self._values['irule'])
-
- @property
- def description(self):
- if self._values['description'] is None:
- return None
- if self._values['description'] == '':
- return ''
- return self._values['description']
-
- @property
- def schedule(self):
- if self._values['schedule'] is None:
- return None
- if self._values['schedule'] == '':
- return ''
- return fq_name(self.partition, self._values['schedule'])
-
- @property
- def source(self):
- result = []
- if self._values['source'] is None:
- return None
- for x in self._values['source']:
- if 'address' in x and x['address'] is not None:
- result += [('address', x['address'])]
- elif 'address_range' in x and x['address_range'] is not None:
- result += [('address', x['address_range'])]
- elif 'address_list' in x and x['address_list'] is not None:
- result += [('address_list', x['address_list'])]
- elif 'country' in x and x['country'] is not None:
- result += [('geo', x['country'])]
- elif 'vlan' in x and x['vlan'] is not None:
- result += [('vlan', fq_name(self.partition, x['vlan']))]
- elif 'port' in x and x['port'] is not None:
- result += [('port', str(x['port']))]
- elif 'port_range' in x and x['port_range'] is not None:
- result += [('port', x['port_range'])]
- elif 'port_list' in x and x['port_list'] is not None:
- result += [('port_list', fq_name(self.partition, x['port_list']))]
- if result:
- return result
- return None
-
- @property
- def destination(self):
- result = []
- if self._values['destination'] is None:
- return None
- for x in self._values['destination']:
- if 'address' in x and x['address'] is not None:
- result += [('address', x['address'])]
- elif 'address_range' in x and x['address_range'] is not None:
- result += [('address', x['address_range'])]
- elif 'address_list' in x and x['address_list'] is not None:
- result += [('address_list', x['address_list'])]
- elif 'country' in x and x['country'] is not None:
- result += [('geo', x['country'])]
- elif 'port' in x and x['port'] is not None:
- result += [('port', str(x['port']))]
- elif 'port_range' in x and x['port_range'] is not None:
- result += [('port', x['port_range'])]
- elif 'port_list' in x and x['port_list'] is not None:
- result += [('port_list', fq_name(self.partition, x['port_list']))]
- if result:
- return result
- return None
-
- @property
- def icmp_message(self):
- if self._values['icmp_message'] is None:
- return None
- result = []
- for x in self._values['icmp_message']:
- type = x.get('type', '255')
- code = x.get('code', '255')
-
- if type is None or type == 'any':
- type = '255'
- if code is None or code == 'any':
- code = '255'
-
- if type == '255' and code == '255':
- result.append("255")
- elif type == '255' and code != '255':
- raise F5ModuleError(
- "A type of 'any' (255) requires a code of 'any'."
- )
- elif code == '255':
- result.append(type)
- else:
- result.append('{0}:{1}'.format(type, code))
- result = list(set(result))
- return result
-
- @property
- def rule_list(self):
- if self._values['rule_list'] is None:
- return None
- if self._values['parent_policy'] is not None:
- return fq_name(self.partition, self._values['rule_list'])
- return None
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class UsableChanges(Changes):
- @property
- def logging(self):
- if self._values['logging'] is None:
- return None
- if self._values['logging'] is True:
- return "yes"
- return "no"
-
- @property
- def source(self):
- if self._values['source'] is None:
- return None
- result = dict(
- addresses=[],
- addressLists=[],
- vlans=[],
- geo=[],
- ports=[],
- portLists=[]
- )
- for x in self._values['source']:
- if x[0] == 'address':
- result['addresses'].append({'name': x[1]})
- elif x[0] == 'address_list':
- result['addressLists'].append(x[1])
- elif x[0] == 'vlan':
- result['vlans'].append(x[1])
- elif x[0] == 'geo':
- result['geo'].append({'name': x[1]})
- elif x[0] == 'port':
- result['ports'].append({'name': str(x[1])})
- elif x[0] == 'port_list':
- result['portLists'].append(x[1])
- return result
-
- @property
- def destination(self):
- if self._values['destination'] is None:
- return None
- result = dict(
- addresses=[],
- addressLists=[],
- vlans=[],
- geo=[],
- ports=[],
- portLists=[]
- )
- for x in self._values['destination']:
- if x[0] == 'address':
- result['addresses'].append({'name': x[1]})
- elif x[0] == 'address_list':
- result['addressLists'].append(x[1])
- elif x[0] == 'geo':
- result['geo'].append({'name': x[1]})
- elif x[0] == 'port':
- result['ports'].append({'name': str(x[1])})
- elif x[0] == 'port_list':
- result['portLists'].append(x[1])
- return result
-
- @property
- def icmp_message(self):
- if self._values['icmp_message'] is None:
- return None
- result = []
- for x in self._values['icmp_message']:
- result.append({'name': x})
- return result
-
-
-class ReportableChanges(Changes):
- @property
- def source(self):
- if self._values['source'] is None:
- return None
- result = []
- v = self._values['source']
- if v['addressLists']:
- result += [('address_list', x) for x in v['addressLists']]
- if v['vlans']:
- result += [('vlan', x) for x in v['vlans']]
- if v['geo']:
- result += [('geo', x['name']) for x in v['geo']]
- if v['addresses']:
- result += [('address', x['name']) for x in v['addresses']]
- if v['ports']:
- result += [('port', str(x)) for x in v['ports']]
- if v['portLists']:
- result += [('port_list', x['name']) for x in v['portLists']]
- if result:
- return dict(result)
- return None
-
- @property
- def destination(self):
- if self._values['destination'] is None:
- return None
- result = []
- v = self._values['destination']
- if v['addressLists']:
- result += [('address_list', x) for x in v['addressLists']]
- if v['geo']:
- result += [('geo', x['name']) for x in v['geo']]
- if v['addresses']:
- result += [('address', x['name']) for x in v['addresses']]
- if v['ports']:
- result += [('port', str(x)) for x in v['ports']]
- if v['portLists']:
- result += [('port_list', x['name']) for x in v['portLists']]
- if result:
- return dict(result)
- return None
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
- @property
- def irule(self):
- if self.want.irule is None:
- return None
- if self.have.irule is None and self.want.irule == '':
- return None
- if self.have.irule is None:
- return self.want.irule
- if self.want.irule != self.have.irule:
- return self.want.irule
-
- @property
- def description(self):
- if self.want.description is None:
- return None
- if self.have.description is None and self.want.description == '':
- return None
- if self.have.description is None:
- return self.want.description
- if self.want.description != self.have.description:
- return self.want.description
-
- @property
- def source(self):
- if self.want.source is None:
- return None
- if self.want.source is None and self.have.source is None:
- return None
- if self.have.source is None:
- return self.want.source
- if set(self.want.source) != set(self.have.source):
- return self.want.source
-
- @property
- def destination(self):
- if self.want.destination is None:
- return None
- if self.want.destination is None and self.have.destination is None:
- return None
- if self.have.destination is None:
- return self.want.destination
- if set(self.want.destination) != set(self.have.destination):
- return self.want.destination
-
- @property
- def icmp_message(self):
- if self.want.icmp_message is None:
- return None
- if self.want.icmp_message is None and self.have.icmp_message is None:
- return None
- if self.have.icmp_message is None:
- return self.want.icmp_message
- if set(self.want.icmp_message) != set(self.have.icmp_message):
- return self.want.icmp_message
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(params=self.module.params)
- self.have = ApiParameters()
- self.changes = UsableChanges()
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = UsableChanges(params=changed)
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def exec_module(self):
- changed = False
- result = dict()
- state = self.want.state
-
- if state == "present":
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.client.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def present(self):
- if self.exists():
- return self.update()
- else:
- return self.create()
-
- def exists(self):
- name = self.want.name
- if self.want.parent_policy:
- uri = "https://{0}:{1}/mgmt/tm/security/firewall/policy/{2}/rules/{3}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.parent_policy),
- name.replace('/', '_')
- )
- else:
- uri = "https://{0}:{1}/mgmt/tm/security/firewall/rule-list/{2}/rules/{3}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.parent_rule_list),
- name.replace('/', '_')
- )
- resp = self.client.api.get(uri)
- if resp.ok:
- return True
- return False
-
- def update(self):
- self.have = self.read_current_from_device()
- if not self.should_update():
- return False
- if self.module.check_mode:
- return True
- self.update_on_device()
- return True
-
- def remove(self):
- if self.module.check_mode:
- return True
- self.remove_from_device()
- if self.exists():
- raise F5ModuleError("Failed to delete the resource.")
- return True
-
- def create(self):
- self._set_changed_options()
- self.set_reasonable_creation_defaults()
- if self.want.status == 'scheduled' and self.want.schedule is None:
- raise F5ModuleError(
- "A 'schedule' must be specified when 'status' is 'scheduled'."
- )
- if self.module.check_mode:
- return True
- self.create_on_device()
- return True
-
- def set_reasonable_creation_defaults(self):
- if self.want.action is None:
- self.changes.update({'action': 'reject'})
- if self.want.logging is None:
- self.changes.update({'logging': False})
- if self.want.status is None:
- self.changes.update({'status': 'enabled'})
-
- def create_on_device(self):
- params = self.changes.api_params()
- name = self.want.name
- params['name'] = name.replace('/', '_')
- params['partition'] = self.want.partition
- params['placeAfter'] = 'last'
-
- if self.want.parent_policy:
- uri = "https://{0}:{1}/mgmt/tm/security/firewall/policy/{2}/rules/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.parent_policy),
- )
- else:
- uri = "https://{0}:{1}/mgmt/tm/security/firewall/rule-list/{2}/rules/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.parent_rule_list),
- )
- if self.changes.protocol not in ['icmp', 'icmpv6']:
- if self.changes.icmp_message is not None:
- raise F5ModuleError(
- "The 'icmp_message' can only be specified when 'protocol' is 'icmp' or 'icmpv6'."
- )
-
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403, 404]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def update_on_device(self):
- name = self.want.name
- if self.want.parent_policy and self.want.rule_list:
- uri = "https://{0}:{1}/mgmt/tm/security/firewall/policy/{2}/rules/{3}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.parent_policy),
- name.replace('/', '_')
- )
-
- elif self.want.parent_policy:
- uri = "https://{0}:{1}/mgmt/tm/security/firewall/policy/{2}/rules/{3}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.parent_policy),
- name.replace('/', '_')
- )
- else:
- uri = "https://{0}:{1}/mgmt/tm/security/firewall/rule-list/{2}/rules/{3}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.parent_rule_list),
- name.replace('/', '_')
- )
-
- if self.have.protocol not in ['icmp', 'icmpv6'] and self.changes.protocol not in ['icmp', 'icmpv6']:
- if self.changes.icmp_message is not None:
- raise F5ModuleError(
- "The 'icmp_message' can only be specified when 'protocol' is 'icmp' or 'icmpv6'."
- )
- if self.changes.protocol in ['icmp', 'icmpv6']:
- self.changes.update({'source': {}})
- self.changes.update({'destination': {}})
-
- params = self.changes.api_params()
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403, 404]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def absent(self):
- if self.exists():
- return self.remove()
- return False
-
- def remove_from_device(self):
- name = self.want.name
- if self.want.parent_policy:
- uri = "https://{0}:{1}/mgmt/tm/security/firewall/policy/{2}/rules/{3}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.parent_policy),
- name.replace('/', '_')
- )
- else:
- uri = "https://{0}:{1}/mgmt/tm/security/firewall/rule-list/{2}/rules/{3}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.parent_rule_list),
- name.replace('/', '_')
- )
-
- resp = self.client.api.delete(uri)
- if resp.status == 200:
- return True
-
- def read_current_from_device(self):
- if self.want.parent_policy:
- uri = "https://{0}:{1}/mgmt/tm/security/firewall/policy/{2}/rules/{3}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.parent_policy),
- self.want.name
- )
- else:
- uri = "https://{0}:{1}/mgmt/tm/security/firewall/rule-list/{2}/rules/{3}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.parent_rule_list),
- self.want.name
- )
-
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return ApiParameters(params=response)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- name=dict(required=True),
- parent_policy=dict(),
- parent_rule_list=dict(),
- logging=dict(type='bool'),
- protocol=dict(),
- irule=dict(),
- description=dict(),
- source=dict(
- type='list',
- elements='dict',
- options=dict(
- address=dict(),
- address_list=dict(),
- address_range=dict(),
- country=dict(),
- port=dict(type='int'),
- port_list=dict(),
- port_range=dict(),
- vlan=dict(),
- ),
- mutually_exclusive=[[
- 'address', 'address_list', 'address_range', 'country', 'vlan',
- 'port', 'port_range', 'port_list'
- ]]
- ),
- destination=dict(
- type='list',
- elements='dict',
- options=dict(
- address=dict(),
- address_list=dict(),
- address_range=dict(),
- country=dict(),
- port=dict(type='int'),
- port_list=dict(),
- port_range=dict(),
- ),
- mutually_exclusive=[[
- 'address', 'address_list', 'address_range', 'country',
- 'port', 'port_range', 'port_list'
- ]]
- ),
- action=dict(
- choices=['accept', 'drop', 'reject', 'accept-decisively']
- ),
- status=dict(
- choices=['enabled', 'disabled', 'scheduled']
- ),
- schedule=dict(),
- rule_list=dict(),
- icmp_message=dict(
- type='list',
- elements='dict',
- options=dict(
- type=dict(),
- code=dict(),
- )
- ),
- partition=dict(
- default='Common',
- fallback=(env_fallback, ['F5_PARTITION'])
- ),
- state=dict(
- default='present',
- choices=['present', 'absent']
- )
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
- self.mutually_exclusive = [
- ['rule_list', 'action'],
- ['rule_list', 'source'],
- ['rule_list', 'destination'],
- ['rule_list', 'irule'],
- ['rule_list', 'protocol'],
- ['rule_list', 'logging'],
- ['parent_policy', 'parent_rule_list']
- ]
- self.required_one_of = [
- ['parent_policy', 'parent_rule_list']
- ]
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode,
- mutually_exclusive=spec.mutually_exclusive,
- required_one_of=spec.required_one_of
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_firewall_rule_list.py b/lib/ansible/modules/network/f5/bigip_firewall_rule_list.py
deleted file mode 100644
index 6eab445bd5..0000000000
--- a/lib/ansible/modules/network/f5/bigip_firewall_rule_list.py
+++ /dev/null
@@ -1,532 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_firewall_rule_list
-short_description: Manage AFM security firewall policies on a BIG-IP
-description:
- - Manages AFM security firewall policies on a BIG-IP.
-version_added: 2.7
-options:
- name:
- description:
- - The name of the policy to create.
- type: str
- required: True
- description:
- description:
- - The description to attach to the policy.
- - This parameter is only supported on versions of BIG-IP >= 12.1.0. On earlier
- versions it will simply be ignored.
- type: str
- state:
- description:
- - When C(state) is C(present), ensures that the rule list exists.
- - When C(state) is C(absent), ensures that the rule list is removed.
- type: str
- choices:
- - present
- - absent
- default: present
- rules:
- description:
- - Specifies a list of rules that you want associated with this policy.
- The order of this list is the order they will be evaluated by BIG-IP.
- If the specified rules do not exist (for example when creating a new
- policy) then they will be created.
- - Rules specified here, if they do not exist, will be created with "default deny"
- behavior. It is expected that you follow-up this module with the actual
- configuration for these rules.
- - The C(bigip_firewall_rule) module can be used to also create, as well as
- edit, existing and new rules.
- type: list
- partition:
- description:
- - Device partition to manage resources on.
- type: str
- default: Common
-extends_documentation_fragment: f5
-author:
- - Tim Rupp (@caphrim007)
-'''
-
-EXAMPLES = r'''
-- name: Create a basic policy with some rule stubs
- bigip_firewall_rule_list:
- name: foo
- rules:
- - rule1
- - rule2
- - rule3
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-'''
-
-RETURN = r'''
-description:
- description: The new description of the policy.
- returned: changed
- type: str
- sample: My firewall policy
-rules:
- description: The list of rules, in the order that they are evaluated, on the device.
- returned: changed
- type: list
- sample: ['rule1', 'rule2', 'rule3']
-'''
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.basic import env_fallback
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.common import transform_name
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.common import transform_name
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'rulesReference': 'rules'
- }
-
- api_attributes = [
- 'description'
- ]
-
- returnables = [
- 'description',
- 'rules',
- ]
-
- updatables = [
- 'description',
- 'rules'
- ]
-
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class ModuleParameters(Parameters):
- @property
- def rules(self):
- if self._values['rules'] is None:
- return None
- # In case rule values are unicode (as they may be coming from the API
- result = [str(x) for x in self._values['rules']]
- return result
-
-
-class ApiParameters(Parameters):
- @property
- def rules(self):
- result = []
- if self._values['rules'] is None or 'items' not in self._values['rules']:
- return []
- for idx, item in enumerate(self._values['rules']['items']):
- result.append(dict(item=item['fullPath'], order=idx))
- result = [x['item'] for x in sorted(result, key=lambda k: k['order'])]
- return result
-
-
-class Changes(Parameters):
- pass
-
-
-class UsableChanges(Changes):
- pass
-
-
-class ReportableChanges(Changes):
- pass
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
- @property
- def rules(self):
- if self.want.rules is None:
- return None
- if self.have.rules is None:
- return self.want.rules
- if set(self.want.rules) != set(self.have.rules):
- return self.want.rules
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(params=self.module.params)
- self.have = ApiParameters()
- self.changes = UsableChanges()
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = Changes(params=changed)
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = Changes(params=changed)
- return True
- return False
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def exec_module(self):
- changed = False
- result = dict()
- state = self.want.state
-
- if state == "present":
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
-
- changes = self.changes.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def present(self):
- if self.exists():
- return self.update()
- else:
- return self.create()
-
- def exists(self):
- uri = "https://{0}:{1}/mgmt/tm/security/firewall/rule-list/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def update(self):
- self.have = self.read_current_from_device()
- if not self.should_update():
- return False
- if self.module.check_mode:
- return True
- self.update_on_device()
- return True
-
- def remove(self):
- if self.module.check_mode:
- return True
- self.remove_from_device()
- if self.exists():
- raise F5ModuleError("Failed to delete the resource.")
- return True
-
- def create(self):
- self._set_changed_options()
- if self.module.check_mode:
- return True
- self.create_on_device()
- return True
-
- def create_on_device(self):
- params = self.changes.api_params()
- params['name'] = self.want.name
- params['partition'] = self.want.partition
- uri = "https://{0}:{1}/mgmt/tm/security/firewall/rule-list/".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- if self.want.rules:
- self._upsert_policy_rules_on_device()
- return response['selfLink']
-
- def update_on_device(self):
- params = self.changes.api_params()
- uri = "https://{0}:{1}/mgmt/tm/security/firewall/rule-list/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- if params:
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return response['selfLink']
- if self.changes.rules is not None:
- self._upsert_policy_rules_on_device()
-
- def absent(self):
- if self.exists():
- return self.remove()
- return False
-
- def remove_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/security/firewall/rule-list/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.delete(uri)
- if resp.status == 200:
- return True
- raise F5ModuleError(resp.content)
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/security/firewall/rule-list/{2}/?expandSubcollections=true".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return ApiParameters(params=response)
-
- def rule_exists(self, rule):
- uri = "https://{0}:{1}/mgmt/tm/security/firewall/rule-list/{2}/rules/{3}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name),
- rule.replace('/', '_')
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def create_default_rule_on_device(self, rule):
- params = dict(
- name=rule.replace('/', '_'),
- action='reject',
- # Adding items to the end of the list causes the list of rules to match
- # what the user specified in the original list.
- placeAfter='last',
- )
- uri = "https://{0}:{1}/mgmt/tm/security/firewall/rule-list/{2}/rules/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name),
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return response['selfLink']
-
- def remove_rule_from_device(self, rule):
- uri = "https://{0}:{1}/mgmt/tm/security/firewall/rule-list/{2}/rules/{3}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name),
- rule.replace('/', '_'),
- )
- # this response returns no payload
- resp = self.client.api.delete(uri)
- if resp.status in [400, 403]:
- raise F5ModuleError(resp.content)
-
- def move_rule_to_front(self, rule):
- params = dict(
- placeAfter='last'
- )
- uri = "https://{0}:{1}/mgmt/tm/security/firewall/rule-list/{2}/rules/{3}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name),
- rule.replace('/', '_')
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return response['selfLink']
-
- def _upsert_policy_rules_on_device(self):
- rules = self.changes.rules
- if rules is None:
- rules = []
- self._remove_rule_difference(rules)
-
- for idx, rule in enumerate(rules):
- if not self.rule_exists(rule):
- self.create_default_rule_on_device(rule)
- for idx, rule in enumerate(rules):
- self.move_rule_to_front(rule)
-
- def _remove_rule_difference(self, rules):
- if rules is None or self.have.rules is None:
- return
- have_rules = set(self.have.rules)
- want_rules = set(rules)
- removable = have_rules.difference(want_rules)
- for remove in removable:
- self.remove_rule_from_device(remove)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- name=dict(required=True),
- description=dict(),
- rules=dict(type='list'),
- partition=dict(
- default='Common',
- fallback=(env_fallback, ['F5_PARTITION'])
- ),
- state=dict(
- default='present',
- choices=['present', 'absent']
- )
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode,
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_firewall_schedule.py b/lib/ansible/modules/network/f5/bigip_firewall_schedule.py
deleted file mode 100644
index 19c596f844..0000000000
--- a/lib/ansible/modules/network/f5/bigip_firewall_schedule.py
+++ /dev/null
@@ -1,670 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2019, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_firewall_schedule
-short_description: Manage BIG-IP AFM schedule configurations
-description:
- - Manage BIG-IP AFM schedule configurations.
-version_added: 2.9
-options:
- name:
- description:
- - Specifies the name of the AFM schedule configuration.
- type: str
- required: True
- description:
- description:
- - Specifies the user defined description text.
- type: str
- daily_hour_end:
- description:
- - Specifies the time of day the rule will stop being used.
- - When not defined, the default of C(24:00) is used when creating a new schedule.
- - The time zone is always assumed to be UTC and values must be provided as C(HH:MM) using 24hour clock format.
- type: str
- daily_hour_start:
- description:
- - Specifies the time of day the rule will start to be in use.
- - The value must be a time before C(daily_hour_end).
- - When not defined, the default of C(0:00) is used when creating a new schedule.
- - When the value is set to C(all-day) both C(daily_hour_end) and C(daily_hour_start) are reset to their respective
- defaults.
- - The time zone is always assumed to be UTC and values must be provided as C(HH:MM) using 24hour clock format.
- type: str
- date_valid_end:
- description:
- - Specifies the end date/time this schedule will apply to the rule.
- - The date must be after C(date_valid_start)
- - When not defined the default of C(indefinite) is used when creating a new schedule.
- - The time zone is always assumed to be UTC.
- - The datetime format should always be the following C(YYYY-MM-DD:HH:MM:SS) format.
- type: str
- date_valid_start:
- description:
- - Specifies the start date/time this schedule will apply to the rule.
- - When not defined the default of C(epoch) is used when creating a new schedule.
- - The time zone is always assumed to be UTC.
- - The datetime format should always be the following C(YYYY-MM-DD:HH:MM:SS) format.
- type: str
- days_of_week:
- description:
- - Specifies which days of the week the rule will be applied.
- - When not defined the default value of C(all) is used when creating a new schedule.
- - The C(all) value is mutually exclusive with other choices.
- type: list
- choices:
- - sunday
- - monday
- - tuesday
- - wednesday
- - thursday
- - friday
- - saturday
- - all
- state:
- description:
- - When C(present), ensures that the resource exists.
- - When C(absent), ensures the resource is removed.
- type: str
- choices:
- - present
- - absent
- default: present
- partition:
- description:
- - Device partition to manage resources on.
- type: str
- default: Common
-extends_documentation_fragment: f5
-author:
- - Wojciech Wypior (@wojtek0806)
-'''
-
-EXAMPLES = r'''
-- name: Create a 6 hour two day schedule, no start/end date
- bigip_firewall_schedule:
- name: barfoo
- daily_hour_start: 13:00
- daily_hour_end: 19:00
- days_of_week:
- - monday
- - tuesday
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-
-- name: Create a seven day schedule with start/end date
- bigip_firewall_schedule:
- name: foobar
- date_valid_start: "{{ lookup('pipe','date +%Y-%m-%d:%H:%M:%S') }}"
- date_valid_end: "{{ lookup('pipe','date -d \"now + 7 days\" +%Y-%m-%d:%H:%M:%S') }}"
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-
-- name: Modify created schedule to all-day
- bigip_firewall_schedule:
- name: barfoo
- daily_hour_start: all-day
- days_of_week:
- - monday
- - tuesday
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-
-- name: Modify a schedule to have no end date
- bigip_firewall_schedule:
- name: foobar
- date_valid_start: "{{ lookup('pipe','date +%Y-%m-%d:%H:%M:%S') }}"
- date_valid_end: "indefinite"
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-
-- name: Remove created schedule
- bigip_firewall_schedule:
- name: foobar
- state: absent
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-'''
-
-RETURN = r'''
-daily_hour_start:
- description: The time of day the rule will start to be in use.
- returned: changed
- type: str
- sample: '13:00'
-daily_hour_end:
- description: The time of day the rule will stop being used.
- returned: changed
- type: str
- sample: '18:00'
-date_valid_start:
- description: The start date/time schedule will apply to the rule.
- returned: changed
- type: str
- sample: 2019-03-01:15:30:00
-date_valid_end:
- description: The end date/time schedule will apply to the rule.
- returned: changed
- type: str
- sample: 2019-03-11:15:30:00
-days_of_week:
- description: The days of the week the rule will be applied.
- returned: changed
- type: list
- sample: ["monday","tuesday"]
-description:
- description: The user defined description text.
- returned: changed
- type: str
- sample: Foo is bar
-'''
-
-import re
-import datetime
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.basic import env_fallback
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import fq_name
- from library.module_utils.network.f5.common import transform_name
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.compare import cmp_str_with_none
- from library.module_utils.network.f5.compare import cmp_simple_list
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import fq_name
- from ansible.module_utils.network.f5.common import transform_name
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.compare import cmp_str_with_none
- from ansible.module_utils.network.f5.compare import cmp_simple_list
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'dailyHourEnd': 'daily_hour_end',
- 'dailyHourStart': 'daily_hour_start',
- 'dateValidEnd': 'date_valid_end',
- 'dateValidStart': 'date_valid_start',
- 'daysOfWeek': 'days_of_week',
- }
-
- api_attributes = [
- 'dailyHourEnd',
- 'dailyHourStart',
- 'dateValidEnd',
- 'dateValidStart',
- 'daysOfWeek',
- 'description',
- ]
-
- returnables = [
- 'daily_hour_end',
- 'daily_hour_start',
- 'date_valid_end',
- 'date_valid_start',
- 'days_of_week',
- 'description'
- ]
-
- updatables = [
- 'daily_hour_end',
- 'daily_hour_start',
- 'date_valid_end',
- 'date_valid_start',
- 'days_of_week',
- 'description'
- ]
-
-
-class ApiParameters(Parameters):
- pass
-
-
-class ModuleParameters(Parameters):
- def _convert_datetime(self, value):
- p = r'(\d{4})-(\d{1,2})-(\d{1,2})[:, T](\d{2}):(\d{2}):(\d{2})'
- match = re.match(p, value)
- if match:
- date = '{0}-{1}-{2}T{3}:{4}:{5}Z'.format(*match.group(1, 2, 3, 4, 5, 6))
- return date
- raise F5ModuleError(
- 'Invalid datetime provided.'
- )
-
- def _validate_time(self, value):
- p = r'(\d{2}):(\d{2})'
- match = re.match(p, value)
- if match:
- time = int(match.group(1)), int(match.group(2))
- try:
- datetime.time(*time)
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- def _compare_date_time(self, value1, value2, time=False):
- if time:
- p1 = r'(\d{2}):(\d{2})'
- m1 = re.match(p1, value1)
- m2 = re.match(p1, value2)
- if m1 and m2:
- start = tuple(int(i) for i in m1.group(1, 2))
- end = tuple(int(i) for i in m2.group(1, 2))
- if datetime.time(*start) > datetime.time(*end):
- raise F5ModuleError(
- 'End time must be later than start time.'
- )
- else:
- p1 = r'(\d{4})-(\d{1,2})-(\d{1,2})[:, T](\d{2}):(\d{2}):(\d{2})'
- m1 = re.match(p1, value1)
- m2 = re.match(p1, value2)
- if m1 and m2:
- start = tuple(int(i) for i in m1.group(1, 2, 3, 4, 5, 6))
- end = tuple(int(i) for i in m2.group(1, 2, 3, 4, 5, 6))
- if datetime.datetime(*start) > datetime.datetime(*end):
- raise F5ModuleError(
- 'End date must be later than start date.'
- )
-
- @property
- def daily_hour_start(self):
- if self._values['daily_hour_start'] is None:
- return None
- if self._values['daily_hour_start'] == 'all-day':
- return '0:00'
- self._validate_time(self._values['daily_hour_start'])
- if self._values['daily_hour_end'] is not None and self.daily_hour_end != '24:00':
- self._compare_date_time(self._values['daily_hour_start'], self.daily_hour_end, time=True)
- return self._values['daily_hour_start']
-
- @property
- def daily_hour_end(self):
- if self._values['daily_hour_end'] is None:
- return None
- if self._values['daily_hour_start'] == 'all-day':
- return '24:00'
- if not self._values['daily_hour_end'] == '24:00':
- self._validate_time(self._values['daily_hour_end'])
- return self._values['daily_hour_end']
-
- @property
- def date_valid_end(self):
- if self._values['date_valid_end'] is None:
- return None
- if self._values['date_valid_end'] in ['2038-1-18:19:14:07', 'indefinite']:
- return 'indefinite'
- result = self._convert_datetime(self._values['date_valid_end'])
- return result
-
- @property
- def date_valid_start(self):
- if self._values['date_valid_start'] is None:
- return None
- if self._values['date_valid_start'] in ['1970-1-1:00:00:00', 'epoch']:
- return 'epoch'
- result = self._convert_datetime(self._values['date_valid_start'])
- if self._values['date_valid_end']:
- if self._values['date_valid_end'] not in ['2038-1-18:19:14:07', 'indefinite']:
- self._compare_date_time(result, self.date_valid_end)
- return result
-
- @property
- def days_of_week(self):
- if self._values['days_of_week'] is None:
- return None
- if 'all' in self._values['days_of_week']:
- if len(self._values['days_of_week']) > 1 and self._values['days_of_week'] is list:
- raise F5ModuleError(
- "The 'all' value must not be specified with other choices."
- )
- week = ['sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday']
- return week
- return self._values['days_of_week']
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class UsableChanges(Changes):
- pass
-
-
-class ReportableChanges(Changes):
- def _convert_datetime(self, value):
- if value is None:
- return None
- p = r'(\d{4})-(\d{1,2})-(\d{1,2})[:, T](\d{2}):(\d{2}):(\d{2})'
- match = re.match(p, value)
- if match:
- date = '{0}-{1}-{2}:{3}:{4}:{5}'.format(*match.group(1, 2, 3, 4, 5, 6))
- return date
-
- @property
- def date_valid_end(self):
- result = self._convert_datetime(self._values['date_valid_end'])
- return result
-
- @property
- def date_valid_start(self):
- result = self._convert_datetime(self._values['date_valid_start'])
- return result
-
- @property
- def days_of_week(self):
- if self._values['days_of_week'] is None:
- return None
- if len(self._values['days_of_week']) == 7:
- return 'all'
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
- @property
- def description(self):
- return cmp_str_with_none(self.want.description, self.have.description)
-
- @property
- def days_of_week(self):
- return cmp_simple_list(self.want.days_of_week, self.have.days_of_week)
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(params=self.module.params)
- self.have = ApiParameters()
- self.changes = UsableChanges()
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = UsableChanges(params=changed)
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.client.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def exec_module(self):
- changed = False
- result = dict()
- state = self.want.state
-
- if state == "present":
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def present(self):
- if self.exists():
- return self.update()
- else:
- return self.create()
-
- def absent(self):
- if self.exists():
- return self.remove()
- return False
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def update(self):
- self.have = self.read_current_from_device()
- if not self.should_update():
- return False
- if self.module.check_mode:
- return True
- self.update_on_device()
- return True
-
- def remove(self):
- if self.module.check_mode:
- return True
- self.remove_from_device()
- if self.exists():
- raise F5ModuleError("Failed to delete the resource.")
- return True
-
- def create(self):
- self._set_changed_options()
- if self.module.check_mode:
- return True
- self.create_on_device()
- return True
-
- def exists(self):
- uri = "https://{0}:{1}/mgmt/tm/security/firewall/schedule/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def create_on_device(self):
- params = self.changes.api_params()
- params['name'] = self.want.name
- params['partition'] = self.want.partition
- uri = "https://{0}:{1}/mgmt/tm/security/firewall/schedule/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 409]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return True
-
- def update_on_device(self):
- params = self.changes.api_params()
- uri = "https://{0}:{1}/mgmt/tm/security/firewall/schedule/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def remove_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/security/firewall/schedule/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- response = self.client.api.delete(uri)
- if response.status == 200:
- return True
- raise F5ModuleError(response.content)
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/security/firewall/schedule/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return ApiParameters(params=response)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- name=dict(
- required=True
- ),
- description=dict(),
- daily_hour_end=dict(),
- daily_hour_start=dict(),
- date_valid_end=dict(),
- date_valid_start=dict(),
- days_of_week=dict(
- type='list',
- choices=[
- 'sunday',
- 'monday',
- 'tuesday',
- 'wednesday',
- 'thursday',
- 'friday',
- 'saturday',
- 'all',
- ]
- ),
- state=dict(default='present', choices=['absent', 'present']),
- partition=dict(
- default='Common',
- fallback=(env_fallback, ['F5_PARTITION'])
- )
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode,
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_gtm_datacenter.py b/lib/ansible/modules/network/f5/bigip_gtm_datacenter.py
deleted file mode 100644
index df56aa96eb..0000000000
--- a/lib/ansible/modules/network/f5/bigip_gtm_datacenter.py
+++ /dev/null
@@ -1,490 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['stableinterface'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_gtm_datacenter
-short_description: Manage Datacenter configuration in BIG-IP
-description:
- - Manage BIG-IP data center configuration. A data center defines the location
- where the physical network components reside, such as the server and link
- objects that share the same subnet on the network. This module is able to
- manipulate the data center definitions in a BIG-IP.
-version_added: 2.2
-options:
- contact:
- description:
- - The name of the contact for the data center.
- type: str
- description:
- description:
- - The description of the data center.
- type: str
- location:
- description:
- - The location of the data center.
- type: str
- name:
- description:
- - The name of the data center.
- type: str
- required: True
- state:
- description:
- - The virtual address state. If C(absent), an attempt to delete the
- virtual address will be made. This will only succeed if this
- virtual address is not in use by a virtual server. C(present) creates
- the virtual address and enables it. If C(enabled), enable the virtual
- address if it exists. If C(disabled), create the virtual address if
- needed, and set state to C(disabled).
- type: str
- choices:
- - present
- - absent
- - enabled
- - disabled
- default: present
- partition:
- description:
- - Device partition to manage resources on.
- type: str
- default: Common
- version_added: 2.5
-extends_documentation_fragment: f5
-author:
- - Tim Rupp (@caphrim007)
- - Wojciech Wypior (@wojtek0806)
-'''
-
-EXAMPLES = r'''
-- name: Create data center "New York"
- bigip_gtm_datacenter:
- name: New York
- location: 222 West 23rd
- provider:
- user: admin
- password: secret
- server: lb.mydomain.com
- delegate_to: localhost
-'''
-
-RETURN = r'''
-contact:
- description: The contact that was set on the datacenter.
- returned: changed
- type: str
- sample: admin@root.local
-description:
- description: The description that was set for the datacenter.
- returned: changed
- type: str
- sample: Datacenter in NYC
-enabled:
- description: Whether the datacenter is enabled or not
- returned: changed
- type: bool
- sample: true
-disabled:
- description: Whether the datacenter is disabled or not.
- returned: changed
- type: bool
- sample: true
-state:
- description: State of the datacenter.
- returned: changed
- type: str
- sample: disabled
-location:
- description: The location that is set for the datacenter.
- returned: changed
- type: str
- sample: 222 West 23rd
-'''
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.basic import env_fallback
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import fq_name
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.common import transform_name
- from library.module_utils.network.f5.icontrol import module_provisioned
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import fq_name
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.common import transform_name
- from ansible.module_utils.network.f5.icontrol import module_provisioned
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {}
-
- updatables = [
- 'location', 'description', 'contact', 'state',
- ]
-
- returnables = [
- 'location', 'description', 'contact', 'state', 'enabled', 'disabled',
- ]
-
- api_attributes = [
- 'enabled', 'location', 'description', 'contact', 'disabled',
- ]
-
-
-class ApiParameters(Parameters):
- @property
- def disabled(self):
- if self._values['disabled'] is True:
- return True
- return None
-
- @property
- def enabled(self):
- if self._values['enabled'] is True:
- return True
- return None
-
-
-class ModuleParameters(Parameters):
- @property
- def disabled(self):
- if self._values['state'] == 'disabled':
- return True
- return None
-
- @property
- def enabled(self):
- if self._values['state'] in ['enabled', 'present']:
- return True
- return None
-
- @property
- def state(self):
- if self.enabled and self._values['state'] != 'present':
- return 'enabled'
- elif self.disabled and self._values['state'] != 'present':
- return 'disabled'
- else:
- return self._values['state']
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class UsableChanges(Changes):
- @property
- def disabled(self):
- if self._values['state'] == 'disabled':
- return True
-
- @property
- def enabled(self):
- if self._values['state'] in ['enabled', 'present']:
- return True
-
-
-class ReportableChanges(Changes):
- @property
- def disabled(self):
- if self._values['state'] == 'disabled':
- return True
- elif self._values['state'] in ['enabled', 'present']:
- return False
- return None
-
- @property
- def enabled(self):
- if self._values['state'] in ['enabled', 'present']:
- return True
- elif self._values['state'] == 'disabled':
- return False
- return None
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
- @property
- def state(self):
- if self.want.enabled != self.have.enabled:
- return dict(
- state=self.want.state,
- enabled=self.want.enabled
- )
- if self.want.disabled != self.have.disabled:
- return dict(
- state=self.want.state,
- disabled=self.want.disabled
- )
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.pop('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(params=self.module.params)
- self.have = ApiParameters()
- self.changes = UsableChanges()
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def exec_module(self):
- if not module_provisioned(self.client, 'gtm'):
- raise F5ModuleError(
- "GTM must be provisioned to use this module."
- )
- changed = False
- result = dict()
- state = self.want.state
-
- if state in ['present', 'enabled', 'disabled']:
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def present(self):
- if self.exists():
- return self.update()
- else:
- return self.create()
-
- def absent(self):
- changed = False
- if self.exists():
- changed = self.remove()
- return changed
-
- def create(self):
- self.have = ApiParameters()
- self.should_update()
- if self.module.check_mode:
- return True
- self.create_on_device()
- if self.exists():
- return True
- else:
- raise F5ModuleError("Failed to create the datacenter")
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def update(self):
- self.have = self.read_current_from_device()
- if not self.should_update():
- return False
- if self.module.check_mode:
- return True
- self.update_on_device()
- return True
-
- def remove(self):
- if self.module.check_mode:
- return True
- self.remove_from_device()
- if self.exists():
- raise F5ModuleError("Failed to delete the datacenter")
- return True
-
- def exists(self):
- uri = "https://{0}:{1}/mgmt/tm/gtm/datacenter/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def create_on_device(self):
- params = self.changes.api_params()
- params['name'] = self.want.name
- params['partition'] = self.want.partition
- uri = "https://{0}:{1}/mgmt/tm/gtm/datacenter/".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def update_on_device(self):
- params = self.changes.api_params()
- uri = "https://{0}:{1}/mgmt/tm/gtm/datacenter/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def remove_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/gtm/datacenter/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.delete(uri)
- if resp.status == 200:
- return True
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/gtm/datacenter/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return ApiParameters(params=response)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- contact=dict(),
- description=dict(),
- location=dict(),
- name=dict(required=True),
- state=dict(
- default='present',
- choices=['present', 'absent', 'disabled', 'enabled']
- ),
- partition=dict(
- default='Common',
- fallback=(env_fallback, ['F5_PARTITION'])
- )
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode,
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_gtm_global.py b/lib/ansible/modules/network/f5/bigip_gtm_global.py
deleted file mode 100644
index ff29498419..0000000000
--- a/lib/ansible/modules/network/f5/bigip_gtm_global.py
+++ /dev/null
@@ -1,349 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2018, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_gtm_global
-short_description: Manages global GTM settings
-description:
- - Manages global GTM settings. These settings include general, load balancing, and metrics
- related settings.
-version_added: 2.6
-options:
- synchronization:
- description:
- - Specifies whether this system is a member of a synchronization group.
- - When you enable synchronization, the system periodically queries other systems in
- the synchronization group to obtain and distribute configuration and metrics collection
- updates.
- - The synchronization group may contain systems configured as Global Traffic Manager and
- Link Controller systems.
- type: bool
- synchronization_group_name:
- description:
- - Specifies the name of the synchronization group to which the system belongs.
- type: str
- synchronize_zone_files:
- description:
- - Specifies that the system synchronizes Domain Name System (DNS) zone files among the
- synchronization group members.
- type: bool
-extends_documentation_fragment: f5
-author:
- - Tim Rupp (@caphrim007)
- - Wojciech Wypior (@wojtek0806)
-'''
-
-EXAMPLES = r'''
-- name: Configure synchronization settings
- bigip_gtm_global:
- synchronization: yes
- synchronization_group_name: my-group
- synchronize_zone_files: yes
- state: present
- provider:
- user: admin
- password: secret
- server: lb.mydomain.com
- delegate_to: localhost
-'''
-
-RETURN = r'''
-synchronization:
- description: The synchronization setting on the system.
- returned: changed
- type: bool
- sample: true
-synchronization_group_name:
- description: The synchronization group name.
- returned: changed
- type: str
- sample: my-group
-synchronize_zone_files:
- description: Whether or not the system will sync zone files.
- returned: changed
- type: str
- sample: my-group
-'''
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import fq_name
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.icontrol import module_provisioned
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import fq_name
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.icontrol import module_provisioned
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'synchronizationGroupName': 'synchronization_group_name',
- 'synchronizeZoneFiles': 'synchronize_zone_files',
- }
-
- api_attributes = [
- 'synchronizeZoneFiles', 'synchronizationGroupName', 'synchronization',
- ]
-
- returnables = [
- 'synchronization', 'synchronization_group_name', 'synchronize_zone_files',
- ]
-
- updatables = [
- 'synchronization', 'synchronization_group_name', 'synchronize_zone_files',
- ]
-
-
-class ApiParameters(Parameters):
- @property
- def synchronization(self):
- if self._values['synchronization'] is None:
- return None
- elif self._values['synchronization'] == 'no':
- return False
- else:
- return True
-
- @property
- def synchronize_zone_files(self):
- if self._values['synchronize_zone_files'] is None:
- return None
- elif self._values['synchronize_zone_files'] == 'no':
- return False
- else:
- return True
-
- @property
- def synchronization_group_name(self):
- if self._values['synchronization_group_name'] is None:
- return None
- return str(self._values['synchronization_group_name'])
-
-
-class ModuleParameters(Parameters):
- pass
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class UsableChanges(Changes):
- @property
- def synchronization(self):
- if self._values['synchronization'] is None:
- return None
- elif self._values['synchronization'] is False:
- return 'no'
- else:
- return 'yes'
-
- @property
- def synchronize_zone_files(self):
- if self._values['synchronize_zone_files'] is None:
- return None
- elif self._values['synchronize_zone_files'] is False:
- return 'no'
- else:
- return 'yes'
-
-
-class ReportableChanges(Changes):
- pass
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
- @property
- def synchronization_group_name(self):
- if self.want.synchronization_group_name is None:
- return None
- if self.want.synchronization_group_name == '' and self.have.synchronization_group_name is None:
- return None
- if self.want.synchronization_group_name != self.have.synchronization_group_name:
- return self.want.synchronization_group_name
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(params=self.module.params)
- self.have = ApiParameters()
- self.changes = UsableChanges()
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.client.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def exec_module(self): # lgtm [py/similar-function]
- if not module_provisioned(self.client, 'gtm'):
- raise F5ModuleError(
- "GTM must be provisioned to use this module."
- )
- result = dict()
-
- changed = self.present()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def present(self):
- return self.update()
-
- def update(self):
- self.have = self.read_current_from_device()
- if not self.should_update():
- return False
- if self.module.check_mode:
- return True
- self.update_on_device()
- return True
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def update_on_device(self):
- params = self.changes.api_params()
- uri = "https://{0}:{1}/mgmt/tm/gtm/global-settings/general/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/gtm/global-settings/general/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return ApiParameters(params=response)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- synchronization=dict(type='bool'),
- synchronization_group_name=dict(),
- synchronize_zone_files=dict(type='bool')
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode,
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_gtm_monitor_bigip.py b/lib/ansible/modules/network/f5/bigip_gtm_monitor_bigip.py
deleted file mode 100644
index 4dd9ecc634..0000000000
--- a/lib/ansible/modules/network/f5/bigip_gtm_monitor_bigip.py
+++ /dev/null
@@ -1,663 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_gtm_monitor_bigip
-short_description: Manages F5 BIG-IP GTM BIG-IP monitors
-description:
- - Manages F5 BIG-IP GTM BIG-IP monitors. This monitor is used by GTM to monitor
- BIG-IPs themselves.
-version_added: 2.6
-options:
- name:
- description:
- - Monitor name.
- type: str
- required: True
- parent:
- description:
- - The parent template of this monitor template. Once this value has
- been set, it cannot be changed. By default, this value is the C(bigip)
- parent on the C(Common) partition.
- type: str
- default: "/Common/bigip"
- ip:
- description:
- - IP address part of the IP/port definition. If this parameter is not
- provided when creating a new monitor, then the default value will be
- '*'.
- type: str
- port:
- description:
- - Port address part of the IP/port definition. If this parameter is not
- provided when creating a new monitor, then the default value will be
- '*'. Note that if specifying an IP address, a value between 1 and 65535
- must be specified
- type: str
- interval:
- description:
- - Specifies, in seconds, the frequency at which the system issues the monitor
- check when either the resource is down or the status of the resource is unknown.
- - When creating a new monitor, if this parameter is not provided, then the
- default value will be C(30). This value B(must) be less than the C(timeout) value.
- type: int
- timeout:
- description:
- - Specifies the number of seconds the target has in which to respond to the
- monitor request.
- - If the target responds within the set time period, it is considered up.
- - If the target does not respond within the set time period, it is considered down.
- - When this value is set to 0 (zero), the system uses the interval from the parent monitor.
- - When creating a new monitor, if this parameter is not provided, then
- the default value will be C(90).
- type: int
- ignore_down_response:
- description:
- - Specifies that the monitor allows more than one probe attempt per interval.
- - When C(yes), specifies that the monitor ignores down responses for the duration of
- the monitor timeout. Once the monitor timeout is reached without the system receiving
- an up response, the system marks the object down.
- - When C(no), specifies that the monitor immediately marks an object down when it
- receives a down response.
- - When creating a new monitor, if this parameter is not provided, then the default
- value will be C(no).
- type: bool
- aggregate_dynamic_ratios:
- description:
- - Specifies how the system combines the module values to create the proportion
- (score) for the load balancing operation.
- - The score represents the module's estimated capacity for handing traffic.
- - Averaged values are appropriate for downstream Web Accelerator or Application
- Security Manager virtual servers.
- - When creating a new monitor, if this parameter is not specified, the default
- of C(none) is used, meaning that the system does not use the scores in the load
- balancing operation.
- - When C(none), specifies that the monitor ignores the nodes and pool member scores.
- - When C(average-nodes), specifies that the system averages the dynamic ratios
- on the nodes associated with the monitor's target virtual servers and returns
- that average as the virtual servers' score.
- - When C(sum-nodes), specifies that the system adds together the scores of the
- nodes associated with the monitor's target virtual servers and uses that value
- in the load balancing operation.
- - When C(average-members), specifies that the system averages the dynamic ratios
- on the pool members associated with the monitor's target virtual servers and
- returns that average as the virtual servers' score.
- - When C(sum-members), specifies that the system adds together the scores of the
- pool members associated with the monitor's target virtual servers and uses
- that value in the load balancing operation.
- type: str
- choices:
- - none
- - average-nodes
- - sum-nodes
- - average-members
- - sum-members
- partition:
- description:
- - Device partition to manage resources on.
- type: str
- default: Common
- state:
- description:
- - When C(present), ensures that the monitor exists.
- - When C(absent), ensures the monitor is removed.
- type: str
- choices:
- - present
- - absent
- default: present
-notes:
- - Requires BIG-IP software version >= 12
-extends_documentation_fragment: f5
-author:
- - Tim Rupp (@caphrim007)
- - Wojciech Wypior (@wojtek0806)
-'''
-
-EXAMPLES = r'''
-- name: Create BIG-IP Monitor
- bigip_gtm_monitor_bigip:
- state: present
- ip: 10.10.10.10
- name: my_monitor
- provider:
- user: admin
- password: secret
- server: lb.mydomain.com
- delegate_to: localhost
-
-- name: Remove BIG-IP Monitor
- bigip_gtm_monitor_bigip:
- state: absent
- name: my_monitor
- provider:
- user: admin
- password: secret
- server: lb.mydomain.com
- delegate_to: localhost
-
-- name: Add BIG-IP monitor for all addresses, port 514
- bigip_gtm_monitor_bigip:
- port: 514
- name: my_monitor
- provider:
- user: admin
- password: secret
- server: lb.mydomain.com
- delegate_to: localhost
-'''
-
-RETURN = r'''
-parent:
- description: New parent template of the monitor.
- returned: changed
- type: str
- sample: bigip
-ip:
- description: The new IP of IP/port definition.
- returned: changed
- type: str
- sample: 10.12.13.14
-interval:
- description: The new interval in which to run the monitor check.
- returned: changed
- type: int
- sample: 2
-timeout:
- description: The new timeout in which the remote system must respond to the monitor.
- returned: changed
- type: int
- sample: 10
-aggregate_dynamic_ratios:
- description: The new aggregate of to the monitor.
- returned: changed
- type: str
- sample: sum-members
-ignore_down_response:
- description: Whether to ignore the down response or not.
- returned: changed
- type: bool
- sample: True
-'''
-
-import os
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.basic import env_fallback
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import fq_name
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.common import transform_name
- from library.module_utils.network.f5.icontrol import module_provisioned
- from library.module_utils.network.f5.ipaddress import is_valid_ip
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import fq_name
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.common import transform_name
- from ansible.module_utils.network.f5.icontrol import module_provisioned
- from ansible.module_utils.network.f5.ipaddress import is_valid_ip
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'defaultsFrom': 'parent',
- 'ignoreDownResponse': 'ignore_down_response',
- 'aggregateDynamicRatios': 'aggregate_dynamic_ratios',
- }
-
- api_attributes = [
- 'defaultsFrom', 'interval', 'timeout', 'destination', 'ignoreDownResponse',
- 'aggregateDynamicRatios',
- ]
-
- returnables = [
- 'parent', 'ip', 'port', 'interval', 'timeout', 'ignore_down_response',
- 'aggregate_dynamic_ratios',
- ]
-
- updatables = [
- 'destination', 'interval', 'timeout', 'ignore_down_response',
- 'aggregate_dynamic_ratios',
- ]
-
- @property
- def interval(self):
- if self._values['interval'] is None:
- return None
-
- if 1 > int(self._values['interval']) > 86400:
- raise F5ModuleError(
- "Interval value must be between 1 and 86400"
- )
- return int(self._values['interval'])
-
- @property
- def timeout(self):
- if self._values['timeout'] is None:
- return None
- return int(self._values['timeout'])
-
- @property
- def type(self):
- return 'bigip'
-
-
-class ApiParameters(Parameters):
- @property
- def ip(self):
- ip, port = self._values['destination'].split(':')
- return ip
-
- @property
- def port(self):
- ip, port = self._values['destination'].split(':')
- return int(port)
-
- @property
- def ignore_down_response(self):
- if self._values['ignore_down_response'] is None:
- return None
- if self._values['ignore_down_response'] == 'disabled':
- return False
- return True
-
-
-class ModuleParameters(Parameters):
- @property
- def destination(self):
- if self.ip is None and self.port is None:
- return None
- destination = '{0}:{1}'.format(self.ip, self.port)
- return destination
-
- @property
- def parent(self):
- if self._values['parent'] is None:
- return None
- if self._values['parent'].startswith('/'):
- parent = os.path.basename(self._values['parent'])
- result = '/{0}/{1}'.format(self.partition, parent)
- else:
- result = '/{0}/{1}'.format(self.partition, self._values['parent'])
- return result
-
- @property
- def ip(self): # lgtm [py/similar-function]
- if self._values['ip'] is None:
- return None
- if self._values['ip'] in ['*', '0.0.0.0']:
- return '*'
- elif is_valid_ip(self._values['ip']):
- return self._values['ip']
- else:
- raise F5ModuleError(
- "The provided 'ip' parameter is not an IP address."
- )
-
- @property
- def port(self):
- if self._values['port'] is None:
- return None
- elif self._values['port'] == '*':
- return '*'
- return int(self._values['port'])
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- return result
- except Exception:
- return result
-
-
-class UsableChanges(Changes):
- @property
- def ignore_down_response(self):
- if self._values['ignore_down_response']:
- return 'enabled'
- return 'disabled'
-
-
-class ReportableChanges(Changes):
- pass
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- result = self.__default(param)
- return result
-
- @property
- def parent(self):
- if self.want.parent != self.have.parent:
- raise F5ModuleError(
- "The parent monitor cannot be changed"
- )
-
- @property
- def destination(self):
- if self.want.ip is None and self.want.port is None:
- return None
- if self.want.port is None:
- self.want.update({'port': self.have.port})
- if self.want.ip is None:
- self.want.update({'ip': self.have.ip})
-
- if self.want.port in [None, '*'] and self.want.ip != '*':
- raise F5ModuleError(
- "Specifying an IP address requires that a port number be specified"
- )
-
- if self.want.destination != self.have.destination:
- return self.want.destination
-
- @property
- def interval(self):
- if self.want.timeout is not None and self.want.interval is not None:
- if self.want.interval >= self.want.timeout:
- raise F5ModuleError(
- "Parameter 'interval' must be less than 'timeout'."
- )
- elif self.want.timeout is not None:
- if self.have.interval >= self.want.timeout:
- raise F5ModuleError(
- "Parameter 'interval' must be less than 'timeout'."
- )
- elif self.want.interval is not None:
- if self.want.interval >= self.have.timeout:
- raise F5ModuleError(
- "Parameter 'interval' must be less than 'timeout'."
- )
- if self.want.interval != self.have.interval:
- return self.want.interval
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.have = None
- self.want = ModuleParameters(params=self.module.params)
- self.changes = UsableChanges()
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = UsableChanges(params=changed)
-
- def _update_changed_options(self): # lgtm [py/similar-function]
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def _set_default_creation_values(self):
- if self.want.timeout is None:
- self.want.update({'timeout': 120})
- if self.want.interval is None:
- self.want.update({'interval': 30})
- if self.want.ip is None:
- self.want.update({'ip': '*'})
- if self.want.port is None:
- self.want.update({'port': '*'})
- if self.want.ignore_down_response is None:
- self.want.update({'ignore_down_response': False})
- if self.want.aggregate_dynamic_ratios is None:
- self.want.update({'aggregate_dynamic_ratios': 'none'})
-
- def exec_module(self):
- if not module_provisioned(self.client, 'gtm'):
- raise F5ModuleError(
- "GTM must be provisioned to use this module."
- )
- changed = False
- result = dict()
- state = self.want.state
-
- if state in ["present", "disabled"]:
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def present(self):
- if self.exists():
- return self.update()
- else:
- return self.create()
-
- def create(self):
- self._set_changed_options()
- self._set_default_creation_values()
- if self.module.check_mode:
- return True
- self.create_on_device()
- return True
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def update(self):
- self.have = self.read_current_from_device()
- if not self.should_update():
- return False
- if self.module.check_mode:
- return True
- self.update_on_device()
- return True
-
- def absent(self):
- if self.exists():
- return self.remove()
- return False
-
- def remove(self):
- if self.module.check_mode:
- return True
- self.remove_from_device()
- if self.exists():
- raise F5ModuleError("Failed to delete the monitor.")
- return True
-
- def exists(self):
- uri = "https://{0}:{1}/mgmt/tm/gtm/monitor/bigip/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def create_on_device(self):
- params = self.changes.api_params()
- params['name'] = self.want.name
- params['partition'] = self.want.partition
- uri = "https://{0}:{1}/mgmt/tm/gtm/monitor/bigip/".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def update_on_device(self):
- params = self.changes.api_params()
- uri = "https://{0}:{1}/mgmt/tm/gtm/monitor/bigip/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def remove_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/gtm/monitor/bigip/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.delete(uri)
- if resp.status == 200:
- return True
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/gtm/monitor/bigip/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return ApiParameters(params=response)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- name=dict(required=True),
- parent=dict(default='/Common/bigip'),
- ip=dict(),
- port=dict(),
- interval=dict(type='int'),
- timeout=dict(type='int'),
- ignore_down_response=dict(type='bool'),
- aggregate_dynamic_ratios=dict(
- choices=[
- 'none', 'average-nodes', 'sum-nodes', 'average-members', 'sum-members'
- ]
- ),
- state=dict(
- default='present',
- choices=['present', 'absent']
- ),
- partition=dict(
- default='Common',
- fallback=(env_fallback, ['F5_PARTITION'])
- )
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode,
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_gtm_monitor_external.py b/lib/ansible/modules/network/f5/bigip_gtm_monitor_external.py
deleted file mode 100644
index b1eea86916..0000000000
--- a/lib/ansible/modules/network/f5/bigip_gtm_monitor_external.py
+++ /dev/null
@@ -1,706 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2018, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_gtm_monitor_external
-short_description: Manages external GTM monitors on a BIG-IP
-description:
- - Manages external GTM monitors on a BIG-IP.
-version_added: 2.6
-options:
- name:
- description:
- - Specifies the name of the monitor.
- type: str
- required: True
- parent:
- description:
- - The parent template of this monitor template. Once this value has
- been set, it cannot be changed. By default, this value is the C(http)
- parent on the C(Common) partition.
- type: str
- default: "/Common/external"
- arguments:
- description:
- - Specifies any command-line arguments that the script requires.
- type: str
- ip:
- description:
- - IP address part of the IP/port definition. If this parameter is not
- provided when creating a new monitor, then the default value will be
- '*'.
- type: str
- port:
- description:
- - Port address part of the IP/port definition. If this parameter is not
- provided when creating a new monitor, then the default value will be
- '*'. Note that if specifying an IP address, a value between 1 and 65535
- must be specified.
- type: str
- external_program:
- description:
- - Specifies the name of the file for the monitor to use. In order to reference
- a file, you must first import it using options on the System > File Management > External
- Monitor Program File List > Import screen. The BIG-IP system automatically
- places the file in the proper location on the file system.
- type: str
- interval:
- description:
- - The interval specifying how frequently the monitor instance of this
- template will run. If this parameter is not provided when creating
- a new monitor, then the default value will be 30. This value B(must)
- be less than the C(timeout) value.
- type: int
- timeout:
- description:
- - The number of seconds in which the node or service must respond to
- the monitor request. If the target responds within the set time
- period, it is considered up. If the target does not respond within
- the set time period, it is considered down. You can change this
- number to any number you want, however, it should be 3 times the
- interval number of seconds plus 1 second. If this parameter is not
- provided when creating a new monitor, then the default value will be 120.
- type: int
- variables:
- description:
- - Specifies any variables that the script requires.
- - Note that double quotes in values will be suppressed.
- type: dict
- partition:
- description:
- - Device partition to manage resources on.
- type: str
- default: Common
- state:
- description:
- - When C(present), ensures that the monitor exists.
- - When C(absent), ensures the monitor is removed.
- type: str
- choices:
- - present
- - absent
- default: present
-extends_documentation_fragment: f5
-author:
- - Tim Rupp (@caphrim007)
- - Wojciech Wypior (@wojtek0806)
-'''
-
-EXAMPLES = r'''
-- name: Create an external monitor
- bigip_gtm_monitor_external:
- name: foo
- state: present
- provider:
- user: admin
- password: secret
- server: lb.mydomain.com
- delegate_to: localhost
-
-- name: Create an external monitor with variables
- bigip_gtm_monitor_external:
- name: foo
- timeout: 10
- variables:
- var1: foo
- var2: bar
- state: present
- provider:
- user: admin
- password: secret
- server: lb.mydomain.com
- delegate_to: localhost
-
-- name: Add a variable to an existing set
- bigip_gtm_monitor_external:
- name: foo
- timeout: 10
- variables:
- var1: foo
- var2: bar
- cat: dog
- state: present
- provider:
- user: admin
- password: secret
- server: lb.mydomain.com
- delegate_to: localhost
-'''
-
-RETURN = r'''
-parent:
- description: New parent template of the monitor.
- returned: changed
- type: str
- sample: external
-ip:
- description: The new IP of IP/port definition.
- returned: changed
- type: str
- sample: 10.12.13.14
-interval:
- description: The new interval in which to run the monitor check.
- returned: changed
- type: int
- sample: 2
-timeout:
- description: The new timeout in which the remote system must respond to the monitor.
- returned: changed
- type: int
- sample: 10
-'''
-
-import os
-import re
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.basic import env_fallback
-from ansible.module_utils.six import iteritems
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import fq_name
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.common import transform_name
- from library.module_utils.network.f5.compare import compare_dictionary
- from library.module_utils.network.f5.icontrol import module_provisioned
- from library.module_utils.network.f5.ipaddress import is_valid_ip
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import fq_name
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.common import transform_name
- from ansible.module_utils.network.f5.compare import compare_dictionary
- from ansible.module_utils.network.f5.icontrol import module_provisioned
- from ansible.module_utils.network.f5.ipaddress import is_valid_ip
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'defaultsFrom': 'parent',
- 'apiRawValues': 'variables',
- 'run': 'external_program',
- 'args': 'arguments',
- }
-
- api_attributes = [
- 'defaultsFrom', 'interval', 'timeout', 'destination', 'run', 'args',
- ]
-
- returnables = [
- 'parent', 'ip', 'port', 'interval', 'timeout', 'variables', 'external_program',
- 'arguments',
- ]
-
- updatables = [
- 'destination', 'interval', 'timeout', 'variables', 'external_program',
- 'arguments',
- ]
-
- @property
- def destination(self):
- if self.ip is None and self.port is None:
- return None
- destination = '{0}:{1}'.format(self.ip, self.port)
- return destination
-
- @destination.setter
- def destination(self, value):
- ip, port = value.split(':')
- self._values['ip'] = ip
- self._values['port'] = port
-
- @property
- def interval(self):
- if self._values['interval'] is None:
- return None
-
- # Per BZ617284, the BIG-IP UI does not raise a warning about this.
- # So I do
- if 1 > int(self._values['interval']) > 86400:
- raise F5ModuleError(
- "Interval value must be between 1 and 86400"
- )
- return int(self._values['interval'])
-
- @property
- def timeout(self):
- if self._values['timeout'] is None:
- return None
- return int(self._values['timeout'])
-
- @property
- def ip(self):
- if self._values['ip'] is None:
- return None
- if self._values['ip'] in ['*', '0.0.0.0']:
- return '*'
- elif is_valid_ip(self._values['ip']):
- return self._values['ip']
- else:
- raise F5ModuleError(
- "The provided 'ip' parameter is not an IP address."
- )
-
- @property
- def port(self):
- if self._values['port'] is None:
- return None
- elif self._values['port'] == '*':
- return '*'
- return int(self._values['port'])
-
- @property
- def parent(self):
- if self._values['parent'] is None:
- return None
- if self._values['parent'].startswith('/'):
- parent = os.path.basename(self._values['parent'])
- result = '/{0}/{1}'.format(self.partition, parent)
- else:
- result = '/{0}/{1}'.format(self.partition, self._values['parent'])
- return result
-
- @property
- def type(self):
- return 'external'
-
-
-class ApiParameters(Parameters):
- @property
- def variables(self):
- if self._values['variables'] is None:
- return None
- pattern = r'^userDefined\s(?P<key>.*)'
- result = {}
- for k, v in iteritems(self._values['variables']):
- matches = re.match(pattern, k)
- if not matches:
- raise F5ModuleError(
- "Unable to find the variable 'key' in the API payload."
- )
- key = matches.group('key')
- result[key] = v
- return result
-
-
-class ModuleParameters(Parameters):
- @property
- def variables(self):
- if self._values['variables'] is None:
- return None
- result = {}
- for k, v in iteritems(self._values['variables']):
- result[k] = str(v).replace('"', '')
- return result
-
- @property
- def external_program(self):
- if self._values['external_program'] is None:
- return None
- return fq_name(self.partition, self._values['external_program'])
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class UsableChanges(Changes):
- pass
-
-
-class ReportableChanges(Changes):
- pass
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
- @property
- def parent(self):
- if self.want.parent != self.have.parent:
- raise F5ModuleError(
- "The parent monitor cannot be changed"
- )
-
- @property
- def destination(self):
- if self.want.ip is None and self.want.port is None:
- return None
- if self.want.port is None:
- self.want.update({'port': self.have.port})
- if self.want.ip is None:
- self.want.update({'ip': self.have.ip})
-
- if self.want.port in [None, '*'] and self.want.ip != '*':
- raise F5ModuleError(
- "Specifying an IP address requires that a port number be specified"
- )
-
- if self.want.destination != self.have.destination:
- return self.want.destination
-
- @property
- def interval(self):
- if self.want.timeout is not None and self.want.interval is not None:
- if self.want.interval >= self.want.timeout:
- raise F5ModuleError(
- "Parameter 'interval' must be less than 'timeout'."
- )
- elif self.want.timeout is not None:
- if self.have.interval >= self.want.timeout:
- raise F5ModuleError(
- "Parameter 'interval' must be less than 'timeout'."
- )
- elif self.want.interval is not None:
- if self.want.interval >= self.have.timeout:
- raise F5ModuleError(
- "Parameter 'interval' must be less than 'timeout'."
- )
- if self.want.interval != self.have.interval:
- return self.want.interval
-
- @property
- def variables(self):
- if self.want.variables is None:
- return None
- if self.have.variables is None:
- return dict(
- variables=self.want.variables
- )
- result = dict()
-
- different = compare_dictionary(self.want.variables, self.have.variables)
- if not different:
- return None
-
- for k, v in iteritems(self.want.variables):
- if k in self.have.variables and v != self.have.variables[k]:
- result[k] = v
- elif k not in self.have.variables:
- result[k] = v
- for k, v in iteritems(self.have.variables):
- if k not in self.want.variables:
- result[k] = "none"
- if result:
- result = dict(
- variables=result
- )
- return result
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(params=self.module.params)
- self.have = ApiParameters()
- self.changes = UsableChanges()
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = UsableChanges(params=changed)
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.client.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def _set_default_creation_values(self):
- if self.want.timeout is None:
- self.want.update({'timeout': 120})
- if self.want.interval is None:
- self.want.update({'interval': 30})
- if self.want.ip is None:
- self.want.update({'ip': '*'})
- if self.want.port is None:
- self.want.update({'port': '*'})
-
- def exec_module(self):
- if not module_provisioned(self.client, 'gtm'):
- raise F5ModuleError(
- "GTM must be provisioned to use this module."
- )
- changed = False
- result = dict()
- state = self.want.state
-
- if state == "present":
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def present(self):
- if self.exists():
- return self.update()
- else:
- return self.create()
-
- def absent(self):
- if self.exists():
- return self.remove()
- return False
-
- def create(self):
- self._set_changed_options()
- self._set_default_creation_values()
- if self.module.check_mode:
- return True
- self.create_on_device()
- return True
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def update(self):
- self.have = self.read_current_from_device()
- if not self.should_update():
- return False
- if self.module.check_mode:
- return True
- self.update_on_device()
- return True
-
- def remove(self):
- if self.module.check_mode:
- return True
- self.remove_from_device()
- if self.exists():
- raise F5ModuleError("Failed to delete the monitor.")
- return True
-
- def exists(self):
- uri = "https://{0}:{1}/mgmt/tm/gtm/monitor/external/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name),
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def create_on_device(self):
- params = self.changes.api_params()
- params['name'] = self.want.name
- params['partition'] = self.want.partition
- uri = "https://{0}:{1}/mgmt/tm/gtm/monitor/external/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- if self.want.variables:
- self.set_variable_on_device(self.want.variables)
-
- def update_on_device(self):
- params = self.changes.api_params()
- if params:
- uri = "https://{0}:{1}/mgmt/tm/gtm/monitor/external/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- if self.changes.variables:
- self.set_variable_on_device(self.changes.variables)
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/gtm/monitor/external/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return ApiParameters(params=response)
-
- def remove_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/gtm/monitor/external/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name),
- )
- response = self.client.api.delete(uri)
- if response.status == 200:
- return True
- raise F5ModuleError(response.content)
-
- def set_variable_on_device(self, commands):
- command = ' '.join(['user-defined {0} \\\"{1}\\\"'.format(k, v) for k, v in iteritems(commands)])
- command = 'tmsh modify gtm monitor external {0} {1}'.format(self.want.name, command)
- uri = "https://{0}:{1}/mgmt/tm/util/bash".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- args = dict(
- command='run',
- utilCmdArgs='-c "{0}"'.format(command)
- )
- resp = self.client.api.post(uri, json=args)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- name=dict(required=True),
- parent=dict(default='/Common/external'),
- arguments=dict(),
- ip=dict(),
- port=dict(),
- external_program=dict(),
- interval=dict(type='int'),
- timeout=dict(type='int'),
- state=dict(
- default='present',
- choices=['present', 'absent']
- ),
- variables=dict(type='dict'),
- partition=dict(
- default='Common',
- fallback=(env_fallback, ['F5_PARTITION'])
- )
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode,
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_gtm_monitor_firepass.py b/lib/ansible/modules/network/f5/bigip_gtm_monitor_firepass.py
deleted file mode 100644
index 634f6a191a..0000000000
--- a/lib/ansible/modules/network/f5/bigip_gtm_monitor_firepass.py
+++ /dev/null
@@ -1,793 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_gtm_monitor_firepass
-short_description: Manages F5 BIG-IP GTM FirePass monitors
-description:
- - Manages F5 BIG-IP GTM FirePass monitors.
-version_added: 2.6
-options:
- name:
- description:
- - Monitor name.
- type: str
- required: True
- parent:
- description:
- - The parent template of this monitor template. Once this value has
- been set, it cannot be changed. By default, this value is the C(tcp)
- parent on the C(Common) partition.
- type: str
- default: /Common/firepass_gtm
- ip:
- description:
- - IP address part of the IP/port definition. If this parameter is not
- provided when creating a new monitor, then the default value will be
- '*'.
- - If this value is an IP address, then a C(port) number must be specified.
- type: str
- port:
- description:
- - Port address part of the IP/port definition. If this parameter is not
- provided when creating a new monitor, then the default value will be
- '*'. Note that if specifying an IP address, a value between 1 and 65535
- must be specified.
- type: str
- interval:
- description:
- - The interval specifying how frequently the monitor instance of this
- template will run.
- - If this parameter is not provided when creating a new monitor, then
- the default value will be 30.
- - This value B(must) be less than the C(timeout) value.
- type: int
- timeout:
- description:
- - The number of seconds in which the node or service must respond to
- the monitor request. If the target responds within the set time
- period, it is considered up. If the target does not respond within
- the set time period, it is considered down. You can change this
- number to any number you want, however, it should be 3 times the
- interval number of seconds plus 1 second.
- - If this parameter is not provided when creating a new monitor, then
- the default value will be 90.
- type: int
- partition:
- description:
- - Device partition to manage resources on.
- type: str
- default: Common
- state:
- description:
- - When C(present), ensures that the monitor exists.
- - When C(absent), ensures the monitor is removed.
- type: str
- choices:
- - present
- - absent
- default: present
- probe_timeout:
- description:
- - Specifies the number of seconds after which the system times out the probe request
- to the system.
- - When creating a new monitor, if this parameter is not provided, then the default
- value will be C(5).
- type: int
- ignore_down_response:
- description:
- - Specifies that the monitor allows more than one probe attempt per interval.
- - When C(yes), specifies that the monitor ignores down responses for the duration of
- the monitor timeout. Once the monitor timeout is reached without the system receiving
- an up response, the system marks the object down.
- - When C(no), specifies that the monitor immediately marks an object down when it
- receives a down response.
- - When creating a new monitor, if this parameter is not provided, then the default
- value will be C(no).
- type: bool
- target_username:
- description:
- - Specifies the user name, if the monitored target requires authentication.
- type: str
- target_password:
- description:
- - Specifies the password, if the monitored target requires authentication.
- type: str
- update_password:
- description:
- - C(always) will update passwords if the C(target_password) is specified.
- - C(on_create) will only set the password for newly created monitors.
- type: str
- choices:
- - always
- - on_create
- default: always
- cipher_list:
- description:
- - Specifies the list of ciphers for this monitor.
- - The items in the cipher list are separated with the colon C(:) symbol.
- - When creating a new monitor, if this parameter is not specified, the default
- list is C(HIGH:!ADH).
- type: str
- max_load_average:
- description:
- - Specifies the number that the monitor uses to mark the Secure Access Manager
- system up or down.
- - The system compares the Max Load Average setting against a one-minute average
- of the Secure Access Manager system load.
- - When the Secure Access Manager system-load average falls within the specified
- Max Load Average, the monitor marks the Secure Access Manager system up.
- - When the average exceeds the setting, the monitor marks the system down.
- - When creating a new monitor, if this parameter is not specified, the default
- is C(12).
- type: int
- concurrency_limit:
- description:
- - Specifies the maximum percentage of licensed connections currently in use under
- which the monitor marks the Secure Access Manager system up.
- - As an example, a setting of 95 percent means that the monitor marks the Secure
- Access Manager system up until 95 percent of licensed connections are in use.
- - When the number of in-use licensed connections exceeds 95 percent, the monitor
- marks the Secure Access Manager system down.
- - When creating a new monitor, if this parameter is not specified, the default is C(95).
- type: int
-extends_documentation_fragment: f5
-author:
- - Tim Rupp (@caphrim007)
- - Wojciech Wypior (@wojtek0806)
-'''
-
-EXAMPLES = r'''
-- name: Create a GTM FirePass monitor
- bigip_gtm_monitor_firepass:
- name: my_monitor
- ip: 1.1.1.1
- port: 80
- state: present
- provider:
- user: admin
- password: secret
- server: lb.mydomain.com
- delegate_to: localhost
-
-- name: Remove FirePass Monitor
- bigip_gtm_monitor_firepass:
- name: my_monitor
- state: absent
- provider:
- user: admin
- password: secret
- server: lb.mydomain.com
- delegate_to: localhost
-
-- name: Add FirePass monitor for all addresses, port 514
- bigip_gtm_monitor_firepass:
- name: my_monitor
- port: 514
- provider:
- user: admin
- password: secret
- server: lb.mydomain.com
- delegate_to: localhost
-'''
-
-RETURN = r'''
-parent:
- description: New parent template of the monitor.
- returned: changed
- type: str
- sample: firepass_gtm
-ip:
- description: The new IP of IP/port definition.
- returned: changed
- type: str
- sample: 10.12.13.14
-port:
- description: The new port the monitor checks the resource on.
- returned: changed
- type: str
- sample: 8080
-interval:
- description: The new interval in which to run the monitor check.
- returned: changed
- type: int
- sample: 2
-timeout:
- description: The new timeout in which the remote system must respond to the monitor.
- returned: changed
- type: int
- sample: 10
-ignore_down_response:
- description: Whether to ignore the down response or not.
- returned: changed
- type: bool
- sample: True
-probe_timeout:
- description: The new timeout in which the system will timeout the monitor probe.
- returned: changed
- type: int
- sample: 10
-cipher_list:
- description: The new value for the cipher list.
- returned: changed
- type: str
- sample: +3DES:+kEDH
-max_load_average:
- description: The new value for the max load average.
- returned: changed
- type: int
- sample: 12
-concurrency_limit:
- description: The new value for the concurrency limit.
- returned: changed
- type: int
- sample: 95
-'''
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.basic import env_fallback
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import fq_name
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.common import transform_name
- from library.module_utils.network.f5.icontrol import module_provisioned
- from library.module_utils.network.f5.ipaddress import is_valid_ip
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import fq_name
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.common import transform_name
- from ansible.module_utils.network.f5.icontrol import module_provisioned
- from ansible.module_utils.network.f5.ipaddress import is_valid_ip
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'defaultsFrom': 'parent',
- 'ignoreDownResponse': 'ignore_down_response',
- 'probeTimeout': 'probe_timeout',
- 'username': 'target_username',
- 'password': 'target_password',
- 'cipherlist': 'cipher_list',
- 'concurrencyLimit': 'concurrency_limit',
- 'maxLoadAverage': 'max_load_average',
- }
-
- api_attributes = [
- 'defaultsFrom',
- 'interval',
- 'timeout',
- 'destination',
- 'probeTimeout',
- 'ignoreDownResponse',
- 'username',
- 'password',
- 'cipherlist',
- 'concurrencyLimit',
- 'maxLoadAverage',
- ]
-
- returnables = [
- 'parent',
- 'ip',
- 'port',
- 'interval',
- 'timeout',
- 'probe_timeout',
- 'ignore_down_response',
- 'cipher_list',
- 'max_load_average',
- 'concurrency_limit',
- ]
-
- updatables = [
- 'destination',
- 'interval',
- 'timeout',
- 'probe_timeout',
- 'ignore_down_response',
- 'ip',
- 'port',
- 'target_username',
- 'target_password',
- 'cipher_list',
- 'max_load_average',
- 'concurrency_limit',
- ]
-
-
-class ApiParameters(Parameters):
- @property
- def ip(self):
- ip, port = self._values['destination'].split(':')
- return ip
-
- @property
- def port(self):
- ip, port = self._values['destination'].split(':')
- try:
- return int(port)
- except ValueError:
- return port
-
- @property
- def ignore_down_response(self):
- if self._values['ignore_down_response'] is None:
- return None
- if self._values['ignore_down_response'] == 'disabled':
- return False
- return True
-
-
-class ModuleParameters(Parameters):
- @property
- def interval(self):
- if self._values['interval'] is None:
- return None
- if 1 > int(self._values['interval']) > 86400:
- raise F5ModuleError(
- "Interval value must be between 1 and 86400"
- )
- return int(self._values['interval'])
-
- @property
- def timeout(self):
- if self._values['timeout'] is None:
- return None
- return int(self._values['timeout'])
-
- @property
- def ip(self): # lgtm [py/similar-function]
- if self._values['ip'] is None:
- return None
- if self._values['ip'] in ['*', '0.0.0.0']:
- return '*'
- elif is_valid_ip(self._values['ip']):
- return self._values['ip']
- else:
- raise F5ModuleError(
- "The provided 'ip' parameter is not an IP address."
- )
-
- @property
- def parent(self):
- if self._values['parent'] is None:
- return None
- result = fq_name(self.partition, self._values['parent'])
- return result
-
- @property
- def port(self):
- if self._values['port'] is None:
- return None
- elif self._values['port'] == '*':
- return '*'
- return int(self._values['port'])
-
- @property
- def destination(self):
- if self.ip is None and self.port is None:
- return None
- destination = '{0}:{1}'.format(self.ip, self.port)
- return destination
-
- @destination.setter
- def destination(self, value):
- ip, port = value.split(':')
- self._values['ip'] = ip
- self._values['port'] = port
-
- @property
- def probe_timeout(self):
- if self._values['probe_timeout'] is None:
- return None
- return int(self._values['probe_timeout'])
-
- @property
- def max_load_average(self):
- if self._values['max_load_average'] is None:
- return None
- return int(self._values['max_load_average'])
-
- @property
- def concurrency_limit(self):
- if self._values['concurrency_limit'] is None:
- return None
- return int(self._values['concurrency_limit'])
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class UsableChanges(Changes):
- @property
- def ignore_down_response(self):
- if self._values['ignore_down_response'] is None:
- return None
- elif self._values['ignore_down_response'] is True:
- return 'enabled'
- return 'disabled'
-
-
-class ReportableChanges(Changes):
- @property
- def ip(self):
- ip, port = self._values['destination'].split(':')
- return ip
-
- @property
- def port(self):
- ip, port = self._values['destination'].split(':')
- return int(port)
-
- @property
- def ignore_down_response(self):
- if self._values['ignore_down_response'] == 'enabled':
- return True
- return False
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
- @property
- def parent(self):
- if self.want.parent != self.have.parent:
- raise F5ModuleError(
- "The parent monitor cannot be changed"
- )
-
- @property
- def destination(self):
- if self.want.ip is None and self.want.port is None:
- return None
- if self.want.port is None:
- self.want.update({'port': self.have.port})
- if self.want.ip is None:
- self.want.update({'ip': self.have.ip})
-
- if self.want.port in [None, '*'] and self.want.ip != '*':
- raise F5ModuleError(
- "Specifying an IP address requires that a port number be specified"
- )
-
- if self.want.destination != self.have.destination:
- return self.want.destination
-
- @property
- def interval(self):
- if self.want.timeout is not None and self.want.interval is not None:
- if self.want.interval >= self.want.timeout:
- raise F5ModuleError(
- "Parameter 'interval' must be less than 'timeout'."
- )
- elif self.want.timeout is not None:
- if self.have.interval >= self.want.timeout:
- raise F5ModuleError(
- "Parameter 'interval' must be less than 'timeout'."
- )
- elif self.want.interval is not None:
- if self.want.interval >= self.have.timeout:
- raise F5ModuleError(
- "Parameter 'interval' must be less than 'timeout'."
- )
- if self.want.interval != self.have.interval:
- return self.want.interval
-
- @property
- def target_password(self):
- if self.want.target_password != self.have.target_password:
- if self.want.update_password == 'always':
- result = self.want.target_password
- return result
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(params=self.module.params)
- self.have = ApiParameters()
- self.changes = UsableChanges()
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = UsableChanges(params=changed)
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.client.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def _set_default_creation_values(self):
- if self.want.timeout is None:
- self.want.update({'timeout': 90})
- if self.want.interval is None:
- self.want.update({'interval': 30})
- if self.want.probe_timeout is None:
- self.want.update({'probe_timeout': 5})
- if self.want.ip is None:
- self.want.update({'ip': '*'})
- if self.want.port is None:
- self.want.update({'port': '*'})
- if self.want.ignore_down_response is None:
- self.want.update({'ignore_down_response': False})
- if self.want.cipher_list is None:
- self.want.update({'cipher_list': 'HIGH:!ADH'})
- if self.want.max_load_average is None:
- self.want.update({'max_load_average': 12})
- if self.want.concurrency_limit is None:
- self.want.update({'concurrency_limit': 95})
-
- def exec_module(self):
- if not module_provisioned(self.client, 'gtm'):
- raise F5ModuleError(
- "GTM must be provisioned to use this module."
- )
- changed = False
- result = dict()
- state = self.want.state
-
- if state == "present":
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def present(self):
- if self.exists():
- return self.update()
- else:
- return self.create()
-
- def absent(self):
- if self.exists():
- return self.remove()
- return False
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def update(self):
- self.have = self.read_current_from_device()
- if not self.should_update():
- return False
- if self.module.check_mode:
- return True
- self.update_on_device()
- return True
-
- def remove(self):
- if self.module.check_mode:
- return True
- self.remove_from_device()
- if self.exists():
- raise F5ModuleError("Failed to delete the resource.")
- return True
-
- def create(self):
- self._set_default_creation_values()
- self._set_changed_options()
- if self.module.check_mode:
- return True
- self.create_on_device()
- return True
-
- def exists(self):
- uri = "https://{0}:{1}/mgmt/tm/gtm/monitor/firepass/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name),
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def create_on_device(self):
- params = self.changes.api_params()
- params['name'] = self.want.name
- params['partition'] = self.want.partition
- uri = "https://{0}:{1}/mgmt/tm/gtm/monitor/firepass/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return response['selfLink']
-
- def update_on_device(self):
- params = self.changes.api_params()
- uri = "https://{0}:{1}/mgmt/tm/gtm/monitor/firepass/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name),
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def remove_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/gtm/monitor/firepass/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name),
- )
- response = self.client.api.delete(uri)
- if response.status == 200:
- return True
- raise F5ModuleError(response.content)
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/gtm/monitor/firepass/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name),
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return ApiParameters(params=response)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- name=dict(required=True),
- parent=dict(default='/Common/firepass_gtm'),
- ip=dict(),
- port=dict(),
- interval=dict(type='int'),
- timeout=dict(type='int'),
- ignore_down_response=dict(type='bool'),
- probe_timeout=dict(type='int'),
- target_username=dict(),
- target_password=dict(no_log=True),
- cipher_list=dict(),
- update_password=dict(
- default='always',
- choices=['always', 'on_create']
- ),
- max_load_average=dict(type='int'),
- concurrency_limit=dict(type='int'),
- state=dict(
- default='present',
- choices=['present', 'absent']
- ),
- partition=dict(
- default='Common',
- fallback=(env_fallback, ['F5_PARTITION'])
- )
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode,
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_gtm_monitor_http.py b/lib/ansible/modules/network/f5/bigip_gtm_monitor_http.py
deleted file mode 100644
index c422849ddb..0000000000
--- a/lib/ansible/modules/network/f5/bigip_gtm_monitor_http.py
+++ /dev/null
@@ -1,837 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_gtm_monitor_http
-short_description: Manages F5 BIG-IP GTM http monitors
-description:
- - Manages F5 BIG-IP GTM http monitors.
-version_added: 2.6
-options:
- name:
- description:
- - Monitor name.
- type: str
- required: True
- parent:
- description:
- - The parent template of this monitor template. Once this value has
- been set, it cannot be changed. By default, this value is the C(tcp)
- parent on the C(Common) partition.
- type: str
- default: /Common/http
- send:
- description:
- - The send string for the monitor call.
- - When creating a new monitor, if this parameter is not provided, the
- default of C(GET /\r\n) will be used.
- type: str
- receive:
- description:
- - The receive string for the monitor call.
- type: str
- ip:
- description:
- - IP address part of the IP/port definition. If this parameter is not
- provided when creating a new monitor, then the default value will be
- '*'.
- - If this value is an IP address, then a C(port) number must be specified.
- type: str
- port:
- description:
- - Port address part of the IP/port definition. If this parameter is not
- provided when creating a new monitor, then the default value will be
- '*'. Note that if specifying an IP address, a value between 1 and 65535
- must be specified
- type: str
- interval:
- description:
- - The interval specifying how frequently the monitor instance of this
- template will run.
- - If this parameter is not provided when creating a new monitor, then the
- default value will be 30.
- - This value B(must) be less than the C(timeout) value.
- type: int
- timeout:
- description:
- - The number of seconds in which the node or service must respond to
- the monitor request. If the target responds within the set time
- period, it is considered up. If the target does not respond within
- the set time period, it is considered down. You can change this
- number to any number you want, however, it should be 3 times the
- interval number of seconds plus 1 second.
- - If this parameter is not provided when creating a new monitor, then the
- default value will be 120.
- type: int
- partition:
- description:
- - Device partition to manage resources on.
- type: str
- default: Common
- state:
- description:
- - When C(present), ensures that the monitor exists.
- - When C(absent), ensures the monitor is removed.
- type: str
- choices:
- - present
- - absent
- default: present
- probe_timeout:
- description:
- - Specifies the number of seconds after which the system times out the probe request
- to the system.
- - When creating a new monitor, if this parameter is not provided, then the default
- value will be C(5).
- type: int
- ignore_down_response:
- description:
- - Specifies that the monitor allows more than one probe attempt per interval.
- - When C(yes), specifies that the monitor ignores down responses for the duration of
- the monitor timeout. Once the monitor timeout is reached without the system receiving
- an up response, the system marks the object down.
- - When C(no), specifies that the monitor immediately marks an object down when it
- receives a down response.
- - When creating a new monitor, if this parameter is not provided, then the default
- value will be C(no).
- type: bool
- transparent:
- description:
- - Specifies whether the monitor operates in transparent mode.
- - A monitor in transparent mode directs traffic through the associated pool members
- or nodes (usually a router or firewall) to the aliased destination (that is, it
- probes the C(ip)-C(port) combination specified in the monitor).
- - If the monitor cannot successfully reach the aliased destination, the pool member
- or node through which the monitor traffic was sent is marked down.
- - When creating a new monitor, if this parameter is not provided, then the default
- value will be C(no).
- type: bool
- reverse:
- description:
- - Instructs the system to mark the target resource down when the test is successful.
- This setting is useful, for example, if the content on your web site home page is
- dynamic and changes frequently, you may want to set up a reverse ECV service check
- that looks for the string Error.
- - A match for this string means that the web server was down.
- - To use this option, you must specify values for C(send) and C(receive).
- type: bool
- target_username:
- description:
- - Specifies the user name, if the monitored target requires authentication.
- type: str
- target_password:
- description:
- - Specifies the password, if the monitored target requires authentication.
- type: str
- update_password:
- description:
- - C(always) will update passwords if the C(target_password) is specified.
- - C(on_create) will only set the password for newly created monitors.
- type: str
- choices:
- - always
- - on_create
- default: always
-extends_documentation_fragment: f5
-author:
- - Tim Rupp (@caphrim007)
- - Wojciech Wypior (@wojtek0806)
-'''
-
-EXAMPLES = r'''
-- name: Create a GTM HTTP monitor
- bigip_gtm_monitor_http:
- name: my_monitor
- ip: 1.1.1.1
- port: 80
- send: my send string
- receive: my receive string
- state: present
- provider:
- user: admin
- password: secret
- server: lb.mydomain.com
- delegate_to: localhost
-
-- name: Remove HTTP Monitor
- bigip_gtm_monitor_http:
- name: my_monitor
- state: absent
- provider:
- user: admin
- password: secret
- server: lb.mydomain.com
- delegate_to: localhost
-
-- name: Add HTTP monitor for all addresses, port 514
- bigip_gtm_monitor_http:
- name: my_monitor
- port: 514
- provider:
- user: admin
- password: secret
- server: lb.mydomain.com
- delegate_to: localhost
-'''
-
-RETURN = r'''
-parent:
- description: New parent template of the monitor.
- returned: changed
- type: str
- sample: http
-ip:
- description: The new IP of IP/port definition.
- returned: changed
- type: str
- sample: 10.12.13.14
-port:
- description: The new port the monitor checks the resource on.
- returned: changed
- type: str
- sample: 8080
-interval:
- description: The new interval in which to run the monitor check.
- returned: changed
- type: int
- sample: 2
-timeout:
- description: The new timeout in which the remote system must respond to the monitor.
- returned: changed
- type: int
- sample: 10
-ignore_down_response:
- description: Whether to ignore the down response or not.
- returned: changed
- type: bool
- sample: True
-send:
- description: The new send string for this monitor.
- returned: changed
- type: str
- sample: tcp string to send
-receive:
- description: The new receive string for this monitor.
- returned: changed
- type: str
- sample: tcp string to receive
-probe_timeout:
- description: The new timeout in which the system will timeout the monitor probe.
- returned: changed
- type: int
- sample: 10
-reverse:
- description: The new value for whether the monitor operates in reverse mode.
- returned: changed
- type: bool
- sample: False
-transparent:
- description: The new value for whether the monitor operates in transparent mode.
- returned: changed
- type: bool
- sample: False
-'''
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.basic import env_fallback
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import fq_name
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.common import transform_name
- from library.module_utils.network.f5.icontrol import module_provisioned
- from library.module_utils.network.f5.ipaddress import is_valid_ip
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import fq_name
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.common import transform_name
- from ansible.module_utils.network.f5.icontrol import module_provisioned
- from ansible.module_utils.network.f5.ipaddress import is_valid_ip
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'defaultsFrom': 'parent',
- 'ignoreDownResponse': 'ignore_down_response',
- 'probeTimeout': 'probe_timeout',
- 'recv': 'receive',
- 'username': 'target_username',
- 'password': 'target_password',
- }
-
- api_attributes = [
- 'defaultsFrom',
- 'interval',
- 'timeout',
- 'destination',
- 'transparent',
- 'probeTimeout',
- 'ignoreDownResponse',
- 'reverse',
- 'send',
- 'recv',
- 'username',
- 'password',
- ]
-
- returnables = [
- 'parent',
- 'ip',
- 'port',
- 'interval',
- 'timeout',
- 'transparent',
- 'probe_timeout',
- 'ignore_down_response',
- 'send',
- 'receive',
- 'reverse',
- ]
-
- updatables = [
- 'destination',
- 'interval',
- 'timeout',
- 'transparent',
- 'probe_timeout',
- 'ignore_down_response',
- 'send',
- 'receive',
- 'reverse',
- 'ip',
- 'port',
- 'target_username',
- 'target_password',
- ]
-
-
-class ApiParameters(Parameters):
- @property
- def ip(self):
- ip, port = self._values['destination'].split(':')
- return ip
-
- @property
- def port(self):
- ip, port = self._values['destination'].split(':')
- try:
- return int(port)
- except ValueError:
- return port
-
- @property
- def ignore_down_response(self):
- if self._values['ignore_down_response'] is None:
- return None
- if self._values['ignore_down_response'] == 'disabled':
- return False
- return True
-
- @property
- def transparent(self):
- if self._values['transparent'] is None:
- return None
- if self._values['transparent'] == 'disabled':
- return False
- return True
-
- @property
- def reverse(self):
- if self._values['reverse'] is None:
- return None
- if self._values['reverse'] == 'disabled':
- return False
- return True
-
-
-class ModuleParameters(Parameters):
- @property
- def interval(self):
- if self._values['interval'] is None:
- return None
- if 1 > int(self._values['interval']) > 86400:
- raise F5ModuleError(
- "Interval value must be between 1 and 86400"
- )
- return int(self._values['interval'])
-
- @property
- def timeout(self):
- if self._values['timeout'] is None:
- return None
- return int(self._values['timeout'])
-
- @property
- def ip(self): # lgtm [py/similar-function]
- if self._values['ip'] is None:
- return None
- if self._values['ip'] in ['*', '0.0.0.0']:
- return '*'
- elif is_valid_ip(self._values['ip']):
- return self._values['ip']
- else:
- raise F5ModuleError(
- "The provided 'ip' parameter is not an IP address."
- )
-
- @property
- def parent(self):
- if self._values['parent'] is None:
- return None
- result = fq_name(self.partition, self._values['parent'])
- return result
-
- @property
- def port(self):
- if self._values['port'] is None:
- return None
- elif self._values['port'] == '*':
- return '*'
- return int(self._values['port'])
-
- @property
- def destination(self):
- if self.ip is None and self.port is None:
- return None
- destination = '{0}:{1}'.format(self.ip, self.port)
- return destination
-
- @destination.setter
- def destination(self, value):
- ip, port = value.split(':')
- self._values['ip'] = ip
- self._values['port'] = port
-
- @property
- def probe_timeout(self):
- if self._values['probe_timeout'] is None:
- return None
- return int(self._values['probe_timeout'])
-
- @property
- def type(self):
- return 'http'
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class UsableChanges(Changes):
- @property
- def transparent(self):
- if self._values['transparent'] is None:
- return None
- elif self._values['transparent'] is True:
- return 'enabled'
- return 'disabled'
-
- @property
- def ignore_down_response(self):
- if self._values['ignore_down_response'] is None:
- return None
- elif self._values['ignore_down_response'] is True:
- return 'enabled'
- return 'disabled'
-
- @property
- def reverse(self):
- if self._values['reverse'] is None:
- return None
- elif self._values['reverse'] is True:
- return 'enabled'
- return 'disabled'
-
-
-class ReportableChanges(Changes):
- @property
- def ip(self):
- ip, port = self._values['destination'].split(':')
- return ip
-
- @property
- def port(self):
- ip, port = self._values['destination'].split(':')
- return int(port)
-
- @property
- def transparent(self):
- if self._values['transparent'] == 'enabled':
- return True
- return False
-
- @property
- def ignore_down_response(self):
- if self._values['ignore_down_response'] == 'enabled':
- return True
- return False
-
- @property
- def reverse(self):
- if self._values['reverse'] == 'enabled':
- return True
- return False
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
- @property
- def parent(self):
- if self.want.parent != self.have.parent:
- raise F5ModuleError(
- "The parent monitor cannot be changed"
- )
-
- @property
- def destination(self):
- if self.want.ip is None and self.want.port is None:
- return None
- if self.want.port is None:
- self.want.update({'port': self.have.port})
- if self.want.ip is None:
- self.want.update({'ip': self.have.ip})
-
- if self.want.port in [None, '*'] and self.want.ip != '*':
- raise F5ModuleError(
- "Specifying an IP address requires that a port number be specified"
- )
-
- if self.want.destination != self.have.destination:
- return self.want.destination
-
- @property
- def interval(self):
- if self.want.timeout is not None and self.want.interval is not None:
- if self.want.interval >= self.want.timeout:
- raise F5ModuleError(
- "Parameter 'interval' must be less than 'timeout'."
- )
- elif self.want.timeout is not None:
- if self.have.interval >= self.want.timeout:
- raise F5ModuleError(
- "Parameter 'interval' must be less than 'timeout'."
- )
- elif self.want.interval is not None:
- if self.want.interval >= self.have.timeout:
- raise F5ModuleError(
- "Parameter 'interval' must be less than 'timeout'."
- )
- if self.want.interval != self.have.interval:
- return self.want.interval
-
- @property
- def target_password(self):
- if self.want.target_password != self.have.target_password:
- if self.want.update_password == 'always':
- result = self.want.target_password
- return result
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(params=self.module.params)
- self.have = ApiParameters()
- self.changes = UsableChanges()
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = UsableChanges(params=changed)
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.client.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def _set_default_creation_values(self):
- if self.want.timeout is None:
- self.want.update({'timeout': 120})
- if self.want.interval is None:
- self.want.update({'interval': 30})
- if self.want.probe_timeout is None:
- self.want.update({'probe_timeout': 5})
- if self.want.ip is None:
- self.want.update({'ip': '*'})
- if self.want.port is None:
- self.want.update({'port': '*'})
- if self.want.ignore_down_response is None:
- self.want.update({'ignore_down_response': False})
- if self.want.transparent is None:
- self.want.update({'transparent': False})
- if self.want.send is None:
- self.want.update({'send': 'GET /\r\n'})
-
- def exec_module(self):
- if not module_provisioned(self.client, 'gtm'):
- raise F5ModuleError(
- "GTM must be provisioned to use this module."
- )
- changed = False
- result = dict()
- state = self.want.state
-
- if state == "present":
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def create(self):
- self._set_default_creation_values()
- self._set_changed_options()
- if self.module.check_mode:
- return True
- self.create_on_device()
- return True
-
- def present(self):
- if self.exists():
- return self.update()
- else:
- return self.create()
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def update(self):
- self.have = self.read_current_from_device()
- if not self.should_update():
- return False
- if self.module.check_mode:
- return True
- self.update_on_device()
- return True
-
- def absent(self):
- if self.exists():
- return self.remove()
- return False
-
- def remove(self):
- if self.module.check_mode:
- return True
- self.remove_from_device()
- if self.exists():
- raise F5ModuleError("Failed to delete the monitor.")
- return True
-
- def exists(self):
- uri = "https://{0}:{1}/mgmt/tm/gtm/monitor/http/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name),
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/gtm/monitor/http/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name),
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return ApiParameters(params=response)
-
- def update_on_device(self):
- params = self.changes.api_params()
- uri = "https://{0}:{1}/mgmt/tm/gtm/monitor/http/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name),
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def create_on_device(self):
- params = self.changes.api_params()
- params['name'] = self.want.name
- params['partition'] = self.want.partition
- uri = "https://{0}:{1}/mgmt/tm/gtm/monitor/http/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return response['selfLink']
-
- def remove_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/gtm/monitor/http/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name),
- )
- response = self.client.api.delete(uri)
- if response.status == 200:
- return True
- raise F5ModuleError(response.content)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- name=dict(required=True),
- parent=dict(default='/Common/http'),
- send=dict(),
- receive=dict(),
- ip=dict(),
- port=dict(),
- interval=dict(type='int'),
- timeout=dict(type='int'),
- ignore_down_response=dict(type='bool'),
- transparent=dict(type='bool'),
- probe_timeout=dict(type='int'),
- reverse=dict(type='bool'),
- target_username=dict(),
- target_password=dict(no_log=True),
- update_password=dict(
- default='always',
- choices=['always', 'on_create']
- ),
- state=dict(
- default='present',
- choices=['present', 'absent']
- ),
- partition=dict(
- default='Common',
- fallback=(env_fallback, ['F5_PARTITION'])
- )
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode,
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_gtm_monitor_https.py b/lib/ansible/modules/network/f5/bigip_gtm_monitor_https.py
deleted file mode 100644
index c88b20eaae..0000000000
--- a/lib/ansible/modules/network/f5/bigip_gtm_monitor_https.py
+++ /dev/null
@@ -1,960 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_gtm_monitor_https
-short_description: Manages F5 BIG-IP GTM https monitors
-description:
- - Manages F5 BIG-IP GTM https monitors.
-version_added: 2.6
-options:
- name:
- description:
- - Monitor name.
- type: str
- required: True
- parent:
- description:
- - The parent template of this monitor template. Once this value has
- been set, it cannot be changed. By default, this value is the C(tcp)
- parent on the C(Common) partition.
- type: str
- default: /Common/https
- send:
- description:
- - The send string for the monitor call.
- - When creating a new monitor, if this parameter is not provided, the
- default of C(GET /\r\n) will be used.
- type: str
- receive:
- description:
- - The receive string for the monitor call.
- type: str
- ip:
- description:
- - IP address part of the IP/port definition. If this parameter is not
- provided when creating a new monitor, then the default value will be
- '*'.
- - If this value is an IP address, then a C(port) number must be specified.
- type: str
- port:
- description:
- - Port address part of the IP/port definition. If this parameter is not
- provided when creating a new monitor, then the default value will be
- '*'. Note that if specifying an IP address, a value between 1 and 65535
- must be specified.
- type: str
- interval:
- description:
- - The interval specifying how frequently the monitor instance of this
- template will run.
- - If this parameter is not provided when creating a new monitor, then
- the default value will be 30.
- - This value B(must) be less than the C(timeout) value.
- type: int
- timeout:
- description:
- - The number of seconds in which the node or service must respond to
- the monitor request. If the target responds within the set time
- period, it is considered up. If the target does not respond within
- the set time period, it is considered down. You can change this
- number to any number you want, however, it should be 3 times the
- interval number of seconds plus 1 second.
- - If this parameter is not provided when creating a new monitor, then the
- default value will be 120.
- type: int
- partition:
- description:
- - Device partition to manage resources on.
- type: str
- default: Common
- state:
- description:
- - When C(present), ensures that the monitor exists.
- - When C(absent), ensures the monitor is removed.
- type: str
- choices:
- - present
- - absent
- default: present
- probe_timeout:
- description:
- - Specifies the number of seconds after which the system times out the probe request
- to the system.
- - When creating a new monitor, if this parameter is not provided, then the default
- value will be C(5).
- type: int
- ignore_down_response:
- description:
- - Specifies that the monitor allows more than one probe attempt per interval.
- - When C(yes), specifies that the monitor ignores down responses for the duration of
- the monitor timeout. Once the monitor timeout is reached without the system receiving
- an up response, the system marks the object down.
- - When C(no), specifies that the monitor immediately marks an object down when it
- receives a down response.
- - When creating a new monitor, if this parameter is not provided, then the default
- value will be C(no).
- type: bool
- transparent:
- description:
- - Specifies whether the monitor operates in transparent mode.
- - A monitor in transparent mode directs traffic through the associated pool members
- or nodes (usually a router or firewall) to the aliased destination (that is, it
- probes the C(ip)-C(port) combination specified in the monitor).
- - If the monitor cannot successfully reach the aliased destination, the pool member
- or node through which the monitor traffic was sent is marked down.
- - When creating a new monitor, if this parameter is not provided, then the default
- value will be C(no).
- type: bool
- reverse:
- description:
- - Instructs the system to mark the target resource down when the test is successful.
- This setting is useful, for example, if the content on your web site home page is
- dynamic and changes frequently, you may want to set up a reverse ECV service check
- that looks for the string Error.
- - A match for this string means that the web server was down.
- - To use this option, you must specify values for C(send) and C(receive).
- type: bool
- target_username:
- description:
- - Specifies the user name, if the monitored target requires authentication.
- type: str
- target_password:
- description:
- - Specifies the password, if the monitored target requires authentication.
- type: str
- update_password:
- description:
- - C(always) will update passwords if the C(target_password) is specified.
- - C(on_create) will only set the password for newly created monitors.
- type: str
- choices:
- - always
- - on_create
- default: always
- cipher_list:
- description:
- - Specifies the list of ciphers for this monitor.
- - The items in the cipher list are separated with the colon C(:) symbol.
- - When creating a new monitor, if this parameter is not specified, the default
- list is C(DEFAULT:+SHA:+3DES:+kEDH).
- type: str
- compatibility:
- description:
- - Specifies, when enabled, that the SSL options setting (in OpenSSL) is set to B(all).
- - When creating a new monitor, if this value is not specified, the default is
- C(yes)
- type: bool
- client_cert:
- description:
- - Specifies a fully-qualified path for a client certificate that the monitor sends to
- the target SSL server.
- type: str
- client_key:
- description:
- - Specifies a key for a client certificate that the monitor sends to the target SSL server.
- type: str
-extends_documentation_fragment: f5
-author:
- - Tim Rupp (@caphrim007)
- - Wojciech Wypior (@wojtek0806)
-'''
-
-EXAMPLES = r'''
-- name: Create a GTM HTTPS monitor
- bigip_gtm_monitor_https:
- name: my_monitor
- ip: 1.1.1.1
- port: 80
- send: my send string
- receive: my receive string
- state: present
- provider:
- user: admin
- password: secret
- server: lb.mydomain.com
- delegate_to: localhost
-
-- name: Remove HTTPS Monitor
- bigip_gtm_monitor_https:
- name: my_monitor
- state: absent
- provider:
- user: admin
- password: secret
- server: lb.mydomain.com
- delegate_to: localhost
-
-- name: Add HTTPS monitor for all addresses, port 514
- bigip_gtm_monitor_https:
- name: my_monitor
- provider:
- user: admin
- password: secret
- server: lb.mydomain.com
- port: 514
- delegate_to: localhost
-'''
-
-RETURN = r'''
-parent:
- description: New parent template of the monitor.
- returned: changed
- type: str
- sample: https
-ip:
- description: The new IP of IP/port definition.
- returned: changed
- type: str
- sample: 10.12.13.14
-port:
- description: The new port the monitor checks the resource on.
- returned: changed
- type: str
- sample: 8080
-interval:
- description: The new interval in which to run the monitor check.
- returned: changed
- type: int
- sample: 2
-timeout:
- description: The new timeout in which the remote system must respond to the monitor.
- returned: changed
- type: int
- sample: 10
-ignore_down_response:
- description: Whether to ignore the down response or not.
- returned: changed
- type: bool
- sample: True
-send:
- description: The new send string for this monitor.
- returned: changed
- type: str
- sample: tcp string to send
-receive:
- description: The new receive string for this monitor.
- returned: changed
- type: str
- sample: tcp string to receive
-probe_timeout:
- description: The new timeout in which the system will timeout the monitor probe.
- returned: changed
- type: int
- sample: 10
-reverse:
- description: The new value for whether the monitor operates in reverse mode.
- returned: changed
- type: bool
- sample: False
-transparent:
- description: The new value for whether the monitor operates in transparent mode.
- returned: changed
- type: bool
- sample: False
-cipher_list:
- description: The new value for the cipher list.
- returned: changed
- type: str
- sample: +3DES:+kEDH
-compatibility:
- description: The new SSL compatibility setting.
- returned: changed
- type: bool
- sample: True
-client_cert:
- description: The new client cert setting.
- returned: changed
- type: str
- sample: /Common/default
-client_key:
- description: The new client key setting.
- returned: changed
- type: str
- sample: /Common/default
-'''
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.basic import env_fallback
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import fq_name
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.common import transform_name
- from library.module_utils.network.f5.icontrol import module_provisioned
- from library.module_utils.network.f5.ipaddress import is_valid_ip
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import fq_name
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.common import transform_name
- from ansible.module_utils.network.f5.icontrol import module_provisioned
- from ansible.module_utils.network.f5.ipaddress import is_valid_ip
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'defaultsFrom': 'parent',
- 'ignoreDownResponse': 'ignore_down_response',
- 'probeTimeout': 'probe_timeout',
- 'recv': 'receive',
- 'username': 'target_username',
- 'password': 'target_password',
- 'cipherlist': 'cipher_list',
- 'cert': 'client_cert',
- 'key': 'client_key',
- }
-
- api_attributes = [
- 'defaultsFrom',
- 'interval',
- 'timeout',
- 'destination',
- 'transparent',
- 'probeTimeout',
- 'ignoreDownResponse',
- 'reverse',
- 'send',
- 'recv',
- 'username',
- 'password',
- 'cipherlist',
- 'compatibility',
- 'cert',
- 'key',
- ]
-
- returnables = [
- 'parent',
- 'ip',
- 'port',
- 'interval',
- 'timeout',
- 'transparent',
- 'probe_timeout',
- 'ignore_down_response',
- 'send',
- 'receive',
- 'reverse',
- 'cipher_list',
- 'compatibility',
- 'client_cert',
- 'client_key',
- ]
-
- updatables = [
- 'destination',
- 'interval',
- 'timeout',
- 'transparent',
- 'probe_timeout',
- 'ignore_down_response',
- 'send',
- 'receive',
- 'reverse',
- 'ip',
- 'port',
- 'target_username',
- 'target_password',
- 'cipher_list',
- 'compatibility',
- 'client_cert',
- 'client_key',
- ]
-
-
-class ApiParameters(Parameters):
- @property
- def ip(self):
- ip, port = self._values['destination'].split(':')
- return ip
-
- @property
- def port(self):
- ip, port = self._values['destination'].split(':')
- try:
- return int(port)
- except ValueError:
- return port
-
- @property
- def ignore_down_response(self):
- if self._values['ignore_down_response'] is None:
- return None
- if self._values['ignore_down_response'] == 'disabled':
- return False
- return True
-
- @property
- def transparent(self):
- if self._values['transparent'] is None:
- return None
- if self._values['transparent'] == 'disabled':
- return False
- return True
-
- @property
- def reverse(self):
- if self._values['reverse'] is None:
- return None
- if self._values['reverse'] == 'disabled':
- return False
- return True
-
- @property
- def compatibility(self):
- if self._values['compatibility'] is None:
- return None
- if self._values['compatibility'] == 'disabled':
- return False
- return True
-
-
-class ModuleParameters(Parameters):
- @property
- def interval(self):
- if self._values['interval'] is None:
- return None
- if 1 > int(self._values['interval']) > 86400:
- raise F5ModuleError(
- "Interval value must be between 1 and 86400"
- )
- return int(self._values['interval'])
-
- @property
- def timeout(self):
- if self._values['timeout'] is None:
- return None
- return int(self._values['timeout'])
-
- @property
- def ip(self):
- if self._values['ip'] is None:
- return None
- if self._values['ip'] in ['*', '0.0.0.0']:
- return '*'
- elif is_valid_ip(self._values['ip']):
- return self._values['ip']
- else:
- raise F5ModuleError(
- "The provided 'ip' parameter is not an IP address."
- )
-
- @property
- def parent(self):
- if self._values['parent'] is None:
- return None
- result = fq_name(self.partition, self._values['parent'])
- return result
-
- @property
- def port(self):
- if self._values['port'] is None:
- return None
- elif self._values['port'] == '*':
- return '*'
- return int(self._values['port'])
-
- @property
- def destination(self):
- if self.ip is None and self.port is None:
- return None
- destination = '{0}:{1}'.format(self.ip, self.port)
- return destination
-
- @destination.setter
- def destination(self, value):
- ip, port = value.split(':')
- self._values['ip'] = ip
- self._values['port'] = port
-
- @property
- def probe_timeout(self):
- if self._values['probe_timeout'] is None:
- return None
- return int(self._values['probe_timeout'])
-
- @property
- def type(self):
- return 'https'
-
- @property
- def client_cert(self):
- if self._values['client_cert'] is None:
- return None
- if self._values['client_cert'] == '':
- return ''
- result = fq_name(self.partition, self._values['client_cert'])
- if not result.endswith('.crt'):
- result += '.crt'
- return result
-
- @property
- def client_key(self):
- if self._values['client_key'] is None:
- return None
- if self._values['client_key'] == '':
- return ''
- result = fq_name(self.partition, self._values['client_key'])
- if not result.endswith('.key'):
- result += '.key'
- return result
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class UsableChanges(Changes):
- @property
- def transparent(self):
- if self._values['transparent'] is None:
- return None
- elif self._values['transparent'] is True:
- return 'enabled'
- return 'disabled'
-
- @property
- def ignore_down_response(self):
- if self._values['ignore_down_response'] is None:
- return None
- elif self._values['ignore_down_response'] is True:
- return 'enabled'
- return 'disabled'
-
- @property
- def reverse(self):
- if self._values['reverse'] is None:
- return None
- elif self._values['reverse'] is True:
- return 'enabled'
- return 'disabled'
-
- @property
- def compatibility(self):
- if self._values['compatibility'] is None:
- return None
- elif self._values['compatibility'] is True:
- return 'enabled'
- return 'disabled'
-
-
-class ReportableChanges(Changes):
- @property
- def ip(self):
- ip, port = self._values['destination'].split(':')
- return ip
-
- @property
- def port(self):
- ip, port = self._values['destination'].split(':')
- return int(port)
-
- @property
- def transparent(self):
- if self._values['transparent'] == 'enabled':
- return True
- return False
-
- @property
- def ignore_down_response(self):
- if self._values['ignore_down_response'] == 'enabled':
- return True
- return False
-
- @property
- def reverse(self):
- if self._values['reverse'] == 'enabled':
- return True
- return False
-
- @property
- def compatibility(self):
- if self._values['compatibility'] == 'enabled':
- return True
- return False
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
- @property
- def parent(self):
- if self.want.parent != self.have.parent:
- raise F5ModuleError(
- "The parent monitor cannot be changed"
- )
-
- @property
- def destination(self):
- if self.want.ip is None and self.want.port is None:
- return None
- if self.want.port is None:
- self.want.update({'port': self.have.port})
- if self.want.ip is None:
- self.want.update({'ip': self.have.ip})
-
- if self.want.port in [None, '*'] and self.want.ip != '*':
- raise F5ModuleError(
- "Specifying an IP address requires that a port number be specified"
- )
-
- if self.want.destination != self.have.destination:
- return self.want.destination
-
- @property
- def interval(self):
- if self.want.timeout is not None and self.want.interval is not None:
- if self.want.interval >= self.want.timeout:
- raise F5ModuleError(
- "Parameter 'interval' must be less than 'timeout'."
- )
- elif self.want.timeout is not None:
- if self.have.interval >= self.want.timeout:
- raise F5ModuleError(
- "Parameter 'interval' must be less than 'timeout'."
- )
- elif self.want.interval is not None:
- if self.want.interval >= self.have.timeout:
- raise F5ModuleError(
- "Parameter 'interval' must be less than 'timeout'."
- )
- if self.want.interval != self.have.interval:
- return self.want.interval
-
- @property
- def target_password(self):
- if self.want.target_password != self.have.target_password:
- if self.want.update_password == 'always':
- result = self.want.target_password
- return result
-
- @property
- def client_cert(self):
- if self.have.client_cert is None and self.want.client_cert == '':
- return None
- if self.have.client_cert != self.want.client_cert:
- return self.want.client_cert
-
- @property
- def client_key(self):
- if self.have.client_key is None and self.want.client_key == '':
- return None
- if self.have.client_key != self.want.client_key:
- return self.want.client_key
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(params=self.module.params)
- self.have = ApiParameters()
- self.changes = UsableChanges()
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = UsableChanges(params=changed)
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.client.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def _set_default_creation_values(self):
- if self.want.timeout is None:
- self.want.update({'timeout': 120})
- if self.want.interval is None:
- self.want.update({'interval': 30})
- if self.want.probe_timeout is None:
- self.want.update({'probe_timeout': 5})
- if self.want.ip is None:
- self.want.update({'ip': '*'})
- if self.want.port is None:
- self.want.update({'port': '*'})
- if self.want.ignore_down_response is None:
- self.want.update({'ignore_down_response': False})
- if self.want.transparent is None:
- self.want.update({'transparent': False})
- if self.want.send is None:
- self.want.update({'send': 'GET /\r\n'})
- if self.want.cipher_list is None:
- self.want.update({'cipher_list': 'DEFAULT:+SHA:+3DES:+kEDH'})
- if self.want.compatibility is None:
- self.want.update({'compatibility': True})
-
- def exec_module(self):
- if not module_provisioned(self.client, 'gtm'):
- raise F5ModuleError(
- "GTM must be provisioned to use this module."
- )
- changed = False
- result = dict()
- state = self.want.state
-
- if state == "present":
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def present(self):
- if self.exists():
- return self.update()
- else:
- return self.create()
-
- def absent(self):
- if self.exists():
- return self.remove()
- return False
-
- def update(self):
- self.have = self.read_current_from_device()
- if not self.should_update():
- return False
- if self.module.check_mode:
- return True
- self.update_on_device()
- return True
-
- def remove(self):
- if self.module.check_mode:
- return True
- self.remove_from_device()
- if self.exists():
- raise F5ModuleError("Failed to delete the resource.")
- return True
-
- def create(self):
- self._set_default_creation_values()
- self._set_changed_options()
- if self.module.check_mode:
- return True
- self.create_on_device()
- return True
-
- def exists(self):
- uri = "https://{0}:{1}/mgmt/tm/gtm/monitor/https/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name),
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def create_on_device(self):
- params = self.changes.api_params()
- params['name'] = self.want.name
- params['partition'] = self.want.partition
- uri = "https://{0}:{1}/mgmt/tm/gtm/monitor/https/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return response['selfLink']
-
- def update_on_device(self):
- params = self.changes.api_params()
- uri = "https://{0}:{1}/mgmt/tm/gtm/monitor/https/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name),
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def remove_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/gtm/monitor/https/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name),
- )
- response = self.client.api.delete(uri)
- if response.status == 200:
- return True
- raise F5ModuleError(response.content)
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/gtm/monitor/https/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name),
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return ApiParameters(params=response)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- name=dict(required=True),
- parent=dict(default='/Common/https'),
- send=dict(),
- receive=dict(),
- ip=dict(),
- port=dict(),
- interval=dict(type='int'),
- timeout=dict(type='int'),
- ignore_down_response=dict(type='bool'),
- transparent=dict(type='bool'),
- probe_timeout=dict(type='int'),
- reverse=dict(type='bool'),
- target_username=dict(),
- target_password=dict(no_log=True),
- cipher_list=dict(),
- compatibility=dict(type='bool'),
- client_cert=dict(),
- client_key=dict(),
- update_password=dict(
- default='always',
- choices=['always', 'on_create']
- ),
- state=dict(
- default='present',
- choices=['present', 'absent']
- ),
- partition=dict(
- default='Common',
- fallback=(env_fallback, ['F5_PARTITION'])
- )
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode,
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_gtm_monitor_tcp.py b/lib/ansible/modules/network/f5/bigip_gtm_monitor_tcp.py
deleted file mode 100644
index 6bccecc860..0000000000
--- a/lib/ansible/modules/network/f5/bigip_gtm_monitor_tcp.py
+++ /dev/null
@@ -1,796 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_gtm_monitor_tcp
-short_description: Manages F5 BIG-IP GTM tcp monitors
-description:
- - Manages F5 BIG-IP GTM tcp monitors.
-version_added: 2.6
-options:
- name:
- description:
- - Monitor name.
- type: str
- required: True
- parent:
- description:
- - The parent template of this monitor template. Once this value has
- been set, it cannot be changed. By default, this value is the C(tcp)
- parent on the C(Common) partition.
- type: str
- default: /Common/tcp
- send:
- description:
- - The send string for the monitor call.
- type: str
- receive:
- description:
- - The receive string for the monitor call.
- type: str
- ip:
- description:
- - IP address part of the IP/port definition. If this parameter is not
- provided when creating a new monitor, then the default value will be
- '*'.
- - If this value is an IP address, then a C(port) number must be specified.
- type: str
- port:
- description:
- - Port address part of the IP/port definition. If this parameter is not
- provided when creating a new monitor, then the default value will be
- '*'. Note that if specifying an IP address, a value between 1 and 65535
- must be specified
- type: str
- interval:
- description:
- - The interval specifying how frequently the monitor instance of this
- template will run.
- - If this parameter is not provided when creating a new monitor, then the
- default value will be 30.
- - This value B(must) be less than the C(timeout) value.
- type: int
- timeout:
- description:
- - The number of seconds in which the node or service must respond to
- the monitor request. If the target responds within the set time
- period, it is considered up. If the target does not respond within
- the set time period, it is considered down. You can change this
- number to any number you want, however, it should be 3 times the
- interval number of seconds plus 1 second.
- - If this parameter is not provided when creating a new monitor, then the
- default value will be 120.
- type: int
- partition:
- description:
- - Device partition to manage resources on.
- type: str
- default: Common
- state:
- description:
- - When C(present), ensures that the monitor exists.
- - When C(absent), ensures the monitor is removed.
- type: str
- choices:
- - present
- - absent
- default: present
- probe_timeout:
- description:
- - Specifies the number of seconds after which the system times out the probe request
- to the system.
- - When creating a new monitor, if this parameter is not provided, then the default
- value will be C(5).
- type: int
- ignore_down_response:
- description:
- - Specifies that the monitor allows more than one probe attempt per interval.
- - When C(yes), specifies that the monitor ignores down responses for the duration of
- the monitor timeout. Once the monitor timeout is reached without the system receiving
- an up response, the system marks the object down.
- - When C(no), specifies that the monitor immediately marks an object down when it
- receives a down response.
- - When creating a new monitor, if this parameter is not provided, then the default
- value will be C(no).
- type: bool
- transparent:
- description:
- - Specifies whether the monitor operates in transparent mode.
- - A monitor in transparent mode directs traffic through the associated pool members
- or nodes (usually a router or firewall) to the aliased destination (that is, it
- probes the C(ip)-C(port) combination specified in the monitor).
- - If the monitor cannot successfully reach the aliased destination, the pool member
- or node through which the monitor traffic was sent is marked down.
- - When creating a new monitor, if this parameter is not provided, then the default
- value will be C(no).
- type: bool
- reverse:
- description:
- - Instructs the system to mark the target resource down when the test is successful.
- This setting is useful, for example, if the content on your web site home page is
- dynamic and changes frequently, you may want to set up a reverse ECV service check
- that looks for the string Error.
- - A match for this string means that the web server was down.
- - To use this option, you must specify values for C(send) and C(receive).
- type: bool
-extends_documentation_fragment: f5
-author:
- - Tim Rupp (@caphrim007)
- - Wojciech Wypior (@wojtek0806)
-'''
-
-EXAMPLES = r'''
-- name: Create a GTM TCP monitor
- bigip_gtm_monitor_tcp:
- name: my_monitor
- ip: 1.1.1.1
- port: 80
- send: my send string
- receive: my receive string
- state: present
- provider:
- user: admin
- password: secret
- server: lb.mydomain.com
- delegate_to: localhost
-
-- name: Remove TCP Monitor
- bigip_gtm_monitor_tcp:
- name: my_monitor
- state: absent
- provider:
- user: admin
- password: secret
- server: lb.mydomain.com
- delegate_to: localhost
-
-- name: Add TCP monitor for all addresses, port 514
- bigip_gtm_monitor_tcp:
- name: my_monitor
- port: 514
- provider:
- user: admin
- password: secret
- server: lb.mydomain.com
- delegate_to: localhost
-'''
-
-RETURN = r'''
-parent:
- description: New parent template of the monitor.
- returned: changed
- type: str
- sample: tcp
-ip:
- description: The new IP of IP/port definition.
- returned: changed
- type: str
- sample: 10.12.13.14
-port:
- description: The new port the monitor checks the resource on.
- returned: changed
- type: str
- sample: 8080
-interval:
- description: The new interval in which to run the monitor check.
- returned: changed
- type: int
- sample: 2
-timeout:
- description: The new timeout in which the remote system must respond to the monitor.
- returned: changed
- type: int
- sample: 10
-ignore_down_response:
- description: Whether to ignore the down response or not.
- returned: changed
- type: bool
- sample: True
-send:
- description: The new send string for this monitor.
- returned: changed
- type: str
- sample: tcp string to send
-receive:
- description: The new receive string for this monitor.
- returned: changed
- type: str
- sample: tcp string to receive
-probe_timeout:
- description: The new timeout in which the system will timeout the monitor probe.
- returned: changed
- type: int
- sample: 10
-reverse:
- description: The new value for whether the monitor operates in reverse mode.
- returned: changed
- type: bool
- sample: False
-transparent:
- description: The new value for whether the monitor operates in transparent mode.
- returned: changed
- type: bool
- sample: False
-'''
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.basic import env_fallback
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import fq_name
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.common import transform_name
- from library.module_utils.network.f5.icontrol import module_provisioned
- from library.module_utils.network.f5.ipaddress import is_valid_ip
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import fq_name
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.common import transform_name
- from ansible.module_utils.network.f5.icontrol import module_provisioned
- from ansible.module_utils.network.f5.ipaddress import is_valid_ip
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'defaultsFrom': 'parent',
- 'ignoreDownResponse': 'ignore_down_response',
- 'probeTimeout': 'probe_timeout',
- 'recv': 'receive',
- }
-
- api_attributes = [
- 'defaultsFrom',
- 'interval',
- 'timeout',
- 'destination',
- 'transparent',
- 'probeTimeout',
- 'ignoreDownResponse',
- 'reverse',
- 'send',
- 'recv',
- ]
-
- returnables = [
- 'parent',
- 'ip',
- 'port',
- 'interval',
- 'timeout',
- 'transparent',
- 'probe_timeout',
- 'ignore_down_response',
- 'send',
- 'receive',
- 'reverse',
- ]
-
- updatables = [
- 'destination',
- 'interval',
- 'timeout',
- 'transparent',
- 'probe_timeout',
- 'ignore_down_response',
- 'send',
- 'receive',
- 'reverse',
- 'ip',
- 'port',
- ]
-
-
-class ApiParameters(Parameters):
- @property
- def ip(self):
- ip, port = self._values['destination'].split(':')
- return ip
-
- @property
- def port(self):
- ip, port = self._values['destination'].split(':')
- try:
- return int(port)
- except ValueError:
- return port
-
- @property
- def ignore_down_response(self):
- if self._values['ignore_down_response'] is None:
- return None
- if self._values['ignore_down_response'] == 'disabled':
- return False
- return True
-
- @property
- def transparent(self):
- if self._values['transparent'] is None:
- return None
- if self._values['transparent'] == 'disabled':
- return False
- return True
-
- @property
- def reverse(self):
- if self._values['reverse'] is None:
- return None
- if self._values['reverse'] == 'disabled':
- return False
- return True
-
-
-class ModuleParameters(Parameters):
- @property
- def interval(self):
- if self._values['interval'] is None:
- return None
- if 1 > int(self._values['interval']) > 86400:
- raise F5ModuleError(
- "Interval value must be between 1 and 86400"
- )
- return int(self._values['interval'])
-
- @property
- def timeout(self):
- if self._values['timeout'] is None:
- return None
- return int(self._values['timeout'])
-
- @property
- def ip(self):
- if self._values['ip'] is None:
- return None
- elif self._values['ip'] in ['*', '0.0.0.0']:
- return '*'
- elif is_valid_ip(self._values['ip']):
- return self._values['ip']
- raise F5ModuleError(
- "The provided 'ip' parameter is not an IP address."
- )
-
- @property
- def parent(self):
- if self._values['parent'] is None:
- return None
- result = fq_name(self.partition, self._values['parent'])
- return result
-
- @property
- def port(self):
- if self._values['port'] is None:
- return None
- elif self._values['port'] == '*':
- return '*'
- return int(self._values['port'])
-
- @property
- def destination(self):
- if self.ip is None and self.port is None:
- return None
- destination = '{0}:{1}'.format(self.ip, self.port)
- return destination
-
- @destination.setter
- def destination(self, value):
- ip, port = value.split(':')
- self._values['ip'] = ip
- self._values['port'] = port
-
- @property
- def probe_timeout(self):
- if self._values['probe_timeout'] is None:
- return None
- return int(self._values['probe_timeout'])
-
- @property
- def type(self):
- return 'tcp'
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class UsableChanges(Changes):
- @property
- def transparent(self):
- if self._values['transparent'] is None:
- return None
- elif self._values['transparent'] is True:
- return 'enabled'
- return 'disabled'
-
- @property
- def ignore_down_response(self):
- if self._values['ignore_down_response'] is None:
- return None
- elif self._values['ignore_down_response'] is True:
- return 'enabled'
- return 'disabled'
-
- @property
- def reverse(self):
- if self._values['reverse'] is None:
- return None
- elif self._values['reverse'] is True:
- return 'enabled'
- return 'disabled'
-
-
-class ReportableChanges(Changes):
- @property
- def ip(self):
- ip, port = self._values['destination'].split(':')
- return ip
-
- @property
- def port(self):
- ip, port = self._values['destination'].split(':')
- return int(port)
-
- @property
- def transparent(self):
- if self._values['transparent'] == 'enabled':
- return True
- return False
-
- @property
- def ignore_down_response(self):
- if self._values['ignore_down_response'] == 'enabled':
- return True
- return False
-
- @property
- def reverse(self):
- if self._values['reverse'] == 'enabled':
- return True
- return False
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
- @property
- def parent(self):
- if self.want.parent != self.have.parent:
- raise F5ModuleError(
- "The parent monitor cannot be changed"
- )
-
- @property
- def destination(self):
- if self.want.ip is None and self.want.port is None:
- return None
- if self.want.port is None:
- self.want.update({'port': self.have.port})
- if self.want.ip is None:
- self.want.update({'ip': self.have.ip})
-
- if self.want.port in [None, '*'] and self.want.ip != '*':
- raise F5ModuleError(
- "Specifying an IP address requires that a port number be specified"
- )
-
- if self.want.destination != self.have.destination:
- return self.want.destination
-
- @property
- def interval(self):
- if self.want.timeout is not None and self.want.interval is not None:
- if self.want.interval >= self.want.timeout:
- raise F5ModuleError(
- "Parameter 'interval' must be less than 'timeout'."
- )
- elif self.want.timeout is not None:
- if self.have.interval >= self.want.timeout:
- raise F5ModuleError(
- "Parameter 'interval' must be less than 'timeout'."
- )
- elif self.want.interval is not None:
- if self.want.interval >= self.have.timeout:
- raise F5ModuleError(
- "Parameter 'interval' must be less than 'timeout'."
- )
- if self.want.interval != self.have.interval:
- return self.want.interval
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(params=self.module.params)
- self.have = ApiParameters()
- self.changes = UsableChanges()
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = UsableChanges(params=changed)
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.client.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def _set_default_creation_values(self):
- if self.want.timeout is None:
- self.want.update({'timeout': 120})
- if self.want.interval is None:
- self.want.update({'interval': 30})
- if self.want.probe_timeout is None:
- self.want.update({'probe_timeout': 5})
- if self.want.ip is None:
- self.want.update({'ip': '*'})
- if self.want.port is None:
- self.want.update({'port': '*'})
- if self.want.ignore_down_response is None:
- self.want.update({'ignore_down_response': False})
- if self.want.transparent is None:
- self.want.update({'transparent': False})
-
- def exec_module(self):
- if not module_provisioned(self.client, 'gtm'):
- raise F5ModuleError(
- "GTM must be provisioned to use this module."
- )
- changed = False
- result = dict()
- state = self.want.state
-
- if state == "present":
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def present(self):
- if self.exists():
- return self.update()
- else:
- return self.create()
-
- def absent(self):
- if self.exists():
- return self.remove()
- return False
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def update(self):
- self.have = self.read_current_from_device()
- if not self.should_update():
- return False
- if self.module.check_mode:
- return True
- self.update_on_device()
- return True
-
- def remove(self):
- if self.module.check_mode:
- return True
- self.remove_from_device()
- if self.exists():
- raise F5ModuleError("Failed to delete the resource.")
- return True
-
- def create(self):
- self._set_default_creation_values()
- self._set_changed_options()
- if self.module.check_mode:
- return True
- self.create_on_device()
- return True
-
- def exists(self):
- uri = "https://{0}:{1}/mgmt/tm/gtm/monitor/tcp/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name),
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def create_on_device(self):
- params = self.changes.api_params()
- params['name'] = self.want.name
- params['partition'] = self.want.partition
- uri = "https://{0}:{1}/mgmt/tm/gtm/monitor/tcp/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return response['selfLink']
-
- def update_on_device(self):
- params = self.changes.api_params()
- uri = "https://{0}:{1}/mgmt/tm/gtm/monitor/tcp/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name),
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def remove_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/gtm/monitor/tcp/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name),
- )
- response = self.client.api.delete(uri)
- if response.status == 200:
- return True
- raise F5ModuleError(response.content)
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/gtm/monitor/tcp/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name),
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return ApiParameters(params=response)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- name=dict(required=True),
- parent=dict(default='/Common/tcp'),
- send=dict(),
- receive=dict(),
- ip=dict(),
- port=dict(),
- interval=dict(type='int'),
- timeout=dict(type='int'),
- ignore_down_response=dict(type='bool'),
- transparent=dict(type='bool'),
- probe_timeout=dict(type='int'),
- reverse=dict(type='bool'),
- state=dict(
- default='present',
- choices=['present', 'absent']
- ),
- partition=dict(
- default='Common',
- fallback=(env_fallback, ['F5_PARTITION'])
- )
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode,
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_gtm_monitor_tcp_half_open.py b/lib/ansible/modules/network/f5/bigip_gtm_monitor_tcp_half_open.py
deleted file mode 100644
index a9f00eeea9..0000000000
--- a/lib/ansible/modules/network/f5/bigip_gtm_monitor_tcp_half_open.py
+++ /dev/null
@@ -1,704 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_gtm_monitor_tcp_half_open
-short_description: Manages F5 BIG-IP GTM tcp half-open monitors
-description:
- - Manages F5 BIG-IP GTM tcp half-open monitors.
-version_added: 2.6
-options:
- name:
- description:
- - Monitor name.
- type: str
- required: True
- parent:
- description:
- - The parent template of this monitor template. Once this value has
- been set, it cannot be changed. By default, this value is the C(tcp_half_open)
- parent on the C(Common) partition.
- type: str
- default: "/Common/tcp_half_open"
- ip:
- description:
- - IP address part of the IP/port definition. If this parameter is not
- provided when creating a new monitor, then the default value will be
- '*'.
- type: str
- port:
- description:
- - Port address part of the IP/port definition. If this parameter is not
- provided when creating a new monitor, then the default value will be
- '*'. Note that if specifying an IP address, a value between 1 and 65535
- must be specified
- type: str
- interval:
- description:
- - Specifies, in seconds, the frequency at which the system issues the monitor
- check when either the resource is down or the status of the resource is unknown.
- - When creating a new monitor, if this parameter is not provided, then the
- default value will be C(30). This value B(must) be less than the C(timeout) value.
- type: int
- timeout:
- description:
- - Specifies the number of seconds the target has in which to respond to the
- monitor request.
- - If the target responds within the set time period, it is considered up.
- - If the target does not respond within the set time period, it is considered down.
- - When this value is set to 0 (zero), the system uses the interval from the parent monitor.
- - When creating a new monitor, if this parameter is not provided, then
- the default value will be C(120).
- type: int
- probe_interval:
- description:
- - Specifies the number of seconds the big3d process waits before sending out a
- subsequent probe attempt when a probe fails and multiple probe attempts have
- been requested.
- - When creating a new monitor, if this parameter is not provided, then the default
- value will be C(1).
- type: int
- probe_timeout:
- description:
- - Specifies the number of seconds after which the system times out the probe request
- to the system.
- - When creating a new monitor, if this parameter is not provided, then the default
- value will be C(5).
- type: int
- probe_attempts:
- description:
- - Specifies the number of times the system attempts to probe the host server, after
- which the system considers the host server down or unavailable.
- - When creating a new monitor, if this parameter is not provided, then the default
- value will be C(3).
- type: int
- ignore_down_response:
- description:
- - Specifies that the monitor allows more than one probe attempt per interval.
- - When C(yes), specifies that the monitor ignores down responses for the duration of
- the monitor timeout. Once the monitor timeout is reached without the system receiving
- an up response, the system marks the object down.
- - When C(no), specifies that the monitor immediately marks an object down when it
- receives a down response.
- - When creating a new monitor, if this parameter is not provided, then the default
- value will be C(no).
- type: bool
- transparent:
- description:
- - Specifies whether the monitor operates in transparent mode.
- - A monitor in transparent mode directs traffic through the associated pool members
- or nodes (usually a router or firewall) to the aliased destination (that is, it
- probes the C(ip)-C(port) combination specified in the monitor).
- - If the monitor cannot successfully reach the aliased destination, the pool member
- or node through which the monitor traffic was sent is marked down.
- - When creating a new monitor, if this parameter is not provided, then the default
- value will be C(no).
- type: bool
- partition:
- description:
- - Device partition to manage resources on.
- type: str
- default: Common
- state:
- description:
- - When C(present), ensures that the monitor exists.
- - When C(absent), ensures the monitor is removed.
- type: str
- choices:
- - present
- - absent
- default: present
-notes:
- - Requires BIG-IP software version >= 12
-extends_documentation_fragment: f5
-author:
- - Tim Rupp (@caphrim007)
- - Wojciech Wypior (@wojtek0806)
-'''
-
-EXAMPLES = r'''
-- name: Create TCP half-open Monitor
- bigip_gtm_monitor_tcp_half_open:
- state: present
- ip: 10.10.10.10
- name: my_monitor
- provider:
- user: admin
- password: secret
- server: lb.mydomain.com
- delegate_to: localhost
-
-- name: Remove TCP half-open Monitor
- bigip_gtm_monitor_tcp_half_open:
- state: absent
- name: my_monitor
- provider:
- user: admin
- password: secret
- server: lb.mydomain.com
- delegate_to: localhost
-
-- name: Add half-open monitor for all addresses, port 514
- bigip_gtm_monitor_tcp_half_open:
- port: 514
- name: my_monitor
- provider:
- user: admin
- password: secret
- server: lb.mydomain.com
- delegate_to: localhost
-'''
-
-RETURN = r'''
-parent:
- description: New parent template of the monitor.
- returned: changed
- type: str
- sample: tcp_half_open
-ip:
- description: The new IP of IP/port definition.
- returned: changed
- type: str
- sample: 10.12.13.14
-interval:
- description: The new interval in which to run the monitor check.
- returned: changed
- type: int
- sample: 2
-timeout:
- description: The new timeout in which the remote system must respond to the monitor.
- returned: changed
- type: int
- sample: 10
-probe_timeout:
- description: The new timeout in which the system will timeout the monitor probe.
- returned: changed
- type: int
- sample: 10
-probe_interval:
- description: The new interval in which the system will check the monitor probe.
- returned: changed
- type: int
- sample: 10
-probe_attempts:
- description: The new number of attempts the system will make in checking the monitor probe.
- returned: changed
- type: int
- sample: 10
-'''
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.basic import env_fallback
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import fq_name
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.common import transform_name
- from library.module_utils.network.f5.icontrol import module_provisioned
- from library.module_utils.network.f5.ipaddress import is_valid_ip
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import fq_name
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.common import transform_name
- from ansible.module_utils.network.f5.icontrol import module_provisioned
- from ansible.module_utils.network.f5.ipaddress import is_valid_ip
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'defaultsFrom': 'parent',
- 'ignoreDownResponse': 'ignore_down_response',
- 'probeAttempts': 'probe_attempts',
- 'probeInterval': 'probe_interval',
- 'probeTimeout': 'probe_timeout',
- }
-
- api_attributes = [
- 'defaultsFrom', 'interval', 'timeout', 'destination', 'transparent', 'probeAttempts',
- 'probeInterval', 'probeTimeout', 'ignoreDownResponse',
- ]
-
- returnables = [
- 'parent', 'ip', 'port', 'interval', 'timeout', 'transparent', 'probe_attempts',
- 'probe_interval', 'probe_timeout', 'ignore_down_response',
- ]
-
- updatables = [
- 'destination', 'interval', 'timeout', 'transparent', 'probe_attempts',
- 'probe_interval', 'probe_timeout', 'ignore_down_response',
- ]
-
- @property
- def interval(self):
- if self._values['interval'] is None:
- return None
-
- if 1 > int(self._values['interval']) > 86400:
- raise F5ModuleError(
- "Interval value must be between 1 and 86400"
- )
- return int(self._values['interval'])
-
- @property
- def timeout(self):
- if self._values['timeout'] is None:
- return None
- return int(self._values['timeout'])
-
- @property
- def probe_attempts(self):
- if self._values['probe_attempts'] is None:
- return None
- return int(self._values['probe_attempts'])
-
- @property
- def probe_interval(self):
- if self._values['probe_interval'] is None:
- return None
- return int(self._values['probe_interval'])
-
- @property
- def probe_timeout(self):
- if self._values['probe_timeout'] is None:
- return None
- return int(self._values['probe_timeout'])
-
- @property
- def type(self):
- return 'tcp_half_open'
-
-
-class ApiParameters(Parameters):
- @property
- def ip(self):
- ip, port = self._values['destination'].split(':')
- return ip
-
- @property
- def port(self):
- ip, port = self._values['destination'].split(':')
- return int(port)
-
- @property
- def ignore_down_response(self):
- if self._values['ignore_down_response'] is None:
- return None
- if self._values['ignore_down_response'] == 'disabled':
- return False
- return True
-
- @property
- def transparent(self):
- if self._values['transparent'] is None:
- return None
- if self._values['transparent'] == 'disabled':
- return False
- return True
-
-
-class ModuleParameters(Parameters):
- @property
- def destination(self):
- if self.ip is None and self.port is None:
- return None
- destination = '{0}:{1}'.format(self.ip, self.port)
- return destination
-
- @property
- def parent(self):
- if self._values['parent'] is None:
- return None
- return fq_name(self.partition, self._values['parent'])
-
- @property
- def ip(self):
- if self._values['ip'] is None:
- return None
- if self._values['ip'] in ['*', '0.0.0.0']:
- return '*'
- elif is_valid_ip(self._values['ip']):
- return self._values['ip']
- else:
- raise F5ModuleError(
- "The provided 'ip' parameter is not an IP address."
- )
-
- @property
- def port(self):
- if self._values['port'] is None:
- return None
- elif self._values['port'] == '*':
- return '*'
- return int(self._values['port'])
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- return result
- except Exception:
- return result
-
-
-class UsableChanges(Changes):
- @property
- def transparent(self):
- if self._values['transparent']:
- return 'enabled'
- return 'disabled'
-
- @property
- def ignore_down_response(self):
- if self._values['ignore_down_response']:
- return 'enabled'
- return 'disabled'
-
-
-class ReportableChanges(Changes):
- pass
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- result = self.__default(param)
- return result
-
- @property
- def parent(self):
- if self.want.parent != self.have.parent:
- raise F5ModuleError(
- "The parent monitor cannot be changed"
- )
-
- @property
- def destination(self):
- if self.want.ip is None and self.want.port is None:
- return None
- if self.want.port is None:
- self.want.update({'port': self.have.port})
- if self.want.ip is None:
- self.want.update({'ip': self.have.ip})
-
- if self.want.port in [None, '*'] and self.want.ip != '*':
- raise F5ModuleError(
- "Specifying an IP address requires that a port number be specified"
- )
-
- if self.want.destination != self.have.destination:
- return self.want.destination
-
- @property
- def interval(self):
- if self.want.timeout is not None and self.want.interval is not None:
- if self.want.interval >= self.want.timeout:
- raise F5ModuleError(
- "Parameter 'interval' must be less than 'timeout'."
- )
- elif self.want.timeout is not None:
- if self.have.interval >= self.want.timeout:
- raise F5ModuleError(
- "Parameter 'interval' must be less than 'timeout'."
- )
- elif self.want.interval is not None:
- if self.want.interval >= self.have.timeout:
- raise F5ModuleError(
- "Parameter 'interval' must be less than 'timeout'."
- )
- if self.want.interval != self.have.interval:
- return self.want.interval
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.have = None
- self.want = ModuleParameters(params=self.module.params)
- self.changes = UsableChanges()
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = UsableChanges(params=changed)
-
- def _update_changed_options(self): # lgtm [py/similar-function]
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def _set_default_creation_values(self):
- if self.want.timeout is None:
- self.want.update({'timeout': 120})
- if self.want.interval is None:
- self.want.update({'interval': 30})
- if self.want.ip is None:
- self.want.update({'ip': '*'})
- if self.want.port is None:
- self.want.update({'port': '*'})
- if self.want.probe_interval is None:
- self.want.update({'probe_interval': 1})
- if self.want.probe_timeout is None:
- self.want.update({'probe_timeout': 5})
- if self.want.probe_attempts is None:
- self.want.update({'probe_attempts': 3})
- if self.want.ignore_down_response is None:
- self.want.update({'ignore_down_response': False})
- if self.want.transparent is None:
- self.want.update({'transparent': False})
-
- def exec_module(self):
- if not module_provisioned(self.client, 'gtm'):
- raise F5ModuleError(
- "GTM must be provisioned to use this module."
- )
- changed = False
- result = dict()
- state = self.want.state
-
- if state == "present":
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def present(self):
- if self.exists():
- return self.update()
- else:
- return self.create()
-
- def create(self):
- self._set_default_creation_values()
- self._set_changed_options()
- if self.module.check_mode:
- return True
- self.create_on_device()
- return True
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def update(self):
- self.have = self.read_current_from_device()
- if not self.should_update():
- return False
- if self.module.check_mode:
- return True
- self.update_on_device()
- return True
-
- def absent(self):
- if self.exists():
- return self.remove()
- return False
-
- def remove(self):
- if self.module.check_mode:
- return True
- self.remove_from_device()
- if self.exists():
- raise F5ModuleError("Failed to delete the monitor.")
- return True
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/gtm/monitor/tcp-half-open/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name),
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return ApiParameters(params=response)
-
- def exists(self):
- uri = "https://{0}:{1}/mgmt/tm/gtm/monitor/tcp-half-open/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name),
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def update_on_device(self):
- params = self.changes.api_params()
- uri = "https://{0}:{1}/mgmt/tm/gtm/monitor/tcp-half-open/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name),
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def create_on_device(self):
- params = self.changes.api_params()
- params['name'] = self.want.name
- params['partition'] = self.want.partition
- uri = "https://{0}:{1}/mgmt/tm/gtm/monitor/tcp-half-open/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return response['selfLink']
-
- def remove_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/gtm/monitor/tcp-half-open/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name),
- )
- response = self.client.api.delete(uri)
- if response.status == 200:
- return True
- raise F5ModuleError(response.content)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- name=dict(required=True),
- parent=dict(default='/Common/tcp_half_open'),
- ip=dict(),
- port=dict(),
- interval=dict(type='int'),
- timeout=dict(type='int'),
- probe_interval=dict(type='int'),
- probe_timeout=dict(type='int'),
- probe_attempts=dict(type='int'),
- ignore_down_response=dict(type='bool'),
- transparent=dict(type='bool'),
- state=dict(
- default='present',
- choices=['present', 'absent']
- ),
- partition=dict(
- default='Common',
- fallback=(env_fallback, ['F5_PARTITION'])
- )
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode,
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_gtm_pool.py b/lib/ansible/modules/network/f5/bigip_gtm_pool.py
deleted file mode 100644
index 7e623c09cb..0000000000
--- a/lib/ansible/modules/network/f5/bigip_gtm_pool.py
+++ /dev/null
@@ -1,1283 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['stableinterface'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_gtm_pool
-short_description: Manages F5 BIG-IP GTM pools
-description:
- - Manages F5 BIG-IP GTM pools.
-version_added: 2.4
-options:
- state:
- description:
- - Pool state. When C(present), ensures that the pool is created and enabled.
- When C(absent), ensures that the pool is removed from the system. When
- C(enabled) or C(disabled), ensures that the pool is enabled or disabled
- (respectively) on the remote device.
- type: str
- choices:
- - present
- - absent
- - enabled
- - disabled
- default: present
- preferred_lb_method:
- description:
- - The load balancing mode that the system tries first.
- type: str
- choices:
- - round-robin
- - return-to-dns
- - ratio
- - topology
- - static-persistence
- - global-availability
- - virtual-server-capacity
- - least-connections
- - lowest-round-trip-time
- - fewest-hops
- - packet-rate
- - cpu
- - completion-rate
- - quality-of-service
- - kilobytes-per-second
- - drop-packet
- - fallback-ip
- - virtual-server-score
- alternate_lb_method:
- description:
- - The load balancing mode that the system tries if the
- C(preferred_lb_method) is unsuccessful in picking a pool.
- type: str
- choices:
- - round-robin
- - return-to-dns
- - none
- - ratio
- - topology
- - static-persistence
- - global-availability
- - virtual-server-capacity
- - packet-rate
- - drop-packet
- - fallback-ip
- - virtual-server-score
- fallback_lb_method:
- description:
- - The load balancing mode that the system tries if both the
- C(preferred_lb_method) and C(alternate_lb_method)s are unsuccessful
- in picking a pool.
- type: str
- choices:
- - round-robin
- - return-to-dns
- - ratio
- - topology
- - static-persistence
- - global-availability
- - virtual-server-capacity
- - least-connections
- - lowest-round-trip-time
- - fewest-hops
- - packet-rate
- - cpu
- - completion-rate
- - quality-of-service
- - kilobytes-per-second
- - drop-packet
- - fallback-ip
- - virtual-server-score
- - none
- fallback_ip:
- description:
- - Specifies the IPv4, or IPv6 address of the server to which the system
- directs requests when it cannot use one of its pools to do so.
- Note that the system uses the fallback IP only if you select the
- C(fallback_ip) load balancing method.
- type: str
- type:
- description:
- - The type of GTM pool that you want to create. On BIG-IP releases
- prior to version 12, this parameter is not required. On later versions
- of BIG-IP, this is a required parameter.
- type: str
- choices:
- - a
- - aaaa
- - cname
- - mx
- - naptr
- - srv
- name:
- description:
- - Name of the GTM pool.
- type: str
- required: True
- partition:
- description:
- - Device partition to manage resources on.
- type: str
- default: Common
- version_added: 2.5
- members:
- description:
- - Members to assign to the pool.
- - The order of the members in this list is the order that they will be listed in the pool.
- suboptions:
- server:
- description:
- - Name of the server which the pool member is a part of.
- type: str
- required: True
- virtual_server:
- description:
- - Name of the virtual server, associated with the server, that the pool member is a part of.
- type: str
- required: True
- type: list
- version_added: 2.6
- monitors:
- description:
- - Specifies the health monitors that the system currently uses to monitor this resource.
- - When C(availability_requirements.type) is C(require), you may only have a single monitor in the
- C(monitors) list.
- type: list
- version_added: 2.6
- availability_requirements:
- description:
- - Specifies, if you activate more than one health monitor, the number of health
- monitors that must receive successful responses in order for the link to be
- considered available.
- suboptions:
- type:
- description:
- - Monitor rule type when C(monitors) is specified.
- - When creating a new pool, if this value is not specified, the default of 'all' will be used.
- type: str
- choices:
- - all
- - at_least
- - require
- at_least:
- description:
- - Specifies the minimum number of active health monitors that must be successful
- before the link is considered up.
- - This parameter is only relevant when a C(type) of C(at_least) is used.
- - This parameter will be ignored if a type of either C(all) or C(require) is used.
- type: int
- number_of_probes:
- description:
- - Specifies the minimum number of probes that must succeed for this server to be declared up.
- - When creating a new virtual server, if this parameter is specified, then the C(number_of_probers)
- parameter must also be specified.
- - The value of this parameter should always be B(lower) than, or B(equal to), the value of C(number_of_probers).
- - This parameter is only relevant when a C(type) of C(require) is used.
- - This parameter will be ignored if a type of either C(all) or C(at_least) is used.
- type: int
- number_of_probers:
- description:
- - Specifies the number of probers that should be used when running probes.
- - When creating a new virtual server, if this parameter is specified, then the C(number_of_probes)
- parameter must also be specified.
- - The value of this parameter should always be B(higher) than, or B(equal to), the value of C(number_of_probers).
- - This parameter is only relevant when a C(type) of C(require) is used.
- - This parameter will be ignored if a type of either C(all) or C(at_least) is used.
- type: int
- type: dict
- version_added: 2.6
- max_answers_returned:
- description:
- - Specifies the maximum number of available virtual servers that the system lists in a response.
- - The maximum is 500.
- type: int
- version_added: 2.8
- ttl:
- description:
- - Specifies the number of seconds that the IP address, once found, is valid.
- type: int
- version_added: 2.8
-notes:
- - Support for TMOS versions below v12.x has been deprecated for this module, and will be removed in Ansible 2.12.
-extends_documentation_fragment: f5
-author:
- - Tim Rupp (@caphrim007)
- - Wojciech Wypior (@wojtek0806)
-'''
-
-EXAMPLES = r'''
-- name: Create a GTM pool
- bigip_gtm_pool:
- name: my_pool
- provider:
- user: admin
- password: secret
- server: lb.mydomain.com
- delegate_to: localhost
-
-- name: Disable pool
- bigip_gtm_pool:
- state: disabled
- name: my_pool
- provider:
- user: admin
- password: secret
- server: lb.mydomain.com
- delegate_to: localhost
-'''
-
-RETURN = r'''
-preferred_lb_method:
- description: New preferred load balancing method for the pool.
- returned: changed
- type: str
- sample: topology
-alternate_lb_method:
- description: New alternate load balancing method for the pool.
- returned: changed
- type: str
- sample: drop-packet
-fallback_lb_method:
- description: New fallback load balancing method for the pool.
- returned: changed
- type: str
- sample: fewest-hops
-fallback_ip:
- description: New fallback IP used when load balancing using the C(fallback_ip) method.
- returned: changed
- type: str
- sample: 10.10.10.10
-monitors:
- description: The new list of monitors for the resource.
- returned: changed
- type: list
- sample: ['/Common/monitor1', '/Common/monitor2']
-members:
- description: List of members in the pool.
- returned: changed
- type: complex
- contains:
- server:
- description: The name of the server portion of the member.
- returned: changed
- type: str
- virtual_server:
- description: The name of the virtual server portion of the member.
- returned: changed
- type: str
-max_answers_returned:
- description: The new Maximum Answers Returned value.
- returned: changed
- type: int
- sample: 25
-'''
-
-import copy
-import re
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.basic import env_fallback
-from distutils.version import LooseVersion
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import fq_name
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.common import transform_name
- from library.module_utils.network.f5.icontrol import tmos_version
- from library.module_utils.network.f5.icontrol import module_provisioned
- from library.module_utils.network.f5.ipaddress import is_valid_ip
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import fq_name
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.common import transform_name
- from ansible.module_utils.network.f5.icontrol import tmos_version
- from ansible.module_utils.network.f5.icontrol import module_provisioned
- from ansible.module_utils.network.f5.ipaddress import is_valid_ip
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'loadBalancingMode': 'preferred_lb_method',
- 'alternateMode': 'alternate_lb_method',
- 'fallbackMode': 'fallback_lb_method',
- 'verifyMemberAvailability': 'verify_member_availability',
- 'fallbackIpv4': 'fallback_ip',
- 'fallbackIpv6': 'fallback_ip',
- 'fallbackIp': 'fallback_ip',
- 'membersReference': 'members',
- 'monitor': 'monitors',
- 'maxAnswersReturned': 'max_answers_returned',
- }
-
- updatables = [
- 'alternate_lb_method',
- 'fallback_ip',
- 'fallback_lb_method',
- 'members',
- 'monitors',
- 'preferred_lb_method',
- 'state',
- 'max_answers_returned',
- 'ttl',
- ]
-
- returnables = [
- 'alternate_lb_method',
- 'fallback_ip',
- 'fallback_lb_method',
- 'members',
- 'monitors',
- 'preferred_lb_method',
- 'enabled',
- 'disabled',
- 'availability_requirements',
- 'max_answers_returned',
- 'ttl',
- ]
-
- api_attributes = [
- 'alternateMode',
- 'disabled',
- 'enabled',
- 'fallbackIp',
- 'fallbackIpv4',
- 'fallbackIpv6',
- 'fallbackMode',
- 'loadBalancingMode',
- 'members',
- 'verifyMemberAvailability',
- 'monitor',
- 'maxAnswersReturned',
- 'ttl',
- ]
-
- @property
- def type(self):
- if self._values['type'] is None:
- return None
- return str(self._values['type'])
-
- @property
- def verify_member_availability(self):
- if self._values['verify_member_availability'] is None:
- return None
- elif self._values['verify_member_availability']:
- return 'enabled'
- else:
- return 'disabled'
-
- @property
- def fallback_ip(self):
- if self._values['fallback_ip'] is None:
- return None
- if self._values['fallback_ip'] == 'any':
- return 'any'
- if self._values['fallback_ip'] == 'any6':
- return 'any6'
- if is_valid_ip(self._values['fallback_ip']):
- return self._values['fallback_ip']
- else:
- raise F5ModuleError(
- 'The provided fallback address is not a valid IPv4 address'
- )
-
- @property
- def state(self):
- if self._values['state'] == 'enabled':
- return 'present'
- return self._values['state']
-
- @property
- def enabled(self):
- if self._values['enabled'] is None:
- return None
- return True
-
- @property
- def disabled(self):
- if self._values['disabled'] is None:
- return None
- return True
-
-
-class ApiParameters(Parameters):
- @property
- def members(self):
- result = []
- if self._values['members'] is None or 'items' not in self._values['members']:
- return []
- for item in self._values['members']['items']:
- result.append(dict(item=item['fullPath'], order=item['memberOrder']))
- result = [x['item'] for x in sorted(result, key=lambda k: k['order'])]
- return result
-
- @property
- def availability_requirement_type(self):
- if self._values['monitors'] is None:
- return None
- if 'min ' in self._values['monitors']:
- return 'at_least'
- elif 'require ' in self._values['monitors']:
- return 'require'
- else:
- return 'all'
-
- @property
- def monitors_list(self):
- if self._values['monitors'] is None:
- return []
- try:
- result = re.findall(r'/\w+/[^\s}]+', self._values['monitors'])
- result.sort()
- return result
- except Exception:
- return self._values['monitors']
-
- @property
- def monitors(self):
- if self._values['monitors'] is None:
- return None
- if self._values['monitors'] == 'default':
- return 'default'
- monitors = [fq_name(self.partition, x) for x in self.monitors_list]
- if self.availability_requirement_type == 'at_least':
- monitors = ' '.join(monitors)
- result = 'min {0} of {{ {1} }}'.format(self.at_least, monitors)
- elif self.availability_requirement_type == 'require':
- monitors = ' '.join(monitors)
- result = 'require {0} from {1} {{ {2} }}'.format(self.number_of_probes, self.number_of_probers, monitors)
- else:
- result = ' and '.join(monitors).strip()
- return result
-
- @property
- def number_of_probes(self):
- """Returns the probes value from the monitor string.
-
- The monitor string for a Require monitor looks like this.
-
- require 1 from 2 { /Common/tcp }
-
- This method parses out the first of the numeric values. This values represents
- the "probes" value that can be updated in the module.
-
- Returns:
- int: The probes value if found. None otherwise.
- """
- if self._values['monitors'] is None:
- return None
- pattern = r'require\s+(?P<probes>\d+)\s+from'
- matches = re.search(pattern, self._values['monitors'])
- if matches is None:
- return None
- return matches.group('probes')
-
- @property
- def number_of_probers(self):
- """Returns the probers value from the monitor string.
-
- The monitor string for a Require monitor looks like this.
-
- require 1 from 2 { /Common/tcp }
-
- This method parses out the first of the numeric values. This values represents
- the "probers" value that can be updated in the module.
-
- Returns:
- int: The probers value if found. None otherwise.
- """
- if self._values['monitors'] is None:
- return None
- pattern = r'require\s+\d+\s+from\s+(?P<probers>\d+)\s+'
- matches = re.search(pattern, self._values['monitors'])
- if matches is None:
- return None
- return matches.group('probers')
-
- @property
- def at_least(self):
- """Returns the 'at least' value from the monitor string.
-
- The monitor string for a Require monitor looks like this.
-
- min 1 of { /Common/gateway_icmp }
-
- This method parses out the first of the numeric values. This values represents
- the "at_least" value that can be updated in the module.
-
- Returns:
- int: The at_least value if found. None otherwise.
- """
- if self._values['monitors'] is None:
- return None
- pattern = r'min\s+(?P<least>\d+)\s+of\s+'
- matches = re.search(pattern, self._values['monitors'])
- if matches is None:
- return None
- return matches.group('least')
-
-
-class ModuleParameters(Parameters):
- def _get_availability_value(self, type):
- if self._values['availability_requirements'] is None:
- return None
- if self._values['availability_requirements'][type] is None:
- return None
- return int(self._values['availability_requirements'][type])
-
- @property
- def members(self):
- if self._values['members'] is None:
- return None
- if len(self._values['members']) == 1 and self._values['members'][0] == '':
- return []
- result = []
- for member in self._values['members']:
- if 'server' not in member:
- raise F5ModuleError(
- "One of the provided members is missing a 'server' sub-option."
- )
- if 'virtual_server' not in member:
- raise F5ModuleError(
- "One of the provided members is missing a 'virtual_server' sub-option."
- )
- name = '{0}:{1}'.format(member['server'], member['virtual_server'])
- name = fq_name(self.partition, name)
- if name in result:
- continue
- result.append(name)
- result = list(result)
- return result
-
- @property
- def monitors_list(self):
- if self._values['monitors'] is None:
- return []
- try:
- result = re.findall(r'/\w+/[^\s}]+', self._values['monitors'])
- result.sort()
- return result
- except Exception:
- return self._values['monitors']
-
- @property
- def monitors(self):
- if self._values['monitors'] is None:
- return None
- if len(self._values['monitors']) == 1 and self._values['monitors'][0] == '':
- return 'default'
- monitors = [fq_name(self.partition, x) for x in self.monitors_list]
- if self.availability_requirement_type == 'at_least':
- if self.at_least > len(self.monitors_list):
- raise F5ModuleError(
- "The 'at_least' value must not exceed the number of 'monitors'."
- )
- monitors = ' '.join(monitors)
- result = 'min {0} of {{ {1} }}'.format(self.at_least, monitors)
- elif self.availability_requirement_type == 'require':
- monitors = ' '.join(monitors)
- if self.number_of_probes > self.number_of_probers:
- raise F5ModuleError(
- "The 'number_of_probes' must not exceed the 'number_of_probers'."
- )
- result = 'require {0} from {1} {{ {2} }}'.format(self.number_of_probes, self.number_of_probers, monitors)
- else:
- result = ' and '.join(monitors).strip()
-
- return result
-
- @property
- def availability_requirement_type(self):
- if self._values['availability_requirements'] is None:
- return None
- return self._values['availability_requirements']['type']
-
- @property
- def number_of_probes(self):
- return self._get_availability_value('number_of_probes')
-
- @property
- def number_of_probers(self):
- return self._get_availability_value('number_of_probers')
-
- @property
- def at_least(self):
- return self._get_availability_value('at_least')
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- return result
-
-
-class UsableChanges(Changes):
- @property
- def monitors(self):
- monitor_string = self._values['monitors']
- if monitor_string is None:
- return None
- if '{' in monitor_string and '}':
- tmp = monitor_string.strip('}').split('{')
- monitor = ''.join(tmp).rstrip()
- return monitor
- return monitor_string
-
- @property
- def members(self):
- results = []
- if self._values['members'] is None:
- return None
- for idx, member in enumerate(self._values['members']):
- result = dict(
- name=member,
- memberOrder=idx
- )
- results.append(result)
- return results
-
-
-class ReportableChanges(Changes):
- @property
- def members(self):
- results = []
- if self._values['members'] is None:
- return None
- for member in self._values['members']:
- parts = member.split(':')
- results.append(dict(
- server=fq_name(self.partition, parts[0]),
- virtual_server=fq_name(self.partition, parts[1])
- ))
- return results
-
- @property
- def monitors(self):
- if self._values['monitors'] is None:
- return []
- try:
- result = re.findall(r'/\w+/[^\s}]+', self._values['monitors'])
- result.sort()
- return result
- except Exception:
- return self._values['monitors']
-
- @property
- def availability_requirement_type(self):
- if self._values['monitors'] is None:
- return None
- if 'min ' in self._values['monitors']:
- return 'at_least'
- elif 'require ' in self._values['monitors']:
- return 'require'
- else:
- return 'all'
-
- @property
- def number_of_probes(self):
- """Returns the probes value from the monitor string.
- The monitor string for a Require monitor looks like this.
- require 1 from 2 { /Common/tcp }
- This method parses out the first of the numeric values. This values represents
- the "probes" value that can be updated in the module.
- Returns:
- int: The probes value if found. None otherwise.
- """
- if self._values['monitors'] is None:
- return None
- pattern = r'require\s+(?P<probes>\d+)\s+from'
- matches = re.search(pattern, self._values['monitors'])
- if matches is None:
- return None
- return int(matches.group('probes'))
-
- @property
- def number_of_probers(self):
- """Returns the probers value from the monitor string.
- The monitor string for a Require monitor looks like this.
- require 1 from 2 { /Common/tcp }
- This method parses out the first of the numeric values. This values represents
- the "probers" value that can be updated in the module.
- Returns:
- int: The probers value if found. None otherwise.
- """
- if self._values['monitors'] is None:
- return None
- pattern = r'require\s+\d+\s+from\s+(?P<probers>\d+)\s+'
- matches = re.search(pattern, self._values['monitors'])
- if matches is None:
- return None
- return int(matches.group('probers'))
-
- @property
- def at_least(self):
- """Returns the 'at least' value from the monitor string.
- The monitor string for a Require monitor looks like this.
- min 1 of { /Common/gateway_icmp }
- This method parses out the first of the numeric values. This values represents
- the "at_least" value that can be updated in the module.
- Returns:
- int: The at_least value if found. None otherwise.
- """
- if self._values['monitors'] is None:
- return None
- pattern = r'min\s+(?P<least>\d+)\s+of\s+'
- matches = re.search(pattern, self._values['monitors'])
- if matches is None:
- return None
- return int(matches.group('least'))
-
- @property
- def availability_requirements(self):
- if self._values['monitors'] is None:
- return None
- result = dict()
- result['type'] = self.availability_requirement_type
- result['at_least'] = self.at_least
- result['number_of_probers'] = self.number_of_probers
- result['number_of_probes'] = self.number_of_probes
- return result
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
- @property
- def state(self):
- if self.want.state == 'disabled' and self.have.enabled:
- return dict(
- disabled=True
- )
- elif self.want.state in ['present', 'enabled'] and self.have.disabled:
- return dict(
- enabled=True
- )
-
- @property
- def monitors(self):
- if self.want.monitors is None:
- return None
- if self.want.monitors == 'default' and self.have.monitors == 'default':
- return None
- if self.want.monitors == 'default' and self.have.monitors is None:
- return None
- if self.want.monitors == 'default' and len(self.have.monitors) > 0:
- return 'default'
- if self.have.monitors is None:
- return self.want.monitors
- if self.have.monitors != self.want.monitors:
- return self.want.monitors
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.kwargs = kwargs
-
- def exec_module(self):
- if not module_provisioned(self.client, 'gtm'):
- raise F5ModuleError(
- "GTM must be provisioned to use this module."
- )
- if self.version_is_less_than_12():
- manager = self.get_manager('untyped')
- else:
- manager = self.get_manager('typed')
- return manager.exec_module()
-
- def get_manager(self, type):
- if type == 'typed':
- return TypedManager(**self.kwargs)
- elif type == 'untyped':
- return UntypedManager(**self.kwargs)
-
- def version_is_less_than_12(self):
- version = tmos_version(self.client)
- if LooseVersion(version) < LooseVersion('12.0.0'):
- return True
- else:
- return False
-
-
-class BaseManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.have = None
- self.want = ModuleParameters(params=self.module.params)
- self.changes = UsableChanges()
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = UsableChanges(params=changed)
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def exec_module(self):
- changed = False
- result = dict()
- state = self.want.state
-
- if state in ["present", "disabled"]:
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- if self.version_is_less_than_12():
- self._deprecate_v11(warnings)
- for warning in warnings:
- self.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def version_is_less_than_12(self):
- version = tmos_version(self.client)
- if LooseVersion(version) < LooseVersion('12.0.0'):
- return True
- else:
- return False
-
- def _deprecate_v11(self, result):
- result.append(
- dict(
- msg='The support for this TMOS version is deprecated.',
- version='2.12'
- )
- )
-
- def present(self):
- if self.exists():
- return self.update()
- else:
- return self.create()
-
- def absent(self):
- if self.exists():
- return self.remove()
- return False
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def update(self):
- self.have = self.read_current_from_device()
- if not self.should_update():
- return False
- if self.module.check_mode:
- return True
- self.update_on_device()
- return True
-
- def create(self):
- if self.want.state == 'disabled':
- self.want.update({'disabled': True})
- elif self.want.state in ['present', 'enabled']:
- self.want.update({'enabled': True})
-
- self._set_changed_options()
-
- if self.want.availability_requirement_type == 'require' and len(self.want.monitors_list) > 1:
- raise F5ModuleError(
- "Only one monitor may be specified when using an availability_requirement type of 'require'"
- )
-
- if self.module.check_mode:
- return True
- self.create_on_device()
- if self.exists():
- return True
- else:
- raise F5ModuleError("Failed to create the GTM pool")
-
- def remove(self):
- if self.module.check_mode:
- return True
- self.remove_from_device()
- if self.exists():
- raise F5ModuleError("Failed to delete the GTM pool")
- return True
-
-
-class TypedManager(BaseManager):
- def __init__(self, *args, **kwargs):
- super(TypedManager, self).__init__(**kwargs)
- if self.want.type is None:
- raise F5ModuleError(
- "The 'type' option is required for BIG-IP instances "
- "greater than or equal to 12.x"
- )
-
- def present(self):
- types = [
- 'a', 'aaaa', 'cname', 'mx', 'naptr', 'srv'
- ]
- if self.want.type is None:
- raise F5ModuleError(
- "A pool 'type' must be specified"
- )
- elif self.want.type not in types:
- raise F5ModuleError(
- "The specified pool type is invalid"
- )
-
- return super(TypedManager, self).present()
-
- def exists(self):
- uri = "https://{0}:{1}/mgmt/tm/gtm/pool/{2}/{3}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- self.want.type,
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def update_on_device(self):
- params = self.changes.api_params()
- uri = "https://{0}:{1}/mgmt/tm/gtm/pool/{2}/{3}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- self.want.type,
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/gtm/pool/{2}/{3}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- self.want.type,
- transform_name(self.want.partition, self.want.name)
- )
-
- query = '?expandSubcollections=true'
- resp = self.client.api.get(uri + query)
-
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return ApiParameters(params=response)
-
- def create_on_device(self):
- params = self.changes.api_params()
- params['name'] = self.want.name
- params['partition'] = self.want.partition
- uri = "https://{0}:{1}/mgmt/tm/gtm/pool/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- self.want.type
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return response['selfLink']
-
- def remove_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/gtm/pool/{2}/{3}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- self.want.type,
- transform_name(self.want.partition, self.want.name)
- )
- response = self.client.api.delete(uri)
- if response.status == 200:
- return True
- raise F5ModuleError(response.content)
-
-
-class UntypedManager(BaseManager):
- def exists(self):
- uri = "https://{0}:{1}/mgmt/tm/gtm/pool/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def create_on_device(self):
- params = self.changes.api_params()
- params['name'] = self.want.name
- params['partition'] = self.want.partition
- uri = "https://{0}:{1}/mgmt/tm/gtm/pool/".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return response['selfLink']
-
- def update_on_device(self):
- params = self.changes.api_params()
- uri = "https://{0}:{1}/mgmt/tm/gtm/pool/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/gtm/pool/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return ApiParameters(params=response)
-
- def remove_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/gtm/pool/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- response = self.client.api.delete(uri)
- if response.status == 200:
- return True
- raise F5ModuleError(response.content)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.states = ['absent', 'present', 'enabled', 'disabled']
- self.preferred_lb_methods = [
- 'round-robin', 'return-to-dns', 'ratio', 'topology',
- 'static-persistence', 'global-availability',
- 'virtual-server-capacity', 'least-connections',
- 'lowest-round-trip-time', 'fewest-hops', 'packet-rate', 'cpu',
- 'completion-rate', 'quality-of-service', 'kilobytes-per-second',
- 'drop-packet', 'fallback-ip', 'virtual-server-score'
- ]
- self.alternate_lb_methods = [
- 'round-robin', 'return-to-dns', 'none', 'ratio', 'topology',
- 'static-persistence', 'global-availability',
- 'virtual-server-capacity', 'packet-rate', 'drop-packet',
- 'fallback-ip', 'virtual-server-score'
- ]
- self.fallback_lb_methods = copy.copy(self.preferred_lb_methods)
- self.fallback_lb_methods.append('none')
- self.types = [
- 'a', 'aaaa', 'cname', 'mx', 'naptr', 'srv'
- ]
- self.supports_check_mode = True
- argument_spec = dict(
- name=dict(required=True),
- state=dict(
- default='present',
- choices=self.states,
- ),
- preferred_lb_method=dict(
- choices=self.preferred_lb_methods,
- ),
- fallback_lb_method=dict(
- choices=self.fallback_lb_methods,
- ),
- alternate_lb_method=dict(
- choices=self.alternate_lb_methods,
- ),
- fallback_ip=dict(),
- type=dict(
- choices=self.types
- ),
- partition=dict(
- default='Common',
- fallback=(env_fallback, ['F5_PARTITION'])
- ),
- members=dict(
- type='list',
- options=dict(
- server=dict(required=True),
- virtual_server=dict(required=True)
- )
- ),
- availability_requirements=dict(
- type='dict',
- options=dict(
- type=dict(
- choices=['all', 'at_least', 'require'],
- required=True
- ),
- at_least=dict(type='int'),
- number_of_probes=dict(type='int'),
- number_of_probers=dict(type='int')
- ),
- mutually_exclusive=[
- ['at_least', 'number_of_probes'],
- ['at_least', 'number_of_probers'],
- ],
- required_if=[
- ['type', 'at_least', ['at_least']],
- ['type', 'require', ['number_of_probes', 'number_of_probers']]
- ]
- ),
- monitors=dict(type='list'),
- max_answers_returned=dict(type='int'),
- ttl=dict(type='int')
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
- self.required_if = [
- ['preferred_lb_method', 'fallback-ip', ['fallback_ip']],
- ['fallback_lb_method', 'fallback-ip', ['fallback_ip']],
- ['alternate_lb_method', 'fallback-ip', ['fallback_ip']]
- ]
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode,
- required_if=spec.required_if
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_gtm_pool_member.py b/lib/ansible/modules/network/f5/bigip_gtm_pool_member.py
deleted file mode 100644
index 9397e5ac10..0000000000
--- a/lib/ansible/modules/network/f5/bigip_gtm_pool_member.py
+++ /dev/null
@@ -1,1089 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_gtm_pool_member
-short_description: Manage GTM pool member settings
-description:
- - Manages a variety of settings on GTM pool members. The settings that can be
- adjusted with this module are much more broad that what can be done in the
- C(bigip_gtm_pool) module. The pool module is intended to allow you to adjust
- the member order in the pool, not the various settings of the members. The
- C(bigip_gtm_pool_member) module should be used to adjust all of the other
- settings.
-version_added: 2.6
-options:
- virtual_server:
- description:
- - Specifies the name of the GTM virtual server which is assigned to the specified
- C(server).
- type: str
- required: True
- server_name:
- description:
- - Specifies the GTM server which contains the C(virtual_server).
- type: str
- required: True
- type:
- description:
- - The type of GTM pool that the member is in.
- type: str
- choices:
- - a
- - aaaa
- - cname
- - mx
- - naptr
- - srv
- required: True
- pool:
- description:
- - Name of the GTM pool.
- - For pools created on different partitions, you must specify partition of the pool in the full path format,
- for example, C(/FooBar/pool_name).
- type: str
- required: True
- partition:
- description:
- - Device partition to manage resources on.
- type: str
- default: Common
- member_order:
- description:
- - Specifies the order in which the member will appear in the pool.
- - The system uses this number with load balancing methods that involve prioritizing
- pool members, such as the Ratio load balancing method.
- - When creating a new member using this module, if the C(member_order) parameter
- is not specified, it will default to C(0) (first member in the pool).
- type: int
- monitor:
- description:
- - Specifies the monitor assigned to this pool member.
- - Pool members only support a single monitor.
- - If the C(port) of the C(gtm_virtual_server) is C(*), the accepted values of this
- parameter will be affected.
- - When creating a new pool member, if this parameter is not specified, the default
- of C(default) will be used.
- - To remove the monitor from the pool member, use the value C(none).
- - For pool members created on different partitions, you can also specify the full
- path to the Common monitor. For example, C(/Common/tcp).
- type: str
- ratio:
- description:
- - Specifies the weight of the pool member for load balancing purposes.
- type: int
- description:
- description:
- - The description of the pool member.
- type: str
- aggregate:
- description:
- - List of GTM pool member definitions to be created, modified or removed.
- - When using C(aggregates) if one of the aggregate definitions is invalid, the aggregate run will fail,
- indicating the error it last encountered.
- - The module will C(NOT) rollback any changes it has made prior to encountering the error.
- - The module also will not indicate what changes were made prior to failure, therefore it is strongly advised
- to run the module in check mode to make basic validation, prior to module execution.
- type: list
- aliases:
- - members
- version_added: 2.8
- replace_all_with:
- description:
- - Remove members not defined in the C(aggregate) parameter.
- - This operation is all or none, meaning that it will stop if there are some pool members
- that cannot be removed.
- default: no
- type: bool
- aliases:
- - purge
- version_added: 2.8
- limits:
- description:
- - Specifies resource thresholds or limit requirements at the pool member level.
- - When you enable one or more limit settings, the system then uses that data to take
- members in and out of service.
- - You can define limits for any or all of the limit settings. However, when a
- member does not meet the resource threshold limit requirement, the system marks
- the member as unavailable and directs load-balancing traffic to another resource.
- suboptions:
- bits_enabled:
- description:
- - Whether the bits limit it enabled or not.
- - This parameter allows you to switch on or off the effect of the limit.
- type: bool
- packets_enabled:
- description:
- - Whether the packets limit it enabled or not.
- - This parameter allows you to switch on or off the effect of the limit.
- type: bool
- connections_enabled:
- description:
- - Whether the current connections limit it enabled or not.
- - This parameter allows you to switch on or off the effect of the limit.
- type: bool
- bits_limit:
- description:
- - Specifies the maximum allowable data throughput rate, in bits per second,
- for the member.
- - If the network traffic volume exceeds this limit, the system marks the
- member as unavailable.
- type: int
- packets_limit:
- description:
- - Specifies the maximum allowable data transfer rate, in packets per second,
- for the member.
- - If the network traffic volume exceeds this limit, the system marks the
- member as unavailable.
- type: int
- connections_limit:
- description:
- - Specifies the maximum number of concurrent connections, combined, for all of
- the member.
- - If the connections exceed this limit, the system marks the server as
- unavailable.
- type: int
- type: dict
- state:
- description:
- - Pool member state. When C(present), ensures that the pool member is
- created and enabled. When C(absent), ensures that the pool member is
- removed from the system. When C(enabled) or C(disabled), ensures
- that the pool member is enabled or disabled (respectively) on the remote
- device.
- - It is recommended that you use the C(members) parameter of the C(bigip_gtm_pool)
- module when adding and removing members and it provides an easier way of
- specifying order. If this is not possible, then the C(state) parameter here
- should be used.
- - Remember that the order of the members will be affected if you add or remove them
- using this method. To some extent, this can be controlled using the C(member_order)
- parameter.
- type: str
- choices:
- - present
- - absent
- - enabled
- - disabled
- default: present
-extends_documentation_fragment: f5
-author:
- - Tim Rupp (@caphrim007)
- - Wojciech Wypior (@wojtek0806)
-'''
-
-EXAMPLES = r'''
-- name: Create a GTM pool member
- bigip_gtm_pool_member:
- pool: pool1
- server_name: server1
- virtual_server: vs1
- type: a
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-
-- name: Create a GTM pool member different partition
- bigip_gtm_pool_member:
- server_name: /Common/foo_name
- virtual_server: GTMVSName
- type: a
- pool: /FooBar/foo-pool
- partition: Common
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-
-- name: Add GTM pool members aggregate
- bigip_gtm_pool_member:
- pool: pool1
- type: a
- aggregate:
- - server_name: server1
- virtual_server: vs1
- partition: Common
- description: web server1
- member_order: 0
- - server_name: server2
- virtual_server: vs2
- partition: Common
- description: web server2
- member_order: 1
- - server_name: server3
- virtual_server: vs3
- partition: Common
- description: web server3
- member_order: 2
- provider:
- server: lb.mydomain.com
- user: admin
- password: secret
- delegate_to: localhost
-
-- name: Add GTM pool members aggregate, remove non aggregates
- bigip_gtm_pool_member:
- pool: pool1
- type: a
- aggregate:
- - server_name: server1
- virtual_server: vs1
- partition: Common
- description: web server1
- member_order: 0
- - server_name: server2
- virtual_server: vs2
- partition: Common
- description: web server2
- member_order: 1
- - server_name: server3
- virtual_server: vs3
- partition: Common
- description: web server3
- member_order: 2
- replace_all_with: yes
- provider:
- server: lb.mydomain.com
- user: admin
- password: secret
- delegate_to: localhost
-'''
-
-RETURN = r'''
-bits_enabled:
- description: Whether the bits limit is enabled.
- returned: changed
- type: bool
- sample: yes
-bits_limit:
- description: The new bits_enabled limit.
- returned: changed
- type: int
- sample: 100
-connections_enabled:
- description: Whether the connections limit is enabled.
- returned: changed
- type: bool
- sample: yes
-connections_limit:
- description: The new connections_limit limit.
- returned: changed
- type: int
- sample: 100
-disabled:
- description: Whether the pool member is disabled or not.
- returned: changed
- type: bool
- sample: yes
-enabled:
- description: Whether the pool member is enabled or not.
- returned: changed
- type: bool
- sample: yes
-member_order:
- description: The new order in which the member appears in the pool.
- returned: changed
- type: int
- sample: 2
-monitor:
- description: The new monitor assigned to the pool member.
- returned: changed
- type: str
- sample: /Common/monitor1
-packets_enabled:
- description: Whether the packets limit is enabled.
- returned: changed
- type: bool
- sample: yes
-packets_limit:
- description: The new packets_limit limit.
- returned: changed
- type: int
- sample: 100
-ratio:
- description: The new weight of the member for load balancing.
- returned: changed
- type: int
- sample: 10
-description:
- description: The new description of the member.
- returned: changed
- type: str
- sample: My description
-replace_all_with:
- description: Purges all non-aggregate pool members from device
- returned: changed
- type: bool
- sample: yes
-'''
-
-from copy import deepcopy
-
-from ansible.module_utils.urls import urlparse
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.basic import env_fallback
-from ansible.module_utils.six import iteritems
-from ansible.module_utils.network.common.utils import remove_default_spec
-
-try:
- from library.module_utils.compat.ipaddress import ip_address
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import fq_name
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.common import transform_name
- from library.module_utils.network.f5.common import flatten_boolean
- from library.module_utils.network.f5.icontrol import module_provisioned
- from library.module_utils.network.f5.icontrol import TransactionContextManager
-except ImportError:
- from ansible.module_utils.compat.ipaddress import ip_address
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import fq_name
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.common import transform_name
- from ansible.module_utils.network.f5.common import flatten_boolean
- from ansible.module_utils.network.f5.icontrol import module_provisioned
- from ansible.module_utils.network.f5.icontrol import TransactionContextManager
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'limitMaxBps': 'bits_limit',
- 'limitMaxBpsStatus': 'bits_enabled',
- 'limitMaxConnections': 'connections_limit',
- 'limitMaxConnectionsStatus': 'connections_enabled',
- 'limitMaxPps': 'packets_limit',
- 'limitMaxPpsStatus': 'packets_enabled',
- 'memberOrder': 'member_order',
- }
-
- api_attributes = [
- 'disabled',
- 'enabled',
- 'limitMaxBps',
- 'limitMaxBpsStatus',
- 'limitMaxConnections',
- 'limitMaxConnectionsStatus',
- 'limitMaxPps',
- 'limitMaxPpsStatus',
- 'memberOrder',
- 'monitor',
- 'ratio',
- 'description',
- ]
-
- returnables = [
- 'bits_enabled',
- 'bits_limit',
- 'connections_enabled',
- 'connections_limit',
- 'disabled',
- 'enabled',
- 'member_order',
- 'monitor',
- 'packets_enabled',
- 'packets_limit',
- 'ratio',
- 'description',
- ]
-
- updatables = [
- 'bits_enabled',
- 'bits_limit',
- 'connections_enabled',
- 'connections_limit',
- 'enabled',
- 'member_order',
- 'monitor',
- 'packets_limit',
- 'packets_enabled',
- 'ratio',
- 'description',
- ]
-
- @property
- def ratio(self):
- if self._values['ratio'] is None:
- return None
- return int(self._values['ratio'])
-
-
-class ApiParameters(Parameters):
- def name(self):
- # We need to do this because BIGIP allows / in names of GTM VS, allowing and users create such names incorrectly
- # Despite the fact that GTM server and GTM Virtual Server cannot be created outside the Common partition
- if self._values['subPath'] is None:
- return self._values['name']
- result = self._values['subPath'] + self._values['name']
- return result
-
- @property
- def enabled(self):
- if 'enabled' in self._values:
- return True
- else:
- return False
-
- @property
- def disabled(self):
- if 'disabled' in self._values:
- return True
- return False
-
- @property
- def monitor(self):
- if self._values['monitor'] is None:
- return None
- # The value of this parameter in the API includes an extra space
- return self._values['monitor'].strip()
-
-
-class ModuleParameters(Parameters):
- def _get_limit_value(self, type):
- if self._values['limits'] is None:
- return None
- if self._values['limits'][type] is None:
- return None
- return int(self._values['limits'][type])
-
- def _get_limit_status(self, type):
- if self._values['limits'] is None:
- return None
- if self._values['limits'][type] is None:
- return None
- if self._values['limits'][type]:
- return 'enabled'
- return 'disabled'
-
- @property
- def name(self):
- result = '{0}:{1}'.format(self.server_name, self.virtual_server)
- return result
-
- @property
- def type(self):
- if self._values['type'] is None:
- return None
- return str(self._values['type'])
-
- @property
- def enabled(self):
- if self._values['state'] == 'enabled':
- return True
- elif self._values['state'] == 'disabled':
- return False
- else:
- return None
-
- @property
- def disabled(self):
- if self._values['state'] == 'enabled':
- return False
- elif self._values['state'] == 'disabled':
- return True
- else:
- return None
-
- @property
- def bits_limit(self):
- return self._get_limit_value('bits_limit')
-
- @property
- def packets_limit(self):
- return self._get_limit_value('packets_limit')
-
- @property
- def connections_limit(self):
- return self._get_limit_value('connections_limit')
-
- @property
- def bits_enabled(self):
- return self._get_limit_status('bits_enabled')
-
- @property
- def packets_enabled(self):
- return self._get_limit_status('packets_enabled')
-
- @property
- def connections_enabled(self):
- return self._get_limit_status('connections_enabled')
-
- @property
- def monitor(self):
- if self._values['monitor'] is None:
- return None
- elif self._values['monitor'] in ['default', '']:
- return 'default'
- return fq_name(self.partition, self._values['monitor'])
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class UsableChanges(Changes):
- pass
-
-
-class ReportableChanges(Changes):
- @property
- def disabled(self):
- return flatten_boolean(self._values['disabled'])
-
- @property
- def enabled(self):
- return flatten_boolean(self._values['enabled'])
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
- @property
- def description(self):
- if self.want.description == '' and self.have.description is None:
- return None
- if self.want.description != self.have.description:
- return self.want.description
-
- @property
- def enabled(self):
- if self.want.state == 'enabled' and self.have.disabled:
- result = dict(
- enabled=True,
- disabled=False
- )
- return result
- elif self.want.state == 'disabled' and self.have.enabled:
- result = dict(
- enabled=False,
- disabled=True
- )
- return result
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = None
- self.have = None
- self.changes = None
- self.replace_all_with = None
- self.purge_links = list()
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = UsableChanges(params=changed)
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def exec_module(self):
- if not module_provisioned(self.client, 'gtm'):
- raise F5ModuleError(
- "GTM must be provisioned to use this module."
- )
- wants = None
- if self.module.params['replace_all_with']:
- self.replace_all_with = True
-
- if self.module.params['aggregate']:
- wants = self.merge_defaults_for_aggregate(self.module.params)
-
- result = dict()
- changed = False
-
- if self.replace_all_with and self.purge_links:
- self.purge()
- changed = True
-
- if self.module.params['aggregate']:
- result['aggregate'] = list()
- for want in wants:
- output = self.execute(want)
- if output['changed']:
- changed = output['changed']
- result['aggregate'].append(output)
- else:
- output = self.execute(self.module.params)
- if output['changed']:
- changed = output['changed']
- result.update(output)
- if changed:
- result['changed'] = True
- return result
-
- def merge_defaults_for_aggregate(self, params):
- defaults = deepcopy(params)
- aggregate = defaults.pop('aggregate')
-
- for i, j in enumerate(aggregate):
- for k, v in iteritems(defaults):
- if k != 'replace_all_with':
- if j.get(k, None) is None and v is not None:
- aggregate[i][k] = v
-
- if self.replace_all_with:
- self.compare_aggregate_names(aggregate)
-
- return aggregate
-
- def _combine_names(self, item):
- server_name = transform_name(item['partition'], item['server_name'])
- virtual_server = transform_name(name=item['virtual_server'])
- result = '{0}:{1}'.format(server_name, virtual_server)
- return result
-
- def _transform_api_names(self, item):
- if 'subPath' in item and item['subPath'] is None:
- return item['name']
- result = transform_name(item['fullPath'])
- return result
-
- def compare_aggregate_names(self, items):
- on_device = self._read_purge_collection()
-
- if not on_device:
- return False
-
- aggregates = [self._combine_names(item) for item in items]
- collection = [self._transform_api_names(item) for item in on_device]
-
- diff = set(collection) - set(aggregates)
-
- if diff:
- to_purge = [item['selfLink'] for item in on_device if self._transform_api_names(item) in diff]
- self.purge_links.extend(to_purge)
-
- def execute(self, params=None):
- self.want = ModuleParameters(params=params)
- self.have = ApiParameters()
- self.changes = UsableChanges()
-
- changed = False
- result = dict()
- state = params['state']
-
- if state in ['present', 'enabled', 'disabled']:
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.client.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def present(self):
- if self.exists():
- return self.update()
- else:
- return self.create()
-
- def absent(self):
- if self.exists():
- return self.remove()
- return False
-
- def purge(self):
- if self.module.check_mode:
- return True
- self.purge_from_device()
- return True
-
- def update(self):
- self.have = self.read_current_from_device()
- if not self.should_update():
- return False
- if self.module.check_mode:
- return True
- self.update_on_device()
- return True
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def remove(self):
- if self.module.check_mode:
- return True
- self.remove_from_device()
- if self.exists():
- raise F5ModuleError("Failed to delete the resource.")
- return True
-
- def create(self):
- if self.want.state == 'disabled':
- self.want.update({'disabled': True})
- elif self.want.state in ['present', 'enabled']:
- self.want.update({'enabled': True})
- self._set_changed_options()
- if self.module.check_mode:
- return True
- self.create_on_device()
- return True
-
- def exists(self):
- if not self.pool_exist():
- raise F5ModuleError('The specified GTM pool does not exist')
-
- uri = "https://{0}:{1}/mgmt/tm/gtm/pool/{2}/{3}/members/{4}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- self.want.type,
- transform_name(name=fq_name(self.want.partition, self.want.pool)),
- transform_name(self.want.partition, self.want.name),
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def pool_exist(self):
- if self.replace_all_with:
- type = self.module.params['type']
- pool_name = transform_name(name=fq_name(self.module.params['partition'], self.module.params['pool']))
- else:
- pool_name = transform_name(name=fq_name(self.want.partition, self.want.pool))
- type = self.want.type
-
- uri = "https://{0}:{1}/mgmt/tm/gtm/pool/{2}/{3}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- type,
- pool_name
-
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def _read_purge_collection(self):
- type = self.module.params['type']
- pool_name = transform_name(name=fq_name(self.module.params['partition'], self.module.params['pool']))
-
- uri = "https://{0}:{1}/mgmt/tm/gtm/pool/{2}/{3}/members".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- type,
- pool_name
- )
-
- query = '?$select=name,selfLink,fullPath,subPath'
- resp = self.client.api.get(uri + query)
-
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- if 'items' in response:
- return response['items']
- return []
-
- def create_on_device(self):
- params = self.changes.api_params()
- params['name'] = self.want.name
- params['partition'] = self.want.partition
- uri = "https://{0}:{1}/mgmt/tm/gtm/pool/{2}/{3}/members/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- self.want.type,
- transform_name(name=fq_name(self.want.partition, self.want.pool)),
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return response['selfLink']
-
- def update_on_device(self):
- params = self.changes.api_params()
- uri = "https://{0}:{1}/mgmt/tm/gtm/pool/{2}/{3}/members/{4}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- self.want.type,
- transform_name(name=fq_name(self.want.partition, self.want.pool)),
- transform_name(self.want.partition, self.want.name),
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def remove_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/gtm/pool/{2}/{3}/members/{4}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- self.want.type,
- transform_name(name=fq_name(self.want.partition, self.want.pool)),
- transform_name(self.want.partition, self.want.name),
- )
- response = self.client.api.delete(uri)
- if response.status == 200:
- return True
- raise F5ModuleError(response.content)
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/gtm/pool/{2}/{3}/members/{4}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- self.want.type,
- transform_name(name=fq_name(self.want.partition, self.want.pool)),
- transform_name(self.want.partition, self.want.name),
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return ApiParameters(params=response)
-
- def _prepare_links(self, collection):
- # this is to ensure no duplicates are in the provided collection
- no_dupes = list(set(collection))
- links = list()
- purge_paths = [urlparse(link).path for link in no_dupes]
-
- for path in purge_paths:
- link = "https://{0}:{1}{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- path
- )
- links.append(link)
- return links
-
- def purge_from_device(self):
- links = self._prepare_links(self.purge_links)
-
- with TransactionContextManager(self.client) as transact:
- for link in links:
- resp = transact.api.delete(link)
-
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return True
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- self.types = [
- 'a', 'aaaa', 'cname', 'mx', 'naptr', 'srv'
- ]
- element_spec = dict(
- server_name=dict(),
- virtual_server=dict(),
- member_order=dict(type='int'),
- monitor=dict(),
- ratio=dict(type='int'),
- description=dict(),
- limits=dict(
- type='dict',
- options=dict(
- bits_enabled=dict(type='bool'),
- packets_enabled=dict(type='bool'),
- connections_enabled=dict(type='bool'),
- bits_limit=dict(type='int'),
- packets_limit=dict(type='int'),
- connections_limit=dict(type='int')
- )
- ),
- state=dict(
- default='present',
- choices=['present', 'absent', 'disabled', 'enabled']
- ),
- partition=dict(
- default='Common',
- fallback=(env_fallback, ['F5_PARTITION'])
- ),
-
- )
-
- aggregate_spec = deepcopy(element_spec)
-
- # remove default in aggregate spec, to handle common arguments
- remove_default_spec(aggregate_spec)
-
- self.argument_spec = dict(
- aggregate=dict(
- type='list',
- elements='dict',
- options=aggregate_spec,
- aliases=['members'],
- required_one_of=[
- ['server_name', 'virtual_server']
- ],
- required_together=[
- ['server_name', 'virtual_server']
- ]
-
- ),
- pool=dict(required=True),
- type=dict(
- choices=self.types,
- required=True
- ),
- replace_all_with=dict(
- type='bool',
- aliases=['purge'],
- default='no'
- ),
- partition=dict(
- default='Common',
- fallback=(env_fallback, ['F5_PARTITION'])
- )
-
- )
- self.argument_spec.update(element_spec)
- self.argument_spec.update(f5_argument_spec)
- self.required_together = [
- ['server_name', 'virtual_server']
- ]
- self.mutually_exclusive = [
- ['server_name', 'aggregate'],
- ['virtual_server', 'aggregate']
- ]
- self.required_one_of = [
- ['server_name', 'virtual_server', 'aggregate']
- ]
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode,
- mutually_exclusive=spec.mutually_exclusive,
- required_one_of=spec.required_one_of,
- required_together=spec.required_together,
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_gtm_server.py b/lib/ansible/modules/network/f5/bigip_gtm_server.py
deleted file mode 100644
index 6b6199870f..0000000000
--- a/lib/ansible/modules/network/f5/bigip_gtm_server.py
+++ /dev/null
@@ -1,1793 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['stableinterface'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_gtm_server
-short_description: Manages F5 BIG-IP GTM servers
-description:
- - Manage BIG-IP server configuration. This module is able to manipulate the server
- definitions in a BIG-IP.
-version_added: 2.5
-options:
- name:
- description:
- - The name of the server.
- type: str
- required: True
- state:
- description:
- - The server state. If C(absent), an attempt to delete the server will be made.
- This will only succeed if this server is not in use by a virtual server.
- C(present) creates the server and enables it. If C(enabled), enable the server
- if it exists. If C(disabled), create the server if needed, and set state to
- C(disabled).
- type: str
- choices:
- - present
- - absent
- - enabled
- - disabled
- default: present
- datacenter:
- description:
- - Data center the server belongs to. When creating a new GTM server, this value
- is required.
- type: str
- devices:
- description:
- - Lists the self IP addresses and translations for each device. When creating a
- new GTM server, this value is required. This list is a complex list that
- specifies a number of keys.
- - The C(name) key specifies a name for the device. The device name must
- be unique per server. This key is required.
- - The C(address) key contains an IP address, or list of IP addresses, for the
- destination server. This key is required.
- - The C(translation) key contains an IP address to translate the C(address)
- value above to. This key is optional.
- - Specifying duplicate C(name) fields is a supported means of providing device
- addresses. In this scenario, the addresses will be assigned to the C(name)'s list
- of addresses.
- type: list
- server_type:
- description:
- - Specifies the server type. The server type determines the metrics that the
- system can collect from the server. When creating a new GTM server, the default
- value C(bigip) is used.
- type: str
- choices:
- - alteon-ace-director
- - cisco-css
- - cisco-server-load-balancer
- - generic-host
- - radware-wsd
- - windows-nt-4.0
- - bigip
- - cisco-local-director-v2
- - extreme
- - generic-load-balancer
- - sun-solaris
- - cacheflow
- - cisco-local-director-v3
- - foundry-server-iron
- - netapp
- - windows-2000-server
- aliases:
- - product
- link_discovery:
- description:
- - Specifies whether the system auto-discovers the links for this server. When
- creating a new GTM server, if this parameter is not specified, the default
- value C(disabled) is used.
- - If you set this parameter to C(enabled) or C(enabled-no-delete), you must
- also ensure that the C(virtual_server_discovery) parameter is also set to
- C(enabled) or C(enabled-no-delete).
- type: str
- choices:
- - enabled
- - disabled
- - enabled-no-delete
- virtual_server_discovery:
- description:
- - Specifies whether the system auto-discovers the virtual servers for this server.
- When creating a new GTM server, if this parameter is not specified, the default
- value C(disabled) is used.
- type: str
- choices:
- - enabled
- - disabled
- - enabled-no-delete
- partition:
- description:
- - Device partition to manage resources on.
- type: str
- default: Common
- version_added: 2.5
- iquery_options:
- description:
- - Specifies whether the Global Traffic Manager uses this BIG-IP
- system to conduct a variety of probes before delegating traffic to it.
- suboptions:
- allow_path:
- description:
- - Specifies that the system verifies the logical network route between a data
- center server and a local DNS server.
- type: bool
- allow_service_check:
- description:
- - Specifies that the system verifies that an application on a server is running,
- by remotely running the application using an external service checker program.
- type: bool
- allow_snmp:
- description:
- - Specifies that the system checks the performance of a server running an SNMP
- agent.
- type: bool
- type: dict
- version_added: 2.7
- monitors:
- description:
- - Specifies the health monitors that the system currently uses to monitor this resource.
- - When C(availability_requirements.type) is C(require), you may only have a single monitor in the
- C(monitors) list.
- type: list
- version_added: 2.8
- availability_requirements:
- description:
- - Specifies, if you activate more than one health monitor, the number of health
- monitors that must receive successful responses in order for the link to be
- considered available.
- suboptions:
- type:
- description:
- - Monitor rule type when C(monitors) is specified.
- - When creating a new pool, if this value is not specified, the default of 'all' will be used.
- type: str
- choices:
- - all
- - at_least
- - require
- at_least:
- description:
- - Specifies the minimum number of active health monitors that must be successful
- before the link is considered up.
- - This parameter is only relevant when a C(type) of C(at_least) is used.
- - This parameter will be ignored if a type of either C(all) or C(require) is used.
- type: int
- number_of_probes:
- description:
- - Specifies the minimum number of probes that must succeed for this server to be declared up.
- - When creating a new virtual server, if this parameter is specified, then the C(number_of_probers)
- parameter must also be specified.
- - The value of this parameter should always be B(lower) than, or B(equal to), the value of C(number_of_probers).
- - This parameter is only relevant when a C(type) of C(require) is used.
- - This parameter will be ignored if a type of either C(all) or C(at_least) is used.
- type: int
- number_of_probers:
- description:
- - Specifies the number of probers that should be used when running probes.
- - When creating a new virtual server, if this parameter is specified, then the C(number_of_probes)
- parameter must also be specified.
- - The value of this parameter should always be B(higher) than, or B(equal to), the value of C(number_of_probers).
- - This parameter is only relevant when a C(type) of C(require) is used.
- - This parameter will be ignored if a type of either C(all) or C(at_least) is used.
- type: int
- type: dict
- version_added: 2.8
- prober_preference:
- description:
- - Specifies the type of prober to use to monitor this server's resources.
- - This option is ignored in C(TMOS) version C(12.x).
- - From C(TMOS) version C(13.x) and up, when prober_preference is set to C(pool)
- a C(prober_pool) parameter must be specified.
- type: str
- choices:
- - inside-datacenter
- - outside-datacenter
- - inherit
- - pool
- version_added: 2.8
- prober_fallback:
- description:
- - Specifies the type of prober to use to monitor this server's resources
- when the preferred prober is not available.
- - This option is ignored in C(TMOS) version C(12.x).
- - From C(TMOS) version C(13.x) and up, when prober_preference is set to C(pool)
- a C(prober_pool) parameter must be specified.
- - The choices are mutually exclusive with prober_preference parameter,
- with the exception of C(any-available) or C(none) option.
- type: str
- choices:
- - any
- - inside-datacenter
- - outside-datacenter
- - inherit
- - pool
- - none
- version_added: 2.8
- prober_pool:
- description:
- - Specifies the name of the prober pool to use to monitor this server's resources.
- - From C(TMOS) version C(13.x) and up, this parameter is mandatory when C(prober_preference) is set to C(pool).
- - Format of the name can be either be prepended by partition (C(/Common/foo)), or specified
- just as an object name (C(foo)).
- - In C(TMOS) version C(12.x) prober_pool can be set to empty string to revert to default setting of inherit.
- type: str
- version_added: 2.8
- limits:
- description:
- - Specifies resource thresholds or limit requirements at the pool member level.
- - When you enable one or more limit settings, the system then uses that data to take
- members in and out of service.
- - You can define limits for any or all of the limit settings. However, when a
- member does not meet the resource threshold limit requirement, the system marks
- the member as unavailable and directs load-balancing traffic to another resource.
- suboptions:
- bits_enabled:
- description:
- - Whether the bits limit it enabled or not.
- - This parameter allows you to switch on or off the effect of the limit.
- type: bool
- packets_enabled:
- description:
- - Whether the packets limit it enabled or not.
- - This parameter allows you to switch on or off the effect of the limit.
- type: bool
- connections_enabled:
- description:
- - Whether the current connections limit it enabled or not.
- - This parameter allows you to switch on or off the effect of the limit.
- type: bool
- cpu_enabled:
- description:
- - Whether the CPU limit it enabled or not.
- - This parameter allows you to switch on or off the effect of the limit.
- type: bool
- memory_enabled:
- description:
- - Whether the memory limit it enabled or not.
- - This parameter allows you to switch on or off the effect of the limit.
- type: bool
- bits_limit:
- description:
- - Specifies the maximum allowable data throughput rate, in bits per second,
- for the member.
- - If the network traffic volume exceeds this limit, the system marks the
- member as unavailable.
- type: int
- packets_limit:
- description:
- - Specifies the maximum allowable data transfer rate, in packets per second,
- for the member.
- - If the network traffic volume exceeds this limit, the system marks the
- member as unavailable.
- type: int
- connections_limit:
- description:
- - Specifies the maximum number of concurrent connections, combined, for all of
- the member.
- - If the connections exceed this limit, the system marks the server as
- unavailable.
- type: int
- cpu_limit:
- description:
- - Specifies the percent of CPU usage.
- - If percent of CPU usage goes above the limit, the system marks the server as unavailable.
- type: int
- memory_limit:
- description:
- - Specifies the available memory required by the virtual servers on the server.
- - If available memory falls below this limit, the system marks the server as unavailable.
- type: int
- type: dict
- version_added: 2.8
-extends_documentation_fragment: f5
-author:
- - Robert Teller (@r-teller)
- - Tim Rupp (@caphrim007)
- - Wojciech Wypior (@wojtek0806)
-'''
-
-EXAMPLES = r'''
-- name: Create server "GTM_Server"
- bigip_gtm_server:
- name: GTM_Server
- datacenter: /Common/New York
- server_type: bigip
- link_discovery: disabled
- virtual_server_discovery: disabled
- devices:
- - name: server_1
- address: 1.1.1.1
- - name: server_2
- address: 2.2.2.1
- translation: 192.168.2.1
- - name: server_2
- address: 2.2.2.2
- - name: server_3
- addresses:
- - address: 3.3.3.1
- - address: 3.3.3.2
- - name: server_4
- addresses:
- - address: 4.4.4.1
- translation: 192.168.14.1
- - address: 4.4.4.2
- provider:
- user: admin
- password: secret
- server: lb.mydomain.com
- delegate_to: localhost
-
-- name: Create server "GTM_Server" with expanded keys
- bigip_gtm_server:
- server: lb.mydomain.com
- user: admin
- password: secret
- name: GTM_Server
- datacenter: /Common/New York
- server_type: bigip
- link_discovery: disabled
- virtual_server_discovery: disabled
- devices:
- - name: server_1
- address: 1.1.1.1
- - name: server_2
- address: 2.2.2.1
- translation: 192.168.2.1
- - name: server_2
- address: 2.2.2.2
- - name: server_3
- addresses:
- - address: 3.3.3.1
- - address: 3.3.3.2
- - name: server_4
- addresses:
- - address: 4.4.4.1
- translation: 192.168.14.1
- - address: 4.4.4.2
- provider:
- user: admin
- password: secret
- server: lb.mydomain.com
- delegate_to: localhost
-'''
-
-RETURN = r'''
-bits_enabled:
- description: Whether the bits limit is enabled.
- returned: changed
- type: bool
- sample: yes
-bits_limit:
- description: The new bits_enabled limit.
- returned: changed
- type: int
- sample: 100
-connections_enabled:
- description: Whether the connections limit is enabled.
- returned: changed
- type: bool
- sample: yes
-connections_limit:
- description: The new connections_limit limit.
- returned: changed
- type: int
- sample: 100
-monitors:
- description: The new list of monitors for the resource.
- returned: changed
- type: list
- sample: ['/Common/monitor1', '/Common/monitor2']
-link_discovery:
- description: The new C(link_discovery) configured on the remote device.
- returned: changed
- type: str
- sample: enabled
-virtual_server_discovery:
- description: The new C(virtual_server_discovery) name for the trap destination.
- returned: changed
- type: str
- sample: disabled
-server_type:
- description: The new type of the server.
- returned: changed
- type: str
- sample: bigip
-datacenter:
- description: The new C(datacenter) which the server is part of.
- returned: changed
- type: str
- sample: datacenter01
-packets_enabled:
- description: Whether the packets limit is enabled.
- returned: changed
- type: bool
- sample: yes
-packets_limit:
- description: The new packets_limit limit.
- returned: changed
- type: int
- sample: 100
-'''
-
-import re
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.basic import env_fallback
-from distutils.version import LooseVersion
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import fq_name
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.common import transform_name
- from library.module_utils.network.f5.common import is_empty_list
- from library.module_utils.network.f5.icontrol import tmos_version
- from library.module_utils.network.f5.icontrol import module_provisioned
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import fq_name
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.common import transform_name
- from ansible.module_utils.network.f5.common import is_empty_list
- from ansible.module_utils.network.f5.icontrol import tmos_version
- from ansible.module_utils.network.f5.icontrol import module_provisioned
-
-try:
- from collections import OrderedDict
-except ImportError:
- try:
- from ordereddict import OrderedDict
- except ImportError:
- pass
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'product': 'server_type',
- 'virtualServerDiscovery': 'virtual_server_discovery',
- 'linkDiscovery': 'link_discovery',
- 'addresses': 'devices',
- 'iqAllowPath': 'iquery_allow_path',
- 'iqAllowServiceCheck': 'iquery_allow_service_check',
- 'iqAllowSnmp': 'iquery_allow_snmp',
- 'monitor': 'monitors',
- 'proberPreference': 'prober_preference',
- 'proberPool': 'prober_pool',
- 'proberFallback': 'prober_fallback',
- 'limitMaxBps': 'bits_limit',
- 'limitMaxBpsStatus': 'bits_enabled',
- 'limitMaxConnections': 'connections_limit',
- 'limitMaxConnectionsStatus': 'connections_enabled',
- 'limitMaxPps': 'packets_limit',
- 'limitMaxPpsStatus': 'packets_enabled',
- 'limitCpuUsage': 'cpu_limit',
- 'limitCpuUsageStatus': 'cpu_enabled',
- 'limitMemAvail': 'memory_limit',
- 'limitMemAvailStatus': 'memory_enabled',
- }
-
- api_attributes = [
- 'linkDiscovery',
- 'virtualServerDiscovery',
- 'product',
- 'addresses',
- 'datacenter',
- 'enabled',
- 'disabled',
- 'iqAllowPath',
- 'iqAllowServiceCheck',
- 'iqAllowSnmp',
- 'monitor',
- 'proberPreference',
- 'proberPool',
- 'proberFallback',
- 'limitMaxBps',
- 'limitMaxBpsStatus',
- 'limitMaxConnections',
- 'limitMaxConnectionsStatus',
- 'limitMaxPps',
- 'limitMaxPpsStatus',
- 'limitCpuUsage',
- 'limitCpuUsageStatus',
- 'limitMemAvail',
- 'limitMemAvailStatus',
- ]
-
- updatables = [
- 'link_discovery',
- 'virtual_server_discovery',
- 'server_type_and_devices',
- 'datacenter',
- 'state',
- 'iquery_allow_path',
- 'iquery_allow_service_check',
- 'iquery_allow_snmp',
- 'monitors',
- 'prober_preference',
- 'prober_pool',
- 'prober_fallback',
- 'bits_enabled',
- 'bits_limit',
- 'connections_enabled',
- 'connections_limit',
- 'packets_enabled',
- 'packets_limit',
- 'cpu_enabled',
- 'cpu_limit',
- 'memory_enabled',
- 'memory_limit',
- ]
-
- returnables = [
- 'link_discovery',
- 'virtual_server_discovery',
- 'server_type',
- 'datacenter',
- 'enabled',
- 'iquery_allow_path',
- 'iquery_allow_service_check',
- 'iquery_allow_snmp',
- 'devices',
- 'monitors',
- 'availability_requirements',
- 'prober_preference',
- 'prober_pool',
- 'prober_fallback',
- 'bits_enabled',
- 'bits_limit',
- 'connections_enabled',
- 'connections_limit',
- 'packets_enabled',
- 'packets_limit',
- 'cpu_enabled',
- 'cpu_limit',
- 'memory_enabled',
- 'memory_limit',
- ]
-
-
-class ApiParameters(Parameters):
- @property
- def devices(self):
- if self._values['devices'] is None:
- return None
- return self._values['devices']
-
- @property
- def server_type(self):
- if self._values['server_type'] is None:
- return None
- elif self._values['server_type'] in ['single-bigip', 'redundant-bigip']:
- return 'bigip'
- else:
- return self._values['server_type']
-
- @property
- def raw_server_type(self):
- if self._values['server_type'] is None:
- return None
- return self._values['server_type']
-
- @property
- def enabled(self):
- if self._values['enabled'] is None:
- return None
- return True
-
- @property
- def disabled(self):
- if self._values['disabled'] is None:
- return None
- return True
-
- @property
- def iquery_allow_path(self):
- if self._values['iquery_allow_path'] is None:
- return None
- elif self._values['iquery_allow_path'] == 'yes':
- return True
- return False
-
- @property
- def iquery_allow_service_check(self):
- if self._values['iquery_allow_service_check'] is None:
- return None
- elif self._values['iquery_allow_service_check'] == 'yes':
- return True
- return False
-
- @property
- def iquery_allow_snmp(self):
- if self._values['iquery_allow_snmp'] is None:
- return None
- elif self._values['iquery_allow_snmp'] == 'yes':
- return True
- return False
-
- @property
- def availability_requirement_type(self):
- if self._values['monitors'] is None:
- return None
- if 'min ' in self._values['monitors']:
- return 'at_least'
- elif 'require ' in self._values['monitors']:
- return 'require'
- else:
- return 'all'
-
- @property
- def monitors_list(self):
- if self._values['monitors'] is None:
- return []
- try:
- result = re.findall(r'/\w+/[^\s}]+', self._values['monitors'])
- result.sort()
- return result
- except Exception:
- return self._values['monitors']
-
- @property
- def monitors(self):
- if self._values['monitors'] is None:
- return None
- if self._values['monitors'] == '/Common/bigip':
- return '/Common/bigip'
- monitors = [fq_name(self.partition, x) for x in self.monitors_list]
- if self.availability_requirement_type == 'at_least':
- monitors = ' '.join(monitors)
- result = 'min {0} of {{ {1} }}'.format(self.at_least, monitors)
- elif self.availability_requirement_type == 'require':
- monitors = ' '.join(monitors)
- result = 'require {0} from {1} {{ {2} }}'.format(self.number_of_probes, self.number_of_probers, monitors)
- else:
- result = ' and '.join(monitors).strip()
- return result
-
- @property
- def number_of_probes(self):
- """Returns the probes value from the monitor string.
-
- The monitor string for a Require monitor looks like this.
-
- require 1 from 2 { /Common/tcp }
-
- This method parses out the first of the numeric values. This values represents
- the "probes" value that can be updated in the module.
-
- Returns:
- int: The probes value if found. None otherwise.
- """
- if self._values['monitors'] is None:
- return None
- pattern = r'require\s+(?P<probes>\d+)\s+from'
- matches = re.search(pattern, self._values['monitors'])
- if matches is None:
- return None
- return matches.group('probes')
-
- @property
- def number_of_probers(self):
- """Returns the probers value from the monitor string.
-
- The monitor string for a Require monitor looks like this.
-
- require 1 from 2 { /Common/tcp }
-
- This method parses out the first of the numeric values. This values represents
- the "probers" value that can be updated in the module.
-
- Returns:
- int: The probers value if found. None otherwise.
- """
- if self._values['monitors'] is None:
- return None
- pattern = r'require\s+\d+\s+from\s+(?P<probers>\d+)\s+'
- matches = re.search(pattern, self._values['monitors'])
- if matches is None:
- return None
- return matches.group('probers')
-
- @property
- def at_least(self):
- """Returns the 'at least' value from the monitor string.
-
- The monitor string for a Require monitor looks like this.
-
- min 1 of { /Common/gateway_icmp }
-
- This method parses out the first of the numeric values. This values represents
- the "at_least" value that can be updated in the module.
-
- Returns:
- int: The at_least value if found. None otherwise.
- """
- if self._values['monitors'] is None:
- return None
- pattern = r'min\s+(?P<least>\d+)\s+of\s+'
- matches = re.search(pattern, self._values['monitors'])
- if matches is None:
- return None
- return matches.group('least')
-
-
-class ModuleParameters(Parameters):
- def _get_limit_value(self, type):
- if self._values['limits'] is None:
- return None
- if self._values['limits'][type] is None:
- return None
- return int(self._values['limits'][type])
-
- def _get_limit_status(self, type):
- if self._values['limits'] is None:
- return None
- if self._values['limits'][type] is None:
- return None
- if self._values['limits'][type]:
- return 'enabled'
- return 'disabled'
-
- @property
- def devices(self):
- if self._values['devices'] is None:
- return None
- result = []
-
- for device in self._values['devices']:
- if not any(x for x in ['address', 'addresses'] if x in device):
- raise F5ModuleError(
- "The specified device list must contain an 'address' or 'addresses' key"
- )
-
- if 'address' in device:
- translation = self._determine_translation(device)
- name = device['address']
- device_name = device['name']
- result.append({
- 'name': name,
- 'deviceName': device_name,
- 'translation': translation
- })
- elif 'addresses' in device:
- for address in device['addresses']:
- translation = self._determine_translation(address)
- name = address['address']
- device_name = device['name']
- result.append({
- 'name': name,
- 'deviceName': device_name,
- 'translation': translation
- })
- return result
-
- @property
- def enabled(self):
- if self._values['state'] in ['present', 'enabled']:
- return True
- return False
-
- @property
- def datacenter(self):
- if self._values['datacenter'] is None:
- return None
- return fq_name(self.partition, self._values['datacenter'])
-
- def _determine_translation(self, device):
- if 'translation' not in device:
- return 'none'
- return device['translation']
-
- @property
- def state(self):
- if self._values['state'] == 'enabled':
- return 'present'
- return self._values['state']
-
- @property
- def iquery_allow_path(self):
- if self._values['iquery_options'] is None:
- return None
- elif self._values['iquery_options']['allow_path'] is None:
- return None
- return self._values['iquery_options']['allow_path']
-
- @property
- def iquery_allow_service_check(self):
- if self._values['iquery_options'] is None:
- return None
- elif self._values['iquery_options']['allow_service_check'] is None:
- return None
- return self._values['iquery_options']['allow_service_check']
-
- @property
- def iquery_allow_snmp(self):
- if self._values['iquery_options'] is None:
- return None
- elif self._values['iquery_options']['allow_snmp'] is None:
- return None
- return self._values['iquery_options']['allow_snmp']
-
- @property
- def monitors_list(self):
- if self._values['monitors'] is None:
- return []
- try:
- result = re.findall(r'/\w+/[^\s}]+', self._values['monitors'])
- result.sort()
- return result
- except Exception:
- return self._values['monitors']
-
- @property
- def monitors(self):
- if self._values['monitors'] is None:
- return None
- if is_empty_list(self._values['monitors']):
- return '/Common/bigip'
- monitors = [fq_name(self.partition, x) for x in self.monitors_list]
- if self.availability_requirement_type == 'at_least':
- if self.at_least > len(self.monitors_list):
- raise F5ModuleError(
- "The 'at_least' value must not exceed the number of 'monitors'."
- )
- monitors = ' '.join(monitors)
- result = 'min {0} of {{ {1} }}'.format(self.at_least, monitors)
- elif self.availability_requirement_type == 'require':
- monitors = ' '.join(monitors)
- if self.number_of_probes > self.number_of_probers:
- raise F5ModuleError(
- "The 'number_of_probes' must not exceed the 'number_of_probers'."
- )
- result = 'require {0} from {1} {{ {2} }}'.format(self.number_of_probes, self.number_of_probers, monitors)
- else:
- result = ' and '.join(monitors).strip()
-
- return result
-
- def _get_availability_value(self, type):
- if self._values['availability_requirements'] is None:
- return None
- if self._values['availability_requirements'][type] is None:
- return None
- return int(self._values['availability_requirements'][type])
-
- @property
- def availability_requirement_type(self):
- if self._values['availability_requirements'] is None:
- return None
- return self._values['availability_requirements']['type']
-
- @property
- def number_of_probes(self):
- return self._get_availability_value('number_of_probes')
-
- @property
- def number_of_probers(self):
- return self._get_availability_value('number_of_probers')
-
- @property
- def at_least(self):
- return self._get_availability_value('at_least')
-
- @property
- def prober_pool(self):
- if self._values['prober_pool'] is None:
- return None
- if self._values['prober_pool'] == '':
- return self._values['prober_pool']
- result = fq_name(self.partition, self._values['prober_pool'])
- return result
-
- @property
- def prober_fallback(self):
- if self._values['prober_fallback'] == 'any':
- return 'any-available'
- return self._values['prober_fallback']
-
- @property
- def bits_limit(self):
- return self._get_limit_value('bits_limit')
-
- @property
- def packets_limit(self):
- return self._get_limit_value('packets_limit')
-
- @property
- def connections_limit(self):
- return self._get_limit_value('connections_limit')
-
- @property
- def cpu_limit(self):
- return self._get_limit_value('cpu_limit')
-
- @property
- def memory_limit(self):
- return self._get_limit_value('memory_limit')
-
- @property
- def bits_enabled(self):
- return self._get_limit_status('bits_enabled')
-
- @property
- def packets_enabled(self):
- return self._get_limit_status('packets_enabled')
-
- @property
- def connections_enabled(self):
- return self._get_limit_status('connections_enabled')
-
- @property
- def cpu_enabled(self):
- return self._get_limit_status('cpu_enabled')
-
- @property
- def memory_enabled(self):
- return self._get_limit_status('memory_enabled')
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- return result
-
-
-class UsableChanges(Changes):
- @property
- def monitors(self):
- monitor_string = self._values['monitors']
- if monitor_string is None:
- return None
-
- if '{' in monitor_string and '}':
- tmp = monitor_string.strip('}').split('{')
- monitor = ''.join(tmp).rstrip()
- return monitor
-
- return monitor_string
-
- @property
- def iquery_allow_path(self):
- if self._values['iquery_allow_path'] is None:
- return None
- elif self._values['iquery_allow_path']:
- return 'yes'
- return 'no'
-
- @property
- def iquery_allow_service_check(self):
- if self._values['iquery_allow_service_check'] is None:
- return None
- elif self._values['iquery_allow_service_check']:
- return 'yes'
- return 'no'
-
- @property
- def iquery_allow_snmp(self):
- if self._values['iquery_allow_snmp'] is None:
- return None
- elif self._values['iquery_allow_snmp']:
- return 'yes'
- return 'no'
-
-
-class ReportableChanges(Changes):
- @property
- def server_type(self):
- if self._values['server_type'] in ['single-bigip', 'redundant-bigip']:
- return 'bigip'
- return self._values['server_type']
-
- @property
- def monitors(self):
- if self._values['monitors'] is None:
- return []
- try:
- result = re.findall(r'/\w+/[^\s}]+', self._values['monitors'])
- result.sort()
- return result
- except Exception:
- return self._values['monitors']
-
- @property
- def availability_requirement_type(self):
- if self._values['monitors'] is None:
- return None
- if 'min ' in self._values['monitors']:
- return 'at_least'
- elif 'require ' in self._values['monitors']:
- return 'require'
- else:
- return 'all'
-
- @property
- def number_of_probes(self):
- """Returns the probes value from the monitor string.
-
- The monitor string for a Require monitor looks like this.
-
- require 1 from 2 { /Common/tcp }
-
- This method parses out the first of the numeric values. This values represents
- the "probes" value that can be updated in the module.
-
- Returns:
- int: The probes value if found. None otherwise.
- """
- if self._values['monitors'] is None:
- return None
- pattern = r'require\s+(?P<probes>\d+)\s+from'
- matches = re.search(pattern, self._values['monitors'])
- if matches is None:
- return None
- return int(matches.group('probes'))
-
- @property
- def number_of_probers(self):
- """Returns the probers value from the monitor string.
-
- The monitor string for a Require monitor looks like this.
-
- require 1 from 2 { /Common/tcp }
-
- This method parses out the first of the numeric values. This values represents
- the "probers" value that can be updated in the module.
-
- Returns:
- int: The probers value if found. None otherwise.
- """
- if self._values['monitors'] is None:
- return None
- pattern = r'require\s+\d+\s+from\s+(?P<probers>\d+)\s+'
- matches = re.search(pattern, self._values['monitors'])
- if matches is None:
- return None
- return int(matches.group('probers'))
-
- @property
- def at_least(self):
- """Returns the 'at least' value from the monitor string.
-
- The monitor string for a Require monitor looks like this.
-
- min 1 of { /Common/gateway_icmp }
-
- This method parses out the first of the numeric values. This values represents
- the "at_least" value that can be updated in the module.
-
- Returns:
- int: The at_least value if found. None otherwise.
- """
- if self._values['monitors'] is None:
- return None
- pattern = r'min\s+(?P<least>\d+)\s+of\s+'
- matches = re.search(pattern, self._values['monitors'])
- if matches is None:
- return None
- return int(matches.group('least'))
-
- @property
- def availability_requirements(self):
- if self._values['monitors'] is None:
- return None
- result = dict()
- result['type'] = self.availability_requirement_type
- result['at_least'] = self.at_least
- result['number_of_probers'] = self.number_of_probers
- result['number_of_probes'] = self.number_of_probes
- return result
-
- @property
- def prober_fallback(self):
- if self._values['prober_fallback'] == 'any-available':
- return 'any'
- return self._values['prober_fallback']
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- def __default(self, param):
- want = getattr(self.want, param)
- try:
- have = getattr(self.have, param)
- if want != have:
- return want
- except AttributeError:
- return want
-
- def _discovery_constraints(self):
- if self.want.virtual_server_discovery is None:
- virtual_server_discovery = self.have.virtual_server_discovery
- else:
- virtual_server_discovery = self.want.virtual_server_discovery
-
- if self.want.link_discovery is None:
- link_discovery = self.have.link_discovery
- else:
- link_discovery = self.want.link_discovery
-
- if link_discovery in ['enabled', 'enabled-no-delete'] and virtual_server_discovery == 'disabled':
- raise F5ModuleError(
- "Virtual server discovery must be enabled if link discovery is enabled"
- )
-
- def _devices_changed(self):
- if self.want.devices is None and self.want.server_type is None:
- return None
- if self.want.devices is None:
- devices = self.have.devices
- else:
- devices = self.want.devices
- if self.have.devices is None:
- have_devices = []
- else:
- have_devices = self.have.devices
- if len(devices) == 0:
- raise F5ModuleError(
- "A GTM server must have at least one device associated with it."
- )
- want = [OrderedDict(sorted(d.items())) for d in devices]
- have = [OrderedDict(sorted(d.items())) for d in have_devices]
- if len(have_devices) > 0:
- if self._false_positive(devices, have_devices):
- return False
- if want != have:
- return True
- return False
-
- def _false_positive(self, devices, have_devices):
- match = 0
- for w in devices:
- for h in have_devices:
- if w.items() == h.items():
- match = match + 1
- if match == len(devices):
- return True
-
- def _server_type_changed(self):
- if self.want.server_type is None:
- self.want.update({'server_type': self.have.server_type})
- if self.want.server_type != self.have.server_type:
- return True
- return False
-
- @property
- def link_discovery(self):
- self._discovery_constraints()
- if self.want.link_discovery != self.have.link_discovery:
- return self.want.link_discovery
-
- @property
- def virtual_server_discovery(self):
- self._discovery_constraints()
- if self.want.virtual_server_discovery != self.have.virtual_server_discovery:
- return self.want.virtual_server_discovery
-
- def _handle_current_server_type_and_devices(self, devices_change, server_change):
- result = {}
- if devices_change:
- result['devices'] = self.want.devices
- if server_change:
- result['server_type'] = self.want.server_type
- return result
-
- def _handle_legacy_server_type_and_devices(self, devices_change, server_change):
- result = {}
- if server_change and devices_change:
- result['devices'] = self.want.devices
- if len(self.want.devices) > 1 and self.want.server_type == 'bigip':
- if self.have.raw_server_type != 'redundant-bigip':
- result['server_type'] = 'redundant-bigip'
- elif self.want.server_type == 'bigip':
- if self.have.raw_server_type != 'single-bigip':
- result['server_type'] = 'single-bigip'
- else:
- result['server_type'] = self.want.server_type
-
- elif devices_change:
- result['devices'] = self.want.devices
- if len(self.want.devices) > 1 and self.have.server_type == 'bigip':
- if self.have.raw_server_type != 'redundant-bigip':
- result['server_type'] = 'redundant-bigip'
- elif self.have.server_type == 'bigip':
- if self.have.raw_server_type != 'single-bigip':
- result['server_type'] = 'single-bigip'
- else:
- result['server_type'] = self.want.server_type
-
- elif server_change:
- if len(self.have.devices) > 1 and self.want.server_type == 'bigip':
- if self.have.raw_server_type != 'redundant-bigip':
- result['server_type'] = 'redundant-bigip'
- elif self.want.server_type == 'bigip':
- if self.have.raw_server_type != 'single-bigip':
- result['server_type'] = 'single-bigip'
- else:
- result['server_type'] = self.want.server_type
- return result
-
- @property
- def server_type_and_devices(self):
- """Compares difference between server type and devices list
-
- These two parameters are linked with each other and, therefore, must be
- compared together to ensure that the correct setting is sent to BIG-IP
-
- :return:
- """
- devices_change = self._devices_changed()
- server_change = self._server_type_changed()
- if not devices_change and not server_change:
- return None
- tmos = tmos_version(self.client)
- if LooseVersion(tmos) >= LooseVersion('13.0.0'):
- result = self._handle_current_server_type_and_devices(
- devices_change, server_change
- )
- return result
- else:
- result = self._handle_legacy_server_type_and_devices(
- devices_change, server_change
- )
- return result
-
- @property
- def state(self):
- if self.want.state == 'disabled' and self.have.enabled:
- return dict(disabled=True)
- elif self.want.state in ['present', 'enabled'] and self.have.disabled:
- return dict(enabled=True)
-
- @property
- def monitors(self):
- if self.want.monitors is None:
- return None
- if self.want.monitors == '/Common/bigip' and self.have.monitors == '/Common/bigip':
- return None
- if self.want.monitors == '/Common/bigip' and self.have.monitors is None:
- return None
- if self.want.monitors == '/Common/bigip' and len(self.have.monitors) > 0:
- return '/Common/bigip'
- if self.have.monitors is None:
- return self.want.monitors
- if self.have.monitors != self.want.monitors:
- return self.want.monitors
-
- @property
- def prober_pool(self):
- if self.want.prober_pool is None:
- return None
- if self.have.prober_pool is None:
- if self.want.prober_pool == '':
- return None
- if self.want.prober_pool != self.have.prober_pool:
- return self.want.prober_pool
-
- @property
- def prober_preference(self):
- if self.want.prober_preference is None:
- return None
- if self.want.prober_preference == self.have.prober_preference:
- return None
- if self.want.prober_preference == 'pool' and self.want.prober_pool is None:
- raise F5ModuleError(
- "A prober_pool needs to be set if prober_preference is set to 'pool'"
- )
- if self.want.prober_preference != 'pool' and self.have.prober_preference == 'pool':
- if self.want.prober_fallback != 'pool' and self.want.prober_pool != '':
- raise F5ModuleError(
- "To change prober_preference from {0} to {1}, set prober_pool to an empty string".format(
- self.have.prober_preference,
- self.want.prober_preference
- )
- )
- if self.want.prober_preference == self.want.prober_fallback:
- raise F5ModuleError(
- "Prober_preference and prober_fallback must not be equal."
- )
- if self.want.prober_preference == self.have.prober_fallback:
- raise F5ModuleError(
- "Cannot set prober_preference to {0} if prober_fallback on device is set to {1}.".format(
- self.want.prober_preference,
- self.have.prober_fallback
- )
- )
- if self.want.prober_preference != self.have.prober_preference:
- return self.want.prober_preference
-
- @property
- def prober_fallback(self):
- if self.want.prober_fallback is None:
- return None
- if self.want.prober_fallback == self.have.prober_fallback:
- return None
- if self.want.prober_fallback == 'pool' and self.want.prober_pool is None:
- raise F5ModuleError(
- "A prober_pool needs to be set if prober_fallback is set to 'pool'"
- )
- if self.want.prober_fallback != 'pool' and self.have.prober_fallback == 'pool':
- if self.want.prober_preference != 'pool' and self.want.prober_pool != '':
- raise F5ModuleError(
- "To change prober_fallback from {0} to {1}, set prober_pool to an empty string".format(
- self.have.prober_fallback,
- self.want.prober_fallback
- )
- )
- if self.want.prober_preference == self.want.prober_fallback:
- raise F5ModuleError(
- "Prober_preference and prober_fallback must not be equal."
- )
- if self.want.prober_fallback == self.have.prober_preference:
- raise F5ModuleError(
- "Cannot set prober_fallback to {0} if prober_preference on device is set to {1}.".format(
- self.want.prober_fallback,
- self.have.prober_preference
- )
- )
- if self.want.prober_fallback != self.have.prober_fallback:
- return self.want.prober_fallback
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.kwargs = kwargs
-
- def exec_module(self):
- if not module_provisioned(self.client, 'gtm'):
- raise F5ModuleError(
- "GTM must be provisioned to use this module."
- )
- if self.version_is_less_than('13.0.0'):
- manager = self.get_manager('v1')
- else:
- manager = self.get_manager('v2')
- return manager.exec_module()
-
- def get_manager(self, type):
- if type == 'v1':
- return V1Manager(**self.kwargs)
- elif type == 'v2':
- return V2Manager(**self.kwargs)
-
- def version_is_less_than(self, version):
- tmos = tmos_version(self.client)
- if LooseVersion(tmos) < LooseVersion(version):
- return True
- else:
- return False
-
-
-class BaseManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(params=self.module.params)
- self.want.update(dict(client=self.client))
- self.have = ApiParameters()
- self.changes = UsableChanges()
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = UsableChanges(params=changed)
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- diff.client = self.client
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def exec_module(self):
- changed = False
- result = dict()
- state = self.want.state
-
- if state in ['present', 'enabled', 'disabled']:
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def _check_link_discovery_requirements(self):
- if self.want.link_discovery in ['enabled', 'enabled-no-delete'] and self.want.virtual_server_discovery == 'disabled':
- raise F5ModuleError(
- "Virtual server discovery must be enabled if link discovery is enabled"
- )
-
- def present(self):
- if self.exists():
- return self.update()
- else:
- return self.create()
-
- def create(self):
- if self.want.state == 'disabled':
- self.want.update({'disabled': True})
- elif self.want.state in ['present', 'enabled']:
- self.want.update({'enabled': True})
-
- self.adjust_server_type_by_version()
- self.should_update()
-
- if self.want.devices is None:
- raise F5ModuleError(
- "You must provide an initial device."
- )
- self._assign_creation_defaults()
- self.handle_prober_settings()
- self._set_changed_options()
- if self.module.check_mode:
- return True
- self.create_on_device()
- if self.exists():
- return True
- else:
- raise F5ModuleError("Failed to create the server")
-
- def create_on_device(self):
- params = self.changes.api_params()
- params['name'] = self.want.name
- params['partition'] = self.want.partition
- uri = "https://{0}:{1}/mgmt/tm/gtm/server/".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return response['selfLink']
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/gtm/server/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return ApiParameters(params=response)
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def update_on_device(self):
- params = self.changes.api_params()
- uri = "https://{0}:{1}/mgmt/tm/gtm/server/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def absent(self):
- changed = False
- if self.exists():
- changed = self.remove()
- return changed
-
- def remove(self):
- if self.module.check_mode:
- return True
- self.remove_from_device()
- if self.exists():
- raise F5ModuleError("Failed to delete the server")
- return True
-
- def remove_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/gtm/server/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- response = self.client.api.delete(uri)
- if response.status == 200:
- return True
- raise F5ModuleError(response.content)
-
- def exists(self):
- uri = "https://{0}:{1}/mgmt/tm/gtm/server/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
-
-class V1Manager(BaseManager):
- def _assign_creation_defaults(self):
- if self.want.server_type is None:
- if len(self.want.devices) == 0:
- raise F5ModuleError(
- "You must provide at least one device."
- )
- elif len(self.want.devices) == 1:
- self.want.update({'server_type': 'single-bigip'})
- else:
- self.want.update({'server_type': 'redundant-bigip'})
- if self.want.link_discovery is None:
- self.want.update({'link_discovery': 'disabled'})
- if self.want.virtual_server_discovery is None:
- self.want.update({'virtual_server_discovery': 'disabled'})
- self._check_link_discovery_requirements()
-
- def adjust_server_type_by_version(self):
- if len(self.want.devices) == 1 and self.want.server_type == 'bigip':
- self.want.update({'server_type': 'single-bigip'})
- if len(self.want.devices) > 1 and self.want.server_type == 'bigip':
- self.want.update({'server_type': 'redundant-bigip'})
-
- def update(self):
- self.have = self.read_current_from_device()
- self.handle_prober_settings()
- if not self.should_update():
- return False
- if self.module.check_mode:
- return True
- self.update_on_device()
- return True
-
- def handle_prober_settings(self):
- if self.want.prober_preference is not None:
- self.want._values.pop('prober_preference')
- if self.want.prober_fallback is not None:
- self.want._values.pop('prober_fallback')
-
-
-class V2Manager(BaseManager):
- def update(self):
- self.have = self.read_current_from_device()
- if not self.should_update():
- return False
- if self.module.check_mode:
- return True
- self.update_on_device()
- return True
-
- def _assign_creation_defaults(self):
- if self.want.server_type is None:
- self.want.update({'server_type': 'bigip'})
- if self.want.link_discovery is None:
- self.want.update({'link_discovery': 'disabled'})
- if self.want.virtual_server_discovery is None:
- self.want.update({'virtual_server_discovery': 'disabled'})
- self._check_link_discovery_requirements()
-
- def adjust_server_type_by_version(self):
- pass
-
- def handle_prober_settings(self):
- if self.want.prober_preference == 'pool' and self.want.prober_pool is None:
- raise F5ModuleError(
- "A prober_pool needs to be set if prober_preference is set to 'pool'"
- )
- if self.want.prober_preference is not None and self.want.prober_fallback is not None:
- if self.want.prober_preference == self.want.prober_fallback:
- raise F5ModuleError(
- "The parameters for prober_preference and prober_fallback must not be the same."
- )
- if self.want.prober_fallback == 'pool' and self.want.prober_pool is None:
- raise F5ModuleError(
- "A prober_pool needs to be set if prober_fallback is set to 'pool'"
- )
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.states = ['absent', 'present', 'enabled', 'disabled']
- self.server_types = [
- 'alteon-ace-director',
- 'cisco-css',
- 'cisco-server-load-balancer',
- 'generic-host',
- 'radware-wsd',
- 'windows-nt-4.0',
- 'bigip',
- 'cisco-local-director-v2',
- 'extreme',
- 'generic-load-balancer',
- 'sun-solaris',
- 'cacheflow',
- 'cisco-local-director-v3',
- 'foundry-server-iron',
- 'netapp',
- 'windows-2000-server'
- ]
- self.supports_check_mode = True
- argument_spec = dict(
- state=dict(
- default='present',
- choices=self.states,
- ),
- name=dict(required=True),
- server_type=dict(
- choices=self.server_types,
- aliases=['product']
- ),
- datacenter=dict(),
- link_discovery=dict(
- choices=['enabled', 'disabled', 'enabled-no-delete']
- ),
- virtual_server_discovery=dict(
- choices=['enabled', 'disabled', 'enabled-no-delete']
- ),
- devices=dict(
- type='list'
- ),
- partition=dict(
- default='Common',
- fallback=(env_fallback, ['F5_PARTITION'])
- ),
- iquery_options=dict(
- type='dict',
- options=dict(
- allow_path=dict(type='bool'),
- allow_service_check=dict(type='bool'),
- allow_snmp=dict(type='bool')
- )
- ),
- availability_requirements=dict(
- type='dict',
- options=dict(
- type=dict(
- choices=['all', 'at_least', 'require'],
- required=True
- ),
- at_least=dict(type='int'),
- number_of_probes=dict(type='int'),
- number_of_probers=dict(type='int')
- ),
- mutually_exclusive=[
- ['at_least', 'number_of_probes'],
- ['at_least', 'number_of_probers'],
- ],
- required_if=[
- ['type', 'at_least', ['at_least']],
- ['type', 'require', ['number_of_probes', 'number_of_probers']]
- ]
- ),
- limits=dict(
- type='dict',
- options=dict(
- bits_enabled=dict(type='bool'),
- packets_enabled=dict(type='bool'),
- connections_enabled=dict(type='bool'),
- cpu_enabled=dict(type='bool'),
- memory_enabled=dict(type='bool'),
- bits_limit=dict(type='int'),
- packets_limit=dict(type='int'),
- connections_limit=dict(type='int'),
- cpu_limit=dict(type='int'),
- memory_limit=dict(type='int'),
- )
- ),
- monitors=dict(type='list'),
- prober_preference=dict(
- choices=['inside-datacenter', 'outside-datacenter', 'inherit', 'pool']
- ),
- prober_fallback=dict(
- choices=['inside-datacenter', 'outside-datacenter',
- 'inherit', 'pool', 'any', 'none']
- ),
- prober_pool=dict()
-
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode,
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_gtm_topology_record.py b/lib/ansible/modules/network/f5/bigip_gtm_topology_record.py
deleted file mode 100644
index 467d43c4af..0000000000
--- a/lib/ansible/modules/network/f5/bigip_gtm_topology_record.py
+++ /dev/null
@@ -1,1080 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2018, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_gtm_topology_record
-short_description: Manages GTM Topology Records
-description:
- - Manages GTM Topology Records. Once created, only topology record C(weight) can be modified.
-version_added: 2.8
-options:
- source:
- description:
- - Specifies the origination of an incoming DNS request.
- suboptions:
- negate:
- description:
- - When set to C(yes) the system selects this topology record, when the request source does not match.
- type: bool
- default: no
- subnet:
- description:
- - An IP address and network mask in the CIDR format.
- type: str
- region:
- description:
- - Specifies the name of region already defined in the configuration.
- type: str
- continent:
- description:
- - Specifies one of the seven continents, along with the C(Unknown) setting.
- - Specifying C(Unknown) forces the system to use a default resolution
- if the system cannot determine the location of the local DNS making the request.
- - Full continent names and their abbreviated versions are supported.
- type: str
- country:
- description:
- - Specifies a country.
- - In addition to the country full names, you may also specify their abbreviated
- form, such as C(US) instead of C(United States).
- - Valid country codes can be found here https://countrycode.org/.
- type: str
- state:
- description:
- - Specifies a state in a given country.
- - This parameter requires country option to be provided.
- type: str
- isp:
- description:
- - Specifies an Internet service provider.
- type: str
- choices:
- - AOL
- - BeijingCNC
- - CNC
- - ChinaEducationNetwork
- - ChinaMobilNetwork
- - ChinaRailwayTelcom
- - ChinaTelecom
- - ChinaUnicom
- - Comcast
- - Earthlink
- - ShanghaiCNC
- - ShanghaiTelecom
- geo_isp:
- description:
- - Specifies a geolocation ISP
- type: str
- type: dict
- required: True
- destination:
- description:
- - Specifies where the system directs the incoming DNS request.
- suboptions:
- negate:
- description:
- - When set to C(yes) the system selects this topology record, when the request destination does not match.
- type: bool
- default: no
- subnet:
- description:
- - An IP address and network mask in the CIDR format.
- type: str
- region:
- description:
- - Specifies the name of region already defined in the configuration.
- type: str
- continent:
- description:
- - Specifies one of the seven continents, along with the C(Unknown) setting.
- - Specifying C(Unknown) forces the system to use a default resolution
- if the system cannot determine the location of the local DNS making the request.
- - Full continent names and their abbreviated versions are supported.
- type: str
- country:
- description:
- - Specifies a country.
- - Full continent names and their abbreviated versions are supported.
- type: str
- state:
- description:
- - Specifies a state in a given country.
- - This parameter requires country option to be provided.
- type: str
- pool:
- description:
- - Specifies the name of GTM pool already defined in the configuration.
- type: str
- datacenter:
- description:
- - Specifies the name of GTM data center already defined in the configuration.
- type: str
- isp:
- description:
- - Specifies an Internet service provider.
- type: str
- choices:
- - AOL
- - BeijingCNC
- - CNC
- - ChinaEducationNetwork
- - ChinaMobilNetwork
- - ChinaRailwayTelcom
- - ChinaTelecom
- - ChinaUnicom
- - Comcast
- - Earthlink
- - ShanghaiCNC
- - ShanghaiTelecom
- geo_isp:
- description:
- - Specifies a geolocation ISP
- type: str
- type: dict
- required: True
- weight:
- description:
- - Specifies the weight of the topology record.
- - The system finds the weight of the first topology record that matches the server object (pool or pool member)
- and the local DNS. The system then assigns that weight as the topology score for that server object.
- - The system load balances to the server object with the highest topology score.
- - If the system finds no topology record that matches both the server object and the local DNS,
- then the system assigns that server object a zero score.
- - If the option is not specified when the record is created the system will set it at a default value of C(1)
- - Valid range is (0 - 4294967295)
- type: int
- partition:
- description:
- - Device partition to manage resources on.
- - Partition parameter is taken into account when used in conjunction with C(pool), C(data_center),
- and C(region) parameters, it is ignored otherwise.
- type: str
- default: Common
- state:
- description:
- - When C(state) is C(present), ensures that the record exists.
- - When C(state) is C(absent), ensures that the record is removed.
- type: str
- choices:
- - present
- - absent
- default: present
-extends_documentation_fragment: f5
-author:
- - Wojciech Wypior (@wojtek0806)
-'''
-
-EXAMPLES = r'''
-- name: Create an IP Subnet and an ISP based topology record
- bigip_gtm_topology_record:
- source:
- - subnet: 192.168.1.0/24
- destination:
- - isp: AOL
- weight: 10
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-
-- name: Create a region and a pool based topology record
- bigip_gtm_topology_record:
- source:
- - region: Foo
- destination:
- - pool: FooPool
- partition: FooBar
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-
-- name: Create a negative region and a negative data center based topology record
- bigip_gtm_topology_record:
- source:
- - region: Baz
- - negate: yes
- destination:
- - datacenter: Baz-DC
- - negate: yes
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-'''
-
-RETURN = r'''
-weight:
- description: The weight of the topology record.
- returned: changed
- type: int
- sample: 20
-'''
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.basic import env_fallback
-from ansible.module_utils.six import iteritems
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import fq_name
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.common import transform_name
- from library.module_utils.network.f5.common import flatten_boolean
- from library.module_utils.network.f5.ipaddress import is_valid_ip_network
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import fq_name
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.common import transform_name
- from ansible.module_utils.network.f5.common import flatten_boolean
- from ansible.module_utils.network.f5.ipaddress import is_valid_ip_network
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'score': 'weight',
- }
-
- api_attributes = [
- 'score',
- ]
-
- returnables = [
- 'weight',
- 'name'
- ]
-
- updatables = [
- 'weight',
- ]
-
-
-class ApiParameters(Parameters):
- pass
-
-
-class ModuleParameters(Parameters):
- countries = {
- 'Afghanistan': 'AF',
- 'Aland Islands': 'AX',
- 'Albania': 'AL',
- 'Algeria': 'DZ',
- 'American Samoa': 'AS',
- 'Andorra': 'AD',
- 'Angola': 'AO',
- 'Anguilla': 'AI',
- 'Antarctica': 'AQ',
- 'Antigua and Barbuda': 'AG',
- 'Argentina': 'AR',
- 'Armenia': 'AM',
- 'Aruba': 'AW',
- 'Australia': 'AU',
- 'Austria': 'AT',
- 'Azerbaijan': 'AZ',
- 'Bahamas': 'BS',
- 'Bahrain': 'BH',
- 'Bangladesh': 'BD',
- 'Barbados': 'BB',
- 'Belarus': 'BY',
- 'Belgium': 'BE',
- 'Belize': 'BZ',
- 'Benin': 'BJ',
- 'Bermuda': 'BM',
- 'Bhutan': 'BT',
- 'Bolivia': 'BO',
- 'Bonaire, Sint Eustatius and Saba': 'BQ',
- 'Bosnia and Herzegovina': 'BA',
- 'Botswana': 'BW',
- 'Bouvet Island': 'BV',
- 'Brazil': 'BR',
- 'British Indian Ocean Territory': 'IO',
- 'Brunei Darussalam': 'BN',
- 'Bulgaria': 'BG',
- 'Burkina Faso': 'BF',
- 'Burundi': 'BI',
- 'Cape Verde': 'CV',
- 'Cambodia': 'KH',
- 'Cameroon': 'CM',
- 'Canada': 'CA',
- 'Cayman Islands': 'KY',
- 'Central African Republic': 'CF',
- 'Chad': 'TD',
- 'Chile': 'CL',
- 'China': 'CN',
- 'Christmas Island': 'CX',
- 'Cocos (Keeling) Islands': 'CC',
- 'Colombia': 'CO',
- 'Comoros': 'KM',
- 'Congo': 'CG',
- 'Congo, The Democratic Republic of the': 'CD',
- 'Cook Islands': 'CK',
- 'Costa Rica': 'CR',
- "Cote D'Ivoire": 'CI',
- 'Croatia': 'HR',
- 'Cuba': 'CU',
- 'Curaçao': 'CW',
- 'Cyprus': 'CY',
- 'Czech Republic': 'CZ',
- 'Denmark': 'DK',
- 'Djibouti': 'DJ',
- 'Dominica': 'DM',
- 'Dominican Republic': 'DO',
- 'Ecuador': 'EC',
- 'Egypt': 'EG',
- 'El Salvador': 'SV',
- 'Equatorial Guinea': 'GQ',
- 'Eritrea': 'ER',
- 'Estonia': 'EE',
- 'Ethiopia': 'ET',
- 'Falkland Islands (Malvinas)': 'FK',
- 'Faroe Islands': 'FO',
- 'Fiji': 'FJ',
- 'Finland': 'FI',
- 'France': 'FR',
- 'French Guiana': 'GF',
- 'French Polynesia': 'PF',
- 'French Southern Territories': 'TF',
- 'Gabon': 'GA',
- 'Gambia': 'GM',
- 'Georgia': 'GE',
- 'Germany': 'DE',
- 'Ghana': 'GH',
- 'Gibraltar': 'GI',
- 'Greece': 'GR',
- 'Greenland': 'GL',
- 'Grenada': 'GD',
- 'Guadeloupe': 'GP',
- 'Guam': 'GU',
- 'Guatemala': 'GT',
- 'Guernsey': 'GG',
- 'Guinea': 'GN',
- 'Guinea-Bissau': 'GW',
- 'Guyana': 'GY',
- 'Haiti': 'HT',
- 'Heard Island and McDonald Islands': 'HM',
- 'Holy See (Vatican City State)': 'VA',
- 'Honduras': 'HN',
- 'Hong Kong': 'HK',
- 'Hungary': 'HU',
- 'Iceland': 'IS',
- 'India': 'IN',
- 'Indonesia': 'ID',
- 'Iran, Islamic Republic of': 'IR',
- 'Iraq': 'IQ',
- 'Ireland': 'IE',
- 'Isle of Man': 'IM',
- 'Israel': 'IL',
- 'Italy': 'IT',
- 'Jamaica': 'JM',
- 'Japan': 'JP',
- 'Jersey': 'JE',
- 'Jordan': 'JO',
- 'Kazakhstan': 'KZ',
- 'Kenya': 'KE',
- 'Kiribati': 'KI',
- "Korea, Democratic People's Republic of": 'KP',
- 'Korea, Republic of': 'KR',
- 'Kuwait': 'KW',
- 'Kyrgyzstan': 'KG',
- "Lao People's Democratic Republic": 'LA',
- 'Latvia': 'LV',
- 'Lebanon': 'LB',
- 'Lesotho': 'LS',
- 'Liberia': 'LR',
- 'Libyan Arab Jamahiriya': 'LY',
- 'Liechtenstein': 'LI',
- 'Lithuania': 'LT',
- 'Luxembourg': 'LU',
- 'Macau': 'MO',
- 'Macedonia': 'MK',
- 'Madagascar': 'MG',
- 'Malawi': 'MW',
- 'Malaysia': 'MY',
- 'Maldives': 'MV',
- 'Mali': 'ML',
- 'Malta': 'MT',
- 'Marshall Islands': 'MH',
- 'Martinique': 'MQ',
- 'Mauritania': 'MR',
- 'Mauritius': 'MU',
- 'Mayotte': 'YT',
- 'Mexico': 'MX',
- 'Micronesia, Federated States of': 'FM',
- 'Moldova, Republic of': 'MD',
- 'Monaco': 'MC',
- 'Mongolia': 'MN',
- 'Montenegro': 'ME',
- 'Montserrat': 'MS',
- 'Morocco': 'MA',
- 'Mozambique': 'MZ',
- 'Myanmar': 'MM',
- 'Namibia': 'NA',
- 'Nauru': 'NR',
- 'Nepal': 'NP',
- 'Netherlands': 'NL',
- 'New Caledonia': 'NC',
- 'New Zealand': 'NZ',
- 'Nicaragua': 'NI',
- 'Niger': 'NE',
- 'Nigeria': 'NG',
- 'Niue': 'NU',
- 'Norfolk Island': 'NF',
- 'Northern Mariana Islands': 'MP',
- 'Norway': 'NO',
- 'Oman': 'OM',
- 'Pakistan': 'PK',
- 'Palau': 'PW',
- 'Palestinian Territory': 'PS',
- 'Panama': 'PA',
- 'Papua New Guinea': 'PG',
- 'Paraguay': 'PY',
- 'Peru': 'PE',
- 'Philippines': 'PH',
- 'Pitcairn Islands': 'PN',
- 'Poland': 'PL',
- 'Portugal': 'PT',
- 'Puerto Rico': 'PR',
- 'Qatar': 'QA',
- 'Reunion': 'RE',
- 'Romania': 'RO',
- 'Russian Federation': 'RU',
- 'Rwanda': 'RW',
- 'Saint Barthelemy': 'BL',
- 'Saint Helena': 'SH',
- 'Saint Kitts and Nevis': 'KN',
- 'Saint Lucia': 'LC',
- 'Saint Martin': 'MF',
- 'Saint Pierre and Miquelon': 'PM',
- 'Saint Vincent and the Grenadines': 'VC',
- 'Samoa': 'WS',
- 'San Marino': 'SM',
- 'Sao Tome and Principe': 'ST',
- 'Saudi Arabia': 'SA',
- 'Senegal': 'SN',
- 'Serbia': 'RS',
- 'Seychelles': 'SC',
- 'Sierra Leone': 'SL',
- 'Singapore': 'SG',
- 'Sint Maarten (Dutch part)': 'SX',
- 'Slovakia': 'SK',
- 'Slovenia': 'SI',
- 'Solomon Islands': 'SB',
- 'Somalia': 'SO',
- 'South Africa': 'ZA',
- 'South Georgia and the South Sandwich Islands': 'GS',
- 'South Sudan': 'SS',
- 'Spain': 'ES',
- 'Sri Lanka': 'LK',
- 'Sudan': 'SD',
- 'Suriname': 'SR',
- 'Svalbard and Jan Mayen': 'SJ',
- 'Swaziland': 'SZ',
- 'Sweden': 'SE',
- 'Switzerland': 'CH',
- 'Syrian Arab Republic': 'SY',
- 'Taiwan': 'TW',
- 'Tajikistan': 'TJ',
- 'Tanzania, United Republic of': 'TZ',
- 'Thailand': 'TH',
- 'Timor-Leste': 'TL',
- 'Togo': 'TG',
- 'Tokelau': 'TK',
- 'Tonga': 'TO',
- 'Trinidad and Tobago': 'TT',
- 'Tunisia': 'TN',
- 'Turkey': 'TR',
- 'Turkmenistan': 'TM',
- 'Turks and Caicos Islands': 'TC',
- 'Tuvalu': 'TV',
- 'Uganda': 'UG',
- 'Ukraine': 'UA',
- 'United Arab Emirates': 'AE',
- 'United Kingdom': 'GB',
- 'United States': 'US',
- 'United States Minor Outlying Islands': 'UM',
- 'Uruguay': 'UY',
- 'Uzbekistan': 'UZ',
- 'Vanuatu': 'VU',
- 'Venezuela': 'VE',
- 'Vietnam': 'VN',
- 'Virgin Islands, British': 'VG',
- 'Virgin Islands, U.S.': 'VI',
- 'Wallis and Futuna': 'WF',
- 'Western Sahara': 'EH',
- 'Yemen': 'YE',
- 'Zambia': 'ZM',
- 'Zimbabwe': 'ZW',
- 'Unrecognized': 'N/A',
- 'Asia/Pacific Region': 'AP',
- 'Europe': 'EU',
- 'Netherlands Antilles': 'AN',
- 'France, Metropolitan': 'FX',
- 'Anonymous Proxy': 'A1',
- 'Satellite Provider': 'A2',
- 'Other': 'O1',
- }
-
- continents = {
- 'Antarctica': 'AN',
- 'Asia': 'AS',
- 'Africa': 'AF',
- 'Europe': 'EU',
- 'North America': 'NA',
- 'South America': 'SA',
- 'Oceania': 'OC',
- 'Unknown': '--',
- }
-
- @property
- def src_negate(self):
- src_negate = self._values['source'].get('negate', None)
- result = flatten_boolean(src_negate)
- if result == 'yes':
- return 'not'
- return None
-
- @property
- def src_subnet(self):
- src_subnet = self._values['source'].get('subnet', None)
- if src_subnet is None:
- return None
- if is_valid_ip_network(src_subnet):
- return src_subnet
- raise F5ModuleError(
- "Specified 'subnet' is not a valid subnet."
- )
-
- @property
- def src_region(self):
- src_region = self._values['source'].get('region', None)
- if src_region is None:
- return None
- return fq_name(self.partition, src_region)
-
- @property
- def src_continent(self):
- src_continent = self._values['source'].get('continent', None)
- if src_continent is None:
- return None
- result = self.continents.get(src_continent, src_continent)
- return result
-
- @property
- def src_country(self):
- src_country = self._values['source'].get('country', None)
- if src_country is None:
- return None
- result = self.countries.get(src_country, src_country)
- return result
-
- @property
- def src_state(self):
- src_country = self._values['source'].get('country', None)
- src_state = self._values['source'].get('state', None)
- if src_state is None:
- return None
- if src_country is None:
- raise F5ModuleError(
- 'Country needs to be provided when specifying state'
- )
- result = '{0}/{1}'.format(src_country, src_state)
- return result
-
- @property
- def src_isp(self):
- src_isp = self._values['source'].get('isp', None)
- if src_isp is None:
- return None
- return fq_name('Common', src_isp)
-
- @property
- def src_geo_isp(self):
- src_geo_isp = self._values['source'].get('geo_isp', None)
- return src_geo_isp
-
- @property
- def dst_negate(self):
- dst_negate = self._values['destination'].get('negate', None)
- result = flatten_boolean(dst_negate)
- if result == 'yes':
- return 'not'
- return None
-
- @property
- def dst_subnet(self):
- dst_subnet = self._values['destination'].get('subnet', None)
- if dst_subnet is None:
- return None
- if is_valid_ip_network(dst_subnet):
- return dst_subnet
- raise F5ModuleError(
- "Specified 'subnet' is not a valid subnet."
- )
-
- @property
- def dst_region(self):
- dst_region = self._values['destination'].get('region', None)
- if dst_region is None:
- return None
- return fq_name(self.partition, dst_region)
-
- @property
- def dst_continent(self):
- dst_continent = self._values['destination'].get('continent', None)
- if dst_continent is None:
- return None
- result = self.continents.get(dst_continent, dst_continent)
- return result
-
- @property
- def dst_country(self):
- dst_country = self._values['destination'].get('country', None)
- if dst_country is None:
- return None
- result = self.countries.get(dst_country, dst_country)
- return result
-
- @property
- def dst_state(self):
- dst_country = self.dst_country
- dst_state = self._values['destination'].get('state', None)
- if dst_state is None:
- return None
- if dst_country is None:
- raise F5ModuleError(
- 'Country needs to be provided when specifying state'
- )
- result = '{0}/{1}'.format(dst_country, dst_state)
- return result
-
- @property
- def dst_isp(self):
- dst_isp = self._values['destination'].get('isp', None)
- if dst_isp is None:
- return None
- return fq_name('Common', dst_isp)
-
- @property
- def dst_geo_isp(self):
- dst_geo_isp = self._values['destination'].get('geo_isp', None)
- return dst_geo_isp
-
- @property
- def dst_pool(self):
- dst_pool = self._values['destination'].get('pool', None)
- if dst_pool is None:
- return None
- return fq_name(self.partition, dst_pool)
-
- @property
- def dst_datacenter(self):
- dst_datacenter = self._values['destination'].get('datacenter', None)
- if dst_datacenter is None:
- return None
- return fq_name(self.partition, dst_datacenter)
-
- @property
- def source(self):
- options = {
- 'negate': self.src_negate,
- 'subnet': self.src_subnet,
- 'region': self.src_region,
- 'continent': self.src_continent,
- 'country': self.src_country,
- 'state': self.src_state,
- 'isp': self.src_isp,
- 'geoip-isp': self.src_geo_isp,
- }
- result = 'ldns: {0}'.format(self._format_options(options))
- return result
-
- @property
- def destination(self):
- options = {
- 'negate': self.dst_negate,
- 'subnet': self.dst_subnet,
- 'region': self.dst_region,
- 'continent': self.dst_continent,
- 'country': self.dst_country,
- 'state': self.dst_state,
- 'datacenter': self.dst_datacenter,
- 'pool': self.dst_pool,
- 'isp': self.dst_isp,
- 'geoip-isp': self.dst_geo_isp,
- }
- result = 'server: {0}'.format(self._format_options(options))
- return result
-
- @property
- def name(self):
- result = '{0} {1}'.format(self.source, self.destination)
- return result
-
- def _format_options(self, options):
- negate = None
- cleaned = dict((k, v) for k, v in iteritems(options) if v is not None)
- if 'country' and 'state' in cleaned.keys():
- del cleaned['country']
- if 'negate' in cleaned.keys():
- negate = cleaned['negate']
- del cleaned['negate']
- name, value = cleaned.popitem()
- if negate:
- result = '{0} {1} {2}'.format(negate, name, value)
- return result
- result = '{0} {1}'.format(name, value)
- return result
-
- @property
- def weight(self):
- weight = self._values['weight']
- if weight is None:
- return None
- if 0 <= weight <= 4294967295:
- return weight
- raise F5ModuleError(
- "Valid weight must be in range 0 - 4294967295"
- )
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class UsableChanges(Changes):
- pass
-
-
-class ReportableChanges(Changes):
- pass
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(params=self.module.params)
- self.have = ApiParameters()
- self.changes = UsableChanges()
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = UsableChanges(params=changed)
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def exec_module(self):
- changed = False
- result = dict()
- state = self.want.state
-
- if state == "present":
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.client.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def present(self):
- if self.exists():
- return self.update()
- else:
- return self.create()
-
- def absent(self):
- if self.exists():
- return self.remove()
- return False
-
- def update(self):
- self.have = self.read_current_from_device()
- if not self.should_update():
- return False
- if self.module.check_mode:
- return True
- self.update_on_device()
- return True
-
- def remove(self):
- if self.module.check_mode:
- return True
- self.remove_from_device()
- if self.exists():
- raise F5ModuleError("Failed to delete the resource.")
- return True
-
- def create(self):
- self._set_changed_options()
- if self.module.check_mode:
- return True
- self.create_on_device()
- return True
-
- def exists(self):
- name = self.want.name
- uri = "https://{0}:{1}/mgmt/tm/gtm/topology/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- name.replace(' ', '%20').replace('/', '~')
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def create_on_device(self):
- params = self.changes.api_params()
- params['name'] = self.want.name
- uri = "https://{0}:{1}/mgmt/tm/gtm/topology/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return True
-
- def update_on_device(self):
- params = self.changes.api_params()
- name = self.want.name
- uri = "https://{0}:{1}/mgmt/tm/gtm/topology/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- name.replace(' ', '%20').replace('/', '~')
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def remove_from_device(self):
- name = self.want.name
- uri = "https://{0}:{1}/mgmt/tm/gtm/topology/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- name.replace(' ', '%20').replace('/', '~')
- )
- response = self.client.api.delete(uri)
- if response.status == 200:
- return True
- raise F5ModuleError(response.content)
-
- def read_current_from_device(self):
- name = self.want.name
- uri = "https://{0}:{1}/mgmt/tm/gtm/topology/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- name.replace(' ', '%20').replace('/', '~')
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- return ApiParameters(params=response)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- self.choices = [
- 'AOL', 'BeijingCNC', 'CNC', 'ChinaEducationNetwork',
- 'ChinaMobilNetwork', 'ChinaRailwayTelcom', 'ChinaTelecom',
- 'ChinaUnicom', 'Comcast', 'Earthlink', 'ShanghaiCNC',
- 'ShanghaiTelecom',
- ]
- argument_spec = dict(
- source=dict(
- required=True,
- type='dict',
- options=dict(
- subnet=dict(),
- region=dict(),
- continent=dict(),
- country=dict(),
- state=dict(),
- isp=dict(
- choices=self.choices
- ),
- geo_isp=dict(),
- negate=dict(
- type='bool',
- default='no'
- ),
- ),
- mutually_exclusive=[
- ['subnet', 'region', 'continent', 'country', 'isp', 'geo_isp']
- ]
- ),
- destination=dict(
- required=True,
- type='dict',
- options=dict(
- subnet=dict(),
- region=dict(),
- continent=dict(),
- country=dict(),
- state=dict(),
- pool=dict(),
- datacenter=dict(),
- isp=dict(
- choices=self.choices
- ),
- geo_isp=dict(),
- negate=dict(
- type='bool',
- default='no'
- ),
- ),
- mutually_exclusive=[
- ['subnet', 'region', 'continent', 'country', 'pool', 'datacenter', 'isp', 'geo_isp']
- ]
- ),
- weight=dict(type='int'),
- partition=dict(
- default='Common',
- fallback=(env_fallback, ['F5_PARTITION'])
- ),
- state=dict(
- default='present',
- choices=['present', 'absent']
- )
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode,
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_gtm_topology_region.py b/lib/ansible/modules/network/f5/bigip_gtm_topology_region.py
deleted file mode 100644
index cde2c83b52..0000000000
--- a/lib/ansible/modules/network/f5/bigip_gtm_topology_region.py
+++ /dev/null
@@ -1,892 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2018, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_gtm_topology_region
-short_description: Manages GTM Topology Regions
-description:
- - Manages GTM Topology Regions.
-version_added: 2.8
-options:
- name:
- description:
- - Specifies the name of the region.
- type: str
- required: True
- region_members:
- description:
- - Specifies the list of region members.
- - This list of members is all or nothing, in order to add or remove a member,
- you must specify the entire list of members.
- - The list will override what is on the device if different.
- - If C(none) value is specified the region members list will be removed.
- suboptions:
- negate:
- description:
- - When set to C(yes) the system selects this topology region, when the request source does not match.
- - Only a single list entry can be specified together with negate.
- type: bool
- default: no
- subnet:
- description:
- - An IP address and network mask in the CIDR format.
- type: str
- version_added: 2.9
- region:
- description:
- - Specifies the name of region already defined in the configuration.
- type: str
- continent:
- description:
- - Specifies one of the seven continents, along with the C(Unknown) setting.
- - Specifying C(Unknown) forces the system to use a default resolution
- if the system cannot determine the location of the local DNS making the request.
- - Full continent names and their abbreviated versions are supported.
- type: str
- country:
- description:
- - The country name, or code to use.
- - In addition to the country full names, you may also specify their abbreviated
- form, such as C(US) instead of C(United States).
- - Valid country codes can be found here https://countrycode.org/.
- type: str
- state:
- description:
- - Specifies a state in a given country.
- type: str
- pool:
- description:
- - Specifies the name of GTM pool already defined in the configuration.
- type: str
- datacenter:
- description:
- - Specifies the name of GTM data center already defined in the configuration.
- type: str
- isp:
- description:
- - Specifies an Internet service provider.
- type: str
- choices:
- - AOL
- - BeijingCNC
- - CNC
- - ChinaEducationNetwork
- - ChinaMobilNetwork
- - ChinaRailwayTelcom
- - ChinaTelecom
- - ChinaUnicom
- - Comcast
- - Earthlink
- - ShanghaiCNC
- - ShanghaiTelecom
- geo_isp:
- description:
- - Specifies a geolocation ISP
- type: str
- type: list
- partition:
- description:
- - Device partition to manage resources on.
- - Partition parameter is also taken into account when used in conjunction with C(pool), C(data_center),
- and C(region) parameters.
- type: str
- default: Common
- state:
- description:
- - When C(state) is C(present), ensures that the region exists.
- - When C(state) is C(absent), ensures that the region is removed.
- type: str
- choices:
- - present
- - absent
- default: present
-extends_documentation_fragment: f5
-author:
- - Wojciech Wypior (@wojtek0806)
-'''
-
-
-EXAMPLES = r'''
-- name: Create topology region
- bigip_gtm_topology_region:
- name: foobar
- region_members:
- - country: CN
- negate: yes
- - datacenter: baz
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-
-- name: Modify topology region
- bigip_gtm_topology_region:
- name: foobar
- region_members:
- - continent: EU
- - country: PL
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-'''
-
-RETURN = r'''
-name:
- description: The name value of the GTM region.
- returned: changed
- type: str
- sample: foobar
-region_members:
- description: The list of members of the GTM region.
- returned: changed
- type: list
- sample: [{"continent": "EU"}, {"country": "PL"}]
-'''
-
-import copy
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.basic import env_fallback
-from ansible.module_utils.six import string_types
-from ansible.module_utils.six import iteritems
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import fq_name
- from library.module_utils.network.f5.common import transform_name
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.common import flatten_boolean
- from library.module_utils.network.f5.compare import cmp_simple_list
- from library.module_utils.network.f5.ipaddress import is_valid_ip_network
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import fq_name
- from ansible.module_utils.network.f5.common import transform_name
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.common import flatten_boolean
- from ansible.module_utils.network.f5.compare import cmp_simple_list
- from ansible.module_utils.network.f5.ipaddress import is_valid_ip_network
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'regionMembers': 'region_members',
- }
-
- api_attributes = [
- 'regionMembers',
- ]
-
- returnables = [
- 'region_members',
- ]
-
- updatables = [
- 'region_members',
- ]
-
-
-class ApiParameters(Parameters):
- @property
- def region_members(self):
- members = self._values['region_members']
- if members is None:
- return None
- result = [member['name'] for member in members]
- return result
-
-
-class ModuleParameters(Parameters):
- countries = {
- 'Afghanistan': 'AF',
- 'Aland Islands': 'AX',
- 'Albania': 'AL',
- 'Algeria': 'DZ',
- 'American Samoa': 'AS',
- 'Andorra': 'AD',
- 'Angola': 'AO',
- 'Anguilla': 'AI',
- 'Antarctica': 'AQ',
- 'Antigua and Barbuda': 'AG',
- 'Argentina': 'AR',
- 'Armenia': 'AM',
- 'Aruba': 'AW',
- 'Australia': 'AU',
- 'Austria': 'AT',
- 'Azerbaijan': 'AZ',
- 'Bahamas': 'BS',
- 'Bahrain': 'BH',
- 'Bangladesh': 'BD',
- 'Barbados': 'BB',
- 'Belarus': 'BY',
- 'Belgium': 'BE',
- 'Belize': 'BZ',
- 'Benin': 'BJ',
- 'Bermuda': 'BM',
- 'Bhutan': 'BT',
- 'Bolivia': 'BO',
- 'Bonaire, Sint Eustatius and Saba': 'BQ',
- 'Bosnia and Herzegovina': 'BA',
- 'Botswana': 'BW',
- 'Bouvet Island': 'BV',
- 'Brazil': 'BR',
- 'British Indian Ocean Territory': 'IO',
- 'Brunei Darussalam': 'BN',
- 'Bulgaria': 'BG',
- 'Burkina Faso': 'BF',
- 'Burundi': 'BI',
- 'Cape Verde': 'CV',
- 'Cambodia': 'KH',
- 'Cameroon': 'CM',
- 'Canada': 'CA',
- 'Cayman Islands': 'KY',
- 'Central African Republic': 'CF',
- 'Chad': 'TD',
- 'Chile': 'CL',
- 'China': 'CN',
- 'Christmas Island': 'CX',
- 'Cocos (Keeling) Islands': 'CC',
- 'Colombia': 'CO',
- 'Comoros': 'KM',
- 'Congo': 'CG',
- 'Congo, The Democratic Republic of the': 'CD',
- 'Cook Islands': 'CK',
- 'Costa Rica': 'CR',
- "Cote D'Ivoire": 'CI',
- 'Croatia': 'HR',
- 'Cuba': 'CU',
- 'Curaçao': 'CW',
- 'Cyprus': 'CY',
- 'Czech Republic': 'CZ',
- 'Denmark': 'DK',
- 'Djibouti': 'DJ',
- 'Dominica': 'DM',
- 'Dominican Republic': 'DO',
- 'Ecuador': 'EC',
- 'Egypt': 'EG',
- 'El Salvador': 'SV',
- 'Equatorial Guinea': 'GQ',
- 'Eritrea': 'ER',
- 'Estonia': 'EE',
- 'Ethiopia': 'ET',
- 'Falkland Islands (Malvinas)': 'FK',
- 'Faroe Islands': 'FO',
- 'Fiji': 'FJ',
- 'Finland': 'FI',
- 'France': 'FR',
- 'French Guiana': 'GF',
- 'French Polynesia': 'PF',
- 'French Southern Territories': 'TF',
- 'Gabon': 'GA',
- 'Gambia': 'GM',
- 'Georgia': 'GE',
- 'Germany': 'DE',
- 'Ghana': 'GH',
- 'Gibraltar': 'GI',
- 'Greece': 'GR',
- 'Greenland': 'GL',
- 'Grenada': 'GD',
- 'Guadeloupe': 'GP',
- 'Guam': 'GU',
- 'Guatemala': 'GT',
- 'Guernsey': 'GG',
- 'Guinea': 'GN',
- 'Guinea-Bissau': 'GW',
- 'Guyana': 'GY',
- 'Haiti': 'HT',
- 'Heard Island and McDonald Islands': 'HM',
- 'Holy See (Vatican City State)': 'VA',
- 'Honduras': 'HN',
- 'Hong Kong': 'HK',
- 'Hungary': 'HU',
- 'Iceland': 'IS',
- 'India': 'IN',
- 'Indonesia': 'ID',
- 'Iran, Islamic Republic of': 'IR',
- 'Iraq': 'IQ',
- 'Ireland': 'IE',
- 'Isle of Man': 'IM',
- 'Israel': 'IL',
- 'Italy': 'IT',
- 'Jamaica': 'JM',
- 'Japan': 'JP',
- 'Jersey': 'JE',
- 'Jordan': 'JO',
- 'Kazakhstan': 'KZ',
- 'Kenya': 'KE',
- 'Kiribati': 'KI',
- "Korea, Democratic People's Republic of": 'KP',
- 'Korea, Republic of': 'KR',
- 'Kuwait': 'KW',
- 'Kyrgyzstan': 'KG',
- "Lao People's Democratic Republic": 'LA',
- 'Latvia': 'LV',
- 'Lebanon': 'LB',
- 'Lesotho': 'LS',
- 'Liberia': 'LR',
- 'Libyan Arab Jamahiriya': 'LY',
- 'Liechtenstein': 'LI',
- 'Lithuania': 'LT',
- 'Luxembourg': 'LU',
- 'Macau': 'MO',
- 'Macedonia': 'MK',
- 'Madagascar': 'MG',
- 'Malawi': 'MW',
- 'Malaysia': 'MY',
- 'Maldives': 'MV',
- 'Mali': 'ML',
- 'Malta': 'MT',
- 'Marshall Islands': 'MH',
- 'Martinique': 'MQ',
- 'Mauritania': 'MR',
- 'Mauritius': 'MU',
- 'Mayotte': 'YT',
- 'Mexico': 'MX',
- 'Micronesia, Federated States of': 'FM',
- 'Moldova, Republic of': 'MD',
- 'Monaco': 'MC',
- 'Mongolia': 'MN',
- 'Montenegro': 'ME',
- 'Montserrat': 'MS',
- 'Morocco': 'MA',
- 'Mozambique': 'MZ',
- 'Myanmar': 'MM',
- 'Namibia': 'NA',
- 'Nauru': 'NR',
- 'Nepal': 'NP',
- 'Netherlands': 'NL',
- 'New Caledonia': 'NC',
- 'New Zealand': 'NZ',
- 'Nicaragua': 'NI',
- 'Niger': 'NE',
- 'Nigeria': 'NG',
- 'Niue': 'NU',
- 'Norfolk Island': 'NF',
- 'Northern Mariana Islands': 'MP',
- 'Norway': 'NO',
- 'Oman': 'OM',
- 'Pakistan': 'PK',
- 'Palau': 'PW',
- 'Palestinian Territory': 'PS',
- 'Panama': 'PA',
- 'Papua New Guinea': 'PG',
- 'Paraguay': 'PY',
- 'Peru': 'PE',
- 'Philippines': 'PH',
- 'Pitcairn Islands': 'PN',
- 'Poland': 'PL',
- 'Portugal': 'PT',
- 'Puerto Rico': 'PR',
- 'Qatar': 'QA',
- 'Reunion': 'RE',
- 'Romania': 'RO',
- 'Russian Federation': 'RU',
- 'Rwanda': 'RW',
- 'Saint Barthelemy': 'BL',
- 'Saint Helena': 'SH',
- 'Saint Kitts and Nevis': 'KN',
- 'Saint Lucia': 'LC',
- 'Saint Martin': 'MF',
- 'Saint Pierre and Miquelon': 'PM',
- 'Saint Vincent and the Grenadines': 'VC',
- 'Samoa': 'WS',
- 'San Marino': 'SM',
- 'Sao Tome and Principe': 'ST',
- 'Saudi Arabia': 'SA',
- 'Senegal': 'SN',
- 'Serbia': 'RS',
- 'Seychelles': 'SC',
- 'Sierra Leone': 'SL',
- 'Singapore': 'SG',
- 'Sint Maarten (Dutch part)': 'SX',
- 'Slovakia': 'SK',
- 'Slovenia': 'SI',
- 'Solomon Islands': 'SB',
- 'Somalia': 'SO',
- 'South Africa': 'ZA',
- 'South Georgia and the South Sandwich Islands': 'GS',
- 'South Sudan': 'SS',
- 'Spain': 'ES',
- 'Sri Lanka': 'LK',
- 'Sudan': 'SD',
- 'Suriname': 'SR',
- 'Svalbard and Jan Mayen': 'SJ',
- 'Swaziland': 'SZ',
- 'Sweden': 'SE',
- 'Switzerland': 'CH',
- 'Syrian Arab Republic': 'SY',
- 'Taiwan': 'TW',
- 'Tajikistan': 'TJ',
- 'Tanzania, United Republic of': 'TZ',
- 'Thailand': 'TH',
- 'Timor-Leste': 'TL',
- 'Togo': 'TG',
- 'Tokelau': 'TK',
- 'Tonga': 'TO',
- 'Trinidad and Tobago': 'TT',
- 'Tunisia': 'TN',
- 'Turkey': 'TR',
- 'Turkmenistan': 'TM',
- 'Turks and Caicos Islands': 'TC',
- 'Tuvalu': 'TV',
- 'Uganda': 'UG',
- 'Ukraine': 'UA',
- 'United Arab Emirates': 'AE',
- 'United Kingdom': 'GB',
- 'United States': 'US',
- 'United States Minor Outlying Islands': 'UM',
- 'Uruguay': 'UY',
- 'Uzbekistan': 'UZ',
- 'Vanuatu': 'VU',
- 'Venezuela': 'VE',
- 'Vietnam': 'VN',
- 'Virgin Islands, British': 'VG',
- 'Virgin Islands, U.S.': 'VI',
- 'Wallis and Futuna': 'WF',
- 'Western Sahara': 'EH',
- 'Yemen': 'YE',
- 'Zambia': 'ZM',
- 'Zimbabwe': 'ZW',
- 'Unrecognized': 'N/A',
- 'Asia/Pacific Region': 'AP',
- 'Europe': 'EU',
- 'Netherlands Antilles': 'AN',
- 'France, Metropolitan': 'FX',
- 'Anonymous Proxy': 'A1',
- 'Satellite Provider': 'A2',
- 'Other': 'O1',
- }
-
- continents = {
- 'Antarctica': 'AN',
- 'Asia': 'AS',
- 'Africa': 'AF',
- 'Europe': 'EU',
- 'North America': 'NA',
- 'South America': 'SA',
- 'Oceania': 'OC',
- 'Unknown': '--',
- }
-
- @property
- def region_members(self):
- result = list()
- negate = None
- if self._values['region_members'] is None:
- return None
- if isinstance(self._values['region_members'], string_types):
- return self._values['region_members']
- if not isinstance(self._values['region_members'], list):
- raise F5ModuleError(
- 'Region members must be either type of string or list.'
- )
- members = copy.deepcopy(self._values['region_members'])
- for item in members:
- member = self._filter_params(item)
- if 'negate' in member.keys():
- if len(member.keys()) > 2:
- raise F5ModuleError(
- 'You cannot specify negate and more than one option together.'
- )
-
- negate = self._flatten_negate(member)
-
- for key, value in iteritems(member):
- if negate:
- output = self._change_value(key, value)
- item = "{0} {1} {2}".format(negate, output[0], output[1])
- result.append(item)
- negate = None
- else:
- output = self._change_value(key, value)
- item = "{0} {1}".format(output[0], output[1])
- result.append(item)
- return result
-
- def _flatten_negate(self, item):
- result = flatten_boolean(item['negate'])
- item.pop('negate')
- if result == 'yes':
- return 'not'
- return None
-
- def _change_value(self, key, value):
- if key in ['region', 'pool', 'datacenter']:
- return key, fq_name(self.partition, value)
- if key == 'isp':
- return key, fq_name('Common', value)
- if key == 'continent':
- return key, self.continents.get(value, value)
- if key == 'country':
- return key, self.countries.get(value, value)
- if key == 'geo_isp':
- return 'geoip-isp', value
- if key == 'subnet':
- return key, self._test_subnet(value)
- return key, value
-
- def _test_subnet(self, item):
- if item is None:
- return None
- if is_valid_ip_network(item):
- return item
- raise F5ModuleError(
- "Specified 'subnet' is not a valid subnet."
- )
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class UsableChanges(Changes):
- @property
- def region_members(self):
- members = self._values['region_members']
- if members is None:
- return None
- if not members:
- return 'none'
- return ' '.join(members)
-
-
-class ReportableChanges(Changes):
- pass
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
- @property
- def region_members(self):
- return cmp_simple_list(self.want.region_members, self.have.region_members)
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(params=self.module.params)
- self.have = ApiParameters()
- self.changes = UsableChanges()
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = UsableChanges(params=changed)
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.client.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def exec_module(self):
- changed = False
- result = dict()
- state = self.want.state
-
- if state == "present":
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def present(self):
- if self.exists():
- return self.update()
- else:
- return self.create()
-
- def absent(self):
- if self.exists():
- return self.remove()
- return False
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def update(self):
- self.have = self.read_current_from_device()
- if not self.should_update():
- return False
- if self.module.check_mode:
- return True
- self.update_on_device()
- return True
-
- def remove(self):
- if self.module.check_mode:
- return True
- self.remove_from_device()
- if self.exists():
- raise F5ModuleError("Failed to delete the resource.")
- return True
-
- def create(self):
- self._set_changed_options()
- if self.module.check_mode:
- return True
- self.create_on_device()
- return True
-
- def exists(self):
- uri = "https://{0}:{1}/mgmt/tm/gtm/region/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def create_on_device(self):
- if self.changes.region_members:
- command = 'tmsh create gtm region {0} region-members add {{ {1} }} '.format(
- fq_name(self.want.partition, self.want.name),
- self.changes.region_members
- )
- else:
- command = 'tmsh create gtm region {0}'.format(
- fq_name(self.want.partition, self.want.name)
- )
- payload = {
- "command": "run",
- "utilCmdArgs": '-c "{0}"'.format(command)
- }
- uri = "https://{0}:{1}/mgmt/tm/util/bash".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- resp = self.client.api.post(uri, json=payload)
- try:
- response = resp.json()
- if 'commandResult' in response:
- raise F5ModuleError(response['commandResult'])
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return True
-
- def update_on_device(self):
- param = self.changes.region_members
- if param:
- if param != 'none':
- command = 'tmsh modify gtm region {0} region-members replace-all-with {{ {1} }} '.format(
- fq_name(self.want.partition, self.want.name),
- param
- )
- else:
- command = 'tmsh modify gtm region {0} region-members {1} '.format(
- fq_name(self.want.partition, self.want.name),
- param
- )
- else:
- command = 'tmsh create gtm region {0}'.format(
- fq_name(self.want.partition, self.want.name)
- )
-
- payload = {
- "command": "run",
- "utilCmdArgs": '-c "{0}"'.format(command)
- }
-
- uri = "https://{0}:{1}/mgmt/tm/util/bash".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- resp = self.client.api.post(uri, json=payload)
- try:
- response = resp.json()
- if 'commandResult' in response:
- raise F5ModuleError(response['commandResult'])
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def remove_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/gtm/region/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- response = self.client.api.delete(uri)
- if response.status == 200:
- return True
- raise F5ModuleError(response.content)
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/gtm/region/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return ApiParameters(params=response)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- self.choices = [
- 'AOL', 'BeijingCNC', 'CNC', 'ChinaEducationNetwork',
- 'ChinaMobilNetwork', 'ChinaRailwayTelcom', 'ChinaTelecom',
- 'ChinaUnicom', 'Comcast', 'Earthlink', 'ShanghaiCNC',
- 'ShanghaiTelecom',
- ]
- argument_spec = dict(
- name=dict(
- required=True
- ),
- region_members=dict(
- type='list',
- elements='dict',
- options=dict(
- subnet=dict(),
- region=dict(),
- continent=dict(),
- country=dict(),
- state=dict(),
- pool=dict(),
- datacenter=dict(),
- isp=dict(
- choices=self.choices
- ),
- geo_isp=dict(),
- negate=dict(
- type='bool',
- default='no'
- ),
- )
- ),
- partition=dict(
- default='Common',
- fallback=(env_fallback, ['F5_PARTITION'])
- ),
- state=dict(
- default='present',
- choices=['present', 'absent']
- )
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode,
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_gtm_virtual_server.py b/lib/ansible/modules/network/f5/bigip_gtm_virtual_server.py
deleted file mode 100644
index a35b831775..0000000000
--- a/lib/ansible/modules/network/f5/bigip_gtm_virtual_server.py
+++ /dev/null
@@ -1,1196 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['stableinterface'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_gtm_virtual_server
-short_description: Manages F5 BIG-IP GTM virtual servers
-description:
- - Manages F5 BIG-IP GTM virtual servers. A GTM server can have many virtual servers
- associated with it. They are arranged in much the same way that pool members are
- to pools.
-version_added: 2.6
-options:
- name:
- description:
- - Specifies the name of the virtual server.
- type: str
- version_added: 2.6
- server_name:
- description:
- - Specifies the name of the server that the virtual server is associated with.
- type: str
- version_added: 2.6
- address:
- description:
- - Specifies the IP Address of the virtual server.
- - When creating a new GTM virtual server, this parameter is required.
- type: str
- version_added: 2.6
- port:
- description:
- - Specifies the service port number for the virtual server or pool member. For example,
- the HTTP service is typically port 80.
- - To specify all ports, use an C(*).
- - When creating a new GTM virtual server, if this parameter is not specified, a
- default of C(*) will be used.
- type: int
- translation_address:
- description:
- - Specifies the translation IP address for the virtual server.
- - To unset this parameter, provide an empty string (C("")) as a value.
- - When creating a new GTM virtual server, if this parameter is not specified, a
- default of C(::) will be used.
- type: str
- version_added: 2.6
- translation_port:
- description:
- - Specifies the translation port number or service name for the virtual server.
- - To specify all ports, use an C(*).
- - When creating a new GTM virtual server, if this parameter is not specified, a
- default of C(*) will be used.
- type: str
- version_added: 2.6
- availability_requirements:
- description:
- - Specifies, if you activate more than one health monitor, the number of health
- monitors that must receive successful responses in order for the link to be
- considered available.
- type: dict
- suboptions:
- type:
- description:
- - Monitor rule type when C(monitors) is specified.
- - When creating a new virtual, if this value is not specified, the default of 'all' will be used.
- type: str
- choices:
- - all
- - at_least
- - require
- at_least:
- description:
- - Specifies the minimum number of active health monitors that must be successful
- before the link is considered up.
- - This parameter is only relevant when a C(type) of C(at_least) is used.
- - This parameter will be ignored if a type of either C(all) or C(require) is used.
- type: int
- number_of_probes:
- description:
- - Specifies the minimum number of probes that must succeed for this server to be declared up.
- - When creating a new virtual server, if this parameter is specified, then the C(number_of_probers)
- parameter must also be specified.
- - The value of this parameter should always be B(lower) than, or B(equal to), the value of C(number_of_probers).
- - This parameter is only relevant when a C(type) of C(require) is used.
- - This parameter will be ignored if a type of either C(all) or C(at_least) is used.
- type: int
- number_of_probers:
- description:
- - Specifies the number of probers that should be used when running probes.
- - When creating a new virtual server, if this parameter is specified, then the C(number_of_probes)
- parameter must also be specified.
- - The value of this parameter should always be B(higher) than, or B(equal to), the value of C(number_of_probers).
- - This parameter is only relevant when a C(type) of C(require) is used.
- - This parameter will be ignored if a type of either C(all) or C(at_least) is used.
- type: int
- version_added: 2.6
- monitors:
- description:
- - Specifies the health monitors that the system currently uses to monitor this resource.
- - When C(availability_requirements.type) is C(require), you may only have a single monitor in the
- C(monitors) list.
- type: list
- version_added: 2.6
- virtual_server_dependencies:
- description:
- - Specifies the virtual servers on which the current virtual server depends.
- - If any of the specified servers are unavailable, the current virtual server is also listed as unavailable.
- type: list
- suboptions:
- server:
- description:
- - Server which the dependant virtual server is part of.
- type: str
- required: True
- virtual_server:
- description:
- - Virtual server to depend on.
- type: str
- required: True
- version_added: 2.6
- link:
- description:
- - Specifies a link to assign to the server or virtual server.
- type: str
- version_added: 2.6
- limits:
- description:
- - Specifies resource thresholds or limit requirements at the server level.
- - When you enable one or more limit settings, the system then uses that data to take servers in and out
- of service.
- - You can define limits for any or all of the limit settings. However, when a server does not meet the resource
- threshold limit requirement, the system marks the entire server as unavailable and directs load-balancing
- traffic to another resource.
- - The limit settings available depend on the type of server.
- type: dict
- suboptions:
- bits_enabled:
- description:
- - Whether the bits limit is enabled or not.
- - This parameter allows you to switch on or off the effect of the limit.
- type: bool
- packets_enabled:
- description:
- - Whether the packets limit is enabled or not.
- - This parameter allows you to switch on or off the effect of the limit.
- type: bool
- connections_enabled:
- description:
- - Whether the current connections limit is enabled or not.
- - This parameter allows you to switch on or off the effect of the limit.
- type: bool
- bits_limit:
- description:
- - Specifies the maximum allowable data throughput rate, in bits per second, for the virtual servers on the server.
- - If the network traffic volume exceeds this limit, the system marks the server as unavailable.
- type: int
- packets_limit:
- description:
- - Specifies the maximum allowable data transfer rate, in packets per second, for the virtual servers on the server.
- - If the network traffic volume exceeds this limit, the system marks the server as unavailable.
- type: int
- connections_limit:
- description:
- - Specifies the maximum number of concurrent connections, combined, for all of the virtual servers on the server.
- - If the connections exceed this limit, the system marks the server as unavailable.
- type: int
- version_added: 2.6
- partition:
- description:
- - Device partition to manage resources on.
- type: str
- default: Common
- version_added: 2.6
- state:
- description:
- - When C(present), ensures that the resource exists.
- - When C(absent), ensures the resource is removed.
- type: str
- choices:
- - present
- - absent
- - enabled
- - disabled
- default: present
-extends_documentation_fragment: f5
-author:
- - Tim Rupp (@caphrim007)
- - Wojciech Wypior (@wojtek0806)
-'''
-
-EXAMPLES = r'''
-- name: Enable virtual server
- bigip_gtm_virtual_server:
- server_name: server1
- name: my-virtual-server
- state: enabled
- provider:
- user: admin
- password: secret
- server: lb.mydomain.com
- delegate_to: localhost
-'''
-
-RETURN = r'''
-server_name:
- description: The server name associated with the virtual server.
- returned: changed
- type: str
- sample: /Common/my-gtm-server
-address:
- description: The new address of the resource.
- returned: changed
- type: str
- sample: 1.2.3.4
-port:
- description: The new port of the resource.
- returned: changed
- type: int
- sample: 500
-translation_address:
- description: The new translation address of the resource.
- returned: changed
- type: int
- sample: 500
-translation_port:
- description: The new translation port of the resource.
- returned: changed
- type: int
- sample: 500
-availability_requirements:
- description: The new availability requirement configurations for the resource.
- returned: changed
- type: dict
- sample: {'type': 'all'}
-monitors:
- description: The new list of monitors for the resource.
- returned: changed
- type: list
- sample: ['/Common/monitor1', '/Common/monitor2']
-virtual_server_dependencies:
- description: The new list of virtual server dependencies for the resource
- returned: changed
- type: list
- sample: ['/Common/vs1', '/Common/vs2']
-link:
- description: The new link value for the resource.
- returned: changed
- type: str
- sample: /Common/my-link
-limits:
- description: The new limit configurations for the resource.
- returned: changed
- type: dict
- sample: { 'bits_enabled': true, 'bits_limit': 100 }
-'''
-
-import os
-import re
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.basic import env_fallback
-
-try:
- from library.module_utils.compat.ipaddress import ip_address
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import fq_name
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.common import transform_name
- from library.module_utils.network.f5.compare import compare_complex_list
- from library.module_utils.network.f5.icontrol import module_provisioned
- from library.module_utils.network.f5.ipaddress import is_valid_ip
- from library.module_utils.network.f5.ipaddress import validate_ip_v6_address
-except ImportError:
- from ansible.module_utils.compat.ipaddress import ip_address
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import fq_name
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.common import transform_name
- from ansible.module_utils.network.f5.compare import compare_complex_list
- from ansible.module_utils.network.f5.icontrol import module_provisioned
- from ansible.module_utils.network.f5.ipaddress import is_valid_ip
- from ansible.module_utils.network.f5.ipaddress import validate_ip_v6_address
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'limitMaxBps': 'bits_limit',
- 'limitMaxBpsStatus': 'bits_enabled',
- 'limitMaxConnections': 'connections_limit',
- 'limitMaxConnectionsStatus': 'connections_enabled',
- 'limitMaxPps': 'packets_limit',
- 'limitMaxPpsStatus': 'packets_enabled',
- 'translationAddress': 'translation_address',
- 'translationPort': 'translation_port',
- 'dependsOn': 'virtual_server_dependencies',
- 'explicitLinkName': 'link',
- 'monitor': 'monitors'
- }
-
- api_attributes = [
- 'dependsOn',
- 'destination',
- 'disabled',
- 'enabled',
- 'explicitLinkName',
- 'limitMaxBps',
- 'limitMaxBpsStatus',
- 'limitMaxConnections',
- 'limitMaxConnectionsStatus',
- 'limitMaxPps',
- 'limitMaxPpsStatus',
- 'translationAddress',
- 'translationPort',
- 'monitor',
- ]
-
- returnables = [
- 'bits_enabled',
- 'bits_limit',
- 'connections_enabled',
- 'connections_limit',
- 'destination',
- 'disabled',
- 'enabled',
- 'link',
- 'monitors',
- 'packets_enabled',
- 'packets_limit',
- 'translation_address',
- 'translation_port',
- 'virtual_server_dependencies',
- 'availability_requirements',
- ]
-
- updatables = [
- 'bits_enabled',
- 'bits_limit',
- 'connections_enabled',
- 'connections_limit',
- 'destination',
- 'enabled',
- 'link',
- 'monitors',
- 'packets_limit',
- 'packets_enabled',
- 'translation_address',
- 'translation_port',
- 'virtual_server_dependencies',
- ]
-
-
-class ApiParameters(Parameters):
- @property
- def address(self):
- if self._values['destination'].count(':') >= 2:
- # IPv6
- parts = self._values['destination'].split('.')
- else:
- # IPv4
- parts = self._values['destination'].split(':')
- if is_valid_ip(parts[0]):
- return str(parts[0])
- raise F5ModuleError(
- "'address' parameter from API was not an IP address."
- )
-
- @property
- def port(self):
- if self._values['destination'].count(':') >= 2:
- # IPv6
- parts = self._values['destination'].split('.')
- return parts[1]
- # IPv4
- parts = self._values['destination'].split(':')
- return int(parts[1])
-
- @property
- def virtual_server_dependencies(self):
- if self._values['virtual_server_dependencies'] is None:
- return None
- results = []
- for dependency in self._values['virtual_server_dependencies']:
- parts = dependency['name'].split(':')
- result = dict(
- server=parts[0],
- virtual_server=parts[1],
- )
- results.append(result)
- if results:
- results = sorted(results, key=lambda k: k['server'])
- return results
-
- @property
- def enabled(self):
- if 'enabled' in self._values:
- return True
- else:
- return False
-
- @property
- def disabled(self):
- if 'disabled' in self._values:
- return True
- return False
-
- @property
- def availability_requirement_type(self):
- if self._values['monitors'] is None:
- return None
- if 'min ' in self._values['monitors']:
- return 'at_least'
- elif 'require ' in self._values['monitors']:
- return 'require'
- else:
- return 'all'
-
- @property
- def monitors_list(self):
- if self._values['monitors'] is None:
- return []
- try:
- result = re.findall(r'/\w+/[^\s}]+', self._values['monitors'])
- result.sort()
- return result
- except Exception:
- return self._values['monitors']
-
- @property
- def monitors(self):
- if self._values['monitors'] is None:
- return None
- monitors = [fq_name(self.partition, x) for x in self.monitors_list]
- if self.availability_requirement_type == 'at_least':
- monitors = ' '.join(monitors)
- result = 'min {0} of {{ {1} }}'.format(self.at_least, monitors)
- elif self.availability_requirement_type == 'require':
- monitors = ' '.join(monitors)
- result = 'require {0} from {1} {{ {2} }}'.format(self.number_of_probes, self.number_of_probers, monitors)
- else:
- result = ' and '.join(monitors).strip()
-
- return result
-
- @property
- def number_of_probes(self):
- """Returns the probes value from the monitor string.
-
- The monitor string for a Require monitor looks like this.
-
- require 1 from 2 { /Common/tcp }
-
- This method parses out the first of the numeric values. This values represents
- the "probes" value that can be updated in the module.
-
- Returns:
- int: The probes value if found. None otherwise.
- """
- if self._values['monitors'] is None:
- return None
- pattern = r'require\s+(?P<probes>\d+)\s+from'
- matches = re.search(pattern, self._values['monitors'])
- if matches is None:
- return None
- return matches.group('probes')
-
- @property
- def number_of_probers(self):
- """Returns the probers value from the monitor string.
-
- The monitor string for a Require monitor looks like this.
-
- require 1 from 2 { /Common/tcp }
-
- This method parses out the first of the numeric values. This values represents
- the "probers" value that can be updated in the module.
-
- Returns:
- int: The probers value if found. None otherwise.
- """
- if self._values['monitors'] is None:
- return None
- pattern = r'require\s+\d+\s+from\s+(?P<probers>\d+)\s+'
- matches = re.search(pattern, self._values['monitors'])
- if matches is None:
- return None
- return matches.group('probers')
-
- @property
- def at_least(self):
- """Returns the 'at least' value from the monitor string.
-
- The monitor string for a Require monitor looks like this.
-
- min 1 of { /Common/gateway_icmp }
-
- This method parses out the first of the numeric values. This values represents
- the "at_least" value that can be updated in the module.
-
- Returns:
- int: The at_least value if found. None otherwise.
- """
- if self._values['monitors'] is None:
- return None
- pattern = r'min\s+(?P<least>\d+)\s+of\s+'
- matches = re.search(pattern, self._values['monitors'])
- if matches is None:
- return None
- return matches.group('least')
-
-
-class ModuleParameters(Parameters):
- def _get_limit_value(self, type):
- if self._values['limits'] is None:
- return None
- if self._values['limits'][type] is None:
- return None
- return int(self._values['limits'][type])
-
- def _get_availability_value(self, type):
- if self._values['availability_requirements'] is None:
- return None
- if self._values['availability_requirements'][type] is None:
- return None
- return int(self._values['availability_requirements'][type])
-
- def _get_limit_status(self, type):
- if self._values['limits'] is None:
- return None
- if self._values['limits'][type] is None:
- return None
- if self._values['limits'][type]:
- return 'enabled'
- return 'disabled'
-
- @property
- def address(self):
- if self._values['address'] is None:
- return None
- if is_valid_ip(self._values['address']):
- ip = str(ip_address(u'{0}'.format(self._values['address'])))
- return ip
- raise F5ModuleError(
- "Specified 'address' is not an IP address."
- )
-
- @property
- def port(self):
- if self._values['port'] is None:
- return None
- if self._values['port'] == '*':
- return 0
- return int(self._values['port'])
-
- @property
- def destination(self):
- if self.address is None:
- return None
- if self.port is None:
- return None
- if validate_ip_v6_address(self.address):
- result = '{0}.{1}'.format(self.address, self.port)
- else:
- result = '{0}:{1}'.format(self.address, self.port)
- return result
-
- @property
- def link(self):
- if self._values['link'] is None:
- return None
- return fq_name(self.partition, self._values['link'])
-
- @property
- def bits_limit(self):
- return self._get_limit_value('bits_limit')
-
- @property
- def packets_limit(self):
- return self._get_limit_value('packets_limit')
-
- @property
- def connections_limit(self):
- return self._get_limit_value('connections_limit')
-
- @property
- def bits_enabled(self):
- return self._get_limit_status('bits_enabled')
-
- @property
- def packets_enabled(self):
- return self._get_limit_status('packets_enabled')
-
- @property
- def connections_enabled(self):
- return self._get_limit_status('connections_enabled')
-
- @property
- def translation_address(self):
- if self._values['translation_address'] is None:
- return None
- if self._values['translation_address'] == '':
- return 'none'
- return self._values['translation_address']
-
- @property
- def translation_port(self):
- if self._values['translation_port'] is None:
- return None
- if self._values['translation_port'] in ['*', ""]:
- return 0
- return int(self._values['translation_port'])
-
- @property
- def virtual_server_dependencies(self):
- if self._values['virtual_server_dependencies'] is None:
- return None
- results = []
- for dependency in self._values['virtual_server_dependencies']:
- result = dict(
- server=fq_name(self.partition, dependency['server']),
- virtual_server=os.path.basename(dependency['virtual_server'])
- )
- results.append(result)
- if results:
- results = sorted(results, key=lambda k: k['server'])
- return results
-
- @property
- def enabled(self):
- if self._values['state'] == 'enabled':
- return True
- elif self._values['state'] == 'disabled':
- return False
- else:
- return None
-
- @property
- def disabled(self):
- if self._values['state'] == 'enabled':
- return False
- elif self._values['state'] == 'disabled':
- return True
- else:
- return None
-
- @property
- def monitors_list(self):
- if self._values['monitors'] is None:
- return []
- try:
- result = re.findall(r'/\w+/[^\s}]+', self._values['monitors'])
- result.sort()
- return result
- except Exception:
- return self._values['monitors']
-
- @property
- def monitors(self):
- if self._values['monitors'] is None:
- return None
- monitors = [fq_name(self.partition, x) for x in self.monitors_list]
- if self.availability_requirement_type == 'at_least':
- if self.at_least > len(self.monitors_list):
- raise F5ModuleError(
- "The 'at_least' value must not exceed the number of 'monitors'."
- )
- monitors = ' '.join(monitors)
- result = 'min {0} of {{ {1} }}'.format(self.at_least, monitors)
- elif self.availability_requirement_type == 'require':
- monitors = ' '.join(monitors)
- if self.number_of_probes > self.number_of_probers:
- raise F5ModuleError(
- "The 'number_of_probes' must not exceed the 'number_of_probers'."
- )
- result = 'require {0} from {1} {{ {2} }}'.format(self.number_of_probes, self.number_of_probers, monitors)
- else:
- result = ' and '.join(monitors).strip()
-
- return result
-
- @property
- def availability_requirement_type(self):
- if self._values['availability_requirements'] is None:
- return None
- return self._values['availability_requirements']['type']
-
- @property
- def number_of_probes(self):
- return self._get_availability_value('number_of_probes')
-
- @property
- def number_of_probers(self):
- return self._get_availability_value('number_of_probers')
-
- @property
- def at_least(self):
- return self._get_availability_value('at_least')
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class UsableChanges(Changes):
-
- @property
- def virtual_server_dependencies(self):
- if self._values['virtual_server_dependencies'] is None:
- return None
- results = []
- for depend in self._values['virtual_server_dependencies']:
- name = '{0}:{1}'.format(depend['server'], depend['virtual_server'])
- results.append(dict(name=name))
- return results
-
- @property
- def monitors(self):
- monitor_string = self._values['monitors']
- if monitor_string is None:
- return None
-
- if '{' in monitor_string and '}':
- tmp = monitor_string.strip('}').split('{')
- monitor = ''.join(tmp).rstrip()
- return monitor
-
- return monitor_string
-
-
-class ReportableChanges(Changes):
-
- @property
- def monitors(self):
- if self._values['monitors'] is None:
- return []
- try:
- result = re.findall(r'/\w+/[^\s}]+', self._values['monitors'])
- result.sort()
- return result
- except Exception:
- return self._values['monitors']
-
- @property
- def availability_requirement_type(self):
- if self._values['monitors'] is None:
- return None
- if 'min ' in self._values['monitors']:
- return 'at_least'
- elif 'require ' in self._values['monitors']:
- return 'require'
- else:
- return 'all'
-
- @property
- def number_of_probes(self):
- """Returns the probes value from the monitor string.
- The monitor string for a Require monitor looks like this.
- require 1 from 2 { /Common/tcp }
- This method parses out the first of the numeric values. This values represents
- the "probes" value that can be updated in the module.
- Returns:
- int: The probes value if found. None otherwise.
- """
- if self._values['monitors'] is None:
- return None
- pattern = r'require\s+(?P<probes>\d+)\s+from'
- matches = re.search(pattern, self._values['monitors'])
- if matches is None:
- return None
- return int(matches.group('probes'))
-
- @property
- def number_of_probers(self):
- """Returns the probers value from the monitor string.
- The monitor string for a Require monitor looks like this.
- require 1 from 2 { /Common/tcp }
- This method parses out the first of the numeric values. This values represents
- the "probers" value that can be updated in the module.
- Returns:
- int: The probers value if found. None otherwise.
- """
- if self._values['monitors'] is None:
- return None
- pattern = r'require\s+\d+\s+from\s+(?P<probers>\d+)\s+'
- matches = re.search(pattern, self._values['monitors'])
- if matches is None:
- return None
- return int(matches.group('probers'))
-
- @property
- def at_least(self):
- """Returns the 'at least' value from the monitor string.
- The monitor string for a Require monitor looks like this.
- min 1 of { /Common/gateway_icmp }
- This method parses out the first of the numeric values. This values represents
- the "at_least" value that can be updated in the module.
- Returns:
- int: The at_least value if found. None otherwise.
- """
- if self._values['monitors'] is None:
- return None
- pattern = r'min\s+(?P<least>\d+)\s+of\s+'
- matches = re.search(pattern, self._values['monitors'])
- if matches is None:
- return None
- return int(matches.group('least'))
-
- @property
- def availability_requirements(self):
- if self._values['monitors'] is None:
- return None
- result = dict()
- result['type'] = self.availability_requirement_type
- result['at_least'] = self.at_least
- result['number_of_probers'] = self.number_of_probers
- result['number_of_probes'] = self.number_of_probes
- return result
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
- @property
- def destination(self):
- if self.want.port is None:
- self.want.update({'port': self.have.port})
- if self.want.address is None:
- self.want.update({'address': self.have.address})
- if self.want.destination != self.have.destination:
- return self.want.destination
-
- @property
- def virtual_server_dependencies(self):
- if self.have.virtual_server_dependencies is None:
- return self.want.virtual_server_dependencies
- if self.want.virtual_server_dependencies is None and self.have.virtual_server_dependencies is None:
- return None
- if self.want.virtual_server_dependencies is None:
- return None
- result = compare_complex_list(self.want.virtual_server_dependencies, self.have.virtual_server_dependencies)
- return result
-
- @property
- def enabled(self):
- if self.want.state == 'enabled' and self.have.disabled:
- result = dict(
- enabled=True,
- disabled=False
- )
- return result
- elif self.want.state == 'disabled' and self.have.enabled:
- result = dict(
- enabled=False,
- disabled=True
- )
- return result
-
- @property
- def monitors(self):
- if self.have.monitors is None:
- return self.want.monitors
- if self.have.monitors != self.want.monitors:
- return self.want.monitors
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(params=self.module.params)
- self.have = ApiParameters()
- self.changes = UsableChanges()
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = UsableChanges(params=changed)
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def exec_module(self):
- if not module_provisioned(self.client, 'gtm'):
- raise F5ModuleError(
- "GTM must be provisioned to use this module."
- )
- changed = False
- result = dict()
- state = self.want.state
-
- if state in ['present', 'enabled', 'disabled']:
- changed = self.present()
- elif state == 'absent':
- changed = self.absent()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.client.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def present(self):
- if self.exists():
- return self.update()
- else:
- return self.create()
-
- def absent(self):
- if self.exists():
- return self.remove()
- return False
-
- def update(self):
- self.have = self.read_current_from_device()
- if not self.should_update():
- return False
- if self.module.check_mode:
- return True
- self.update_on_device()
- return True
-
- def remove(self):
- if self.module.check_mode:
- return True
- self.remove_from_device()
- if self.exists():
- raise F5ModuleError("Failed to delete the resource.")
- return True
-
- def create(self):
- if self.want.port in [None, ""]:
- self.want.update({'port': '*'})
- if self.want.translation_port in [None, ""]:
- self.want.update({'translation_port': '*'})
- if self.want.translation_address in [None, ""]:
- self.want.update({'translation_address': '::'})
-
- self._set_changed_options()
-
- if self.want.address is None:
- raise F5ModuleError(
- "You must supply an 'address' when creating a new virtual server."
- )
- if self.want.availability_requirement_type == 'require' and len(self.want.monitors_list) > 1:
- raise F5ModuleError(
- "Only one monitor may be specified when using an availability_requirement type of 'require'"
- )
- if self.module.check_mode:
- return True
- self.create_on_device()
- return True
-
- def exists(self):
- uri = "https://{0}:{1}/mgmt/tm/gtm/server/{2}/virtual-servers/{3}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.server_name),
- transform_name(name=self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def create_on_device(self):
- params = self.changes.api_params()
- params['name'] = self.want.name
- params['partition'] = self.want.partition
- uri = "https://{0}:{1}/mgmt/tm/gtm/server/{2}/virtual-servers/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.server_name)
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403, 404]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def update_on_device(self):
- params = self.changes.api_params()
- uri = "https://{0}:{1}/mgmt/tm/gtm/server/{2}/virtual-servers/{3}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.server_name),
- transform_name(name=self.want.name)
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def remove_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/gtm/server/{2}/virtual-servers/{3}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.server_name),
- transform_name(name=self.want.name)
- )
- response = self.client.api.delete(uri)
- if response.status == 200:
- return True
- raise F5ModuleError(response.content)
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/gtm/server/{2}/virtual-servers/{3}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.server_name),
- transform_name(name=self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return ApiParameters(params=response)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- name=dict(required=True),
- server_name=dict(required=True),
- address=dict(),
- port=dict(type='int'),
- translation_address=dict(),
- translation_port=dict(),
- availability_requirements=dict(
- type='dict',
- options=dict(
- type=dict(
- choices=['all', 'at_least', 'require'],
- required=True
- ),
- at_least=dict(type='int'),
- number_of_probes=dict(type='int'),
- number_of_probers=dict(type='int')
- ),
- mutually_exclusive=[
- ['at_least', 'number_of_probes'],
- ['at_least', 'number_of_probers'],
- ],
- required_if=[
- ['type', 'at_least', ['at_least']],
- ['type', 'require', ['number_of_probes', 'number_of_probers']]
- ]
- ),
- monitors=dict(type='list'),
- virtual_server_dependencies=dict(
- type='list',
- options=dict(
- server=dict(required=True),
- virtual_server=dict(required=True)
- )
- ),
- link=dict(),
- limits=dict(
- type='dict',
- options=dict(
- bits_enabled=dict(type='bool'),
- packets_enabled=dict(type='bool'),
- connections_enabled=dict(type='bool'),
- bits_limit=dict(type='int'),
- packets_limit=dict(type='int'),
- connections_limit=dict(type='int')
- )
- ),
- state=dict(
- default='present',
- choices=['present', 'absent', 'disabled', 'enabled']
- ),
- partition=dict(
- default='Common',
- fallback=(env_fallback, ['F5_PARTITION'])
- )
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode,
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_gtm_wide_ip.py b/lib/ansible/modules/network/f5/bigip_gtm_wide_ip.py
deleted file mode 100644
index 6c8ce13ae2..0000000000
--- a/lib/ansible/modules/network/f5/bigip_gtm_wide_ip.py
+++ /dev/null
@@ -1,948 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['stableinterface'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_gtm_wide_ip
-short_description: Manages F5 BIG-IP GTM wide ip
-description:
- - Manages F5 BIG-IP GTM wide ip.
-version_added: 2.0
-options:
- pool_lb_method:
- description:
- - Specifies the load balancing method used to select a pool in this wide
- IP. This setting is relevant only when multiple pools are configured
- for a wide IP.
- type: str
- required: True
- aliases: ['lb_method']
- choices:
- - round-robin
- - ratio
- - topology
- - global-availability
- version_added: 2.5
- name:
- description:
- - Wide IP name. This name must be formatted as a fully qualified
- domain name (FQDN). You can also use the alias C(wide_ip) but this
- is deprecated and will be removed in a future Ansible version.
- type: str
- required: True
- aliases:
- - wide_ip
- type:
- description:
- - Specifies the type of wide IP. GTM wide IPs need to be keyed by query
- type in addition to name, since pool members need different attributes
- depending on the response RDATA they are meant to supply. This value
- is required if you are using BIG-IP versions >= 12.0.0.
- type: str
- choices:
- - a
- - aaaa
- - cname
- - mx
- - naptr
- - srv
- version_added: 2.4
- state:
- description:
- - When C(present) or C(enabled), ensures that the Wide IP exists and
- is enabled.
- - When C(absent), ensures that the Wide IP has been removed.
- - When C(disabled), ensures that the Wide IP exists and is disabled.
- type: str
- choices:
- - present
- - absent
- - disabled
- - enabled
- default: present
- version_added: 2.4
- partition:
- description:
- - Device partition to manage resources on.
- type: str
- default: Common
- version_added: 2.5
- pools:
- description:
- - The pools that you want associated with the Wide IP.
- - If C(ratio) is not provided when creating a new Wide IP, it will default
- to 1.
- type: list
- suboptions:
- name:
- description:
- - The name of the pool to include.
- type: str
- required: True
- ratio:
- description:
- - Ratio for the pool.
- - The system uses this number with the Ratio load balancing method.
- type: int
- version_added: 2.5
- irules:
- description:
- - List of rules to be applied.
- - If you want to remove all existing iRules, specify a single empty value; C("").
- See the documentation for an example.
- type: list
- version_added: 2.6
- aliases:
- description:
- - Specifies alternate domain names for the web site content you are load
- balancing.
- - You can use the same wildcard characters for aliases as you can for actual
- wide IP names.
- type: list
- version_added: 2.7
- last_resort_pool:
- description:
- - Specifies which GTM pool, for the system to use as the last resort pool for
- the wide IP.
- - The valid pools for this parameter are those with the C(type) specified in this
- module.
- type: str
- version_added: 2.8
-notes:
- - Support for TMOS versions below v12.x has been deprecated for this module, and will be removed in Ansible 2.12.
-extends_documentation_fragment: f5
-author:
- - Tim Rupp (@caphrim007)
- - Wojciech Wypior (@wojtek0806)
-'''
-
-EXAMPLES = r'''
-- name: Set lb method
- bigip_gtm_wide_ip:
- pool_lb_method: round-robin
- name: my-wide-ip.example.com
- provider:
- user: admin
- password: secret
- server: lb.mydomain.com
- delegate_to: localhost
-
-- name: Add iRules to the Wide IP
- bigip_gtm_wide_ip:
- pool_lb_method: round-robin
- name: my-wide-ip.example.com
- irules:
- - irule1
- - irule2
- provider:
- user: admin
- password: secret
- server: lb.mydomain.com
- delegate_to: localhost
-
-- name: Remove one iRule from the Virtual Server
- bigip_gtm_wide_ip:
- pool_lb_method: round-robin
- name: my-wide-ip.example.com
- irules:
- - irule1
- provider:
- user: admin
- password: secret
- server: lb.mydomain.com
- delegate_to: localhost
-
-- name: Remove all iRules from the Virtual Server
- bigip_gtm_wide_ip:
- pool_lb_method: round-robin
- name: my-wide-ip.example.com
- irules: ""
- provider:
- user: admin
- password: secret
- server: lb.mydomain.com
- delegate_to: localhost
-
-- name: Assign a pool with ratio to the Wide IP
- bigip_gtm_wide_ip:
- pool_lb_method: round-robin
- name: my-wide-ip.example.com
- pools:
- - name: pool1
- ratio: 100
- provider:
- user: admin
- password: secret
- server: lb.mydomain.com
- delegate_to: localhost
-'''
-
-RETURN = r'''
-lb_method:
- description: The new load balancing method used by the wide IP.
- returned: changed
- type: str
- sample: topology
-state:
- description: The new state of the wide IP.
- returned: changed
- type: str
- sample: disabled
-irules:
- description: iRules set on the Wide IP.
- returned: changed
- type: list
- sample: ['/Common/irule1', '/Common/irule2']
-aliases:
- description: Aliases set on the Wide IP.
- returned: changed
- type: list
- sample: ['alias1.foo.com', '*.wildcard.domain']
-'''
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.basic import env_fallback
-from ansible.module_utils.six import iteritems
-from distutils.version import LooseVersion
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import fq_name
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.common import transform_name
- from library.module_utils.network.f5.common import is_valid_fqdn
- from library.module_utils.network.f5.icontrol import tmos_version
- from library.module_utils.network.f5.icontrol import module_provisioned
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import fq_name
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.common import transform_name
- from ansible.module_utils.network.f5.common import is_valid_fqdn
- from ansible.module_utils.network.f5.icontrol import tmos_version
- from ansible.module_utils.network.f5.icontrol import module_provisioned
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'poolLbMode': 'pool_lb_method',
- 'rules': 'irules',
- 'lastResortPool': 'last_resort_pool',
- }
-
- updatables = [
- 'pool_lb_method',
- 'state',
- 'pools',
- 'irules',
- 'enabled',
- 'disabled',
- 'aliases',
- 'last_resort_pool',
- ]
-
- returnables = [
- 'name',
- 'pool_lb_method',
- 'state',
- 'pools',
- 'irules',
- 'aliases',
- 'last_resort_pool',
- ]
-
- api_attributes = [
- 'poolLbMode',
- 'enabled',
- 'disabled',
- 'pools',
- 'rules',
- 'aliases',
- 'lastResortPool',
- ]
-
-
-class ApiParameters(Parameters):
- @property
- def disabled(self):
- if self._values['disabled'] is True:
- return True
- return False
-
- @property
- def enabled(self):
- if self._values['enabled'] is True:
- return True
- return False
-
- @property
- def pools(self):
- result = []
- if self._values['pools'] is None:
- return []
- pools = sorted(self._values['pools'], key=lambda x: x['order'])
- for item in pools:
- pool = dict()
- pool.update(item)
- name = '/{0}/{1}'.format(item['partition'], item['name'])
- del pool['nameReference']
- del pool['order']
- del pool['name']
- del pool['partition']
- pool['name'] = name
- result.append(pool)
- return result
-
- @property
- def last_resort_pool(self):
- if self._values['last_resort_pool'] in [None, '', 'none']:
- return ''
- return self._values['last_resort_pool']
-
-
-class ModuleParameters(Parameters):
- @property
- def last_resort_pool(self):
- if self._values['last_resort_pool'] in [None, '', 'none']:
- return ''
- return '{0} {1}'.format(
- self.type, fq_name(self.partition, self._values['last_resort_pool'])
- )
-
- @property
- def pool_lb_method(self):
- if self._values['pool_lb_method'] is None:
- return None
- lb_method = str(self._values['pool_lb_method'])
- return lb_method
-
- @property
- def type(self):
- if self._values['type'] is None:
- return None
- return str(self._values['type'])
-
- @property
- def name(self):
- if self._values['name'] is None:
- return None
- if not is_valid_fqdn(self._values['name']):
- raise F5ModuleError(
- "The provided name must be a valid FQDN"
- )
- return self._values['name']
-
- @property
- def state(self):
- if self._values['state'] == 'enabled':
- return 'present'
- return self._values['state']
-
- @property
- def enabled(self):
- if self._values['state'] == 'disabled':
- return False
- elif self._values['state'] in ['present', 'enabled']:
- return True
- else:
- return None
-
- @property
- def disabled(self):
- if self._values['state'] == 'disabled':
- return True
- elif self._values['state'] in ['present', 'enabled']:
- return False
- else:
- return None
-
- @property
- def pools(self):
- result = []
- if self._values['pools'] is None:
- return None
- for item in self._values['pools']:
- pool = dict()
- if 'name' not in item:
- raise F5ModuleError(
- "'name' is a required key for items in the list of pools."
- )
- if 'ratio' in item:
- pool['ratio'] = item['ratio']
- pool['name'] = fq_name(self.partition, item['name'])
- result.append(pool)
- return result
-
- @property
- def irules(self):
- results = []
- if self._values['irules'] is None:
- return None
- if len(self._values['irules']) == 1 and self._values['irules'][0] == '':
- return ''
- for irule in self._values['irules']:
- result = fq_name(self.partition, irule)
- results.append(result)
- return results
-
- @property
- def aliases(self):
- if self._values['aliases'] is None:
- return None
- if len(self._values['aliases']) == 1 and self._values['aliases'][0] == '':
- return ''
- self._values['aliases'].sort()
- return self._values['aliases']
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- change = getattr(self, returnable)
- if isinstance(change, dict):
- result.update(change)
- else:
- result[returnable] = change
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class UsableChanges(Changes):
- @property
- def irules(self):
- if self._values['irules'] is None:
- return None
- if self._values['irules'] == '':
- return []
- return self._values['irules']
-
-
-class ReportableChanges(Changes):
- @property
- def pool_lb_method(self):
- result = dict(
- lb_method=self._values['pool_lb_method'],
- pool_lb_method=self._values['pool_lb_method'],
- )
- return result
-
- @property
- def last_resort_pool(self):
- if self._values['last_resort_pool'] is None:
- return None
- if self._values['last_resort_pool'] in ['', 'none']:
- return 'none'
- return self._values['last_resort_pool'].split(' ')[1]
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
- def to_tuple(self, items):
- result = []
- for x in items:
- tmp = [(str(k), str(v)) for k, v in iteritems(x)]
- result += tmp
- return result
-
- def _diff_complex_items(self, want, have):
- if want == [] and have is None:
- return None
- if want is None:
- return None
- w = self.to_tuple(want)
- h = self.to_tuple(have)
- if set(w).issubset(set(h)):
- return None
- else:
- return want
-
- @property
- def last_resort_pool(self):
- if self.want.last_resort_pool is None:
- return None
- if self.want.last_resort_pool == '' and self.have.last_resort_pool == '':
- return None
- if self.want.last_resort_pool != self.have.last_resort_pool:
- return self.want.last_resort_pool
-
- @property
- def state(self):
- if self.want.state == 'disabled' and self.have.enabled:
- return self.want.state
- elif self.want.state in ['present', 'enabled'] and self.have.disabled:
- return self.want.state
-
- @property
- def pools(self):
- result = self._diff_complex_items(self.want.pools, self.have.pools)
- return result
-
- @property
- def irules(self):
- if self.want.irules is None:
- return None
- if self.want.irules == '' and self.have.irules is None:
- return None
- if self.want.irules == '' and len(self.have.irules) > 0:
- return []
- if sorted(set(self.want.irules)) != sorted(set(self.have.irules)):
- return self.want.irules
-
- @property
- def aliases(self):
- if self.want.aliases is None:
- return None
- if self.want.aliases == '' and self.have.aliases is None:
- return None
- if self.want.aliases == '' and len(self.have.aliases) > 0:
- return []
- if self.have.aliases is None:
- return self.want.aliases
- if set(self.want.aliases) != set(self.have.aliases):
- return self.want.aliases
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.kwargs = kwargs
-
- def exec_module(self):
- if not module_provisioned(self.client, 'gtm'):
- raise F5ModuleError(
- "GTM must be provisioned to use this module."
- )
- if self.version_is_less_than_12():
- manager = self.get_manager('untyped')
- else:
- manager = self.get_manager('typed')
- return manager.exec_module()
-
- def get_manager(self, type):
- if type == 'typed':
- return TypedManager(**self.kwargs)
- elif type == 'untyped':
- return UntypedManager(**self.kwargs)
-
- def version_is_less_than_12(self):
- version = tmos_version(self.client)
- if LooseVersion(version) < LooseVersion('12.0.0'):
- return True
- else:
- return False
-
-
-class BaseManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(params=self.module.params)
- self.have = ApiParameters()
- self.changes = UsableChanges()
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = UsableChanges(params=changed)
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def exec_module(self):
- changed = False
- result = dict()
- state = self.want.state
-
- if state in ["present", "disabled"]:
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- if self.version_is_less_than_12():
- self._deprecate_v11(warnings)
- for warning in warnings:
- self.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def version_is_less_than_12(self):
- version = tmos_version(self.client)
- if LooseVersion(version) < LooseVersion('12.0.0'):
- return True
- else:
- return False
-
- def _deprecate_v11(self, result):
- result.append(
- dict(
- msg='The support for this TMOS version is deprecated.',
- version='2.12'
- )
- )
-
- def present(self):
- if self.exists():
- return self.update()
- else:
- return self.create()
-
- def create(self):
- if self.want.pool_lb_method is None:
- raise F5ModuleError(
- "The 'pool_lb_method' option is required when state is 'present'"
- )
- self._set_changed_options()
- if self.module.check_mode:
- return True
- self.create_on_device()
- return True
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def update(self):
- self.have = self.read_current_from_device()
- if not self.should_update():
- return False
- if self.module.check_mode:
- return True
- self.update_on_device()
- return True
-
- def absent(self):
- if self.exists():
- return self.remove()
- return False
-
- def remove(self):
- if self.module.check_mode:
- return True
- self.remove_from_device()
- if self.exists():
- raise F5ModuleError("Failed to delete the Wide IP")
- return True
-
-
-class UntypedManager(BaseManager):
- def exists(self):
- uri = "https://{0}:{1}/mgmt/tm/gtm/wideip/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def update_on_device(self):
- params = self.changes.api_params()
- uri = "https://{0}:{1}/mgmt/tm/gtm/wideip/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/gtm/wideip/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return ApiParameters(params=response)
-
- def create_on_device(self):
- params = self.changes.api_params()
- params['name'] = self.want.name
- params['partition'] = self.want.partition
- uri = "https://{0}:{1}/mgmt/tm/gtm/wideip/".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return response['selfLink']
-
- def remove_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/gtm/wideip/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- response = self.client.api.delete(uri)
- if response.status == 200:
- return True
- raise F5ModuleError(response.content)
-
-
-class TypedManager(BaseManager):
- def __init__(self, *args, **kwargs):
- super(TypedManager, self).__init__(**kwargs)
- if self.want.type is None:
- raise F5ModuleError(
- "The 'type' option is required for BIG-IP instances "
- "greater than or equal to 12.x"
- )
-
- def exists(self):
- uri = "https://{0}:{1}/mgmt/tm/gtm/wideip/{2}/{3}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- self.want.type,
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def update_on_device(self):
- params = self.changes.api_params()
- uri = "https://{0}:{1}/mgmt/tm/gtm/wideip/{2}/{3}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- self.want.type,
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/gtm/wideip/{2}/{3}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- self.want.type,
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return ApiParameters(params=response)
-
- def create_on_device(self):
- params = self.changes.api_params()
- params['name'] = self.want.name
- params['partition'] = self.want.partition
- uri = "https://{0}:{1}/mgmt/tm/gtm/wideip/{2}/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- self.want.type
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return response['selfLink']
-
- def remove_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/gtm/wideip/{2}/{3}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- self.want.type,
- transform_name(self.want.partition, self.want.name)
- )
- response = self.client.api.delete(uri)
- if response.status == 200:
- return True
- raise F5ModuleError(response.content)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- lb_method_choices = [
- 'round-robin', 'topology', 'ratio', 'global-availability',
- ]
- self.supports_check_mode = True
- argument_spec = dict(
- pool_lb_method=dict(
- choices=lb_method_choices,
- aliases=['lb_method']
- ),
- name=dict(
- required=True,
- aliases=['wide_ip']
- ),
- type=dict(
- choices=[
- 'a', 'aaaa', 'cname', 'mx', 'naptr', 'srv'
- ]
- ),
- state=dict(
- default='present',
- choices=['absent', 'present', 'enabled', 'disabled']
- ),
- pools=dict(
- type='list',
- options=dict(
- name=dict(required=True),
- ratio=dict(type='int')
- )
- ),
- partition=dict(
- default='Common',
- fallback=(env_fallback, ['F5_PARTITION'])
- ),
- irules=dict(
- type='list',
- ),
- aliases=dict(
- type='list'
- ),
- last_resort_pool=dict(),
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode,
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_hostname.py b/lib/ansible/modules/network/f5/bigip_hostname.py
deleted file mode 100644
index 439528944e..0000000000
--- a/lib/ansible/modules/network/f5/bigip_hostname.py
+++ /dev/null
@@ -1,308 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['stableinterface'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_hostname
-short_description: Manage the hostname of a BIG-IP
-description:
- - Manage the hostname of a BIG-IP.
-version_added: 2.3
-options:
- hostname:
- description:
- - Hostname of the BIG-IP host.
- type: str
- required: True
-extends_documentation_fragment: f5
-author:
- - Tim Rupp (@caphrim007)
- - Matthew Lam (@mryanlam)
- - Wojciech Wypior (@wojtek0806)
-'''
-
-EXAMPLES = r'''
-- name: Set the hostname of the BIG-IP
- bigip_hostname:
- hostname: bigip.localhost.localdomain
- provider:
- user: admin
- password: secret
- server: lb.mydomain.com
- delegate_to: localhost
-'''
-
-RETURN = r'''
-hostname:
- description: The new hostname of the device
- returned: changed
- type: str
- sample: big-ip01.internal
-'''
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import f5_argument_spec
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import f5_argument_spec
-
-
-class Parameters(AnsibleF5Parameters):
- api_attributes = ['hostname']
- updatables = ['hostname']
- returnables = ['hostname']
-
- def to_return(self):
- result = {}
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- return result
-
- @property
- def hostname(self):
- if self._values['hostname'] is None:
- return None
- return str(self._values['hostname'])
-
-
-class ApiParameters(Parameters):
- pass
-
-
-class ModuleParameters(Parameters):
- pass
-
-
-class Changes(Parameters):
- pass
-
-
-class UsableChanges(Changes):
- pass
-
-
-class ReportableChanges(Changes):
- pass
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.have = ApiParameters()
- self.want = ModuleParameters(params=self.module.params)
- self.changes = UsableChanges()
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = UsableChanges(params=changed)
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def exec_module(self):
- result = dict()
-
- changed = self.update()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def _read_global_settings_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/sys/global-settings/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return response
-
- def read_current_from_device(self):
- result = self._read_global_settings_from_device()
- uri = "https://{0}:{1}/mgmt/tm/cm/device/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- self_device = next((x['name'] for x in response['items'] if x['selfDevice'] == "true"), None)
- result['self_device'] = self_device
-
- return ApiParameters(params=result)
-
- def update(self):
- self.have = self.read_current_from_device()
- if not self.should_update():
- return False
- if self.module.check_mode:
- return True
- self.update_on_device()
- return True
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def update_on_device(self):
- params = self.want.api_params()
- uri = "https://{0}:{1}/mgmt/tm/sys/global-settings/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- if self.have.self_device:
- uri = "https://{0}:{1}/mgmt/tm/cm/device".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- args = dict(
- command='mv',
- name=self.have.self_device,
- target=self.want.hostname
- )
- resp = self.client.api.post(uri, json=args)
-
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- hostname=dict(
- required=True
- )
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_iapp_service.py b/lib/ansible/modules/network/f5/bigip_iapp_service.py
deleted file mode 100644
index 4bd560b8a6..0000000000
--- a/lib/ansible/modules/network/f5/bigip_iapp_service.py
+++ /dev/null
@@ -1,994 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['stableinterface'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_iapp_service
-short_description: Manages TCL iApp services on a BIG-IP
-description:
- - Manages TCL iApp services on a BIG-IP.
- - If you are looking for the API that is communicated with on the BIG-IP,
- the one the is used is C(/mgmt/tm/sys/application/service/).
-version_added: 2.4
-options:
- name:
- description:
- - The name of the iApp service that you want to deploy.
- type: str
- required: True
- template:
- description:
- - The iApp template from which to instantiate a new service. This
- template must exist on your BIG-IP before you can successfully
- create a service.
- - When creating a new service, this parameter is required.
- type: str
- parameters:
- description:
- - A hash of all the required template variables for the iApp template.
- If your parameters are stored in a file (the more common scenario)
- it is recommended you use either the C(file) or C(template) lookups
- to supply the expected parameters.
- - These parameters typically consist of the C(lists), C(tables), and
- C(variables) fields.
- type: dict
- force:
- description:
- - Forces the updating of an iApp service even if the parameters to the
- service have not changed. This option is of particular importance if
- the iApp template that underlies the service has been updated in-place.
- This option is equivalent to re-configuring the iApp if that template
- has changed.
- type: bool
- default: no
- state:
- description:
- - When C(present), ensures that the iApp service is created and running.
- When C(absent), ensures that the iApp service has been removed.
- type: str
- choices:
- - present
- - absent
- default: present
- partition:
- description:
- - Device partition to manage resources on.
- type: str
- default: Common
- version_added: 2.5
- strict_updates:
- description:
- - Indicates whether the application service is tied to the template,
- so when the template is updated, the application service changes to
- reflect the updates.
- - When C(yes), disallows any updates to the resources that the iApp
- service has created, if they are not updated directly through the
- iApp.
- - When C(no), allows updates outside of the iApp.
- - If this option is specified in the Ansible task, it will take precedence
- over any similar setting in the iApp Service payload that you provide in
- the C(parameters) field.
- type: bool
- default: yes
- version_added: 2.5
- traffic_group:
- description:
- - The traffic group for the iApp service. When creating a new service, if
- this value is not specified, the default of C(/Common/traffic-group-1)
- will be used.
- - If this option is specified in the Ansible task, it will take precedence
- over any similar setting in the iApp Service payload that you provide in
- the C(parameters) field.
- type: str
- version_added: 2.5
- metadata:
- description:
- - Metadata associated with the iApp service.
- - If this option is specified in the Ansible task, it will take precedence
- over any similar setting in the iApp Service payload that you provide in
- the C(parameters) field.
- type: list
- version_added: 2.7
- description:
- description:
- - Description of the iApp service.
- - If this option is specified in the Ansible task, it will take precedence
- over any similar setting in the iApp Service payload that you provide in
- the C(parameters) field.
- type: str
- version_added: 2.7
- device_group:
- description:
- - The device group for the iApp service.
- - If this option is specified in the Ansible task, it will take precedence
- over any similar setting in the iApp Service payload that you provide in
- the C(parameters) field.
- type: str
- version_added: 2.7
-extends_documentation_fragment: f5
-author:
- - Tim Rupp (@caphrim007)
- - Wojciech Wypior (@wojtek0806)
-'''
-
-EXAMPLES = r'''
-- name: Create HTTP iApp service from iApp template
- bigip_iapp_service:
- name: foo-service
- template: f5.http
- parameters: "{{ lookup('file', 'f5.http.parameters.json') }}"
- state: present
- provider:
- user: admin
- password: secret
- server: lb.mydomain.com
- delegate_to: localhost
-
-- name: Upgrade foo-service to v1.2.0rc4 of the f5.http template
- bigip_iapp_service:
- name: foo-service
- template: f5.http.v1.2.0rc4
- state: present
- provider:
- user: admin
- password: secret
- server: lb.mydomain.com
- delegate_to: localhost
-
-- name: Configure a service using parameters in YAML
- bigip_iapp_service:
- name: tests
- template: web_frontends
- state: present
- parameters:
- variables:
- - name: var__vs_address
- value: 1.1.1.1
- - name: pm__apache_servers_for_http
- value: 2.2.2.1:80
- - name: pm__apache_servers_for_https
- value: 2.2.2.2:80
- provider:
- user: admin
- password: secret
- server: lb.mydomain.com
- delegate_to: localhost
-
-- name: Re-configure a service whose underlying iApp was updated in place
- bigip_iapp_service:
- name: tests
- template: web_frontends
- force: yes
- state: present
- parameters:
- variables:
- - name: var__vs_address
- value: 1.1.1.1
- - name: pm__apache_servers_for_http
- value: 2.2.2.1:80
- - name: pm__apache_servers_for_https
- value: 2.2.2.2:80
- provider:
- user: admin
- password: secret
- server: lb.mydomain.com
- delegate_to: localhost
-
-- name: Try to remove the iApp template before the associated Service is removed
- bigip_iapp_template:
- name: web_frontends
- state: absent
- provider:
- user: admin
- password: secret
- server: lb.mydomain.com
- register: result
- failed_when:
- - result is not success
- - "'referenced by one or more applications' not in result.msg"
-
-- name: Configure a service using more complicated parameters
- bigip_iapp_service:
- name: tests
- template: web_frontends
- state: present
- provider:
- user: admin
- password: secret
- server: lb.mydomain.com
- parameters:
- variables:
- - name: var__vs_address
- value: 1.1.1.1
- - name: pm__apache_servers_for_http
- value: 2.2.2.1:80
- - name: pm__apache_servers_for_https
- value: 2.2.2.2:80
- lists:
- - name: irules__irules
- value:
- - foo
- - bar
- tables:
- - name: basic__snatpool_members
- - name: net__snatpool_members
- - name: optimizations__hosts
- - name: pool__hosts
- columnNames:
- - name
- rows:
- - row:
- - internal.company.bar
- - name: pool__members
- columnNames:
- - addr
- - port
- - connection_limit
- rows:
- - row:
- - "none"
- - 80
- - 0
- - name: server_pools__servers
- delegate_to: localhost
-
-- name: Override metadata that may or may not exist in parameters
- bigip_iapp_service:
- name: foo-service
- template: f5.http
- parameters: "{{ lookup('file', 'f5.http.parameters.json') }}"
- metadata:
- - persist: yes
- name: data 1
- - persist: yes
- name: data 2
- state: present
- provider:
- user: admin
- password: secret
- server: lb.mydomain.com
- delegate_to: localhost
-'''
-
-RETURN = r'''
-# only common fields returned
-'''
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.basic import env_fallback
-from ansible.module_utils.six import iteritems
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import fq_name
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.common import transform_name
- from library.module_utils.network.f5.common import flatten_boolean
- from library.module_utils.network.f5.urls import build_service_uri
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import fq_name
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.common import transform_name
- from ansible.module_utils.network.f5.common import flatten_boolean
- from ansible.module_utils.network.f5.urls import build_service_uri
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'strictUpdates': 'strict_updates',
- 'trafficGroup': 'traffic_group',
- 'deviceGroup': 'device_group',
- }
-
- returnables = [
- 'tables',
- 'variables',
- 'lists',
- 'strict_updates',
- 'traffic_group',
- 'device_group',
- 'metadata',
- 'template',
- 'description',
- ]
-
- api_attributes = [
- 'tables',
- 'variables',
- 'template',
- 'lists',
- 'deviceGroup',
- 'inheritedDevicegroup',
- 'inheritedTrafficGroup',
- 'trafficGroup',
- 'strictUpdates',
- # 'metadata',
- 'description',
- ]
-
- updatables = [
- 'tables',
- 'variables',
- 'lists',
- 'strict_updates',
- 'device_group',
- 'traffic_group',
- 'metadata',
- 'description',
- ]
-
- def to_return(self):
- result = {}
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- return result
-
- def normalize_tables(self, tables):
- result = []
- for table in tables:
- tmp = dict()
- name = table.get('name', None)
- if name is None:
- raise F5ModuleError(
- "One of the provided tables does not have a name"
- )
- tmp['name'] = str(name)
- columns = table.get('columnNames', None)
- if columns:
- tmp['columnNames'] = [str(x) for x in columns]
- # You cannot have rows without columns
- rows = table.get('rows', None)
- if rows:
- tmp['rows'] = []
- for row in rows:
- tmp['rows'].append(dict(row=[str(x) for x in row['row']]))
- result.append(tmp)
- result = sorted(result, key=lambda k: k['name'])
- return result
-
- def normalize_variables(self, variables):
- result = []
- for variable in variables:
- tmp = dict((str(k), str(v)) for k, v in iteritems(variable))
- if 'encrypted' not in tmp:
- # BIG-IP will inject an 'encrypted' key if you don't provide one.
- # If you don't provide one, then we give you the default 'no', by
- # default.
- tmp['encrypted'] = 'no'
- if 'value' not in tmp:
- tmp['value'] = ''
-
- # This seems to happen only on 12.0.0
- elif tmp['value'] == 'none':
- tmp['value'] = ''
- elif tmp['value'] == 'True':
- tmp['value'] = 'yes'
- elif tmp['value'] == 'False':
- tmp['value'] = 'no'
- elif isinstance(tmp['value'], bool):
- if tmp['value'] is True:
- tmp['value'] = 'yes'
- else:
- tmp['value'] = 'no'
-
- if tmp['encrypted'] == 'True':
- tmp['encrypted'] = 'yes'
- elif tmp['encrypted'] == 'False':
- tmp['encrypted'] = 'no'
- elif isinstance(tmp['encrypted'], bool):
- if tmp['encrypted'] is True:
- tmp['encrypted'] = 'yes'
- else:
- tmp['encrypted'] = 'no'
-
- result.append(tmp)
- result = sorted(result, key=lambda k: k['name'])
- return result
-
- def normalize_list(self, lists):
- result = []
- for list in lists:
- tmp = dict((str(k), str(v)) for k, v in iteritems(list) if k != 'value')
- if 'encrypted' not in list:
- # BIG-IP will inject an 'encrypted' key if you don't provide one.
- # If you don't provide one, then we give you the default 'no', by
- # default.
- tmp['encrypted'] = 'no'
- if 'value' in list:
- if len(list['value']) > 0:
- # BIG-IP removes empty values entries, so mimic this behavior
- # for user-supplied values.
- tmp['value'] = [str(x) for x in list['value']]
-
- if tmp['encrypted'] == 'True':
- tmp['encrypted'] = 'yes'
- elif tmp['encrypted'] == 'False':
- tmp['encrypted'] = 'no'
- elif isinstance(tmp['encrypted'], bool):
- if tmp['encrypted'] is True:
- tmp['encrypted'] = 'yes'
- else:
- tmp['encrypted'] = 'no'
-
- result.append(tmp)
- result = sorted(result, key=lambda k: k['name'])
- return result
-
- def normalize_metadata(self, metadata):
- result = []
- for item in metadata:
- name = item.get('name', None)
- persist = flatten_boolean(item.get('persist', "no"))
- if persist == "yes":
- persist = "true"
- else:
- persist = "false"
- result.append({
- "name": name,
- "persist": persist
- })
- return result
-
-
-class ApiParameters(Parameters):
- @property
- def metadata(self):
- if self._values['metadata'] is None:
- return None
- return self._values['metadata']
-
- @property
- def tables(self):
- if self._values['tables'] is None:
- return None
- return self.normalize_tables(self._values['tables'])
-
- @property
- def lists(self):
- if self._values['lists'] is None:
- return None
- return self.normalize_list(self._values['lists'])
-
- @property
- def variables(self):
- if self._values['variables'] is None:
- return None
- return self.normalize_variables(self._values['variables'])
-
- @property
- def device_group(self):
- if self._values['device_group'] in [None, 'none']:
- return None
- return self._values['device_group']
-
-
-class ModuleParameters(Parameters):
- @property
- def param_lists(self):
- if self._values['parameters'] is None:
- return None
- result = self._values['parameters'].get('lists', None)
- return result
-
- @property
- def param_tables(self):
- if self._values['parameters'] is None:
- return None
- result = self._values['parameters'].get('tables', None)
- return result
-
- @property
- def param_variables(self):
- if self._values['parameters'] is None:
- return None
- result = self._values['parameters'].get('variables', None)
- return result
-
- @property
- def param_metadata(self):
- if self._values['parameters'] is None:
- return None
- result = self._values['parameters'].get('metadata', None)
- return result
-
- @property
- def param_description(self):
- if self._values['parameters'] is None:
- return None
- result = self._values['parameters'].get('description', None)
- return result
-
- @property
- def param_traffic_group(self):
- if self._values['parameters'] is None:
- return None
- result = self._values['parameters'].get('trafficGroup', None)
- if not result:
- return result
- return fq_name(self.partition, result)
-
- @property
- def param_device_group(self):
- if self._values['parameters'] is None:
- return None
- result = self._values['parameters'].get('deviceGroup', None)
- if not result:
- return result
- return fq_name(self.partition, result)
-
- @property
- def param_strict_updates(self):
- if self._values['parameters'] is None:
- return None
- result = self._values['parameters'].get('strictUpdates', None)
- return flatten_boolean(result)
-
- @property
- def tables(self):
- if self._values['tables']:
- return self.normalize_tables(self._values['tables'])
- elif self.param_tables:
- return self.normalize_tables(self.param_tables)
- return None
-
- @property
- def lists(self):
- if self._values['lists']:
- return self.normalize_list(self._values['lists'])
- elif self.param_lists:
- return self.normalize_list(self.param_lists)
- return None
-
- @property
- def variables(self):
- if self._values['variables']:
- return self.normalize_variables(self._values['variables'])
- elif self.param_variables:
- return self.normalize_variables(self.param_variables)
- return None
-
- @property
- def metadata(self):
- if self._values['metadata']:
- result = self.normalize_metadata(self._values['metadata'])
- elif self.param_metadata:
- result = self.normalize_metadata(self.param_metadata)
- else:
- return None
- return result
-
- @property
- def template(self):
- if self._values['template'] is None:
- return None
- return fq_name(self.partition, self._values['template'])
-
- @property
- def device_group(self):
- if self._values['device_group'] not in [None, 'none']:
- result = fq_name(self.partition, self._values['device_group'])
- elif self.param_device_group not in [None, 'none']:
- result = self.param_device_group
- else:
- return None
- if not result.startswith('/Common/'):
- raise F5ModuleError(
- "Device groups can only exist in /Common"
- )
- return result
-
- @property
- def traffic_group(self):
- if self._values['traffic_group']:
- result = fq_name(self.partition, self._values['traffic_group'])
- elif self.param_traffic_group:
- result = self.param_traffic_group
- else:
- return None
- if not result.startswith('/Common/'):
- raise F5ModuleError(
- "Traffic groups can only exist in /Common"
- )
- return result
-
- @property
- def strict_updates(self):
- if self._values['strict_updates'] is not None:
- result = flatten_boolean(self._values['strict_updates'])
- elif self.param_strict_updates is not None:
- result = flatten_boolean(self.param_strict_updates)
- else:
- return None
- if result == 'yes':
- return 'enabled'
- return 'disabled'
-
- @property
- def description(self):
- if self._values['description']:
- return self._values['description']
- elif self.param_description:
- return self.param_description
- return None
-
-
-class Changes(Parameters):
- pass
-
-
-class UsableChanges(Changes):
- pass
-
-
-class ReportableChanges(Changes):
- pass
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
- @property
- def metadata(self):
- if self.want.metadata is None:
- return None
- if self.have.metadata is None:
- return self.want.metadata
- want = [(k, v) for d in self.want.metadata for k, v in iteritems(d)]
- have = [(k, v) for d in self.have.metadata for k, v in iteritems(d)]
- if set(want) != set(have):
- return dict(
- metadata=self.want.metadata
- )
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.have = None
- self.want = ModuleParameters(params=self.module.params)
- self.changes = UsableChanges()
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = UsableChanges(params=changed)
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def exec_module(self):
- changed = False
- result = dict()
- state = self.want.state
-
- if state == "present":
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
-
- changes = self.changes.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- return result
-
- def present(self):
- if self.exists():
- return self.update()
- else:
- return self.create()
-
- def absent(self):
- if self.exists():
- return self.remove()
- return False
-
- def create(self):
- self._set_changed_options()
- if self.want.traffic_group is None:
- self.want.update({'traffic_group': '/Common/traffic-group-1'})
- if not self.template_exists():
- raise F5ModuleError(
- "The specified template does not exist in the provided partition."
- )
- if self.module.check_mode:
- return True
- self.create_on_device()
- return True
-
- def remove(self):
- if self.module.check_mode:
- return True
- self.remove_from_device()
- if self.exists():
- raise F5ModuleError("Failed to delete the iApp service")
- return True
-
- def update(self):
- self.have = self.read_current_from_device()
- if not self.should_update() and not self.want.force:
- return False
- if self.module.check_mode:
- return True
- self.update_on_device()
- return True
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def exists(self):
- base_uri = "https://{0}:{1}/mgmt/tm/sys/application/service/".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- uri = build_service_uri(base_uri, self.want.partition, self.want.name)
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def update_on_device(self):
- params = self.changes.api_params()
- if params:
- params['execute-action'] = 'definition'
- base_uri = "https://{0}:{1}/mgmt/tm/sys/application/service/".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- uri = build_service_uri(base_uri, self.want.partition, self.want.name)
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- if self.changes.metadata:
- params = dict(metadata=self.changes.metadata)
- params.update({'execute-action': 'definition'})
- base_uri = "https://{0}:{1}/mgmt/tm/sys/application/service/".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- uri = build_service_uri(base_uri, self.want.partition, self.want.name)
- resp = self.client.api.patch(uri, json=params)
-
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def read_current_from_device(self):
- base_uri = "https://{0}:{1}/mgmt/tm/sys/application/service/".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- uri = build_service_uri(base_uri, self.want.partition, self.want.name)
- resp = self.client.api.get(uri)
-
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return ApiParameters(params=response)
-
- def template_exists(self):
- name = fq_name(self.want.partition, self.want.template)
- parts = name.split('/')
- uri = "https://{0}:{1}/mgmt/tm/sys/application/template/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(parts[1], parts[2])
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def create_on_device(self):
- params = self.changes.api_params()
- params['name'] = self.want.name
- params['partition'] = self.want.partition
- uri = "https://{0}:{1}/mgmt/tm/sys/application/service/".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- resp = self.client.api.post(uri, json=params)
-
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- if self.changes.metadata:
- payload = dict(metadata=self.changes.metadata)
- base_uri = "https://{0}:{1}/mgmt/tm/sys/application/service/".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- uri = build_service_uri(base_uri, self.want.partition, self.want.name)
- resp = self.client.api.patch(uri, json=payload)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def remove_from_device(self):
- base_uri = "https://{0}:{1}/mgmt/tm/sys/application/service/".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- uri = build_service_uri(base_uri, self.want.partition, self.want.name)
-
- # Metadata needs to be zero'd before the service is removed because
- # otherwise, the API will error out saying that "configuration items"
- # currently exist.
- #
- # In other words, the REST API is not able to delete a service while
- # there is existing metadata
- payload = dict(metadata=[])
- resp = self.client.api.patch(uri, json=payload)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- resp = self.client.api.delete(uri)
-
- if resp.status == 200:
- return True
- raise F5ModuleError(resp.content)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- name=dict(required=True),
- template=dict(),
- description=dict(),
- device_group=dict(),
- parameters=dict(
- type='dict'
- ),
- state=dict(
- default='present',
- choices=['absent', 'present']
- ),
- force=dict(
- default='no',
- type='bool'
- ),
- strict_updates=dict(
- type='bool',
- default='yes'
- ),
- metadata=dict(type='list'),
- traffic_group=dict(),
- partition=dict(
- default='Common',
- fallback=(env_fallback, ['F5_PARTITION'])
- )
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_iapp_template.py b/lib/ansible/modules/network/f5/bigip_iapp_template.py
deleted file mode 100644
index 21b40d63d3..0000000000
--- a/lib/ansible/modules/network/f5/bigip_iapp_template.py
+++ /dev/null
@@ -1,571 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['stableinterface'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_iapp_template
-short_description: Manages TCL iApp templates on a BIG-IP
-description:
- - Manages TCL iApp templates on a BIG-IP. This module will allow you to
- deploy iApp templates to the BIG-IP and manage their lifecycle. The
- conventional way to use this module is to import new iApps as needed
- or by extracting the contents of the iApp archive that is provided at
- downloads.f5.com and then importing all the iApps with this module.
- This module can also update existing iApps provided that the source
- of the iApp changed while the name stayed the same. Note however that
- this module will not reconfigure any services that may have been
- created using the C(bigip_iapp_service) module. iApps are normally
- not updated in production. Instead, new versions are deployed and then
- existing services are changed to consume that new template. As such,
- the ability to update templates in-place requires the C(force) option
- to be used.
-version_added: 2.4
-options:
- force:
- description:
- - Specifies whether or not to force the uploading of an iApp. When
- C(yes), will force update the iApp even if there are iApp services
- using it. This will not update the running service though. Use
- C(bigip_iapp_service) to do that. When C(no), will update the iApp
- only if there are no iApp services using the template.
- type: bool
- name:
- description:
- - The name of the iApp template that you want to delete. This option
- is only available when specifying a C(state) of C(absent) and is
- provided as a way to delete templates that you may no longer have
- the source of.
- type: str
- content:
- description:
- - Sets the contents of an iApp template directly to the specified
- value. This is for simple values, but can be used with lookup
- plugins for anything complex or with formatting. C(content) must
- be provided when creating new templates.
- type: str
- state:
- description:
- - Whether the iApp template should exist or not.
- type: str
- choices:
- - present
- - absent
- default: present
- partition:
- description:
- - Device partition to manage resources on.
- type: str
- default: Common
-extends_documentation_fragment: f5
-author:
- - Tim Rupp (@caphrim007)
- - Wojciech Wypior (@wojtek0806)
-'''
-
-EXAMPLES = r'''
-- name: Add the iApp contained in template iapp.tmpl
- bigip_iapp_template:
- content: "{{ lookup('template', 'iapp.tmpl') }}"
- state: present
- provider:
- user: admin
- password: secret
- server: lb.mydomain.com
- delegate_to: localhost
-
-- name: Update a template in place
- bigip_iapp_template:
- content: "{{ lookup('template', 'iapp-new.tmpl') }}"
- state: present
- provider:
- user: admin
- password: secret
- server: lb.mydomain.com
- delegate_to: localhost
-
-- name: Update a template in place that has existing services created from it.
- bigip_iapp_template:
- content: "{{ lookup('template', 'iapp-new.tmpl') }}"
- force: yes
- state: present
- provider:
- user: admin
- password: secret
- server: lb.mydomain.com
- delegate_to: localhost
-'''
-
-RETURN = r'''
-# only common fields returned
-'''
-
-import re
-import uuid
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.basic import env_fallback
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import fq_name
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.common import transform_name
- from library.module_utils.network.f5.icontrol import upload_file
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import fq_name
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.common import transform_name
- from ansible.module_utils.network.f5.icontrol import upload_file
-
-try:
- from StringIO import StringIO
-except ImportError:
- from io import StringIO
-
-
-class Parameters(AnsibleF5Parameters):
- api_attributes = []
-
- returnables = []
-
- @property
- def name(self):
- if self._values['name']:
- return self._values['name']
- if self._values['content']:
- name = self._get_template_name()
- return name
- return None
-
- @property
- def content(self):
- if self._values['content'] is None:
- return None
- result = self._squash_template_name_prefix()
- result = self._replace_template_name(result)
- return result
-
- @property
- def checksum(self):
- return self._values['tmplChecksum']
-
- def _squash_template_name_prefix(self):
- """Removes the template name prefix
-
- This method removes that partition from the name
- in the iApp so that comparisons can be done properly and entries
- can be created properly when using REST.
-
- :return string
- """
- pattern = r'sys\s+application\s+template\s+/Common/'
- replace = 'sys application template '
- return re.sub(pattern, replace, self._values['content'])
-
- def _replace_template_name(self, template):
- """Replaces template name at runtime
-
- To allow us to do the switch-a-roo with temporary templates and
- checksum comparisons, we need to take the template provided to us
- and change its name to a temporary value so that BIG-IP will create
- a clone for us.
-
- :return string
- """
- pattern = r'sys\s+application\s+template\s+[^ ]+'
-
- if self._values['name']:
- name = self._values['name']
- else:
- name = self._get_template_name()
-
- replace = 'sys application template {0}'.format(fq_name(self.partition, name))
- return re.sub(pattern, replace, template)
-
- def _get_template_name(self):
- pattern = r'sys\s+application\s+template\s+(?P<path>\/[^\{}"\'*?|#]+\/)?(?P<name>[^\{}"\'*?|#]+)'
- matches = re.search(pattern, self._values['content'])
- try:
- result = matches.group('name').strip()
- except IndexError:
- result = None
- if result:
- return result
- raise F5ModuleError(
- "No template name was found in the template"
- )
-
-
-class ApiParameters(Parameters):
- pass
-
-
-class ModuleParameters(Parameters):
- pass
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class UsableChanges(Changes):
- pass
-
-
-class ReportableChanges(Changes):
- pass
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(params=self.module.params)
- self.have = ApiParameters()
- self.changes = UsableChanges()
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.client.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def exec_module(self):
- changed = False
- result = dict()
- state = self.want.state
-
- if state == "present":
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def present(self):
- if self.exists():
- return self.update()
- else:
- return self.create()
-
- def absent(self):
- changed = False
- if self.exists():
- changed = self.remove()
- return changed
-
- def create(self):
- if self.module.check_mode:
- return True
- self.create_on_device()
- if self.exists():
- return True
- else:
- raise F5ModuleError("Failed to create the iApp template")
-
- def remove(self):
- if self.module.check_mode:
- return True
- self.remove_from_device()
- if self.exists():
- raise F5ModuleError("Failed to delete the iApp template")
- return True
-
- def update(self):
- self.have = self.read_current_from_device()
-
- if not self.templates_differ():
- return False
-
- if not self.want.force and self.template_in_use():
- return False
-
- if self.module.check_mode:
- return True
-
- self._remove_iapp_checksum()
- # The same process used for creating (load) can be used for updating
- self.create_on_device()
- self._generate_template_checksum_on_device()
- return True
-
- def exists(self):
- uri = "https://{0}:{1}/mgmt/tm/sys/application/template/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def template_in_use(self):
- uri = "https://{0}:{1}/mgmt/tm/sys/application/service/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
-
- name = fq_name(self.want.partition, self.want.name)
- resp = self.client.api.get(uri)
-
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
-
- for item in response['items']:
- if item['template'] == name:
- return True
- return False
-
- def read_current_from_device(self):
- self._generate_template_checksum_on_device()
- uri = "https://{0}:{1}/mgmt/tm/sys/application/template/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
-
- resp = self.client.api.get(uri)
-
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return ApiParameters(params=response)
-
- def _remove_iapp_checksum(self):
- """Removes the iApp tmplChecksum
-
- This is required for updating in place or else the load command will
- fail with a "AppTemplate ... content does not match the checksum"
- error.
-
- :return:
- """
- uri = "https://{0}:{1}/mgmt/tm/sys/application/template/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- params = dict(tmplChecksum=None)
-
- resp = self.client.api.patch(uri, json=params)
-
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def templates_differ(self):
- # BIG-IP can generate checksums of iApps, but the iApp needs to be
- # on the box to do this. Additionally, the checksum is MD5, but it
- # is not an MD5 of the entire content of the template. Instead, it
- # is a hash of some portion of the template that is unknown to me.
- #
- # The code below is responsible for uploading the provided template
- # under a unique name and creating a checksum for it so that that
- # checksum can be compared to the one of the existing template.
- #
- # Using this method we can compare the checksums of the existing
- # iApp and the iApp that the user is providing to the module.
- backup = self.want.name
-
- # Override whatever name may have been provided so that we can
- # temporarily create a new template to test checksums with
- self.want.update({
- 'name': 'ansible-{0}'.format(str(uuid.uuid4()))
- })
-
- # Create and remove temporary template
- temp = self._get_temporary_template()
-
- # Set the template name back to what it was originally so that
- # any future operations only happen on the real template.
- self.want.update({
- 'name': backup
- })
- if temp.checksum != self.have.checksum:
- return True
- return False
-
- def _get_temporary_template(self):
- self.create_on_device()
- temp = self.read_current_from_device()
- self.remove_from_device()
- return temp
-
- def _generate_template_checksum_on_device(self):
- command = 'tmsh generate sys application template {0} checksum'.format(
- self.want.name
- )
- params = dict(
- command="run",
- utilCmdArgs='-c "{0}"'.format(command)
- )
- uri = "https://{0}:{1}/mgmt/tm/util/bash".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
-
- resp = self.client.api.post(uri, json=params)
-
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def upload_file_to_device(self, content, name):
- url = 'https://{0}:{1}/mgmt/shared/file-transfer/uploads'.format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- try:
- upload_file(self.client, url, content, name)
- except F5ModuleError:
- raise F5ModuleError(
- "Failed to upload the file."
- )
-
- def create_on_device(self):
- remote_path = "/var/config/rest/downloads/{0}".format(self.want.name)
- load_command = 'tmsh load sys application template {0}'.format(remote_path)
-
- template = StringIO(self.want.content)
- self.upload_file_to_device(template, self.want.name)
-
- uri = "https://{0}:{1}/mgmt/tm/util/bash".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- params = dict(
- command="run",
- utilCmdArgs='-c "{0}"'.format(load_command)
- )
-
- resp = self.client.api.post(uri, json=params)
-
- try:
- response = resp.json()
- if 'commandResult' in response:
- if 'Syntax Error' in response['commandResult']:
- raise F5ModuleError(response['commandResult'])
- if 'ERROR' in response['commandResult']:
- raise F5ModuleError(response['commandResult'])
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return True
-
- def remove_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/sys/application/template/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- response = self.client.api.delete(uri)
- if response.status == 200:
- return True
- raise F5ModuleError(response.content)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- name=dict(),
- state=dict(
- default='present',
- choices=['present', 'absent']
- ),
- force=dict(
- type='bool'
- ),
- content=dict(),
- partition=dict(
- default='Common',
- fallback=(env_fallback, ['F5_PARTITION'])
- )
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_ike_peer.py b/lib/ansible/modules/network/f5/bigip_ike_peer.py
deleted file mode 100644
index 2651f11741..0000000000
--- a/lib/ansible/modules/network/f5/bigip_ike_peer.py
+++ /dev/null
@@ -1,804 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2018, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_ike_peer
-short_description: Manage IPSec IKE Peer configuration on BIG-IP
-description:
- - Manage IPSec IKE Peer configuration on BIG-IP.
-version_added: 2.8
-options:
- name:
- description:
- - Specifies the name of the IKE peer.
- type: str
- required: True
- description:
- description:
- - Description of the IKE peer.
- type: str
- version:
- description:
- - Specifies which version of IKE is used.
- - If the system you are configuring is the IPsec initiator, and you select
- both versions, the system tries using IKEv2 for negotiation. If the remote
- peer does not support IKEv2, the IPsec tunnel fails. To use IKEv1 in this
- case, you must deselect Version 2 and try again.
- - If the system you are configuring is the IPsec responder, and you select
- both versions, the IPsec initiator system determines which IKE version to use.
- - When creating a new IKE peer, this value is required.
- type: list
- choices:
- - v1
- - v2
- presented_id_type:
- description:
- - Specifies the identifier type that the local system uses to identify
- itself to the peer during IKE Phase 1 negotiations.
- type: str
- choices:
- - address
- - asn1dn
- - fqdn
- - keyid-tag
- - user-fqdn
- - override
- presented_id_value:
- description:
- - This is a required value when C(version) includes (Cv2).
- - Specifies a value for the identity when using a C(presented_id_type) of
- C(override).
- type: str
- verified_id_type:
- description:
- - Specifies the identifier type that the local system uses to identify
- the peer during IKE Phase 1 negotiation.
- - This is a required value when C(version) includes (Cv2).
- - When C(user-fqdn), value of C(verified_id_value) must be in the form of
- User @ DNS domain string.
- type: str
- choices:
- - address
- - asn1dn
- - fqdn
- - keyid-tag
- - user-fqdn
- - override
- verified_id_value:
- description:
- - This is a required value when C(version) includes (Cv2).
- - Specifies a value for the identity when using a C(verified_id_type) of
- C(override).
- type: str
- phase1_auth_method:
- description:
- - Specifies the authentication method for phase 1 negotiation.
- - When creating a new IKE peer, if this value is not specified, the default is
- C(rsa-signature).
- type: str
- choices:
- - pre-shared-key
- - rsa-signature
- phase1_cert:
- description:
- - Specifies the digital certificate to use for the RSA signature.
- - When creating a new IKE peer, if this value is not specified, and
- C(phase1_auth_method) is C(rsa-signature), the default is C(default.crt).
- - This parameter is invalid when C(phase1_auth_method) is C(pre-shared-key).
- type: str
- phase1_key:
- description:
- - Specifies the public key that the digital certificate contains.
- - When creating a new IKE peer, if this value is not specified, and
- C(phase1_auth_method) is C(rsa-signature), the default is C(default.key).
- - This parameter is invalid when C(phase1_auth_method) is C(pre-shared-key).
- type: str
- phase1_verify_peer_cert:
- description:
- - In IKEv2, specifies whether the certificate sent by the IKE peer is verified
- using the Trusted Certificate Authorities, a CRL, and/or a peer certificate.
- - In IKEv1, specifies whether the identifier sent by the peer is verified with
- the credentials in the certificate, in the following manner - ASN1DN; specifies
- that the entire certificate subject name is compared with the identifier.
- Address, FQDN, or User FQDN; specifies that the certificate's subjectAltName is
- compared with the identifier. If the two do not match, the negotiation fails.
- - When creating a new IKE peer, if this value is not specified, and
- C(phase1_auth_method) is C(rsa-signature), the default is C(no).
- - This parameter is invalid when C(phase1_auth_method) is C(pre-shared-key).
- type: bool
- preshared_key:
- description:
- - Specifies a string that the IKE peers share for authenticating each other.
- - This parameter is only relevant when C(phase1_auth_method) is C(pre-shared-key).
- - This parameter is invalid when C(phase1_auth_method) is C(rsa-signature).
- type: str
- remote_address:
- description:
- - Displays the IP address of the BIG-IP system that is remote to the system
- you are configuring.
- type: str
- phase1_encryption_algorithm:
- description:
- - Specifies the algorithm to use for IKE encryption.
- - IKE C(version) C(v2) does not support C(blowfish), C(camellia), or C(cast128).
- type: str
- choices:
- - 3des
- - des
- - blowfish
- - cast128
- - aes128
- - aes192
- - aes256
- - camellia
- phase1_hash_algorithm:
- description:
- - Specifies the algorithm to use for IKE authentication.
- type: str
- choices:
- - sha1
- - md5
- - sha256
- - sha384
- - sha512
- phase1_perfect_forward_secrecy:
- description:
- - Specifies the Diffie-Hellman group to use for IKE Phase 1 and Phase 2 negotiations.
- type: str
- choices:
- - ecp256
- - ecp384
- - ecp521
- - modp768
- - modp1024
- - modp1536
- - modp2048
- - modp3072
- - modp4096
- - modp6144
- - modp8192
- update_password:
- description:
- - C(always) will allow to update passwords if the user chooses to do so.
- C(on_create) will only set the password for newly created IKE peers.
- type: str
- choices:
- - always
- - on_create
- default: always
- partition:
- description:
- - Device partition to manage resources on.
- type: str
- default: Common
- state:
- description:
- - When C(present), ensures that the resource exists.
- - When C(absent), ensures the resource is removed.
- type: str
- choices:
- - present
- - absent
- default: present
-extends_documentation_fragment: f5
-author:
- - Tim Rupp (@caphrim007)
- - Wojciech Wypior (@wojtek0806)
-'''
-
-EXAMPLES = r'''
-- name: Create new IKE peer
- bigip_ike_peer:
- name: ike1
- remote_address: 1.2.3.4
- version:
- - v1
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-
-- name: Change presented id type - keyid-tag
- bigip_ike_peer:
- name: ike1
- presented_id_type: keyid-tag
- presented_id_value: key1
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-
-- name: Remove IKE peer
- bigip_ike_peer:
- name: ike1
- state: absent
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-'''
-
-RETURN = r'''
-presented_id_type:
- description: The new Presented ID Type value of the resource.
- returned: changed
- type: str
- sample: address
-verified_id_type:
- description: The new Verified ID Type value of the resource.
- returned: changed
- type: str
- sample: address
-phase1_auth_method:
- description: The new IKE Phase 1 Credentials Authentication Method value of the resource.
- returned: changed
- type: str
- sample: rsa-signature
-remote_address:
- description: The new Remote Address value of the resource.
- returned: changed
- type: str
- sample: 1.2.2.1
-version:
- description: The new list of IKE versions.
- returned: changed
- type: list
- sample: ['v1', 'v2']
-phase1_encryption_algorithm:
- description: The new IKE Phase 1 Encryption Algorithm.
- returned: changed
- type: str
- sample: 3des
-phase1_hash_algorithm:
- description: The new IKE Phase 1 Authentication Algorithm.
- returned: changed
- type: str
- sample: sha256
-phase1_perfect_forward_secrecy:
- description: The new IKE Phase 1 Perfect Forward Secrecy.
- returned: changed
- type: str
- sample: modp1024
-phase1_cert:
- description: The new IKE Phase 1 Certificate Credentials.
- returned: changed
- type: str
- sample: /Common/cert1.crt
-phase1_key:
- description: The new IKE Phase 1 Key Credentials.
- returned: changed
- type: str
- sample: /Common/cert1.key
-phase1_verify_peer_cert:
- description: The new IKE Phase 1 Key Verify Peer Certificate setting.
- returned: changed
- type: bool
- sample: yes
-verified_id_value:
- description: The new Verified ID Value setting for the Verified ID Type.
- returned: changed
- type: str
- sample: 1.2.3.1
-presented_id_value:
- description: The new Presented ID Value setting for the Presented ID Type.
- returned: changed
- type: str
- sample: 1.2.3.1
-'''
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.basic import env_fallback
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import fq_name
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.common import transform_name
- from library.module_utils.network.f5.common import flatten_boolean
- from library.module_utils.network.f5.compare import cmp_str_with_none
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import fq_name
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.common import transform_name
- from ansible.module_utils.network.f5.common import flatten_boolean
- from ansible.module_utils.network.f5.compare import cmp_str_with_none
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'myIdType': 'presented_id_type',
- 'peersIdType': 'verified_id_type',
- 'phase1AuthMethod': 'phase1_auth_method',
- 'presharedKeyEncrypted': 'preshared_key',
- 'remoteAddress': 'remote_address',
- 'version': 'version',
- 'phase1EncryptAlgorithm': 'phase1_encryption_algorithm',
- 'phase1HashAlgorithm': 'phase1_hash_algorithm',
- 'phase1PerfectForwardSecrecy': 'phase1_perfect_forward_secrecy',
- 'myCertFile': 'phase1_cert',
- 'myCertKeyFile': 'phase1_key',
- 'verifyCert': 'phase1_verify_peer_cert',
- 'peersIdValue': 'verified_id_value',
- 'myIdValue': 'presented_id_value',
- }
-
- api_attributes = [
- 'myIdType',
- 'peersIdType',
- 'phase1AuthMethod',
- 'presharedKeyEncrypted',
- 'remoteAddress',
- 'version',
- 'phase1EncryptAlgorithm',
- 'phase1HashAlgorithm',
- 'phase1PerfectForwardSecrecy',
- 'myCertFile',
- 'myCertKeyFile',
- 'verifyCert',
- 'peersIdValue',
- 'myIdValue',
- 'description',
- ]
-
- returnables = [
- 'presented_id_type',
- 'verified_id_type',
- 'phase1_auth_method',
- 'preshared_key',
- 'remote_address',
- 'version',
- 'phase1_encryption_algorithm',
- 'phase1_hash_algorithm',
- 'phase1_perfect_forward_secrecy',
- 'phase1_cert',
- 'phase1_key',
- 'phase1_verify_peer_cert',
- 'verified_id_value',
- 'presented_id_value',
- 'description',
- ]
-
- updatables = [
- 'presented_id_type',
- 'verified_id_type',
- 'phase1_auth_method',
- 'preshared_key',
- 'remote_address',
- 'version',
- 'phase1_encryption_algorithm',
- 'phase1_hash_algorithm',
- 'phase1_perfect_forward_secrecy',
- 'phase1_cert',
- 'phase1_key',
- 'phase1_verify_peer_cert',
- 'verified_id_value',
- 'presented_id_value',
- 'description',
- ]
-
- @property
- def phase1_verify_peer_cert(self):
- return flatten_boolean(self._values['phase1_verify_peer_cert'])
-
-
-class ApiParameters(Parameters):
- @property
- def description(self):
- if self._values['description'] in [None, 'none']:
- return None
- return self._values['description']
-
-
-class ModuleParameters(Parameters):
- @property
- def phase1_cert(self):
- if self._values['phase1_cert'] is None:
- return None
- if self._values['phase1_cert'] in ['', 'none']:
- return ''
- return fq_name(self.partition, self._values['phase1_cert'])
-
- @property
- def phase1_key(self):
- if self._values['phase1_key'] is None:
- return None
- if self._values['phase1_key'] in ['', 'none']:
- return ''
- return fq_name(self.partition, self._values['phase1_key'])
-
- @property
- def description(self):
- if self._values['description'] is None:
- return None
- elif self._values['description'] in ['none', '']:
- return ''
- return self._values['description']
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class UsableChanges(Changes):
- @property
- def phase1_verify_peer_cert(self):
- if self._values['phase1_verify_peer_cert'] is None:
- return None
- elif self._values['phase1_verify_peer_cert'] == 'yes':
- return 'true'
- else:
- return 'false'
-
-
-class ReportableChanges(Changes):
- @property
- def phase1_verify_peer_cert(self):
- return flatten_boolean(self._values['phase1_verify_peer_cert'])
-
- @property
- def preshared_key(self):
- return None
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
- @property
- def description(self):
- return cmp_str_with_none(self.want.description, self.have.description)
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(params=self.module.params)
- self.have = ApiParameters()
- self.changes = UsableChanges()
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = UsableChanges(params=changed)
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def exec_module(self):
- changed = False
- result = dict()
- state = self.want.state
-
- if state == "present":
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.client.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def present(self):
- if self.exists():
- return self.update()
- else:
- return self.create()
-
- def exists(self):
- uri = "https://{0}:{1}/mgmt/tm/net/ipsec/ike-peer/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def update(self):
- self.have = self.read_current_from_device()
-
- if self.changes.version is not None and len(self.changes.version) == 0:
- raise F5ModuleError(
- "At least one version value must be specified."
- )
-
- if self.changes.phase1_auth_method == 'pre-shared-key':
- if self.changes.preshared_key is None and self.have.preshared_key is None:
- raise F5ModuleError(
- "A 'preshared_key' must be specified when changing 'phase1_auth_method' "
- "to 'pre-shared-key'."
- )
-
- if self.want.update_password == 'always':
- self.want.update({'preshared_key': self.want.preshared_key})
- else:
- if self.want.preshared_key:
- del self.want._values['preshared_key']
-
- if not self.should_update():
- return False
- if self.module.check_mode:
- return True
- self.update_on_device()
- return True
-
- def remove(self):
- if self.module.check_mode:
- return True
- self.remove_from_device()
- if self.exists():
- raise F5ModuleError("Failed to delete the resource.")
- return True
-
- def create(self):
- self._set_changed_options()
- if self.changes.version is None:
- raise F5ModuleError(
- "The 'version' parameter is required when creating a new IKE peer."
- )
- if self.changes.phase1_auth_method is None:
- self.changes.update({'phase1_auth_method': 'rsa-signature'})
- if self.changes.phase1_cert is None:
- self.changes.update({'phase1_cert': 'default.crt'})
- if self.changes.phase1_key is None:
- self.changes.update({'phase1_key': 'default.key'})
-
- if self.module.check_mode:
- return True
- self.create_on_device()
- return True
-
- def create_on_device(self):
- params = self.changes.api_params()
- params['name'] = self.want.name
- params['partition'] = self.want.partition
- uri = "https://{0}:{1}/mgmt/tm/net/ipsec/ike-peer/".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def update_on_device(self):
- params = self.changes.api_params()
- uri = "https://{0}:{1}/mgmt/tm/net/ipsec/ike-peer/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def absent(self):
- if self.exists():
- return self.remove()
- return False
-
- def remove_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/net/ipsec/ike-peer/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.delete(uri)
- if resp.status == 200:
- return True
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/net/ipsec/ike-peer/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return ApiParameters(params=response)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- name=dict(required=True),
- presented_id_type=dict(
- choices=['address', 'asn1dn', 'fqdn', 'keyid-tag', 'user-fqdn', 'override']
- ),
- presented_id_value=dict(),
- verified_id_type=dict(
- choices=['address', 'asn1dn', 'fqdn', 'keyid-tag', 'user-fqdn', 'override']
- ),
- verified_id_value=dict(),
- phase1_auth_method=dict(
- choices=[
- 'pre-shared-key', 'rsa-signature'
- ]
- ),
- preshared_key=dict(no_log=True),
- remote_address=dict(),
- version=dict(
- type='list',
- choices=['v1', 'v2']
- ),
- phase1_encryption_algorithm=dict(
- choices=[
- '3des', 'des', 'blowfish', 'cast128', 'aes128', 'aes192',
- 'aes256', 'camellia'
- ]
- ),
- phase1_hash_algorithm=dict(
- choices=[
- 'sha1', 'md5', 'sha256', 'sha384', 'sha512'
- ]
- ),
- phase1_perfect_forward_secrecy=dict(
- choices=[
- 'ecp256', 'ecp384', 'ecp521', 'modp768', 'modp1024', 'modp1536',
- 'modp2048', 'modp3072', 'modp4096', 'modp6144', 'modp8192'
- ]
- ),
- phase1_cert=dict(),
- phase1_key=dict(),
- phase1_verify_peer_cert=dict(type='bool'),
- update_password=dict(
- default='always',
- choices=['always', 'on_create']
- ),
- description=dict(),
- state=dict(default='present', choices=['absent', 'present']),
- partition=dict(
- default='Common',
- fallback=(env_fallback, ['F5_PARTITION'])
- )
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
- self.required_if = [
- ['presented_id_type', 'fqdn', ['presented_id_value']],
- ['presented_id_type', 'keyid-tag', ['presented_id_value']],
- ['presented_id_type', 'user-fqdn', ['presented_id_value']],
- ['presented_id_type', 'override', ['presented_id_value']],
-
- ['verified_id_type', 'fqdn', ['verified_id_value']],
- ['verified_id_type', 'keyid-tag', ['verified_id_value']],
- ['verified_id_type', 'user-fqdn', ['verified_id_value']],
- ['verified_id_type', 'override', ['verified_id_value']],
- ]
- self.required_together = [
- ['phase1_cert', 'phase1_key']
- ]
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode,
- required_if=spec.required_if,
- required_together=spec.required_together,
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_imish_config.py b/lib/ansible/modules/network/f5/bigip_imish_config.py
deleted file mode 100644
index 059ec300f5..0000000000
--- a/lib/ansible/modules/network/f5/bigip_imish_config.py
+++ /dev/null
@@ -1,831 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2018, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_imish_config
-short_description: Manage BIG-IP advanced routing configuration sections
-description:
- - This module provides an implementation for working with advanced routing
- configuration sections in a deterministic way.
-version_added: 2.8
-options:
- route_domain:
- description:
- - Route domain to manage BGP configuration on.
- type: str
- default: 0
- lines:
- description:
- - The ordered set of commands that should be configured in the
- section.
- - The commands must be the exact same commands as found in the device
- running-config.
- - Be sure to note the configuration command syntax as some commands
- are automatically modified by the device config parser.
- type: list
- aliases: ['commands']
- parents:
- description:
- - The ordered set of parents that uniquely identify the section or hierarchy
- the commands should be checked against.
- - If the C(parents) argument is omitted, the commands are checked against
- the set of top level or global commands.
- type: list
- src:
- description:
- - The I(src) argument provides a path to the configuration file
- to load into the remote system.
- - The path can either be a full system path to the configuration
- file if the value starts with / or relative to the root of the
- implemented role or playbook.
- - This argument is mutually exclusive with the I(lines) and
- I(parents) arguments.
- type: path
- before:
- description:
- - The ordered set of commands to push on to the command stack if
- a change needs to be made.
- - This allows the playbook designer the opportunity to perform
- configuration commands prior to pushing any changes without
- affecting how the set of commands are matched against the system.
- type: list
- after:
- description:
- - The ordered set of commands to append to the end of the command
- stack if a change needs to be made.
- - Just like with I(before) this allows the playbook designer to
- append a set of commands to be executed after the command set.
- type: list
- match:
- description:
- - Instructs the module on the way to perform the matching of
- the set of commands against the current device config.
- - If match is set to I(line), commands are matched line by line.
- - If match is set to I(strict), command lines are matched with respect
- to position.
- - If match is set to I(exact), command lines must be an equal match.
- - Finally, if match is set to I(none), the module will not attempt to
- compare the source configuration with the running configuration on
- the remote device.
- type: str
- choices:
- - line
- - strict
- - exact
- - none
- default: line
- replace:
- description:
- - Instructs the module on the way to perform the configuration
- on the device.
- - If the replace argument is set to I(line) then the modified lines
- are pushed to the device in configuration mode.
- - If the replace argument is set to I(block) then the entire
- command block is pushed to the device in configuration mode if any
- line is not correct.
- type: str
- choices:
- - line
- - block
- default: line
- backup:
- description:
- - This argument will cause the module to create a full backup of
- the current C(running-config) from the remote device before any
- changes are made.
- - The backup file is written to the C(backup) folder in the playbook
- root directory or role root directory, if playbook is part of an
- ansible role. If the directory does not exist, it is created.
- type: bool
- default: 'no'
- running_config:
- description:
- - The module, by default, will connect to the remote device and
- retrieve the current running-config to use as a base for comparing
- against the contents of source.
- - There are times when it is not desirable to have the task get the
- current running-config for every task in a playbook.
- - The I(running_config) argument allows the implementer to pass in
- the configuration to use as the base config for comparison.
- type: str
- aliases: ['config']
- save_when:
- description:
- - When changes are made to the device running-configuration, the
- changes are not copied to non-volatile storage by default.
- - If the argument is set to I(always), then the running-config will
- always be copied to the startup-config and the I(modified) flag will
- always be set to C(True).
- - If the argument is set to I(modified), then the running-config
- will only be copied to the startup-config if it has changed since
- the last save to startup-config.
- - If the argument is set to I(never), the running-config will never be
- copied to the startup-config.
- - If the argument is set to I(changed), then the running-config
- will only be copied to the startup-config if the task has made a change.
- type: str
- choices:
- - always
- - never
- - modified
- - changed
- default: never
- diff_against:
- description:
- - When using the C(ansible-playbook --diff) command line argument
- the module can generate diffs against different sources.
- - When this option is configure as I(startup), the module will return
- the diff of the running-config against the startup-config.
- - When this option is configured as I(intended), the module will
- return the diff of the running-config against the configuration
- provided in the C(intended_config) argument.
- - When this option is configured as I(running), the module will
- return the before and after diff of the running-config with respect
- to any changes made to the device configuration.
- type: str
- choices:
- - startup
- - intended
- - running
- default: startup
- diff_ignore_lines:
- description:
- - Use this argument to specify one or more lines that should be
- ignored during the diff.
- - This is used for lines in the configuration that are automatically
- updated by the system.
- - This argument takes a list of regular expressions or exact line matches.
- type: list
- intended_config:
- description:
- - The C(intended_config) provides the master configuration that
- the node should conform to and is used to check the final
- running-config against.
- - This argument will not modify any settings on the remote device and
- is strictly used to check the compliance of the current device's
- configuration against.
- - When specifying this argument, the task should also modify the
- C(diff_against) value and set it to I(intended).
- type: str
- backup_options:
- description:
- - This is a dict object containing configurable options related to backup file path.
- The value of this option is read only when C(backup) is set to I(yes), if C(backup) is set
- to I(no) this option will be silently ignored.
- suboptions:
- filename:
- description:
- - The filename to be used to store the backup configuration. If the filename
- is not given it will be generated based on the hostname, current time and date
- in format defined by <hostname>_config.<current-date>@<current-time>
- type: str
- dir_path:
- description:
- - This option provides the path ending with directory name in which the backup
- configuration file will be stored. If the directory does not exist it will be first
- created and the filename is either the value of C(filename) or default filename
- as described in C(filename) options description. If the path value is not given
- in that case a I(backup) directory will be created in the current working directory
- and backup configuration will be copied in C(filename) within I(backup) directory.
- type: path
- type: dict
- version_added: "2.8"
-notes:
- - Abbreviated commands are NOT idempotent, see
- L(Network FAQ,../network/user_guide/faq.html#why-do-the-config-modules-always-return-changed-true-with-abbreviated-commands).
-extends_documentation_fragment: f5
-author:
- - Tim Rupp (@caphrim007)
-'''
-
-EXAMPLES = r'''
-- name: configure top level configuration and save it
- bigip_imish_config:
- lines: bfd slow-timer 2000
- save_when: modified
- provider:
- user: admin
- password: secret
- server: lb.mydomain.com
- delegate_to: localhost
-
-- name: diff the running-config against a provided config
- bigip_imish_config:
- diff_against: intended
- intended_config: "{{ lookup('file', 'master.cfg') }}"
- provider:
- user: admin
- password: secret
- server: lb.mydomain.com
- delegate_to: localhost
-
-- name: Add config to a parent block
- bigip_imish_config:
- lines:
- - bgp graceful-restart restart-time 120
- - redistribute kernel route-map rhi
- - neighbor 10.10.10.11 remote-as 65000
- - neighbor 10.10.10.11 fall-over bfd
- - neighbor 10.10.10.11 remote-as 65000
- - neighbor 10.10.10.11 fall-over bfd
- parents: router bgp 64664
- match: exact
- provider:
- user: admin
- password: secret
- server: lb.mydomain.com
- delegate_to: localhost
-
-- name: Remove an existing acl before writing it
- bigip_imish_config:
- lines:
- - access-list 10 permit 20.20.20.20
- - access-list 10 permit 20.20.20.21
- - access-list 10 deny any
- before: no access-list 10
- provider:
- user: admin
- password: secret
- server: lb.mydomain.com
- delegate_to: localhost
-
-- name: for idempotency, use full-form commands
- bigip_imish_config:
- lines:
- # - desc My interface
- - description My Interface
- # parents: int ANYCAST-P2P-2
- parents: interface ANYCAST-P2P-2
- provider:
- user: admin
- password: secret
- server: lb.mydomain.com
- delegate_to: localhost
-
-- name: configurable backup path
- bigip_imish_config:
- lines: bfd slow-timer 2000
- backup: yes
- provider:
- user: admin
- password: secret
- server: lb.mydomain.com
- backup_options:
- filename: backup.cfg
- dir_path: /home/user
- delegate_to: localhost
-'''
-
-RETURN = r'''
-commands:
- description: The set of commands that will be pushed to the remote device
- returned: always
- type: list
- sample: ['interface ANYCAST-P2P-2', 'neighbor 20.20.20.21 remote-as 65000', 'neighbor 20.20.20.21 fall-over bfd']
-updates:
- description: The set of commands that will be pushed to the remote device
- returned: always
- type: list
- sample: ['interface ANYCAST-P2P-2', 'neighbor 20.20.20.21 remote-as 65000', 'neighbor 20.20.20.21 fall-over bfd']
-backup_path:
- description: The full path to the backup file
- returned: when backup is yes
- type: str
- sample: /playbooks/ansible/backup/bigip_imish_config.2016-07-16@22:28:34
-'''
-
-
-try:
- from StringIO import StringIO
-except ImportError:
- from io import StringIO
-
-
-import os
-import tempfile
-
-from ansible.module_utils.network.common.config import NetworkConfig, dumps
-from ansible.module_utils.network.common.utils import to_list
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import fq_name
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.icontrol import upload_file
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import fq_name
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.icontrol import upload_file
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
-
- }
-
- api_attributes = [
-
- ]
-
- returnables = [
- '__backup__',
- 'commands',
- 'updates'
- ]
-
- updatables = [
-
- ]
-
-
-class ApiParameters(Parameters):
- pass
-
-
-class ModuleParameters(Parameters):
- pass
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class UsableChanges(Changes):
- pass
-
-
-class ReportableChanges(Changes):
- pass
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(params=self.module.params)
- self.have = ApiParameters()
- self.changes = UsableChanges()
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = UsableChanges(params=changed)
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def exec_module(self):
- result = dict()
- changed = self.present()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- return result
-
- def present(self):
- result = dict(changed=False)
- config = None
- contents = None
-
- if self.want.backup or (self.module._diff and self.want.diff_against == 'running'):
- contents = self.read_current_from_device()
- config = NetworkConfig(indent=1, contents=contents)
- if self.want.backup:
- # The backup file is created in the bigip_imish_config action plugin. Refer
- # to that if you have questions. The key below is removed by the action plugin.
- result['__backup__'] = contents
-
- if any((self.want.src, self.want.lines)):
- match = self.want.match
- replace = self.want.replace
-
- candidate = self.get_candidate()
- running = self.get_running_config(contents)
-
- response = self.get_diff(
- candidate=candidate,
- running=running,
- diff_match=match,
- diff_ignore_lines=self.want.diff_ignore_lines,
- path=self.want.parents,
- diff_replace=replace
- )
-
- config_diff = response['config_diff']
-
- if config_diff:
- commands = config_diff.split('\n')
-
- if self.want.before:
- commands[:0] = self.want.before
-
- if self.want.after:
- commands.extend(self.want.after)
-
- result['commands'] = commands
- result['updates'] = commands
-
- if not self.module.check_mode:
- self.load_config(commands)
-
- result['changed'] = True
-
- running_config = self.want.running_config
- startup_config = None
-
- if self.want.save_when == 'always':
- self.save_config(result)
- elif self.want.save_when == 'modified':
- output = self.execute_show_commands(['show running-config', 'show startup-config'])
-
- running_config = NetworkConfig(indent=1, contents=output[0], ignore_lines=self.want.diff_ignore_lines)
- startup_config = NetworkConfig(indent=1, contents=output[1], ignore_lines=self.want.diff_ignore_lines)
-
- if running_config.sha1 != startup_config.sha1:
- self.save_config(result)
- elif self.want.save_when == 'changed' and result['changed']:
- self.save_on_device()
-
- if self.module._diff:
- if not running_config:
- output = self.execute_show_commands('show running-config')
- contents = output[0]
- else:
- contents = running_config
-
- # recreate the object in order to process diff_ignore_lines
- running_config = NetworkConfig(indent=1, contents=contents, ignore_lines=self.want.diff_ignore_lines)
-
- if self.want.diff_against == 'running':
- if self.module.check_mode:
- self.module.warn("unable to perform diff against running-config due to check mode")
- contents = None
- else:
- contents = config.config_text
-
- elif self.want.diff_against == 'startup':
- if not startup_config:
- output = self.execute_show_commands('show startup-config')
- contents = output[0]
- else:
- contents = startup_config.config_text
-
- elif self.want.diff_against == 'intended':
- contents = self.want.intended_config
-
- if contents is not None:
- base_config = NetworkConfig(indent=1, contents=contents, ignore_lines=self.want.diff_ignore_lines)
-
- if running_config.sha1 != base_config.sha1:
- if self.want.diff_against == 'intended':
- before = running_config
- after = base_config
- elif self.want.diff_against in ('startup', 'running'):
- before = base_config
- after = running_config
-
- result.update({
- 'changed': True,
- 'diff': {'before': str(before), 'after': str(after)}
- })
- self.changes.update(result)
- return result['changed']
-
- def load_config(self, commands):
- content = StringIO("\n".join(commands))
-
- file = tempfile.NamedTemporaryFile()
- name = os.path.basename(file.name)
-
- self.upload_file_to_device(content, name)
- self.load_config_on_device(name)
- self.remove_uploaded_file_from_device(name)
-
- def remove_uploaded_file_from_device(self, name):
- filepath = '/var/config/rest/downloads/{0}'.format(name)
- params = {
- "command": "run",
- "utilCmdArgs": filepath
- }
- uri = "https://{0}:{1}/mgmt/tm/util/unix-rm".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def upload_file_to_device(self, content, name):
- url = 'https://{0}:{1}/mgmt/shared/file-transfer/uploads'.format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- try:
- upload_file(self.client, url, content, name)
- except F5ModuleError:
- raise F5ModuleError(
- "Failed to upload the file."
- )
-
- def load_config_on_device(self, name):
- filepath = '/var/config/rest/downloads/{0}'.format(name)
- command = 'imish -r {0} -f {1}'.format(self.want.route_domain, filepath)
-
- params = {
- "command": "run",
- "utilCmdArgs": '-c "{0}"'.format(command)
- }
- uri = "https://{0}:{1}/mgmt/tm/util/bash".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- if 'commandResult' in response:
- if 'Dynamic routing is not enabled' in response['commandResult']:
- raise F5ModuleError(response['commandResult'])
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def read_current_from_device(self):
- command = 'imish -r {0} -e \\\"show running-config\\\"'.format(self.want.route_domain)
-
- params = {
- "command": "run",
- "utilCmdArgs": '-c "{0}"'.format(command)
- }
- uri = "https://{0}:{1}/mgmt/tm/util/bash".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- if 'commandResult' in response:
- if 'Dynamic routing is not enabled' in response['commandResult']:
- raise F5ModuleError(response['commandResult'])
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return response['commandResult']
-
- def save_on_device(self):
- command = 'imish -e write'
- params = {
- "command": "run",
- "utilCmdArgs": '-c "{0}"'.format(command)
- }
- uri = "https://{0}:{1}/mgmt/tm/util/bash".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def get_diff(self, candidate=None, running=None, diff_match='line', diff_ignore_lines=None, path=None, diff_replace='line'):
- diff = {}
-
- # prepare candidate configuration
- candidate_obj = NetworkConfig(indent=1)
- candidate_obj.load(candidate)
-
- if running and diff_match != 'none' and diff_replace != 'config':
- # running configuration
- running_obj = NetworkConfig(indent=1, contents=running, ignore_lines=diff_ignore_lines)
- configdiffobjs = candidate_obj.difference(running_obj, path=path, match=diff_match, replace=diff_replace)
- else:
- configdiffobjs = candidate_obj.items
-
- diff['config_diff'] = dumps(configdiffobjs, 'commands') if configdiffobjs else ''
- return diff
-
- def get_running_config(self, config=None):
- contents = self.want.running_config
- if not contents:
- if config:
- contents = config
- else:
- contents = self.read_current_from_device()
- return contents
-
- def get_candidate(self):
- candidate = ''
- if self.want.src:
- candidate = self.want.src
-
- elif self.want.lines:
- candidate_obj = NetworkConfig(indent=1)
- parents = self.want.parents or list()
- candidate_obj.add(self.want.lines, parents=parents)
- candidate = dumps(candidate_obj, 'raw')
- return candidate
-
- def execute_show_commands(self, commands):
- body = []
-
- uri = "https://{0}:{1}/mgmt/tm/util/bash".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- for command in to_list(commands):
- command = 'imish -r {0} -e \\\"{1}\\\"'.format(self.want.route_domain, command)
- params = {
- "command": "run",
- "utilCmdArgs": '-c "{0}"'.format(command)
- }
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- if 'commandResult' in response:
- if 'Dynamic routing is not enabled' in response['commandResult']:
- raise F5ModuleError(response['commandResult'])
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- body.append(response['commandResult'])
- return body
-
- def save_config(self, result):
- result['changed'] = True
- if self.module.check_mode:
- self.module.warn(
- 'Skipping command `copy running-config startup-config` '
- 'due to check_mode. Configuration not copied to '
- 'non-volatile storage'
- )
- return
- self.save_on_device()
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- backup_spec = dict(
- filename=dict(),
- dir_path=dict(type='path')
- )
- argument_spec = dict(
- route_domain=dict(default=0),
- src=dict(type='path'),
- lines=dict(aliases=['commands'], type='list'),
- parents=dict(type='list'),
-
- before=dict(type='list'),
- after=dict(type='list'),
-
- match=dict(default='line', choices=['line', 'strict', 'exact', 'none']),
- replace=dict(default='line', choices=['line', 'block']),
-
- running_config=dict(aliases=['config']),
- intended_config=dict(),
-
- backup=dict(type='bool', default=False),
- backup_options=dict(type='dict', options=backup_spec),
-
- save_when=dict(choices=['always', 'never', 'modified', 'changed'], default='never'),
-
- diff_against=dict(choices=['running', 'startup', 'intended'], default='startup'),
- diff_ignore_lines=dict(type='list'),
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
- self.mutually_exclusive = [
- ('lines', 'src'),
- ('parents', 'src'),
- ]
- self.required_if = [
- ('match', 'strict', ['lines']),
- ('match', 'exact', ['lines']),
- ('replace', 'block', ['lines']),
- ('diff_against', 'intended', ['intended_config'])
- ]
- self.add_file_common_args = True
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode,
- mutually_exclusive=spec.mutually_exclusive,
- required_if=spec.required_if,
- add_file_common_args=spec.add_file_common_args,
- )
-
- client = F5RestClient(**module.params)
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_ipsec_policy.py b/lib/ansible/modules/network/f5/bigip_ipsec_policy.py
deleted file mode 100644
index 0adfad915b..0000000000
--- a/lib/ansible/modules/network/f5/bigip_ipsec_policy.py
+++ /dev/null
@@ -1,778 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2018, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_ipsec_policy
-short_description: Manage IPSec policies on a BIG-IP
-description:
- - Manage IPSec policies on a BIG-IP.
-version_added: 2.8
-options:
- name:
- description:
- - Specifies the name of the IPSec policy.
- type: str
- required: True
- description:
- description:
- - Description of the policy
- type: str
- protocol:
- description:
- - Specifies the IPsec protocol
- - Options include ESP (Encapsulating Security Protocol) or AH (Authentication Header).
- type: str
- choices:
- - esp
- - ah
- mode:
- description:
- - Specifies the processing mode.
- - When C(transport), specifies a mode that encapsulates only the payload (adding
- an ESP header, trailer, and authentication tag).
- - When C(tunnel), specifies a mode that includes encapsulation of the header as
- well as the payload (adding a new IP header, in addition to adding an ESP header,
- trailer, and authentication tag). If you select this option, you must also
- provide IP addresses for the local and remote endpoints of the IPsec tunnel.
- - When C(isession), specifies the use of iSession over an IPsec tunnel. To use
- this option, you must also configure the iSession endpoints with IPsec in the
- Acceleration section of the user interface.
- - When C(interface), specifies that the IPsec policy can be used in the tunnel
- profile for network interfaces.
- type: str
- choices:
- - transport
- - interface
- - isession
- - tunnel
- tunnel_local_address:
- description:
- - Specifies the local endpoint IP address of the IPsec tunnel.
- - This parameter is only valid when C(mode) is C(tunnel).
- type: str
- tunnel_remote_address:
- description:
- - Specifies the remote endpoint IP address of the IPsec tunnel.
- - This parameter is only valid when C(mode) is C(tunnel).
- type: str
- encrypt_algorithm:
- description:
- - Specifies the algorithm to use for IKE encryption.
- type: str
- choices:
- - none
- - 3des
- - aes128
- - aes192
- - aes256
- - aes-gmac256
- - aes-gmac192
- - aes-gmac128
- - aes-gcm256
- - aes-gcm192
- - aes-gcm256
- - aes-gcm128
- route_domain:
- description:
- - Specifies the route domain, when C(interface) is selected for the C(mode) setting.
- type: int
- auth_algorithm:
- description:
- - Specifies the algorithm to use for IKE authentication.
- type: str
- choices:
- - sha1
- - sha256
- - sha384
- - sha512
- - aes-gcm128
- - aes-gcm192
- - aes-gcm256
- - aes-gmac128
- - aes-gmac192
- - aes-gmac256
- ipcomp:
- description:
- - Specifies whether to use IPComp encapsulation.
- - When C(none), specifies that IPComp is disabled.
- - When C(deflate), specifies that IPComp is enabled and uses the Deflate
- compression algorithm.
- type: str
- choices:
- - none
- - "null"
- - deflate
- lifetime:
- description:
- - Specifies the length of time, in minutes, before the IKE security association
- expires.
- type: int
- kb_lifetime:
- description:
- - Specifies the length of time, in kilobytes, before the IKE security association
- expires.
- type: int
- perfect_forward_secrecy:
- description:
- - Specifies the Diffie-Hellman group to use for IKE Phase 2 negotiation.
- type: str
- choices:
- - none
- - modp768
- - modp1024
- - modp1536
- - modp2048
- - modp3072
- - modp4096
- - modp6144
- - modp8192
- ipv4_interface:
- description:
- - When C(mode) is C(interface) indicate if the IPv4 C(any) address should be used.
- By default C(BIG-IP) assumes C(any6) address for tunnel addresses when C(mode) is C(interface).
- - This option takes effect only when C(mode) is set to C(interface).
- type: bool
- version_added: 2.9
- partition:
- description:
- - Device partition to manage resources on.
- type: str
- default: Common
- state:
- description:
- - When C(present), ensures that the resource exists.
- - When C(absent), ensures the resource is removed.
- type: str
- choices:
- - present
- - absent
- default: present
-extends_documentation_fragment: f5
-author:
- - Tim Rupp (@caphrim007)
- - Wojciech Wypior (@wojtek0806)
-'''
-
-EXAMPLES = r'''
-- name: Create a IPSec policy
- bigip_ipsec_policy:
- name: policy1
- mode: tunnel
- tunnel_local_address: 1.1.1.1
- tunnel_remote_address: 2.2.2.
- auth_algorithm: sha1
- encrypt_algorithm: 3des
- protocol: esp
- perfect_forward_secrecy: modp1024
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-'''
-
-RETURN = r'''
-auth_algorithm:
- description: The new IKE Phase 2 Authentication Algorithm value.
- returned: changed
- type: str
- sample: sha512
-encrypt_algorithm:
- description: The new IKE Phase 2 Encryption Algorithm value.
- returned: changed
- type: str
- sample: aes256
-lifetime:
- description: The new IKE Phase 2 Lifetime value.
- returned: changed
- type: int
- sample: 1440
-kb_lifetime:
- description: The new IKE Phase 2 KB Lifetime value.
- returned: changed
- type: int
- sample: 0
-perfect_forward_secrecy:
- description: The new IKE Phase 2 Perfect Forward Secrecy value.
- returned: changed
- type: str
- sample: modp2048
-tunnel_local_address:
- description: The new Tunnel Local Address value.
- returned: changed
- type: str
- sample: 1.2.2.1
-tunnel_remote_address:
- description: The new Tunnel Remote Address value.
- returned: changed
- type: str
- sample: 2.1.1.2
-mode:
- description: The new Mode value.
- returned: changed
- type: str
- sample: tunnel
-protocol:
- description: The new IPsec Protocol value.
- returned: changed
- type: str
- sample: ah
-ipcomp:
- description: The new IKE Phase 2 IPComp value.
- returned: changed
- type: str
- sample: deflate
-description:
- description: The new description value.
- returned: changed
- type: str
- sample: My policy
-route_domain:
- description: The new Route Domain value when in Tunnel mode.
- returned: changed
- type: int
- sample: 2
-'''
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.basic import env_fallback
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import fq_name
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.common import transform_name
- from library.module_utils.network.f5.common import flatten_boolean
- from library.module_utils.network.f5.compare import cmp_str_with_none
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import fq_name
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.common import transform_name
- from ansible.module_utils.network.f5.common import flatten_boolean
- from ansible.module_utils.network.f5.compare import cmp_str_with_none
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'ikePhase2AuthAlgorithm': 'auth_algorithm',
- 'ikePhase2EncryptAlgorithm': 'encrypt_algorithm',
- 'ikePhase2Lifetime': 'lifetime',
- 'ikePhase2LifetimeKilobytes': 'kb_lifetime',
- 'ikePhase2PerfectForwardSecrecy': 'perfect_forward_secrecy',
- 'tunnelLocalAddress': 'tunnel_local_address',
- 'tunnelRemoteAddress': 'tunnel_remote_address',
- }
-
- api_attributes = [
- 'ikePhase2AuthAlgorithm',
- 'ikePhase2EncryptAlgorithm',
- 'ikePhase2Lifetime',
- 'ikePhase2LifetimeKilobytes',
- 'ikePhase2PerfectForwardSecrecy',
- 'tunnelLocalAddress',
- 'tunnelRemoteAddress',
- 'mode',
- 'protocol',
- 'ipcomp',
- 'description',
- ]
-
- returnables = [
- 'auth_algorithm',
- 'encrypt_algorithm',
- 'lifetime',
- 'kb_lifetime',
- 'perfect_forward_secrecy',
- 'tunnel_local_address',
- 'tunnel_remote_address',
- 'mode',
- 'protocol',
- 'ipcomp',
- 'description',
- 'route_domain',
- ]
-
- updatables = [
- 'auth_algorithm',
- 'encrypt_algorithm',
- 'lifetime',
- 'kb_lifetime',
- 'perfect_forward_secrecy',
- 'tunnel_local_address',
- 'tunnel_remote_address',
- 'mode',
- 'protocol',
- 'ipcomp',
- 'description',
- 'route_domain',
- ]
-
- @property
- def tunnel_local_address(self):
- if self._values['tunnel_local_address'] is None:
- return None
- result = self._values['tunnel_local_address'].split('%')[0]
- return result
-
- @property
- def tunnel_remote_address(self):
- if self._values['tunnel_remote_address'] is None:
- return None
- result = self._values['tunnel_remote_address'].split('%')[0]
- return result
-
-
-class ApiParameters(Parameters):
- @property
- def description(self):
- if self._values['description'] in [None, 'none']:
- return None
- return self._values['description']
-
- @property
- def encrypt_algorithm(self):
- if self._values['encrypt_algorithm'] is None:
- return None
- elif self._values['encrypt_algorithm'] == 'null':
- return 'none'
- return self._values['encrypt_algorithm']
-
- @property
- def route_domain(self):
- if self._values['tunnel_local_address'] is None and self._values['tunnel_remote_address'] is None:
- return None
- elif self._values['tunnel_local_address'] is None and self._values['tunnel_remote_address'] is not None:
- if self._values['tunnel_remote_address'] == 'any6':
- result = 'any6'
- elif self._values['tunnel_remote_address'] == 'any':
- result = 'any'
- else:
- result = int(self._values['tunnel_remote_address'].split('%')[1])
- elif self._values['tunnel_remote_address'] is None and self._values['tunnel_local_address'] is not None:
- if self._values['tunnel_local_address'] == 'any6':
- result = 'any6'
- elif self._values['tunnel_local_address'] == 'any':
- result = 'any'
- else:
- result = int(self._values['tunnel_local_address'].split('%')[1])
- else:
- try:
- result = int(self._values['tunnel_local_address'].split('%')[1])
- except Exception:
- if self._values['tunnel_local_address'] in ['any6', 'any']:
- return 0
- return None
- try:
- if result in ['any6', 'any']:
- return 0
- return int(self._values['tunnel_local_address'].split('%')[1])
- except Exception:
- return None
-
-
-class ModuleParameters(Parameters):
- @property
- def ipv4_interface(self):
- result = flatten_boolean(self._values['ipv4_interface'])
- if result == 'yes':
- return True
- return False
-
- @property
- def description(self):
- if self._values['description'] is None:
- return None
- elif self._values['description'] in ['none', '']:
- return ''
- return self._values['description']
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class UsableChanges(Changes):
- @property
- def encrypt_algorithm(self):
- if self._values['encrypt_algorithm'] is None:
- return None
- elif self._values['encrypt_algorithm'] == 'none':
- return 'null'
- return self._values['encrypt_algorithm']
-
- @property
- def tunnel_local_address(self):
- if self._values['tunnel_local_address'] is None:
- return None
- if self._values['route_domain'] and len(self._values['tunnel_local_address'].split('%')) == 1:
- result = '{0}%{1}'.format(self._values['tunnel_local_address'], self._values['route_domain'])
- return result
- return self._values['tunnel_local_address']
-
- @property
- def tunnel_remote_address(self):
- if self._values['tunnel_remote_address'] is None:
- return None
- if self._values['route_domain'] and len(self._values['tunnel_remote_address'].split('%')) == 1:
- result = '{0}%{1}'.format(self._values['tunnel_remote_address'], self._values['route_domain'])
- return result
- return self._values['tunnel_remote_address']
-
-
-class ReportableChanges(Changes):
- @property
- def encrypt_algorithm(self):
- if self._values['encrypt_algorithm'] is None:
- return None
- elif self._values['encrypt_algorithm'] == 'null':
- return 'none'
- return self._values['encrypt_algorithm']
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
- @property
- def description(self):
- return cmp_str_with_none(self.want.description, self.have.description)
-
- @property
- def route_domain(self):
- if self.want.route_domain is None:
- return None
- if self.have.route_domain != self.want.route_domain:
- if self.want.route_domain == 0 and self.want.ipv4_interface:
- return dict(
- tunnel_local_address='any',
- tunnel_remote_address='any',
- route_domain=self.want.route_domain,
- )
- elif self.want.route_domain == 0 and not self.want.ipv4_interface:
- return dict(
- tunnel_local_address='any6',
- tunnel_remote_address='any6',
- route_domain=self.want.route_domain,
- )
- else:
- return dict(
- tunnel_local_address='any%{0}'.format(self.want.route_domain),
- tunnel_remote_address='any%{0}'.format(self.want.route_domain),
- route_domain=self.want.route_domain,
- )
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(params=self.module.params)
- self.have = ApiParameters()
- self.changes = UsableChanges()
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = UsableChanges(params=changed)
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def exec_module(self):
- changed = False
- result = dict()
- state = self.want.state
-
- if state == "present":
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.client.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def present(self):
- if self.exists():
- return self.update()
- else:
- return self.create()
-
- def exists(self):
- uri = "https://{0}:{1}/mgmt/tm/net/ipsec/ipsec-policy/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def update(self):
- self.have = self.read_current_from_device()
- if not self.should_update():
- return False
- if self.module.check_mode:
- return True
- self.update_on_device()
- return True
-
- def remove(self):
- if self.module.check_mode:
- return True
- self.remove_from_device()
- if self.exists():
- raise F5ModuleError("Failed to delete the resource.")
- return True
-
- def create(self):
- if self.want.mode == 'interface':
- if self.want.ipv4_interface:
- self._set_any_on_interface(ip='ipv4')
- else:
- self._set_any_on_interface()
- self._set_changed_options()
- if self.module.check_mode:
- return True
- self.create_on_device()
- return True
-
- def _set_any_on_interface(self, ip='ipv6'):
- if ip == 'ipv4':
- self.want.update({'tunnel_local_address': 'any'})
- self.want.update({'tunnel_remote_address': 'any'})
- else:
- self.want.update({'tunnel_local_address': 'any6'})
- self.want.update({'tunnel_remote_address': 'any6'})
-
- def create_on_device(self):
- params = self.changes.api_params()
- params['name'] = self.want.name
- params['partition'] = self.want.partition
- uri = "https://{0}:{1}/mgmt/tm/net/ipsec/ipsec-policy/".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def update_on_device(self):
- params = self.changes.api_params()
- uri = "https://{0}:{1}/mgmt/tm/net/ipsec/ipsec-policy/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def absent(self):
- if self.exists():
- return self.remove()
- return False
-
- def remove_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/net/ipsec/ipsec-policy/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.delete(uri)
- if resp.status == 200:
- return True
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/net/ipsec/ipsec-policy/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return ApiParameters(params=response)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- name=dict(required=True),
- description=dict(),
- protocol=dict(
- choices=['esp', 'ah']
- ),
- mode=dict(
- choices=['transport', 'interface', 'isession', 'tunnel']
- ),
- ipv4_interface=dict(type='bool'),
- tunnel_local_address=dict(),
- tunnel_remote_address=dict(),
- encrypt_algorithm=dict(
- choices=[
- 'none', '3des', 'aes128', 'aes192', 'aes256', 'aes-gmac256',
- 'aes-gmac192', 'aes-gmac128', 'aes-gcm256', 'aes-gcm192',
- 'aes-gcm256', 'aes-gcm128'
- ]
- ),
- route_domain=dict(type='int'),
- auth_algorithm=dict(
- choices=[
- 'sha1', 'sha256', 'sha384', 'sha512', 'aes-gcm128',
- 'aes-gcm192', 'aes-gcm256', 'aes-gmac128', 'aes-gmac192',
- 'aes-gmac256',
- ]
- ),
- ipcomp=dict(
- choices=['none', 'null', 'deflate']
- ),
- lifetime=dict(type='int'),
- kb_lifetime=dict(type='int'),
- perfect_forward_secrecy=dict(
- choices=[
- 'none', 'modp768', 'modp1024', 'modp1536', 'modp2048', 'modp3072',
- 'modp4096', 'modp6144', 'modp8192'
- ]
- ),
- state=dict(default='present', choices=['absent', 'present']),
- partition=dict(
- default='Common',
- fallback=(env_fallback, ['F5_PARTITION'])
- )
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
- self.required_if = [
- ['mode', 'tunnel', ['tunnel_local_address', 'tunnel_remote_address']],
- ['mode', 'interface', ['route_domain']]
- ]
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode,
- required_if=spec.required_if
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_irule.py b/lib/ansible/modules/network/f5/bigip_irule.py
deleted file mode 100644
index 66416bf9b0..0000000000
--- a/lib/ansible/modules/network/f5/bigip_irule.py
+++ /dev/null
@@ -1,577 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['stableinterface'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_irule
-short_description: Manage iRules across different modules on a BIG-IP
-description:
- - Manage iRules across different modules on a BIG-IP.
-version_added: 2.2
-options:
- content:
- description:
- - When used instead of 'src', sets the contents of an iRule directly to
- the specified value. This is for simple values, but can be used with
- lookup plugins for anything complex or with formatting. Either one
- of C(src) or C(content) must be provided.
- type: str
- module:
- description:
- - The BIG-IP module to add the iRule to.
- type: str
- required: True
- choices:
- - ltm
- - gtm
- name:
- description:
- - The name of the iRule.
- type: str
- required: True
- src:
- description:
- - The iRule file to interpret and upload to the BIG-IP. Either one
- of C(src) or C(content) must be provided.
- type: path
- required: True
- state:
- description:
- - Whether the iRule should exist or not.
- type: str
- choices:
- - present
- - absent
- default: present
- partition:
- description:
- - Device partition to manage resources on.
- type: str
- default: Common
- version_added: 2.5
-extends_documentation_fragment: f5
-author:
- - Tim Rupp (@caphrim007)
- - Wojciech Wypior (@wojtek0806)
-'''
-
-EXAMPLES = r'''
-- name: Add the iRule contained in template irule.tcl to the LTM module
- bigip_irule:
- content: "{{ lookup('template', 'irule.tcl') }}"
- module: ltm
- name: MyiRule
- state: present
- provider:
- user: admin
- password: secret
- server: lb.mydomain.com
- delegate_to: localhost
-
-- name: Add the iRule contained in static file irule.tcl to the LTM module
- bigip_irule:
- module: ltm
- name: MyiRule
- src: irule.tcl
- state: present
- provider:
- user: admin
- password: secret
- server: lb.mydomain.com
- delegate_to: localhost
-'''
-
-RETURN = r'''
-module:
- description: The module that the iRule was added to
- returned: changed and success
- type: str
- sample: gtm
-src:
- description: The filename that included the iRule source
- returned: changed and success, when provided
- type: str
- sample: /opt/src/irules/example1.tcl
-content:
- description: The content of the iRule that was managed
- returned: changed and success
- type: str
- sample: "when LB_FAILED { set wipHost [LB::server addr] }"
-'''
-
-import os
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.basic import env_fallback
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.common import transform_name
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.common import transform_name
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'apiAnonymous': 'content',
- }
-
- updatables = [
- 'content',
- ]
-
- api_attributes = [
- 'apiAnonymous',
- ]
-
- returnables = [
- 'content', 'src', 'module',
- ]
-
-
-class ApiParameters(Parameters):
- pass
-
-
-class ModuleParameters(Parameters):
- @property
- def content(self):
- if self._values['content'] is None:
- result = self.src_content
- else:
- result = self._values['content']
-
- return str(result).strip()
-
- @property
- def src(self):
- if self._values['src'] is None:
- return None
- return self._values['src']
-
- @property
- def src_content(self):
- if not os.path.exists(self._values['src']):
- raise F5ModuleError(
- "The specified 'src' was not found."
- )
- with open(self._values['src']) as f:
- result = f.read()
- return result
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- return result
-
-
-class UsableChanges(Changes):
- pass
-
-
-class ReportableChanges(Changes):
- pass
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.client = kwargs.get('client', None)
- self.module = kwargs.get('module', None)
- self.kwargs = kwargs
-
- def exec_module(self):
- if self.module.params['module'] == 'ltm':
- manager = self.get_manager('ltm')
- elif self.module.params['module'] == 'gtm':
- manager = self.get_manager('gtm')
- else:
- raise F5ModuleError(
- "An unknown iRule module type was specified"
- )
- return manager.exec_module()
-
- def get_manager(self, type):
- if type == 'ltm':
- return LtmManager(**self.kwargs)
- elif type == 'gtm':
- return GtmManager(**self.kwargs)
-
-
-class BaseManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.have = None
- self.want = ModuleParameters(params=self.module.params)
- self.changes = UsableChanges()
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = UsableChanges(params=changed)
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def exec_module(self):
- changed = False
- result = dict()
- state = self.want.state
-
- if state in ["present"]:
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def present(self):
- if not self.want.content and not self.want.src:
- raise F5ModuleError(
- "Either 'content' or 'src' must be provided"
- )
- if self.exists():
- return self.update()
- else:
- return self.create()
-
- def create(self):
- self._set_changed_options()
- if self.module.check_mode:
- return True
- self.create_on_device()
- if not self.exists():
- raise F5ModuleError("Failed to create the iRule")
- return True
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def update(self):
- self.have = self.read_current_from_device()
- if not self.should_update():
- return False
- if self.module.check_mode:
- return True
- self.update_on_device()
- return True
-
- def absent(self):
- if self.exists():
- return self.remove()
- return False
-
- def remove(self):
- if self.module.check_mode:
- return True
- self.remove_from_device()
- if self.exists():
- raise F5ModuleError("Failed to delete the iRule")
- return True
-
-
-class LtmManager(BaseManager):
- def exists(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/rule/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def update_on_device(self):
- params = self.changes.api_params()
- uri = "https://{0}:{1}/mgmt/tm/ltm/rule/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def create_on_device(self):
- params = self.changes.api_params()
- params['name'] = self.want.name
- params['partition'] = self.want.partition
- uri = "https://{0}:{1}/mgmt/tm/ltm/rule/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return response['selfLink']
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/rule/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
-
- resp = self.client.api.get(uri)
-
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return ApiParameters(params=response)
-
- def remove_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/rule/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- response = self.client.api.delete(uri)
- if response.status == 200:
- return True
- raise F5ModuleError(response.content)
-
-
-class GtmManager(BaseManager):
- def exists(self):
- uri = "https://{0}:{1}/mgmt/tm/gtm/rule/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def update_on_device(self):
- params = self.changes.api_params()
- uri = "https://{0}:{1}/mgmt/tm/gtm/rule/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def create_on_device(self):
- params = self.changes.api_params()
- params['name'] = self.want.name
- params['partition'] = self.want.partition
- uri = "https://{0}:{1}/mgmt/tm/gtm/rule/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return response['selfLink']
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/gtm/rule/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
-
- resp = self.client.api.get(uri)
-
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return ApiParameters(params=response)
-
- def remove_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/gtm/rule/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- response = self.client.api.delete(uri)
- if response.status == 200:
- return True
- raise F5ModuleError(response.content)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- content=dict(),
- src=dict(
- type='path',
- ),
- name=dict(required=True),
- module=dict(
- required=True,
- choices=['gtm', 'ltm']
- ),
- state=dict(
- default='present',
- choices=['present', 'absent']
- ),
- partition=dict(
- default='Common',
- fallback=(env_fallback, ['F5_PARTITION'])
- )
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
- self.mutually_exclusive = [
- ['content', 'src']
- ]
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode,
- mutually_exclusive=spec.mutually_exclusive
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_log_destination.py b/lib/ansible/modules/network/f5/bigip_log_destination.py
deleted file mode 100644
index 61c5935a94..0000000000
--- a/lib/ansible/modules/network/f5/bigip_log_destination.py
+++ /dev/null
@@ -1,1765 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_log_destination
-short_description: Manages log destinations on a BIG-IP.
-description:
- - Manages log destinations on a BIG-IP.
-version_added: 2.6
-options:
- name:
- description:
- - Specifies the name of the log destination.
- type: str
- required: True
- type:
- description:
- - Specifies the type of log destination.
- - Once created, this parameter cannot be changed.
- type: str
- choices:
- - remote-high-speed-log
- - remote-syslog
- - arcsight
- - splunk
- - management-port
- - ipfix
- required: True
- description:
- description:
- - The description of the log destination.
- type: str
- pool_settings:
- description:
- - This parameter is only available when C(type) is C(remote-high-speed-log).
- - Deprecated. Use the equivalent top-level parameters instead.
- suboptions:
- pool:
- description:
- - Specifies the existing pool of remote high-speed log servers where logs will be sent.
- - When creating a new destination (and C(type) is C(remote-high-speed-log)), this parameter
- is required.
- type: str
- protocol:
- description:
- - Specifies the protocol for the system to use to send logs to the pool of remote high-speed
- log servers, where the logs are stored.
- - When creating a new log destination (and C(type) is C(remote-high-speed-log)), if this
- parameter is not specified, the default is C(tcp).
- type: str
- choices:
- - tcp
- - udp
- distribution:
- description:
- - Specifies the distribution method used by the Remote High Speed Log destination to send
- messages to pool members.
- - When C(adaptive), connections to pool members will be added as required to provide enough
- logging bandwidth. This can have the undesirable effect of logs accumulating on only one
- pool member when it provides sufficient logging bandwidth on its own.
- - When C(balanced), sends each successive log to a new pool member, balancing the logs among
- them according to the pool's load balancing method.
- - When C(replicated), replicates each log to all pool members, for redundancy.
- - When creating a new log destination (and C(type) is C(remote-high-speed-log)), if this
- parameter is not specified, the default is C(adaptive).
- type: str
- choices:
- - adaptive
- - balanced
- - replicated
- type: dict
- syslog_settings:
- description:
- - This parameter is only available when C(type) is C(remote-syslog).
- - Deprecated. Use the equivalent top-level parameters instead.
- suboptions:
- syslog_format:
- description:
- - Specifies the method to use to format the logs associated with the remote Syslog log destination.
- - When creating a new log destination (and C(type) is C(remote-syslog)), if this parameter is
- not specified, the default is C(bsd-syslog).
- - The C(syslog) and C(rfc5424) choices are two ways of saying the same thing.
- - The C(bsd-syslog) and C(rfc3164) choices are two ways of saying the same thing.
- type: str
- choices:
- - bsd-syslog
- - syslog
- - legacy-bigip
- - rfc5424
- - rfc3164
- forward_to:
- description:
- - Specifies the management port log destination, which will be used to forward the logs to a
- single log server, or a remote high-speed log destination, which will be used to forward the
- logs to a pool of remote log servers.
- - When creating a new log destination (and C(type) is C(remote-syslog)), this parameter is required.
- type: str
- type: dict
- syslog_format:
- description:
- - Specifies the method to use to format the logs associated with the remote Syslog log destination.
- - When creating a new log destination (and C(type) is C(remote-syslog)), if this parameter is
- not specified, the default is C(bsd-syslog).
- - The C(syslog) and C(rfc5424) choices are two ways of saying the same thing.
- - The C(bsd-syslog) and C(rfc3164) choices are two ways of saying the same thing.
- type: str
- choices:
- - bsd-syslog
- - syslog
- - legacy-bigip
- - rfc5424
- - rfc3164
- version_added: 2.8
- forward_to:
- description:
- - When C(type) is C(remote-syslog), specifies the management port log destination, which will
- be used to forward the logs to a single log server, or a remote high-speed log destination,
- which will be used to forward the logs to a pool of remote log servers.
- - When C(type) is C(splunk) or C(arcsight), specifies the log destination to which logs are
- forwarded. This log destination may be a management port destination, a remote high-speed
- log destination, or a remote Syslog destination which is configured to send logs to an
- ArcSight or Splunk server.
- - When creating a new log destination and C(type) is C(remote-syslog), C(splunk), or C(arcsight),
- this parameter is required.
- type: str
- version_added: 2.8
- pool:
- description:
- - When C(type) is C(remote-high-speed-log), specifies the existing pool of remote high-speed
- log servers where logs will be sent.
- - When C(type) is C(ipfix), specifies the existing LTM pool of remote IPFIX collectors. Any
- BIG-IP application that uses this log destination sends its IP-traffic logs to this pool
- of collectors.
- - When creating a new destination and C(type) is C(remote-high-speed-log) or C(ipfix), this
- parameter is required.
- type: str
- version_added: 2.8
- protocol:
- description:
- - When C(type) is C(remote-high-speed-log), specifies the protocol for the system to use to
- send logs to the pool of remote high-speed log servers, where the logs are stored.
- - When C(type) is C(ipfix), can be IPFIX or Netflow v9, depending on the type of collectors
- you have in the pool that you specify.
- - When C(type) is C(management-port), specifies the protocol used to send messages to the
- specified location.
- - When C(type) is C(management-port), only C(tcp) and C(udp) are valid values.
- type: str
- choices:
- - tcp
- - udp
- - ipfix
- - netflow-9
- version_added: 2.8
- distribution:
- description:
- - Specifies the distribution method used by the Remote High Speed Log destination to send
- messages to pool members.
- - When C(adaptive), connections to pool members will be added as required to provide enough
- logging bandwidth. This can have the undesirable effect of logs accumulating on only one
- pool member when it provides sufficient logging bandwidth on its own.
- - When C(balanced), sends each successive log to a new pool member, balancing the logs among
- them according to the pool's load balancing method.
- - When C(replicated), replicates each log to all pool members, for redundancy.
- - When creating a new log destination and C(type) is C(remote-high-speed-log), if this
- parameter is not specified, the default is C(adaptive).
- type: str
- choices:
- - adaptive
- - balanced
- - replicated
- version_added: 2.8
- address:
- description:
- - Specifies the IP address that will receive messages from the specified local Log Destination.
- - This parameter is only available when C(type) is C(management-port).
- - When creating a new log destination and C(type) is C(management-port), this parameter
- is required.
- type: str
- version_added: 2.8
- port:
- description:
- - Specifies the port of the IP address that will receive messages from the specified local
- Log Destination.
- - This parameter is only available when C(type) is C(management-port).
- - When creating a new log destination and C(type) is C(management-port), this parameter
- is required.
- type: int
- version_added: 2.8
- transport_profile:
- description:
- - Is a transport profile based on either TCP or UDP.
- - This profile defines the TCP or UDP options used to send IP-traffic logs
- to the pool of collectors.
- - This parameter is only available when C(type) is C(ipfix).
- type: str
- version_added: 2.8
- server_ssl_profile:
- description:
- - If the C(transport_profile) is a TCP profile, you can use this field to
- choose a Secure Socket Layer (SSL) profile for sending logs to the IPFIX
- collectors.
- - An SSL server profile defines how to communicate securely over SSL or
- Transport Layer Security (TLS).
- - This parameter is only available when C(type) is C(ipfix).
- type: str
- version_added: 2.8
- template_retransmit_interval:
- description:
- - Enter the time (in seconds) between each transmission of IPFIX templates
- to the pool of IPFIX collectors.
- - The logging destination periodically retransmits all of its IPFIX templates
- at the interval you set in this field. These retransmissions are helpful
- for UDP, a lossy transport mechanism.
- - This parameter is only available when C(type) is C(ipfix).
- type: int
- version_added: 2.8
- template_delete_delay:
- description:
- - Enter the time (in seconds) that the BIG-IP device should pause between
- deleting an obsolete IPFIX template and reusing its template ID.
- - This feature is useful for systems where you use iRules to create
- customized IPFIX templates.
- type: int
- version_added: 2.8
- partition:
- description:
- - Device partition to manage resources on.
- type: str
- default: Common
- state:
- description:
- - When C(present), ensures that the resource exists.
- - When C(absent), ensures the resource is removed.
- type: str
- choices:
- - present
- - absent
- default: present
-extends_documentation_fragment: f5
-author:
- - Tim Rupp (@caphrim007)
-'''
-
-EXAMPLES = r'''
-- name: Create a high-speed logging destination
- bigip_log_destination:
- name: foo
- type: remote-high-speed-log
- pool: my-ltm-pool
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-
-- name: Create a remote-syslog logging destination
- bigip_log_destination:
- name: foo
- type: remote-syslog
- syslog_format: rfc5424
- forward_to: my-destination
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-'''
-
-RETURN = r'''
-forward_to:
- description: The new Forward To value.
- returned: changed
- type: str
- sample: /Common/dest1
-pool:
- description: The new Pool value.
- returned: changed
- type: str
- sample: /Common/pool1
-distribution:
- description: The new Distribution Method value.
- returned: changed
- type: str
- sample: balanced
-protocol:
- description: The new Protocol value.
- returned: changed
- type: str
- sample: tcp
-syslog_format:
- description: The new Syslog format value.
- returned: changed
- type: str
- sample: syslog
-address:
- description: The new Address value.
- returned: changed
- type: str
- sample: 1.2.3.2
-port:
- description: The new Port value.
- returned: changed
- type: int
- sample: 2020
-template_delete_delay:
- description: The new Template Delete Delay value.
- returned: changed
- type: int
- sample: 20
-template_retransmit_interval:
- description: The new Template Retransmit Interval value.
- returned: changed
- type: int
- sample: 200
-transport_profile:
- description: The new Transport Profile value.
- returned: changed
- type: str
- sample: /Common/tcp
-server_ssl_profile:
- description: The new Server SSL Profile value.
- returned: changed
- type: str
- sample: /Common/serverssl
-'''
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.basic import env_fallback
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import fq_name
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.common import transform_name
- from library.module_utils.network.f5.compare import cmp_str_with_none
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import fq_name
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.common import transform_name
- from ansible.module_utils.network.f5.compare import cmp_str_with_none
-
-
-class V1Parameters(AnsibleF5Parameters):
- """Base Parameters for remote-syslog
-
- """
- api_map = {
- 'remoteHighSpeedLog': 'forward_to',
- 'format': 'syslog_format'
- }
-
- api_attributes = [
- 'remoteHighSpeedLog',
- 'format'
- ]
-
- returnables = [
- 'forward_to',
- 'syslog_format'
- ]
-
- updatables = [
- 'forward_to',
- 'syslog_format',
- 'type'
- ]
-
-
-# TODO(Remove in 2.12)
-class V1ModuleParameters(V1Parameters):
- @property
- def forward_to(self):
- if self._values['forward_to']:
- result = self._values['forward_to']
- else:
- if self._values['syslog_settings'] is None:
- return None
- result = self._values['syslog_settings'].get('forward_to', None)
-
- if result:
- result = fq_name(self.partition, result)
- return result
-
- @property
- def syslog_format(self):
- if self._values['syslog_format']:
- result = self._values['syslog_format']
- else:
- if self._values['syslog_settings'] is None:
- return None
- result = self._values['syslog_settings'].get('syslog_format', None)
-
- if result == 'syslog':
- result = 'rfc5424'
- if result == 'bsd-syslog':
- result = 'rfc3164'
- return result
-
-
-# TODO(Remove in 2.12)
-class V1ApiParameters(V1Parameters):
- @property
- def type(self):
- return 'remote-syslog'
-
-
-# TODO(Remove in 2.12)
-class V1Changes(V1Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-# TODO(Remove in 2.12)
-class V1UsableChanges(V1Changes):
- pass
-
-
-# TODO(Remove in 2.12)
-class V1ReportableChanges(V1Changes):
- pass
-
-
-# TODO(Remove in 2.12)
-class V2Parameters(AnsibleF5Parameters):
- """Base Parameters for remote-high-speed-log
-
- """
- api_map = {
- 'poolName': 'pool'
- }
-
- api_attributes = [
- 'distribution',
- 'poolName',
- 'protocol'
- ]
-
- returnables = [
- 'pool',
- 'distribution',
- 'protocol'
- ]
-
- updatables = [
- 'pool',
- 'distribution',
- 'protocol',
- 'type'
- ]
-
-
-# TODO(Remove in 2.12)
-class V2ModuleParameters(V2Parameters):
- @property
- def pool(self):
- if self._values['pool']:
- result = self._values['pool']
- else:
- if self._values['pool_settings'] is None:
- return None
- result = self._values['pool_settings'].get('pool', None)
- if result:
- result = fq_name(self.partition, result)
- return result
-
- @property
- def protocol(self):
- if self._values['protocol']:
- return self._values['protocol']
- else:
- if self._values['pool_settings'] is None:
- return None
- return self._values['pool_settings'].get('protocol', None)
-
- @property
- def distribution(self):
- if self._values['distribution']:
- return self._values['distribution']
- else:
- if self._values['pool_settings'] is None:
- return None
- return self._values['pool_settings'].get('distribution', None)
-
-
-# TODO(Remove in 2.12)
-class V2ApiParameters(V2Parameters):
- @property
- def type(self):
- return 'remote-high-speed-log'
-
-
-# TODO(Remove in 2.12)
-class V2Changes(V2Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-# TODO(Remove in 2.12)
-class V2UsableChanges(V2Changes):
- pass
-
-
-# TODO(Remove in 2.12)
-class V2ReportableChanges(V2Changes):
- pass
-
-
-class V3Parameters(AnsibleF5Parameters):
- api_map = {
- 'forwardTo': 'forward_to',
- 'poolName': 'pool',
- 'remoteHighSpeedLog': 'forward_to',
- 'format': 'syslog_format',
- 'ipAddress': 'address',
- 'protocolVersion': 'protocol',
- 'templateDeleteDelay': 'template_delete_delay',
- 'templateRetransmitInterval': 'template_retransmit_interval',
- 'transportProfile': 'transport_profile',
- 'serversslProfile': 'server_ssl_profile',
- }
-
- api_attributes = [
- 'forwardTo',
- 'distribution',
- 'poolName',
- 'protocol',
- 'remoteHighSpeedLog',
- 'format',
- 'ipAddress',
- 'port',
- 'serversslProfile',
- 'transportProfile',
- 'templateRetransmitInterval',
- 'templateDeleteDelay',
- 'protocolVersion',
- ]
-
- returnables = [
- 'forward_to',
- 'pool',
- 'distribution',
- 'protocol',
- 'syslog_format',
- 'address',
- 'port',
- 'template_delete_delay',
- 'template_retransmit_interval',
- 'transport_profile',
- 'server_ssl_profile',
- ]
-
- updatables = [
- 'forward_to',
- 'type',
- 'pool',
- 'distribution',
- 'protocol',
- 'syslog_format',
- 'address',
- 'port',
- 'template_delete_delay',
- 'template_retransmit_interval',
- 'transport_profile',
- 'server_ssl_profile',
- 'type',
- ]
-
-
-class V3ModuleParameters(V3Parameters):
- @property
- def forward_to(self):
- if self._values['forward_to'] is None:
- return None
- return fq_name(self.partition, self._values['forward_to'])
-
- @property
- def pool(self):
- if self._values['pool'] is None:
- return None
- return fq_name(self.partition, self._values['pool'])
-
- @property
- def syslog_format(self):
- if self._values['syslog_format'] is None:
- return None
- result = self._values['syslog_format']
- if result == 'syslog':
- result = 'rfc5424'
- if result == 'bsd-syslog':
- result = 'rfc3164'
- return result
-
- @property
- def server_ssl_profile(self):
- if self._values['server_ssl_profile'] is None:
- return None
- elif self._values['server_ssl_profile'] in ['', 'none']:
- return ''
- return fq_name(self.partition, self._values['server_ssl_profile'])
-
- @property
- def transport_profile(self):
- if self._values['transport_profile'] is None:
- return None
- return fq_name(self.partition, self._values['transport_profile'])
-
-
-class V3ApiParameters(V3Parameters):
- pass
-
-
-class V3Changes(V3Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class V3UsableChanges(V3Changes):
- pass
-
-
-class V3ReportableChanges(V3Changes):
- pass
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
- @property
- def type(self):
- if self.want.type != self.have.type:
- raise F5ModuleError(
- "'type' cannot be changed once it is set."
- )
-
- @property
- def server_ssl_profile(self):
- return cmp_str_with_none(self.want.server_ssl_profile, self.have.server_ssl_profile)
-
- @property
- def transport_profile(self):
- return cmp_str_with_none(self.want.transport_profile, self.have.transport_profile)
-
-
-class BaseManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
-
- def _set_changed_options(self):
- changed = {}
- for key in self.get_returnables():
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = self.get_usable_changes(params=changed)
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = self.get_updatables()
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = self.get_usable_changes(params=changed)
- return True
- return False
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def exec_module(self):
- changed = False
- result = dict()
- state = self.want.state
-
- if state == "present":
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
-
- reportable = self.get_reportable_changes(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.client.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def _validate_creation_parameters(self):
- pass
-
- def present(self):
- if self.exists():
- return self.update()
- else:
- return self.create()
-
- def update(self):
- self.have = self.read_current_from_device()
- if not self.should_update():
- return False
- if self.module.check_mode:
- return True
- self.update_on_device()
- return True
-
- def remove(self):
- if self.module.check_mode:
- return True
- self.remove_from_device()
- if self.exists():
- raise F5ModuleError("Failed to delete the resource.")
- return True
-
- def create(self):
- self._validate_creation_parameters()
- self._set_changed_options()
- if self.module.check_mode:
- return True
- self.create_on_device()
- return True
-
- def absent(self):
- if self.exists():
- return self.remove()
- return False
-
-
-class V1Manager(BaseManager):
- """Manages remote-syslog settings
-
- """
-
- def __init__(self, *args, **kwargs):
- super(V1Manager, self).__init__(*args, **kwargs)
- self.want = self.get_module_params(params=self.module.params)
- self.have = self.get_api_params()
- self.changes = self.get_usable_changes()
-
- def _validate_creation_parameters(self):
- if self.want.syslog_format is None:
- self.want.update({'syslog_format': 'bsd-syslog'})
- if self.want.forward_to is None:
- raise F5ModuleError(
- "'forward_to' is required when creating a new remote-syslog destination."
- )
-
- # TODO(In 2.12, these get_* methods should no longer be needed)
- def get_reportable_changes(self, params=None):
- if params:
- return V1ReportableChanges(params=params)
- return V1ReportableChanges()
-
- def get_usable_changes(self, params=None):
- if params:
- return V1UsableChanges(params=params)
- return V1UsableChanges()
-
- def get_returnables(self):
- return V1ApiParameters.returnables
-
- def get_updatables(self):
- return V1ApiParameters.updatables
-
- def get_module_params(self, params=None):
- if params:
- return V1ModuleParameters(params=params)
- return V1ModuleParameters()
-
- def get_api_params(self, params=None):
- if params:
- return V1ApiParameters(params=params)
- return V1ApiParameters()
-
- def exists(self):
- uri = "https://{0}:{1}/mgmt/tm/sys/log-config/destination/remote-syslog/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def create_on_device(self):
- params = self.changes.api_params()
- params['name'] = self.want.name
- params['partition'] = self.want.partition
- uri = "https://{0}:{1}/mgmt/tm/sys/log-config/destination/remote-syslog/".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def update_on_device(self):
- params = self.changes.api_params()
- uri = "https://{0}:{1}/mgmt/tm/sys/log-config/destination/remote-syslog/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def remove_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/sys/log-config/destination/remote-syslog/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.delete(uri)
- if resp.status == 200:
- return True
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/sys/log-config/destination/remote-syslog/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- response['type'] = 'remote-syslog'
- return V1ApiParameters(params=response)
-
-
-class V2Manager(BaseManager):
- """Manages remote-high-speed-log settings
-
- """
- def __init__(self, *args, **kwargs):
- super(V2Manager, self).__init__(*args, **kwargs)
- self.want = self.get_module_params(params=self.module.params)
- self.have = self.get_api_params()
- self.changes = self.get_usable_changes()
-
- def get_reportable_changes(self, params=None):
- if params:
- return V2ReportableChanges(params=params)
- return V2ReportableChanges()
-
- def get_usable_changes(self, params=None):
- if params:
- return V2UsableChanges(params=params)
- return V2UsableChanges()
-
- def _validate_creation_parameters(self):
- if self.want.protocol is None:
- self.want.update({'protocol': 'tcp'})
- if self.want.distribution is None:
- self.want.update({'distribution': 'adaptive'})
- if self.want.pool is None:
- raise F5ModuleError(
- "'pool' is required when creating a new remote-high-speed-log destination."
- )
-
- def get_returnables(self):
- return V2ApiParameters.returnables
-
- def get_updatables(self):
- return V2ApiParameters.updatables
-
- def get_module_params(self, params=None):
- if params:
- return V2ModuleParameters(params=params)
- return V2ModuleParameters()
-
- def get_api_params(self, params=None):
- if params:
- return V2ApiParameters(params=params)
- return V2ApiParameters()
-
- def exists(self):
- uri = "https://{0}:{1}/mgmt/tm/sys/log-config/destination/remote-high-speed-log/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def create_on_device(self):
- params = self.changes.api_params()
- params['name'] = self.want.name
- params['partition'] = self.want.partition
- uri = "https://{0}:{1}/mgmt/tm/sys/log-config/destination/remote-high-speed-log/".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def update_on_device(self):
- params = self.changes.api_params()
- uri = "https://{0}:{1}/mgmt/tm/sys/log-config/destination/remote-high-speed-log/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def remove_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/sys/log-config/destination/remote-high-speed-log/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.delete(uri)
- if resp.status == 200:
- return True
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/sys/log-config/destination/remote-high-speed-log/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- response['type'] = 'remote-high-speed-log'
- return V2ApiParameters(params=response)
-
-
-class V3Manager(BaseManager):
- def __init__(self, *args, **kwargs):
- super(V3Manager, self).__init__(*args, **kwargs)
- self.want = self.get_module_params(params=self.module.params)
- self.have = self.get_api_params()
- self.changes = self.get_usable_changes()
-
- def get_reportable_changes(self, params=None):
- if params:
- return V3ReportableChanges(params=params)
- return V3ReportableChanges()
-
- def get_usable_changes(self, params=None):
- if params:
- return V3UsableChanges(params=params)
- return V3UsableChanges()
-
- def _validate_creation_parameters(self):
- if self.want.forward_to is None:
- raise F5ModuleError(
- "'forward_to' is required when creating a new arcsight destination."
- )
-
- def get_returnables(self):
- return V3ApiParameters.returnables
-
- def get_updatables(self):
- return V3ApiParameters.updatables
-
- def get_module_params(self, params=None):
- if params:
- return V3ModuleParameters(params=params)
- return V3ModuleParameters()
-
- def get_api_params(self, params=None):
- if params:
-
- return V3ApiParameters(params=params)
- return V3ApiParameters()
-
- def exists(self):
- uri = "https://{0}:{1}/mgmt/tm/sys/log-config/destination/arcsight/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def create_on_device(self):
- params = self.changes.api_params()
- params['name'] = self.want.name
- params['partition'] = self.want.partition
- uri = "https://{0}:{1}/mgmt/tm/sys/log-config/destination/arcsight/".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def update_on_device(self):
- params = self.changes.api_params()
- uri = "https://{0}:{1}/mgmt/tm/sys/log-config/destination/arcsight/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def remove_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/sys/log-config/destination/arcsight/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.delete(uri)
- if resp.status == 200:
- return True
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/sys/log-config/destination/arcsight/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- response['type'] = 'arcsight'
- return V3ApiParameters(params=response)
-
-
-class V4Manager(BaseManager):
- """Manager for Splunk
-
- Do not worry about the usage of V3 classes in this V4 manager.
- In Ansible 2.12, the Parameter classes will undergo a rename
- because of parameters being deprecated.
-
- The correct Parameter classes to use in this class are the
- V3 Parameter classes.
-
- """
- def __init__(self, *args, **kwargs):
- super(V4Manager, self).__init__(*args, **kwargs)
- self.want = self.get_module_params(params=self.module.params)
- self.have = self.get_api_params()
- self.changes = self.get_usable_changes()
-
- def get_reportable_changes(self, params=None):
- if params:
- return V3ReportableChanges(params=params)
- return V3ReportableChanges()
-
- def get_usable_changes(self, params=None):
- if params:
- return V3UsableChanges(params=params)
- return V3UsableChanges()
-
- def _validate_creation_parameters(self):
- if self.want.forward_to is None:
- raise F5ModuleError(
- "'forward_to' is required when creating a new splunk destination."
- )
-
- def get_returnables(self):
- return V3ApiParameters.returnables
-
- def get_updatables(self):
- return V3ApiParameters.updatables
-
- def get_module_params(self, params=None):
- if params:
- return V3ModuleParameters(params=params)
- return V3ModuleParameters()
-
- def get_api_params(self, params=None):
- if params:
-
- return V3ApiParameters(params=params)
- return V3ApiParameters()
-
- def exists(self):
- uri = "https://{0}:{1}/mgmt/tm/sys/log-config/destination/splunk/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def create_on_device(self):
- params = self.changes.api_params()
- params['name'] = self.want.name
- params['partition'] = self.want.partition
- uri = "https://{0}:{1}/mgmt/tm/sys/log-config/destination/splunk/".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def update_on_device(self):
- params = self.changes.api_params()
- uri = "https://{0}:{1}/mgmt/tm/sys/log-config/destination/splunk/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def remove_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/sys/log-config/destination/splunk/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.delete(uri)
- if resp.status == 200:
- return True
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/sys/log-config/destination/splunk/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- response['type'] = 'splunk'
- return V3ApiParameters(params=response)
-
-
-class V5Manager(BaseManager):
- """Manager for Management Port
-
- Do not worry about the usage of V3 classes in this V5 manager.
- In Ansible 2.12, the Parameter classes will undergo a rename
- because of parameters being deprecated.
-
- The correct Parameter classes to use in this class are the
- V3 Parameter classes.
-
- """
- def __init__(self, *args, **kwargs):
- super(V5Manager, self).__init__(*args, **kwargs)
- self.want = self.get_module_params(params=self.module.params)
- self.have = self.get_api_params()
- self.changes = self.get_usable_changes()
-
- def get_reportable_changes(self, params=None):
- if params:
- return V3ReportableChanges(params=params)
- return V3ReportableChanges()
-
- def get_usable_changes(self, params=None):
- if params:
- return V3UsableChanges(params=params)
- return V3UsableChanges()
-
- def _validate_creation_parameters(self):
- if self.want.address is None:
- raise F5ModuleError(
- "'address' is required when creating a new management-port destination."
- )
- if self.want.port is None:
- raise F5ModuleError(
- "'port' is required when creating a new management-port destination."
- )
-
- def get_returnables(self):
- return V3ApiParameters.returnables
-
- def get_updatables(self):
- return V3ApiParameters.updatables
-
- def get_module_params(self, params=None):
- if params:
- return V3ModuleParameters(params=params)
- return V3ModuleParameters()
-
- def get_api_params(self, params=None):
- if params:
-
- return V3ApiParameters(params=params)
- return V3ApiParameters()
-
- def exists(self):
- uri = "https://{0}:{1}/mgmt/tm/sys/log-config/destination/management-port/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def create_on_device(self):
- params = self.changes.api_params()
- params['name'] = self.want.name
- params['partition'] = self.want.partition
- uri = "https://{0}:{1}/mgmt/tm/sys/log-config/destination/management-port/".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def update_on_device(self):
- params = self.changes.api_params()
- uri = "https://{0}:{1}/mgmt/tm/sys/log-config/destination/management-port/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def remove_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/sys/log-config/destination/management-port/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.delete(uri)
- if resp.status == 200:
- return True
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/sys/log-config/destination/management-port/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- response['type'] = 'management-port'
- return V3ApiParameters(params=response)
-
-
-class V6Manager(BaseManager):
- """Manager for IPFIX
-
- Do not worry about the usage of V3 classes in this V6 manager.
- In Ansible 2.12, the Parameter classes will undergo a rename
- because of parameters being deprecated.
-
- The correct Parameter classes to use in this class are the
- V3 Parameter classes.
-
- """
- def __init__(self, *args, **kwargs):
- super(V6Manager, self).__init__(*args, **kwargs)
- self.want = self.get_module_params(params=self.module.params)
- self.have = self.get_api_params()
- self.changes = self.get_usable_changes()
-
- def get_reportable_changes(self, params=None):
- if params:
- return V3ReportableChanges(params=params)
- return V3ReportableChanges()
-
- def get_usable_changes(self, params=None):
- if params:
- return V3UsableChanges(params=params)
- return V3UsableChanges()
-
- def _validate_creation_parameters(self):
- if self.want.protocol is None:
- raise F5ModuleError(
- "'protocol' is required when creating a new ipfix destination."
- )
- if self.want.pool is None:
- raise F5ModuleError(
- "'port' is required when creating a new ipfix destination."
- )
- if self.want.transport_profile is None:
- raise F5ModuleError(
- "'transport_profile' is required when creating a new ipfix destination."
- )
-
- def get_returnables(self):
- return V3ApiParameters.returnables
-
- def get_updatables(self):
- return V3ApiParameters.updatables
-
- def get_module_params(self, params=None):
- if params:
- return V3ModuleParameters(params=params)
- return V3ModuleParameters()
-
- def get_api_params(self, params=None):
- if params:
-
- return V3ApiParameters(params=params)
- return V3ApiParameters()
-
- def exists(self):
- uri = "https://{0}:{1}/mgmt/tm/sys/log-config/destination/ipfix/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def create_on_device(self):
- params = self.changes.api_params()
- params['name'] = self.want.name
- params['partition'] = self.want.partition
- uri = "https://{0}:{1}/mgmt/tm/sys/log-config/destination/ipfix/".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def update_on_device(self):
- params = self.changes.api_params()
- uri = "https://{0}:{1}/mgmt/tm/sys/log-config/destination/ipfix/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def remove_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/sys/log-config/destination/ipfix/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.delete(uri)
- if resp.status == 200:
- return True
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/sys/log-config/destination/ipfix/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- response['type'] = 'ipfix'
- return V3ApiParameters(params=response)
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.kwargs = kwargs
- self.module = kwargs.get('module', None)
-
- def exec_module(self):
- if self.module.params['type'] == 'remote-syslog':
- manager = self.get_manager('v1')
- elif self.module.params['type'] == 'remote-high-speed-log':
- manager = self.get_manager('v2')
- elif self.module.params['type'] == 'arcsight':
- manager = self.get_manager('v3')
- elif self.module.params['type'] == 'splunk':
- manager = self.get_manager('v4')
- elif self.module.params['type'] == 'management-port':
- manager = self.get_manager('v5')
- elif self.module.params['type'] == 'ipfix':
- manager = self.get_manager('v6')
- else:
- raise F5ModuleError(
- "Unknown type specified."
- )
- result = manager.exec_module()
- return result
-
- def get_manager(self, type):
- if type == 'v1':
- return V1Manager(**self.kwargs)
- elif type == 'v2':
- return V2Manager(**self.kwargs)
- elif type == 'v3':
- return V3Manager(**self.kwargs)
- elif type == 'v4':
- return V4Manager(**self.kwargs)
- elif type == 'v5':
- return V5Manager(**self.kwargs)
- elif type == 'v6':
- return V6Manager(**self.kwargs)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- name=dict(required=True),
- type=dict(
- required=True,
- choices=[
- 'arcsight',
- 'remote-high-speed-log',
- 'remote-syslog',
- 'splunk',
- 'management-port',
- 'ipfix',
- ]
- ),
- description=dict(),
- syslog_format=dict(
- choices=[
- 'bsd-syslog',
- 'syslog',
- 'legacy-bigip',
- 'rfc5424',
- 'rfc3164'
- ]
- ),
- forward_to=dict(),
- pool=dict(),
- protocol=dict(
- choices=['tcp', 'udp', 'ipfix', 'netflow-9']
- ),
- distribution=dict(
- choices=[
- 'adaptive',
- 'balanced',
- 'replicated',
- ]
- ),
- state=dict(
- default='present',
- choices=['present', 'absent']
- ),
- partition=dict(
- default='Common',
- fallback=(env_fallback, ['F5_PARTITION'])
- ),
- address=dict(),
- port=dict(type='int'),
- transport_profile=dict(),
- server_ssl_profile=dict(),
- template_retransmit_interval=dict(type='int'),
- template_delete_delay=dict(type='int'),
-
- # Deprecated settings
- pool_settings=dict(
- type='dict',
- suboptions=dict(
- pool=dict(),
- protocol=dict(
- choices=['tcp', 'udp']
- ),
- distribution=dict(
- choices=[
- 'adaptive',
- 'balanced',
- 'replicated',
- ]
- )
- ),
- removed_in_version=2.12,
- ),
- syslog_settings=dict(
- type='dict',
- suboptions=dict(
- syslog_format=dict(
- choices=[
- 'bsd-syslog',
- 'syslog',
- 'legacy-bigip',
- 'rfc5424',
- 'rfc3164'
- ]
- ),
- forward_to=dict()
- ),
- removed_in_version=2.12,
- ),
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
- self.mutually_exclusive = [
- ['syslog_settings', 'syslog_format'],
- ['syslog_settings', 'forward_to'],
-
- ['pool_settings', 'pool'],
- ['pool_settings', 'protocol'],
- ['pool_settings', 'distribution'],
- ]
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode,
- mutually_exclusive=spec.mutually_exclusive
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_log_publisher.py b/lib/ansible/modules/network/f5/bigip_log_publisher.py
deleted file mode 100644
index 37edc3a6ce..0000000000
--- a/lib/ansible/modules/network/f5/bigip_log_publisher.py
+++ /dev/null
@@ -1,425 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_log_publisher
-short_description: Manages log publishers on a BIG-IP
-description:
- - Manages log publishers on a BIG-IP.
-version_added: 2.6
-options:
- name:
- description:
- - Specifies the name of the log publisher.
- type: str
- required: True
- description:
- description:
- - Specifies a description for the log publisher.
- type: str
- destinations:
- description:
- - Specifies log destinations for this log publisher to use.
- type: list
- partition:
- description:
- - Device partition to manage resources on.
- type: str
- default: Common
- state:
- description:
- - When C(present), ensures that the resource exists.
- - When C(absent), ensures the resource is removed.
- type: str
- choices:
- - present
- - absent
- default: present
-extends_documentation_fragment: f5
-author:
- - Tim Rupp (@caphrim007)
- - Wojciech Wypior (@wojtek0806)
-'''
-
-EXAMPLES = r'''
-- name: Create a log publisher for use in high speed loggins
- bigip_log_publisher:
- name: publisher1
- destinations:
- - hsl1
- - security-log-servers-logging
- state: present
- provider:
- user: admin
- password: secret
- server: lb.mydomain.com
- delegate_to: localhost
-'''
-
-RETURN = r'''
-description:
- description: The new description of the resource.
- returned: changed
- type: str
- sample: "Security log publisher"
-destinations:
- description: The new list of destinations for the resource.
- returned: changed
- type: list
- sample: ['/Common/destination1', '/Common/destination2']
-'''
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.basic import env_fallback
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import transform_name
- from library.module_utils.network.f5.common import fq_name
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.compare import cmp_simple_list
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import transform_name
- from ansible.module_utils.network.f5.common import fq_name
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.compare import cmp_simple_list
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
-
- }
-
- api_attributes = [
- 'destinations',
- 'description',
- ]
-
- returnables = [
- 'destinations',
- 'description',
- ]
-
- updatables = [
- 'destinations',
- 'description',
- ]
-
-
-class ApiParameters(Parameters):
- @property
- def destinations(self):
- if self._values['destinations'] is None:
- return None
- results = []
- for destination in self._values['destinations']:
- result = fq_name(destination['partition'], destination['name'])
- results.append(result)
- results.sort()
- return results
-
-
-class ModuleParameters(Parameters):
- @property
- def destinations(self):
- if self._values['destinations'] is None:
- return None
- if len(self._values['destinations']) == 1 and self._values['destinations'][0] == '':
- return ''
- result = [fq_name(self.partition, x) for x in self._values['destinations']]
- result = list(set(result))
- result.sort()
- return result
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class UsableChanges(Changes):
- pass
-
-
-class ReportableChanges(Changes):
- pass
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
- @property
- def destinations(self):
- result = cmp_simple_list(self.want.destinations, self.have.destinations)
- return result
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(params=self.module.params)
- self.have = ApiParameters()
- self.changes = UsableChanges()
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = UsableChanges(params=changed)
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def exec_module(self):
- changed = False
- result = dict()
- state = self.want.state
-
- if state == "present":
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.client.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def present(self):
- if self.exists():
- return self.update()
- else:
- return self.create()
-
- def update(self):
- self.have = self.read_current_from_device()
- if not self.should_update():
- return False
- if self.module.check_mode:
- return True
- self.update_on_device()
- return True
-
- def remove(self):
- if self.module.check_mode:
- return True
- self.remove_from_device()
- if self.exists():
- raise F5ModuleError("Failed to delete the resource.")
- return True
-
- def create(self):
- self._set_changed_options()
- if self.module.check_mode:
- return True
- self.create_on_device()
- return True
-
- def absent(self):
- if self.exists():
- return self.remove()
- return False
-
- def exists(self):
- uri = "https://{0}:{1}/mgmt/tm/sys/log-config/publisher/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def update_on_device(self):
- params = self.changes.api_params()
- uri = "https://{0}:{1}/mgmt/tm/sys/log-config/publisher/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/sys/log-config/publisher/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
-
- resp = self.client.api.get(uri)
-
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return ApiParameters(params=response)
-
- def create_on_device(self):
- params = self.changes.api_params()
- params['name'] = self.want.name
- params['partition'] = self.want.partition
- uri = "https://{0}:{1}/mgmt/tm/sys/log-config/publisher/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return response['selfLink']
-
- def remove_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/sys/log-config/publisher/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- response = self.client.api.delete(uri)
- if response.status == 200:
- return True
- raise F5ModuleError(response.content)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- name=dict(required=True),
- description=dict(),
- destinations=dict(type='list'),
- state=dict(
- default='present',
- choices=['present', 'absent']
- ),
- partition=dict(
- default='Common',
- fallback=(env_fallback, ['F5_PARTITION'])
- )
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_lx_package.py b/lib/ansible/modules/network/f5/bigip_lx_package.py
deleted file mode 100644
index 2a43e1f4b3..0000000000
--- a/lib/ansible/modules/network/f5/bigip_lx_package.py
+++ /dev/null
@@ -1,480 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_lx_package
-short_description: Manages Javascript LX packages on a BIG-IP
-description:
- - Manages Javascript LX packages on a BIG-IP. This module will allow
- you to deploy LX packages to the BIG-IP and manage their lifecycle.
-version_added: 2.5
-options:
- package:
- description:
- - The LX package that you want to upload or remove. When C(state) is C(present),
- and you intend to use this module in a C(role), it is recommended that you use
- the C({{ role_path }}) variable. An example is provided in the C(EXAMPLES) section.
- - When C(state) is C(absent), it is not necessary for the package to exist on the
- Ansible controller. If the full path to the package is provided, the filename will
- specifically be cherry picked from it to properly remove the package.
- type: path
- state:
- description:
- - Whether the LX package should exist or not.
- type: str
- default: present
- choices:
- - present
- - absent
-notes:
- - Requires the rpm tool be installed on the host. This can be accomplished through
- different ways on each platform. On Debian based systems with C(apt);
- C(apt-get install rpm). On Mac with C(brew); C(brew install rpm).
- This command is already present on RedHat based systems.
- - Requires BIG-IP >= 12.1.0 because the required functionality is missing
- on versions earlier than that.
- - The module name C(bigip_iapplx_package) has been deprecated in favor of C(bigip_lx_package).
-requirements:
- - Requires BIG-IP >= 12.1.0
- - The 'rpm' tool installed on the Ansible controller
-extends_documentation_fragment: f5
-author:
- - Tim Rupp (@caphrim007)
- - Wojciech Wypior (@wojtek0806)
-'''
-
-EXAMPLES = r'''
-- name: Install AS3
- bigip_lx_package:
- package: f5-appsvcs-3.5.0-3.noarch.rpm
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-
-- name: Add an LX package stored in a role
- bigip_lx_package:
- package: "{{ roles_path }}/files/MyApp-0.1.0-0001.noarch.rpm'"
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-
-- name: Remove an LX package
- bigip_lx_package:
- package: MyApp-0.1.0-0001.noarch.rpm
- state: absent
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-'''
-
-RETURN = r'''
-# only common fields returned
-'''
-
-import os
-import time
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.urls import urlparse
-from distutils.version import LooseVersion
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.icontrol import tmos_version
- from library.module_utils.network.f5.icontrol import upload_file
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.icontrol import tmos_version
- from ansible.module_utils.network.f5.icontrol import upload_file
-
-
-class Parameters(AnsibleF5Parameters):
- api_attributes = []
- returnables = []
-
- @property
- def package(self):
- if self._values['package'] is None:
- return None
- return self._values['package']
-
- @property
- def package_file(self):
- if self._values['package'] is None:
- return None
- return os.path.basename(self._values['package'])
-
- @property
- def package_name(self):
- """Return a valid name for the package
-
- BIG-IP determines the package name by the content of the RPM info.
- It does not use the filename. Therefore, we do the same. This method
- is only used though when the file actually exists on your Ansible
- controller.
-
- If the package does not exist, then we instead use the filename
- portion of the 'package' argument that is provided.
-
- Non-existence typically occurs when using 'state' = 'absent'
-
- :return:
- """
- cmd = ['rpm', '-qp', '--queryformat', '%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}', self.package]
- rc, out, err = self._module.run_command(cmd)
- if not out:
- return str(self.package_file)
- return out
-
- @property
- def package_root(self):
- if self._values['package'] is None:
- return None
- base = os.path.basename(self._values['package'])
- result = os.path.splitext(base)
- return result[0]
-
-
-class ApiParameters(Parameters):
- pass
-
-
-class ModuleParameters(Parameters):
- pass
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class UsableChanges(Changes):
- pass
-
-
-class ReportableChanges(Changes):
- pass
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(module=self.module, params=self.module.params)
- self.changes = UsableChanges()
-
- def exec_module(self):
- result = dict()
- changed = False
- state = self.want.state
-
- version = tmos_version(self.client)
- if LooseVersion(version) <= LooseVersion('12.0.0'):
- raise F5ModuleError(
- "This version of BIG-IP is not supported."
- )
-
- if state == "present":
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
-
- changes = self.changes.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- return result
-
- def present(self):
- if self.exists():
- return False
- else:
- return self.create()
-
- def absent(self):
- changed = False
- if self.exists():
- changed = self.remove()
- return changed
-
- def remove(self):
- if self.module.check_mode:
- return True
- self.remove_from_device()
- if self.exists():
- raise F5ModuleError("Failed to delete the LX package.")
- return True
-
- def create(self):
- if self.module.check_mode:
- return True
- if not os.path.exists(self.want.package):
- if self.want.package.startswith('/'):
- raise F5ModuleError(
- "The specified LX package was not found at {0}.".format(self.want.package)
- )
- else:
- raise F5ModuleError(
- "The specified LX package was not found in {0}.".format(os.getcwd())
- )
- self.upload_to_device()
- self.create_on_device()
- self.enable_iapplx_on_device()
- self.remove_package_file_from_device()
- if self.exists():
- return True
- else:
- raise F5ModuleError("Failed to install LX package.")
-
- def exists(self):
- exists = False
- packages = self.get_installed_packages_on_device()
- if os.path.exists(self.want.package):
- exists = True
- for package in packages:
- if exists:
- if self.want.package_name == package['packageName']:
- return True
- else:
- if self.want.package_root == package['packageName']:
- return True
- return False
-
- def get_installed_packages_on_device(self):
- uri = "https://{0}:{1}/mgmt/shared/iapp/package-management-tasks".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- params = dict(operation='QUERY')
- resp = self.client.api.post(uri, json=params)
-
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- path = urlparse(response["selfLink"]).path
- task = self._wait_for_task(path)
-
- if task['status'] == 'FINISHED':
- return task['queryResponse']
- raise F5ModuleError(
- "Failed to find the installed packages on the device."
- )
-
- def _wait_for_task(self, path):
- task = None
- for x in range(0, 60):
- task = self.check_task_on_device(path)
- if task['status'] in ['FINISHED', 'FAILED']:
- return task
- time.sleep(1)
- return task
-
- def check_task_on_device(self, path):
- uri = "https://{0}:{1}{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- path
- )
- resp = self.client.api.get(uri)
-
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return response
-
- def upload_to_device(self):
- url = 'https://{0}:{1}/mgmt/shared/file-transfer/uploads'.format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- try:
- upload_file(self.client, url, self.want.package)
- except F5ModuleError:
- raise F5ModuleError(
- "Failed to upload the file."
- )
-
- def remove_package_file_from_device(self):
- params = dict(
- command="run",
- utilCmdArgs="/var/config/rest/downloads/{0}".format(self.want.package_file)
- )
- uri = "https://{0}:{1}/mgmt/tm/util/unix-rm".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def create_on_device(self):
- remote_path = "/var/config/rest/downloads/{0}".format(self.want.package_file)
- params = dict(
- operation='INSTALL', packageFilePath=remote_path
- )
- uri = "https://{0}:{1}/mgmt/shared/iapp/package-management-tasks".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
-
- resp = self.client.api.post(uri, json=params)
-
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- path = urlparse(response["selfLink"]).path
- task = self._wait_for_task(path)
-
- if task['status'] == 'FINISHED':
- return True
- else:
- raise F5ModuleError(task['errorMessage'])
-
- def remove_from_device(self):
- params = dict(
- operation='UNINSTALL',
- packageName=self.want.package_root
- )
- uri = "https://{0}:{1}/mgmt/shared/iapp/package-management-tasks".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
-
- resp = self.client.api.post(uri, json=params)
-
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- path = urlparse(response["selfLink"]).path
- task = self._wait_for_task(path)
-
- if task['status'] == 'FINISHED':
- return True
- return False
-
- def enable_iapplx_on_device(self):
- params = dict(
- command="run",
- utilCmdArgs='-c "touch /var/config/rest/iapps/enable"'
- )
- uri = "https://{0}:{1}/mgmt/tm/util/bash".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- state=dict(
- default='present',
- choices=['present', 'absent']
- ),
- package=dict(type='path')
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
- self.required_if = [
- ['state', 'present', ['package']]
- ]
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode,
- required_if=spec.required_if
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_management_route.py b/lib/ansible/modules/network/f5/bigip_management_route.py
deleted file mode 100644
index 75e79b056f..0000000000
--- a/lib/ansible/modules/network/f5/bigip_management_route.py
+++ /dev/null
@@ -1,453 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2018, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_management_route
-short_description: Manage system management routes on a BIG-IP
-description:
- - Configures route settings for the management interface of a BIG-IP.
-version_added: 2.6
-options:
- name:
- description:
- - Specifies the name of the management route.
- type: str
- required: True
- description:
- description:
- - Description of the management route.
- type: str
- gateway:
- description:
- - Specifies that the system forwards packets to the destination through the
- gateway with the specified IP address.
- type: str
- network:
- description:
- - The subnet and netmask to be used for the route.
- - To specify that the route is the default route for the system, provide the
- value C(default).
- - Only one C(default) entry is allowed.
- - This parameter cannot be changed after it is set. Therefore, if you do need to change
- it, it is required that you delete and create a new route.
- type: str
- partition:
- description:
- - Device partition to manage resources on.
- type: str
- default: Common
- state:
- description:
- - When C(present), ensures that the resource exists.
- - When C(absent), ensures the resource is removed.
- type: str
- choices:
- - present
- - absent
- default: present
-extends_documentation_fragment: f5
-author:
- - Tim Rupp (@caphrim007)
- - Wojciech Wypior (@wojtek0806)
-'''
-
-EXAMPLES = r'''
-- name: Create a management route
- bigip_management_route:
- name: tacacs
- description: Route to TACACS
- gateway: 10.10.10.10
- network: 11.11.11.0/24
- state: present
- provider:
- user: admin
- password: secret
- server: lb.mydomain.com
- delegate_to: localhost
-'''
-
-RETURN = r'''
-description:
- description: The new description of the management route.
- returned: changed
- type: str
- sample: Route to TACACS
-gateway:
- description: The new gateway of the management route.
- returned: changed
- type: str
- sample: 10.10.10.10
-network:
- description: The new network to use for the management route.
- returned: changed
- type: str
- sample: default
-'''
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.basic import env_fallback
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.ipaddress import is_valid_ip
- from library.module_utils.compat.ipaddress import ip_network
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.ipaddress import is_valid_ip
- from ansible.module_utils.compat.ipaddress import ip_network
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
-
- }
-
- api_attributes = [
- 'description',
- 'gateway',
- 'network',
- ]
-
- returnables = [
- 'description',
- 'gateway',
- 'network',
- ]
-
- updatables = [
- 'description',
- 'gateway',
- 'network',
- ]
-
-
-class ApiParameters(Parameters):
- pass
-
-
-class ModuleParameters(Parameters):
- @property
- def network(self):
- if self._values['network'] is None:
- return None
- if self._values['network'] == 'default':
- return 'default'
- try:
- addr = ip_network(u"{0}".format(str(self._values['network'])))
- return str(addr)
- except ValueError:
- raise F5ModuleError(
- "The 'network' must either be a network address (with CIDR) or the word 'default'."
- )
-
- @property
- def gateway(self):
- if self._values['gateway'] is None:
- return None
- if is_valid_ip(self._values['gateway']):
- return self._values['gateway']
- else:
- raise F5ModuleError(
- "The 'gateway' must an IP address."
- )
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class UsableChanges(Changes):
- pass
-
-
-class ReportableChanges(Changes):
- pass
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
- @property
- def network(self):
- if self.want.network is None:
- return None
- if self.want.network == '0.0.0.0/0' and self.have.network == 'default':
- return None
- if self.want.network != self.have.network:
- raise F5ModuleError(
- "'network' cannot be changed after it is set."
- )
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(params=self.module.params)
- self.have = ApiParameters()
- self.changes = UsableChanges()
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = UsableChanges(params=changed)
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def exec_module(self):
- changed = False
- result = dict()
- state = self.want.state
-
- if state == "present":
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.client.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def present(self):
- if self.exists():
- return self.update()
- else:
- return self.create()
-
- def absent(self):
- if self.exists():
- return self.remove()
- return False
-
- def update(self):
- self.have = self.read_current_from_device()
- if not self.should_update():
- return False
- if self.module.check_mode:
- return True
- self.update_on_device()
- return True
-
- def remove(self):
- if self.module.check_mode:
- return True
- self.remove_from_device()
- if self.exists():
- raise F5ModuleError("Failed to delete the resource.")
- return True
-
- def create(self):
- self._set_changed_options()
- if self.module.check_mode:
- return True
- self.create_on_device()
- return True
-
- def exists(self):
- uri = "https://{0}:{1}/mgmt/tm/sys/management-route/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- self.want.name
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def create_on_device(self):
- params = self.changes.api_params()
- params['name'] = self.want.name
- params['partition'] = self.want.partition
- uri = "https://{0}:{1}/mgmt/tm/sys/management-route/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
-
- resp = self.client.api.post(uri, json=params)
-
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return response['selfLink']
-
- def update_on_device(self):
- params = self.changes.api_params()
- uri = "https://{0}:{1}/mgmt/tm/sys/management-route/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- self.want.name
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def remove_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/sys/management-route/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- self.want.name
- )
- response = self.client.api.delete(uri)
- if response.status == 200:
- return True
- raise F5ModuleError(response.content)
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/sys/management-route/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- self.want.name
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return ApiParameters(params=response)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- name=dict(required=True),
- gateway=dict(),
- network=dict(),
- description=dict(),
- partition=dict(
- default='Common',
- fallback=(env_fallback, ['F5_PARTITION'])
- ),
- state=dict(
- default='present',
- choices=['present', 'absent']
- )
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_message_routing_peer.py b/lib/ansible/modules/network/f5/bigip_message_routing_peer.py
deleted file mode 100644
index 00afcf8c73..0000000000
--- a/lib/ansible/modules/network/f5/bigip_message_routing_peer.py
+++ /dev/null
@@ -1,659 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2019, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_message_routing_peer
-short_description: Manage peers for routing generic message protocol messages
-description:
- - Manage peers for routing generic message protocol messages.
-version_added: 2.9
-options:
- name:
- description:
- - Specifies the name of the peer to manage.
- type: str
- required: True
- description:
- description:
- - The user defined description of the peer.
- type: str
- type:
- description:
- - Parameter used to specify the type of the peer to manage.
- - Default setting is C(generic) with more options added in future.
- type: str
- choices:
- - generic
- default: generic
- auto_init:
- description:
- - If C(yes), the BIGIP will automatically create outbound connections to the active pool members in the
- specified C(pool) using the configuration of the specified C(transport_config).
- - For auto-initialization to attempt to create a connection, the peer must be included in a route that is attached
- to a router instance. For each router instance that the peer is contained in, a connection will be initiated.
- - The C(auto_init) logic will verify at C(auto_init_interval) if the a connection exists between
- the BIG-IP and the pool members of the pool. If a connection does not exist, it will attempt to reestablish one.
- type: bool
- auto_init_interval:
- description:
- - Specifies the interval that attempts to initiate a connection occur.
- - The default value upon peer object creation, that supplied by the system is C(5000) milliseconds.
- - The accepted range is between 0 and 4294967295 inclusive.
- type: int
- connection_mode:
- description:
- - Specifies how the number of connections per host are to be limited.
- type: str
- choices:
- - per-blade
- - per-client
- - per-peer
- - per-tmm
- number_of_connections:
- description:
- - Specifies the distribution of connections between the BIG-IP and a remote host.
- - The accepted range is between 0 and 65535 inclusive.
- type: int
- pool:
- description:
- - Specifies the name of the pool that messages will be routed towards.
- - The specified pool must be on the same partition as the peer.
- type: str
- ratio:
- description:
- - Specifies the ratio to be used for selection of a peer within a list of peers in a ltm route.
- - The accepted range is between 0 and 4294967295 inclusive.
- type: int
- transport_config:
- description:
- - The name of the ltm virtual or ltm transport-config to use for creating an outgoing connection.
- - The resource must exist on the same partition as the peer object.
- type: str
- partition:
- description:
- - Device partition to create peer object on.
- type: str
- default: Common
- state:
- description:
- - When C(present), ensures that the peer exists.
- - When C(absent), ensures the peer is removed.
- type: str
- choices:
- - present
- - absent
- default: present
-notes:
- - Requires BIG-IP >= 14.0.0
-extends_documentation_fragment: f5
-author:
- - Wojciech Wypior (@wojtek0806)
-'''
-
-EXAMPLES = r'''
-- name: Create a simple peer
- bigip_message_routing_peer:
- name: foobar
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-
-- name: Create message routing peer with additional settings
- bigip_message_routing_peer:
- name: foobar
- connection_mode: per-blade
- pool: /baz/bar
- partition: baz
- transport_config: foovirtual
- ratio: 10
- auto_init: yes
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-
-- name: Modify message routing peer settings
- bigip_message_routing_peer:
- name: foobar
- partition: baz
- ratio: 20
- auto_init_interval: 2000
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-
-- name: Remove message routing peer
- bigip_message_routing_peer:
- name: foobar
- partition: baz
- state: absent
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-'''
-
-RETURN = r'''
-auto_init:
- description: Enables creation of outbound connections to the active pool members.
- returned: changed
- type: bool
- sample: yes
-auto_init_interval:
- description: The interval that attempts to initiate a connection occur.
- returned: changed
- type: int
- sample: 2000
-connection_mode:
- description: Specifies how the number of connections per host are to be limited.
- returned: changed
- type: str
- sample: per-peer
-number_of_connections:
- description: The distribution of connections between the BIG-IP and a remote host.
- returned: changed
- type: int
- sample: 2000
-transport_config:
- description: The ltm virtual or ltm transport-config to use for creating an outgoing connection.
- returned: changed
- type: str
- sample: /Common/foobar
-description:
- description: The user defined description of the peer.
- returned: changed
- type: str
- sample: Some description
-pool:
- description: The name of the pool that messages will be routed towards.
- returned: changed
- type: str
- sample: /Bazbar/foobar
-ratio:
- description: The ratio to be used for selection of a peer within a list of peers in a ltm route.
- returned: changed
- type: int
- sample: 500
-'''
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.basic import env_fallback
-from distutils.version import LooseVersion
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import fq_name
- from library.module_utils.network.f5.common import flatten_boolean
- from library.module_utils.network.f5.common import transform_name
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.compare import cmp_str_with_none
- from library.module_utils.network.f5.icontrol import tmos_version
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import fq_name
- from ansible.module_utils.network.f5.common import flatten_boolean
- from ansible.module_utils.network.f5.common import transform_name
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.compare import cmp_str_with_none
- from ansible.module_utils.network.f5.icontrol import tmos_version
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'autoInitialization': 'auto_init',
- 'autoInitializationInterval': 'auto_init_interval',
- 'connectionMode': 'connection_mode',
- 'numberConnections': 'number_of_connections',
- 'transportConfig': 'transport_config',
- }
-
- api_attributes = [
- 'autoInitialization',
- 'autoInitializationInterval',
- 'connectionMode',
- 'description',
- 'numberConnections',
- 'pool',
- 'ratio',
- 'transportConfig',
- ]
-
- returnables = [
- 'auto_init',
- 'auto_init_interval',
- 'connection_mode',
- 'number_of_connections',
- 'transport_config',
- 'description',
- 'pool',
- 'ratio',
- ]
-
- updatables = [
- 'auto_init',
- 'auto_init_interval',
- 'connection_mode',
- 'number_of_connections',
- 'transport_config',
- 'description',
- 'pool',
- 'ratio',
- ]
-
-
-class ApiParameters(Parameters):
- pass
-
-
-class ModuleParameters(Parameters):
- @property
- def auto_init(self):
- result = flatten_boolean(self._values['auto_init'])
- if result is None:
- return None
- if result == 'yes':
- return 'enabled'
- return 'disabled'
-
- @property
- def auto_init_interval(self):
- if self._values['auto_init_interval'] is None:
- return None
- if 0 <= self._values['auto_init_interval'] <= 4294967295:
- return self._values['auto_init_interval']
- raise F5ModuleError(
- "Valid 'auto_init_interval' must be in range 0 - 4294967295 milliseconds."
- )
-
- @property
- def number_of_connections(self):
- if self._values['number_of_connections'] is None:
- return None
- if 0 <= self._values['number_of_connections'] <= 65535:
- return self._values['number_of_connections']
- raise F5ModuleError(
- "Valid 'number_of_connections' must be in range 0 - 65535."
- )
-
- @property
- def ratio(self):
- if self._values['ratio'] is None:
- return None
- if 0 <= self._values['ratio'] <= 4294967295:
- return self._values['ratio']
- raise F5ModuleError(
- "Valid 'ratio' must be in range 0 - 4294967295."
- )
-
- @property
- def pool(self):
- if self._values['pool'] is None:
- return None
- if self._values['pool'] == "":
- return ""
- result = fq_name(self.partition, self._values['pool'])
- return result
-
- @property
- def transport_config(self):
- if self._values['transport_config'] is None:
- return None
- if self._values['transport_config'] == "":
- return ""
- result = fq_name(self.partition, self._values['transport_config'])
- return result
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class UsableChanges(Changes):
- pass
-
-
-class ReportableChanges(Changes):
- @property
- def auto_init(self):
- result = flatten_boolean(self._values['auto_init'])
- return result
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
- @property
- def description(self):
- result = cmp_str_with_none(self.want.description, self.have.description)
- return result
-
- @property
- def transport_config(self):
- result = cmp_str_with_none(self.want.transport_config, self.have.transport_config)
- return result
-
- @property
- def pool(self):
- result = cmp_str_with_none(self.want.pool, self.have.pool)
- return result
-
-
-class BaseManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(params=self.module.params)
- self.have = ApiParameters()
- self.changes = UsableChanges()
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = UsableChanges(params=changed)
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.client.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def exec_module(self):
- changed = False
- result = dict()
- state = self.want.state
-
- if state == "present":
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def present(self):
- if self.exists():
- return self.update()
- else:
- return self.create()
-
- def absent(self):
- if self.exists():
- return self.remove()
- return False
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def update(self):
- self.have = self.read_current_from_device()
- if not self.should_update():
- return False
- if self.module.check_mode:
- return True
- self.update_on_device()
- return True
-
- def remove(self):
- if self.module.check_mode:
- return True
- self.remove_from_device()
- if self.exists():
- raise F5ModuleError("Failed to delete the resource.")
- return True
-
- def create(self):
- self._set_changed_options()
- if self.module.check_mode:
- return True
- self.create_on_device()
- return True
-
-
-class GenericModuleManager(BaseManager):
- def exists(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/message-routing/generic/peer/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def create_on_device(self):
- params = self.changes.api_params()
- params['name'] = self.want.name
- params['partition'] = self.want.partition
- uri = "https://{0}:{1}/mgmt/tm/ltm/message-routing/generic/peer/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 409]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return True
-
- def update_on_device(self):
- params = self.changes.api_params()
- uri = "https://{0}:{1}/mgmt/tm/ltm/message-routing/generic/peer/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def remove_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/message-routing/generic/peer/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- response = self.client.api.delete(uri)
- if response.status == 200:
- return True
- raise F5ModuleError(response.content)
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/message-routing/generic/peer/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return ApiParameters(params=response)
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.kwargs = kwargs
-
- def version_less_than_14(self):
- version = tmos_version(self.client)
- if LooseVersion(version) < LooseVersion('14.0.0'):
- return True
- return False
-
- def exec_module(self):
- if self.version_less_than_14():
- raise F5ModuleError('Message routing is not supported on TMOS version below 14.x')
- if self.module.params['type'] == 'generic':
- manager = self.get_manager('generic')
- else:
- raise F5ModuleError(
- "Unknown type specified."
- )
- return manager.exec_module()
-
- def get_manager(self, type):
- if type == 'generic':
- return GenericModuleManager(**self.kwargs)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- name=dict(required=True),
- auto_init=dict(type='bool'),
- auto_init_interval=dict(type='int'),
- connection_mode=dict(
- choices=['per-blade', 'per-client', 'per-peer', 'per-tmm']
- ),
- description=dict(),
- number_of_connections=dict(type='int'),
- pool=dict(),
- ratio=dict(type='int'),
- transport_config=dict(),
- type=dict(
- choices=['generic'],
- default='generic'
- ),
- partition=dict(
- default='Common',
- fallback=(env_fallback, ['F5_PARTITION'])
- ),
- state=dict(
- default='present',
- choices=['present', 'absent']
- )
- )
- self.required_if = [
- ['auto_init', True, ['transport_config']]
- ]
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode,
- required_if=spec.required_if,
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_message_routing_protocol.py b/lib/ansible/modules/network/f5/bigip_message_routing_protocol.py
deleted file mode 100644
index 58b22d752e..0000000000
--- a/lib/ansible/modules/network/f5/bigip_message_routing_protocol.py
+++ /dev/null
@@ -1,566 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2019, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_message_routing_protocol
-short_description: Manage generic message parser profile.
-description:
- - Manages generic message parser profile for use with the message routing framework.
-version_added: 2.9
-options:
- name:
- description:
- - Specifies the name of the generic parser profile.
- required: True
- type: str
- description:
- description:
- - The user defined description of the generic parser profile.
- type: str
- parent:
- description:
- - The parent template of this parser profile. Once this value has been set, it cannot be changed.
- - When creating a new profile, if this parameter is not specified,
- the default is the system-supplied C(genericmsg) profile.
- type: str
- disable_parser:
- description:
- - When C(yes), the generic message parser will be disabled ignoring all incoming packets and not directly
- send message data.
- - This mode supports iRule script protocol implementations that will generate messages from the incoming transport
- stream and send outgoing messages on the outgoing transport stream.
- type: bool
- max_egress_buffer:
- description:
- - Specifies the maximum size of the send buffer in bytes. If the number of bytes in the send buffer for a
- connection exceeds this value, the generic message protocol will stop receiving outgoing messages from the
- router until the size of the size of the buffer drops below this setting.
- - The accepted range is between 0 and 4294967295 inclusive.
- type: int
- max_msg_size:
- description:
- - Specifies the maximum size of a received message. If a message exceeds this size, the connection will be reset.
- - The accepted range is between 0 and 4294967295 inclusive.
- type: int
- msg_terminator:
- description:
- - The string of characters used to terminate a message. If the message-terminator is not specified,
- the generic message parser will not separate the input stream into messages.
- type: str
- no_response:
- description:
- - When set, matching of responses to requests is disabled.
- type: bool
- partition:
- description:
- - Device partition to create route object on.
- type: str
- default: Common
- state:
- description:
- - When C(present), ensures that the route exists.
- - When C(absent), ensures the route is removed.
- type: str
- choices:
- - present
- - absent
- default: present
-notes:
- - Requires BIG-IP >= 14.0.0
-extends_documentation_fragment: f5
-author:
- - Wojciech Wypior (@wojtek0806)
-'''
-
-EXAMPLES = r'''
-- name: Create a generic parser
- bigip_message_routing_protocol:
- name: foo
- description: 'This is parser'
- no_response: yes
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-
-- name: Modify a generic parser
- bigip_message_routing_protocol:
- name: foo
- no_response: no
- max_egress_buffer: 10000
- max_msg_size: 2000
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-
-- name: Remove generic parser
- bigip_message_routing_protocol:
- name: foo
- state: absent
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-'''
-
-RETURN = r'''
-description:
- description: The user defined description of the parser profile.
- returned: changed
- type: str
- sample: My description
-parent:
- description: The parent template of this parser profile.
- returned: changed
- type: str
- sample: /Common/genericmsg
-disable_parser:
- description: Disables generic message parser.
- returned: changed
- type: bool
- sample: yes
-max_egress_buffer:
- description: The maximum size of the send buffer in bytes.
- returned: changed
- type: int
- sample: 10000
-max_msg_size:
- description: The maximum size of a received message.
- returned: changed
- type: int
- sample: 4000
-msg_terminator:
- description: The string of characters used to terminate a message.
- returned: changed
- type: str
- sample: '%%%%'
-no_response:
- description: Disables matching of responses to requests.
- returned: changed
- type: bool
- sample: yes
-'''
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.basic import env_fallback
-from distutils.version import LooseVersion
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import fq_name
- from library.module_utils.network.f5.common import transform_name
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.common import flatten_boolean
- from library.module_utils.network.f5.compare import cmp_str_with_none
- from library.module_utils.network.f5.icontrol import tmos_version
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import fq_name
- from ansible.module_utils.network.f5.common import transform_name
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.common import flatten_boolean
- from ansible.module_utils.network.f5.compare import cmp_str_with_none
- from ansible.module_utils.network.f5.icontrol import tmos_version
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'defaultsFrom': 'parent',
- 'disableParser': 'disable_parser',
- 'maxEgressBuffer': 'max_egress_buffer',
- 'maxMessageSize': 'max_msg_size',
- 'messageTerminator': 'msg_terminator',
- 'noResponse': 'no_response',
-
- }
-
- api_attributes = [
- 'description',
- 'defaultsFrom',
- 'disableParser',
- 'maxEgressBuffer',
- 'maxMessageSize',
- 'messageTerminator',
- 'noResponse',
- ]
-
- returnables = [
- 'description',
- 'parent',
- 'disable_parser',
- 'max_egress_buffer',
- 'max_msg_size',
- 'msg_terminator',
- 'no_response',
- ]
-
- updatables = [
- 'description',
- 'parent',
- 'disable_parser',
- 'max_egress_buffer',
- 'max_msg_size',
- 'msg_terminator',
- 'no_response',
- ]
-
- @property
- def no_response(self):
- return flatten_boolean(self._values['no_response'])
-
- @property
- def disable_parser(self):
- return flatten_boolean(self._values['disable_parser'])
-
-
-class ApiParameters(Parameters):
- pass
-
-
-class ModuleParameters(Parameters):
- @property
- def parent(self):
- if self._values['parent'] is None:
- return None
- result = fq_name(self.partition, self._values['parent'])
- return result
-
- @property
- def max_msg_size(self):
- if self._values['max_msg_size'] is None:
- return None
- if 0 <= self._values['max_msg_size'] <= 4294967295:
- return self._values['max_msg_size']
- raise F5ModuleError(
- "Valid 'max_msg_size' must be in range 0 - 4294967295."
- )
-
- @property
- def max_egress_buffer(self):
- if self._values['max_egress_buffer'] is None:
- return None
- if 0 <= self._values['max_egress_buffer'] <= 4294967295:
- return self._values['max_egress_buffer']
- raise F5ModuleError(
- "Valid 'max_egress_buffer' must be in range 0 - 4294967295."
- )
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class UsableChanges(Changes):
- pass
-
-
-class ReportableChanges(Changes):
- pass
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
- @property
- def parent(self):
- if self.want.parent is None:
- return None
- if self.want.parent != self.have.parent:
- raise F5ModuleError(
- "The parent router profile cannot be changed."
- )
-
- @property
- def description(self):
- return cmp_str_with_none(self.want.description, self.have.description)
-
- @property
- def msg_terminator(self):
- return cmp_str_with_none(self.want.msg_terminator, self.have.msg_terminator)
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(params=self.module.params)
- self.have = ApiParameters()
- self.changes = UsableChanges()
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = UsableChanges(params=changed)
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.client.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def version_less_than_14(self):
- version = tmos_version(self.client)
- if LooseVersion(version) < LooseVersion('14.0.0'):
- return True
- return False
-
- def exec_module(self):
- if self.version_less_than_14():
- raise F5ModuleError('Message routing is not supported on TMOS version below 14.x')
- changed = False
- result = dict()
- state = self.want.state
-
- if state == "present":
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def present(self):
- if self.exists():
- return self.update()
- else:
- return self.create()
-
- def absent(self):
- if self.exists():
- return self.remove()
- return False
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def update(self):
- self.have = self.read_current_from_device()
- if not self.should_update():
- return False
- if self.module.check_mode:
- return True
- self.update_on_device()
- return True
-
- def remove(self):
- if self.module.check_mode:
- return True
- self.remove_from_device()
- if self.exists():
- raise F5ModuleError("Failed to delete the resource.")
- return True
-
- def create(self):
- self._set_changed_options()
- if self.module.check_mode:
- return True
- self.create_on_device()
- return True
-
- def exists(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/message-routing/generic/protocol/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def create_on_device(self):
- params = self.changes.api_params()
- params['name'] = self.want.name
- params['partition'] = self.want.partition
- uri = "https://{0}:{1}/mgmt/tm/ltm/message-routing/generic/protocol/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 409]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return True
-
- def update_on_device(self):
- params = self.changes.api_params()
- uri = "https://{0}:{1}/mgmt/tm/ltm/message-routing/generic/protocol/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def remove_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/message-routing/generic/protocol/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- response = self.client.api.delete(uri)
- if response.status == 200:
- return True
- raise F5ModuleError(response.content)
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/message-routing/generic/protocol/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return ApiParameters(params=response)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- name=dict(required=True),
- description=dict(),
- parent=dict(),
- disable_parser=dict(type='bool'),
- max_egress_buffer=dict(type='int'),
- max_msg_size=dict(type='int'),
- msg_terminator=dict(),
- no_response=dict(type='bool'),
- partition=dict(
- default='Common',
- fallback=(env_fallback, ['F5_PARTITION'])
- ),
- state=dict(
- default='present',
- choices=['present', 'absent']
- )
-
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode,
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_message_routing_route.py b/lib/ansible/modules/network/f5/bigip_message_routing_route.py
deleted file mode 100644
index b1e98ab3ba..0000000000
--- a/lib/ansible/modules/network/f5/bigip_message_routing_route.py
+++ /dev/null
@@ -1,555 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2019, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_message_routing_route
-short_description: Manages static routes for routing message protocol messages
-description:
- - Manages static routes for routing message protocol messages.
-version_added: 2.9
-options:
- name:
- description:
- - Specifies the name of the static route.
- required: True
- type: str
- description:
- description:
- - The user defined description of the static route.
- type: str
- type:
- description:
- - Parameter used to specify the type of the route to manage.
- - Default setting is C(generic) with more options added in future.
- type: str
- choices:
- - generic
- default: generic
- src_address:
- description:
- - Specifies the source address of the route.
- - Setting the attribute to an empty string will create a wildcard matching all message source-addresses, which is
- the default when creating a new route.
- type: str
- dst_address:
- description:
- - Specifies the destination address of the route.
- - Setting the attribute to an empty string will create a wildcard matching all message destination-addresses,
- which is the default when creating a new route.
- type: str
- peer_selection_mode:
- description:
- - Specifies the method to use when selecting a peer from the provided list of C(peers).
- type: str
- choices:
- - ratio
- - sequential
- peers:
- description:
- - Specifies a list of ltm messagerouting-peer objects.
- - The specified peer must be on the same partition as the route.
- type: list
- partition:
- description:
- - Device partition to create route object on.
- type: str
- default: Common
- state:
- description:
- - When C(present), ensures that the route exists.
- - When C(absent), ensures the route is removed.
- type: str
- choices:
- - present
- - absent
- default: present
-notes:
- - Requires BIG-IP >= 14.0.0
-extends_documentation_fragment: f5
-author:
- - Wojciech Wypior (@wojtek0806)
-'''
-
-EXAMPLES = r'''
-- name: Create a simple generic route
- bigip_message_routing_route:
- name: foobar
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-
-- name: Modify a generic route
- bigip_message_routing_route:
- name: foobar
- peers:
- - peer1
- - peer2
- peer_selection_mode: ratio
- src_address: annoying_user
- dst_address: blackhole
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-
-- name: Remove a generic
- bigip_message_routing_route:
- name: foobar
- state: absent
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-'''
-
-RETURN = r'''
-description:
- description: The user defined description of the route.
- returned: changed
- type: str
- sample: Some description
-src_address:
- description: The source address of the route.
- returned: changed
- type: str
- sample: annyoing_user
-dst_address:
- description: The destination address of the route.
- returned: changed
- type: str
- sample: blackhole
-peer_selection_mode:
- description: The method to use when selecting a peer.
- returned: changed
- type: str
- sample: ratio
-peers:
- description: The list of ltm messagerouting-peer object.
- returned: changed
- type: list
- sample: ['/Common/peer1', '/Common/peer2']
-'''
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.basic import env_fallback
-from distutils.version import LooseVersion
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import fq_name
- from library.module_utils.network.f5.common import flatten_boolean
- from library.module_utils.network.f5.common import transform_name
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.common import is_empty_list
- from library.module_utils.network.f5.compare import cmp_str_with_none
- from library.module_utils.network.f5.compare import cmp_simple_list
- from library.module_utils.network.f5.icontrol import tmos_version
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import fq_name
- from ansible.module_utils.network.f5.common import flatten_boolean
- from ansible.module_utils.network.f5.common import transform_name
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.common import is_empty_list
- from ansible.module_utils.network.f5.compare import cmp_str_with_none
- from ansible.module_utils.network.f5.compare import cmp_simple_list
- from ansible.module_utils.network.f5.icontrol import tmos_version
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'peerSelectionMode': 'peer_selection_mode',
- 'sourceAddress': 'src_address',
- 'destinationAddress': 'dst_address',
-
- }
-
- api_attributes = [
- 'description',
- 'peerSelectionMode',
- 'peers',
- 'sourceAddress',
- 'destinationAddress',
- ]
-
- returnables = [
- 'peer_selection_mode',
- 'peers',
- 'description',
- 'src_address',
- 'dst_address'
- ]
-
- updatables = [
- 'peer_selection_mode',
- 'peers',
- 'description',
- 'src_address',
- 'dst_address'
- ]
-
-
-class ApiParameters(Parameters):
- pass
-
-
-class ModuleParameters(Parameters):
- @property
- def peers(self):
- if self._values['peers'] is None:
- return None
- if is_empty_list(self._values['peers']):
- return ""
- result = [fq_name(self.partition, peer) for peer in self._values['peers']]
- return result
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class UsableChanges(Changes):
- pass
-
-
-class ReportableChanges(Changes):
- pass
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
- @property
- def description(self):
- result = cmp_str_with_none(self.want.description, self.have.description)
- return result
-
- @property
- def dst_address(self):
- result = cmp_str_with_none(self.want.dst_address, self.have.dst_address)
- return result
-
- @property
- def src_address(self):
- result = cmp_str_with_none(self.want.src_address, self.have.src_address)
- return result
-
- @property
- def peers(self):
- result = cmp_simple_list(self.want.peers, self.have.peers)
- return result
-
-
-class BaseManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(params=self.module.params)
- self.have = ApiParameters()
- self.changes = UsableChanges()
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = UsableChanges(params=changed)
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.client.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def exec_module(self):
- changed = False
- result = dict()
- state = self.want.state
-
- if state == "present":
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def present(self):
- if self.exists():
- return self.update()
- else:
- return self.create()
-
- def absent(self):
- if self.exists():
- return self.remove()
- return False
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def update(self):
- self.have = self.read_current_from_device()
- if not self.should_update():
- return False
- if self.module.check_mode:
- return True
- self.update_on_device()
- return True
-
- def remove(self):
- if self.module.check_mode:
- return True
- self.remove_from_device()
- if self.exists():
- raise F5ModuleError("Failed to delete the resource.")
- return True
-
- def create(self):
- self._set_changed_options()
- if self.module.check_mode:
- return True
- self.create_on_device()
- return True
-
-
-class GenericModuleManager(BaseManager):
- def exists(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/message-routing/generic/route/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def create_on_device(self):
- params = self.changes.api_params()
- params['name'] = self.want.name
- params['partition'] = self.want.partition
- uri = "https://{0}:{1}/mgmt/tm/ltm/message-routing/generic/route/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 409]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return True
-
- def update_on_device(self):
- params = self.changes.api_params()
- uri = "https://{0}:{1}/mgmt/tm/ltm/message-routing/generic/route/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def remove_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/message-routing/generic/route/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- response = self.client.api.delete(uri)
- if response.status == 200:
- return True
- raise F5ModuleError(response.content)
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/message-routing/generic/route/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return ApiParameters(params=response)
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.kwargs = kwargs
-
- def version_less_than_14(self):
- version = tmos_version(self.client)
- if LooseVersion(version) < LooseVersion('14.0.0'):
- return True
- return False
-
- def exec_module(self):
- if self.version_less_than_14():
- raise F5ModuleError('Message routing is not supported on TMOS version below 14.x')
- if self.module.params['type'] == 'generic':
- manager = self.get_manager('generic')
- else:
- raise F5ModuleError(
- "Unknown type specified."
- )
- return manager.exec_module()
-
- def get_manager(self, type):
- if type == 'generic':
- return GenericModuleManager(**self.kwargs)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- name=dict(required=True),
- description=dict(),
- src_address=dict(),
- dst_address=dict(),
- peer_selection_mode=dict(
- choices=['ratio', 'sequential']
- ),
- peers=dict(
- type='list'
- ),
- type=dict(
- choices=['generic'],
- default='generic'
- ),
- partition=dict(
- default='Common',
- fallback=(env_fallback, ['F5_PARTITION'])
- ),
- state=dict(
- default='present',
- choices=['present', 'absent']
- )
-
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode,
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_message_routing_router.py b/lib/ansible/modules/network/f5/bigip_message_routing_router.py
deleted file mode 100644
index ca03f8b056..0000000000
--- a/lib/ansible/modules/network/f5/bigip_message_routing_router.py
+++ /dev/null
@@ -1,751 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2019, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_message_routing_router
-short_description: Manages router profiles for message-routing protocols
-description:
- - Manages router profiles for message-routing protocols.
-version_added: 2.9
-options:
- name:
- description:
- - Specifies the name of the router profile.
- required: True
- type: str
- description:
- description:
- - The user defined description of the router profile.
- type: str
- type:
- description:
- - Parameter used to specify the type of the router profile to manage.
- - Default setting is C(generic) with more options added in future.
- type: str
- choices:
- - generic
- default: generic
- parent:
- description:
- - The parent template of this router profile. Once this value has been set, it cannot be changed.
- - The default values are set by the system if not specified and they correspond to the router type created, ie.
- C(/Common/messagerouter) for C(generic) C(type) and so on.
- type: str
- ignore_client_port:
- description:
- - When C(yes), the remote port on clientside connections ie. connections where the peer connected to the BIG-IP
- is ignored when searching for an existing connection.
- type: bool
- inherited_traffic_group:
- description:
- - When set to C(yes) the C(traffic_group) will be inherited from the containing folder. When not specified the
- system sets this to C(no) when creating new router profile.
- type: bool
- traffic_group:
- description:
- - Specifies the traffic-group of the router profile.
- - Setting the C(traffic_group) to an empty string value C("") will cause the device to inherit from containing
- folder, which means the value of C(inherited_traffic_group) on device will be C(yes).
- type: str
- use_local_connection:
- description:
- - If C(yes), the router will route a message to an existing connection on the same TMM as the message was
- received on.
- type: bool
- max_pending_bytes:
- description:
- - The maximum number of bytes worth of pending messages that will be held while waiting for a connection to a
- peer to be created. Once reached, any additional messages to the peer will be flagged as undeliverable
- and returned to the originator.
- - The accepted range is between 0 and 4294967295 inclusive.
- type: int
- max_pending_messages:
- description:
- - The maximum number of pending messages that will be held while waiting for a connection to a peer to be created.
- Once reached, any additional messages to the peer will be flagged as undeliverable and returned
- to the originator.
- - The accepted range is between 0 and 65535 inclusive.
- type: int
- max_retries:
- description:
- - Sets the maximum number of time a message may be resubmitted for rerouting by the C(MR::retry) iRule command.
- - The accepted range is between 0 and 4294967295 inclusive.
- type: int
- mirror:
- description:
- - Enables or disables state mirroring. State mirroring can be used to maintain the same state information in the
- standby unit that is in the active unit.
- type: bool
- mirrored_msg_sweeper_interval:
- description:
- - Specifies the maximum time in milliseconds that a message will be held on the standby device as it waits for
- the active device to route the message.
- - Messages on the standby device held for longer then the configurable sweeper interval, will be dropped.
- - The accepted range is between 0 and 4294967295 inclusive.
- type: int
- routes:
- description:
- - Specifies a list of static routes for the router instance to use.
- - The route must be on the same partition as router profile.
- type: list
- partition:
- description:
- - Device partition to create router profile on.
- type: str
- default: Common
- state:
- description:
- - When C(present), ensures that the router profile exists.
- - When C(absent), ensures the router profile is removed.
- type: str
- choices:
- - present
- - absent
- default: present
-notes:
- - Requires BIG-IP >= 14.0.0
-extends_documentation_fragment: f5
-author:
- - Wojciech Wypior (@wojtek0806)
-'''
-
-EXAMPLES = r'''
-- name: Create a generic router profile
- bigip_message_routing_router:
- name: foo
- max_retries: 10
- ignore_client_port: yes
- routes:
- - /Common/route1
- - /Common/route2
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-
-- name: Modify a generic router profile
- bigip_message_routing_router:
- name: foo
- ignore_client_port: no
- mirror: yes
- mirrored_msg_sweeper_interval: 4000
- traffic_group: /Common/traffic-group-2
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-
-- name: Remove a generic router profile
- bigip_message_routing_router:
- name: foo
- state: absent
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-'''
-
-RETURN = r'''
-description:
- description: The user defined description of the router profile.
- returned: changed
- type: str
- sample: My description
-parent:
- description: The parent template of this router profile.
- returned: changed
- type: str
- sample: /Common/messagerouter
-ignore_client_port:
- description: Enables ignoring of the remote port on clientside connections when searching for an existing connection.
- returned: changed
- type: bool
- sample: no
-inherited_traffic_group:
- description: Specifies if traffic-group should be inherited from containing folder.
- returned: changed
- type: bool
- sample: yes
-traffic_group:
- description: The traffic-group of the router profile.
- returned: changed
- type: str
- sample: /Common/traffic-group-1
-use_local_connection:
- description: Enables routing of messages to an existing connection on the same TMM as the message was received on.
- returned: changed
- type: bool
- sample: yes
-max_pending_bytes:
- description: The maximum number of bytes worth of pending messages that will be held.
- returned: changed
- type: int
- sample: 10000
-max_pending_messages:
- description: The maximum number of pending messages that will be held.
- returned: changed
- type: int
- sample: 64
-max_retries:
- description: The maximum number of time a message may be resubmitted for rerouting.
- returned: changed
- type: int
- sample: 10
-mirror:
- description: Enables or disables state mirroring.
- returned: changed
- type: bool
- sample: yes
-mirrored_msg_sweeper_interval:
- description: The maximum time in milliseconds that a message will be held on the standby device.
- returned: changed
- type: int
- sample: 2000
-routes:
- description: The list of static routes for the router instance to use.
- returned: changed
- type: list
- sample: ['/Common/route1', '/Common/route2']
-'''
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.basic import env_fallback
-from distutils.version import LooseVersion
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import fq_name
- from library.module_utils.network.f5.common import transform_name
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.common import flatten_boolean
- from library.module_utils.network.f5.compare import cmp_str_with_none
- from library.module_utils.network.f5.compare import cmp_simple_list
- from library.module_utils.network.f5.icontrol import tmos_version
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import fq_name
- from ansible.module_utils.network.f5.common import transform_name
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.common import flatten_boolean
- from ansible.module_utils.network.f5.compare import cmp_str_with_none
- from ansible.module_utils.network.f5.compare import cmp_simple_list
- from ansible.module_utils.network.f5.icontrol import tmos_version
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'defaultsFrom': 'parent',
- 'useLocalConnection': 'use_local_connection',
- 'ignoreClientPort': 'ignore_client_port',
- 'inheritedTrafficGroup': 'inherited_traffic_group',
- 'maxPendingBytes': 'max_pending_bytes',
- 'maxPendingMessages': 'max_pending_messages',
- 'maxRetries': 'max_retries',
- 'mirroredMessageSweeperInterval': 'mirrored_msg_sweeper_interval',
- 'trafficGroup': 'traffic_group',
- }
-
- api_attributes = [
- 'description',
- 'useLocalConnection',
- 'ignoreClientPort',
- 'inheritedTrafficGroup',
- 'maxPendingBytes',
- 'maxPendingMessages',
- 'maxRetries',
- 'mirror',
- 'mirroredMessageSweeperInterval',
- 'trafficGroup',
- 'routes',
- 'defaultsFrom',
- ]
-
- returnables = [
- 'parent',
- 'description',
- 'use_local_connection',
- 'ignore_client_port',
- 'inherited_traffic_group',
- 'max_pending_bytes',
- 'max_pending_messages',
- 'max_retries',
- 'mirrored_msg_sweeper_interval',
- 'traffic_group',
- 'mirror',
- 'routes',
- ]
-
- updatables = [
- 'description',
- 'use_local_connection',
- 'ignore_client_port',
- 'inherited_traffic_group',
- 'max_pending_bytes',
- 'max_pending_messages',
- 'max_retries',
- 'mirrored_msg_sweeper_interval',
- 'traffic_group',
- 'mirror',
- 'routes',
- 'parent',
- ]
-
- @property
- def ignore_client_port(self):
- return flatten_boolean(self._values['ignore_client_port'])
-
- @property
- def use_local_connection(self):
- return flatten_boolean(self._values['use_local_connection'])
-
-
-class ApiParameters(Parameters):
- pass
-
-
-class ModuleParameters(Parameters):
- @property
- def parent(self):
- if self._values['parent'] is None:
- return None
- result = fq_name(self.partition, self._values['parent'])
- return result
-
- @property
- def inherited_traffic_group(self):
- result = flatten_boolean(self._values['inherited_traffic_group'])
- if result is None:
- return None
- if result == 'yes':
- return 'true'
- return 'false'
-
- @property
- def mirror(self):
- result = flatten_boolean(self._values['mirror'])
- if result is None:
- return None
- if result == 'yes':
- return 'enabled'
- return 'disabled'
-
- @property
- def max_pending_bytes(self):
- if self._values['max_pending_bytes'] is None:
- return None
- if 0 <= self._values['max_pending_bytes'] <= 4294967295:
- return self._values['max_pending_bytes']
- raise F5ModuleError(
- "Valid 'max_pending_bytes' must be in range 0 - 4294967295 bytes."
- )
-
- @property
- def max_retries(self):
- if self._values['max_retries'] is None:
- return None
- if 0 <= self._values['max_retries'] <= 4294967295:
- return self._values['max_retries']
- raise F5ModuleError(
- "Valid 'max_retries' must be in range 0 - 4294967295."
- )
-
- @property
- def max_pending_messages(self):
- if self._values['max_pending_messages'] is None:
- return None
- if 0 <= self._values['max_pending_messages'] <= 65535:
- return self._values['max_pending_messages']
- raise F5ModuleError(
- "Valid 'max_pending_messages' must be in range 0 - 65535 messages."
- )
-
- @property
- def mirrored_msg_sweeper_interval(self):
- if self._values['mirrored_msg_sweeper_interval'] is None:
- return None
- if 0 <= self._values['mirrored_msg_sweeper_interval'] <= 4294967295:
- return self._values['mirrored_msg_sweeper_interval']
- raise F5ModuleError(
- "Valid 'mirrored_msg_sweeper_interval' must be in range 0 - 4294967295 milliseconds."
- )
-
- @property
- def routes(self):
- if self._values['routes'] is None:
- return None
- if len(self._values['routes']) == 1 and self._values['routes'][0] == "":
- return ""
- result = [fq_name(self.partition, peer) for peer in self._values['routes']]
- return result
-
- @property
- def traffic_group(self):
- if self._values['traffic_group'] is None:
- return None
- if self._values['traffic_group'] == "":
- return ""
- result = fq_name('Common', self._values['traffic_group'])
- return result
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class UsableChanges(Changes):
- pass
-
-
-class ReportableChanges(Changes):
- @property
- def mirror(self):
- result = flatten_boolean(self._values['mirror'])
- return result
-
- @property
- def inherited_traffic_group(self):
- result = self._values['inherited_traffic_group']
- if result == 'true':
- return 'yes'
- if result == 'false':
- return 'no'
- return None
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
- @property
- def description(self):
- return cmp_str_with_none(self.want.description, self.have.description)
-
- @property
- def parent(self):
- if self.want.parent is None:
- return None
- if self.want.parent != self.have.parent:
- raise F5ModuleError(
- "The parent router profile cannot be changed."
- )
-
- @property
- def routes(self):
- result = cmp_simple_list(self.want.routes, self.have.routes)
- return result
-
-
-class BaseManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(params=self.module.params)
- self.have = ApiParameters()
- self.changes = UsableChanges()
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = UsableChanges(params=changed)
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.client.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def exec_module(self):
- changed = False
- result = dict()
- state = self.want.state
-
- if state == "present":
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def present(self):
- if self.exists():
- return self.update()
- else:
- return self.create()
-
- def absent(self):
- if self.exists():
- return self.remove()
- return False
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def update(self):
- self.have = self.read_current_from_device()
- if not self.should_update():
- return False
- if self.module.check_mode:
- return True
- self.update_on_device()
- return True
-
- def remove(self):
- if self.module.check_mode:
- return True
- self.remove_from_device()
- if self.exists():
- raise F5ModuleError("Failed to delete the resource.")
- return True
-
- def create(self):
- self._set_changed_options()
- if self.module.check_mode:
- return True
- self.create_on_device()
- return True
-
-
-class GenericModuleManager(BaseManager):
- def exists(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/message-routing/generic/router/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def create_on_device(self):
- params = self.changes.api_params()
- params['name'] = self.want.name
- params['partition'] = self.want.partition
- uri = "https://{0}:{1}/mgmt/tm/ltm/message-routing/generic/router/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 409]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return True
-
- def update_on_device(self):
- params = self.changes.api_params()
- uri = "https://{0}:{1}/mgmt/tm/ltm/message-routing/generic/router/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def remove_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/message-routing/generic/router/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- response = self.client.api.delete(uri)
- if response.status == 200:
- return True
- raise F5ModuleError(response.content)
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/message-routing/generic/router/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return ApiParameters(params=response)
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.kwargs = kwargs
-
- def version_less_than_14(self):
- version = tmos_version(self.client)
- if LooseVersion(version) < LooseVersion('14.0.0'):
- return True
- return False
-
- def exec_module(self):
- if self.version_less_than_14():
- raise F5ModuleError('Message routing is not supported on TMOS version below 14.x')
- if self.module.params['type'] == 'generic':
- manager = self.get_manager('generic')
- else:
- raise F5ModuleError(
- "Unknown type specified."
- )
- return manager.exec_module()
-
- def get_manager(self, type):
- if type == 'generic':
- return GenericModuleManager(**self.kwargs)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- name=dict(required=True),
- description=dict(),
- parent=dict(),
- ignore_client_port=dict(type='bool'),
- inherited_traffic_group=dict(type='bool'),
- use_local_connection=dict(type='bool'),
- max_pending_bytes=dict(type='int'),
- max_pending_messages=dict(type='int'),
- max_retries=dict(type='int'),
- mirror=dict(type='bool'),
- mirrored_msg_sweeper_interval=dict(type='int'),
- routes=dict(type='list'),
- traffic_group=dict(),
- type=dict(
- choices=['generic'],
- default='generic'
- ),
- partition=dict(
- default='Common',
- fallback=(env_fallback, ['F5_PARTITION'])
- ),
- state=dict(
- default='present',
- choices=['present', 'absent']
- )
-
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode,
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_message_routing_transport_config.py b/lib/ansible/modules/network/f5/bigip_message_routing_transport_config.py
deleted file mode 100644
index fe64faa7a3..0000000000
--- a/lib/ansible/modules/network/f5/bigip_message_routing_transport_config.py
+++ /dev/null
@@ -1,667 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2019, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_message_routing_transport_config
-short_description: Manages configuration for an outgoing connection
-description:
- - Manages configuration for an outgoing connection in BIG-IP message routing.
-version_added: 2.9
-options:
- name:
- description:
- - Specifies the name of the transport config to manage.
- type: str
- required: True
- description:
- description:
- - The user defined description of the transport config.
- type: str
- profiles:
- description:
- - Specifies a list profiles for the outgoing connection to use to direct and manage traffic.
- type: list
- src_addr_translation:
- description:
- - Specifies the type of source address translation enabled for the transport config and the pool
- that the source address translation will use.
- suboptions:
- type:
- description:
- - Specifies the type of source address translation associated with the specified transport config.
- - When set to C(snat) the C(pool) parameter needs to contain a name for a valid LSN or SNAT pool.
- type: str
- choices:
- - snat
- - none
- - automap
- pool:
- description:
- - Specifies the name of a LSN or SNAT pool used by the specified transport config.
- - "Name can also be specified in C(fullPath) format: C(/Common/foobar)"
- - When C(type) is C(none) or C(automap) the pool parameter will be replaced by C(none) keyword,
- thus any defined C(pool) parameter will be ignored.
- type: str
- type: dict
- src_port:
- description:
- - Specifies the source port to be used for the connection being created.
- - If no value is specified an ephemeral port is chosen for the connection being created.
- - The accepted range is between 0 and 65535 inclusive.
- type: int
- rules:
- description:
- - The iRules you want run on this transport config. iRules help automate the intercepting, processing,
- and routing of application traffic.
- type: list
- type:
- description:
- - Parameter used to specify the type of the transport-config object to manage.
- - Default setting is C(generic) with more options added in future.
- type: str
- choices:
- - generic
- default: generic
- partition:
- description:
- - Device partition to create transport-config object on.
- type: str
- default: Common
- state:
- description:
- - When C(present), ensures that the transport-config object exists.
- - When C(absent), ensures the transport-config object is removed.
- type: str
- choices:
- - present
- - absent
- default: present
-notes:
- - Requires BIG-IP >= 14.0.0
-extends_documentation_fragment: f5
-author:
- - Wojciech Wypior (@wojtek0806)
-'''
-
-EXAMPLES = r'''
-- name: Create generic transport config
- bigip_message_routing_transport_config:
- name: foo
- profiles:
- transport: genericmsg
- tcp: tcp-lan-optimized
- description: new_transport
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-
-- name: Modify generic transport config
- bigip_message_routing_transport_config:
- name: foo
- rules:
- - rule_1
- - rule_2
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-
-- name: Remove generic transport config
- bigip_message_routing_transport_config:
- name: foo
- state: absent
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-'''
-
-RETURN = r'''
-description:
- description: The user defined description of the router profile.
- returned: changed
- type: str
- sample: My description
-rules:
- description: The iRules running on transport config.
- returned: changed
- type: list
- sample: ['/Common/rule1', '/Common/rule2']
-profiles:
- description: The profiles for the outgoing connection .
- returned: changed
- type: list
- sample: ['/Common/profile1', '/Common/profile2']
-src_addr_translation:
- description: The type of source address translation enabled for the transport config.
- type: complex
- returned: changed
- contains:
- type:
- description: the type of source address translation associated with the specified transport config.
- type: str
- returned: changed
- sample: automap
- pool:
- description: The name of a LSN or SNAT pool used by the specified transport config.
- type: str
- returned: changed
- sample: /Common/pool1
- sample: hash/dictionary of values
-source_port:
- description: The source port to be used for the connection being created.
- returned: changed
- type: int
- sample: 10041
-'''
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.basic import env_fallback
-from distutils.version import LooseVersion
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import fq_name
- from library.module_utils.network.f5.common import transform_name
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.common import flatten_boolean
- from library.module_utils.network.f5.compare import cmp_str_with_none
- from library.module_utils.network.f5.compare import cmp_simple_list
- from library.module_utils.network.f5.icontrol import tmos_version
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import fq_name
- from ansible.module_utils.network.f5.common import transform_name
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.common import flatten_boolean
- from ansible.module_utils.network.f5.compare import cmp_str_with_none
- from ansible.module_utils.network.f5.compare import cmp_simple_list
- from ansible.module_utils.network.f5.icontrol import tmos_version
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'sourceAddressTranslation': 'src_addr_translation',
- 'sourcePort': 'src_port',
- }
-
- api_attributes = [
- 'description',
- 'sourceAddressTranslation',
- 'sourcePort',
- 'profiles',
- 'rules',
- ]
-
- returnables = [
- 'description',
- 'snat_pool',
- 'snat_type',
- 'profiles',
- 'rules',
- 'src_port',
- ]
-
- updatables = [
- 'description',
- 'snat_pool',
- 'snat_type',
- 'profiles',
- 'rules',
- 'src_port',
- ]
-
-
-class ApiParameters(Parameters):
- @property
- def profiles(self):
- if 'profilesReference' not in self._values:
- return None
- if 'items' not in self._values['profilesReference']:
- return None
- result = [item['fullPath'] for item in self._values['profilesReference']['items']]
- return result
-
- @property
- def snat_pool(self):
- if self._values['src_addr_translation'] is None:
- return None
- if 'pool' in self._values['src_addr_translation']:
- return self._values['src_addr_translation']['pool']
-
- @property
- def snat_type(self):
- if self._values['src_addr_translation'] is None:
- return None
- return self._values['src_addr_translation']['type']
-
-
-class ModuleParameters(Parameters):
- @property
- def profiles(self):
- if self._values['profiles'] is None:
- return None
- result = [fq_name(self.partition, p) for p in self._values['profiles']]
- return result
-
- @property
- def rules(self):
- if self._values['rules'] is None:
- return None
- result = [fq_name(self.partition, rule) for rule in self._values['rules']]
- return result
-
- @property
- def snat_pool(self):
- if self._values['src_addr_translation'] is None:
- return None
- if self._values['src_addr_translation']['pool']:
- result = fq_name(self.partition, self._values['src_addr_translation']['pool'])
- return result
-
- @property
- def snat_type(self):
- if self._values['src_addr_translation'] is None:
- return None
- return self._values['src_addr_translation']['type']
-
- @property
- def src_port(self):
- if self._values['src_port'] is None:
- return None
- if 0 <= self._values['src_port'] <= 65535:
- return self._values['src_port']
- raise F5ModuleError(
- "Valid 'src_port' must be in range 0 - 65535 inclusive."
- )
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class UsableChanges(Changes):
- @property
- def src_addr_translation(self):
- if self._values['snat_type'] is None:
- return None
- if self._values['snat_type'] in ['none', 'automap']:
- result = dict(
- pool='none',
- type=self._values['snat_type']
- )
- return result
-
- result = dict(
- pool=self._values['snat_pool'],
- type=self._values['snat_type']
- )
- return result
-
-
-class ReportableChanges(Changes):
- returnables = [
- 'description',
- 'src_addr_translation',
- 'rules',
- 'src_port',
- 'profiles',
- ]
-
- @property
- def src_addr_translation(self):
- if self._values['snat_type'] is None:
- return None
- to_filter = dict(
- pool=self._values['snat_pool'],
- type=self._values['snat_type']
- )
- result = self._filter_params(to_filter)
- if result:
- return result
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
- @property
- def profiles(self):
- result = cmp_simple_list(self.want.profiles, self.have.profiles)
- return result
-
- @property
- def rules(self):
- result = cmp_simple_list(self.want.rules, self.have.rules)
- return result
-
- @property
- def description(self):
- result = cmp_str_with_none(self.want.description, self.have.description)
- return result
-
-
-class BaseManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(params=self.module.params)
- self.have = ApiParameters()
- self.changes = UsableChanges()
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = UsableChanges(params=changed)
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.client.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def exec_module(self):
- changed = False
- result = dict()
- state = self.want.state
-
- if state == "present":
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def present(self):
- if self.exists():
- return self.update()
- else:
- return self.create()
-
- def absent(self):
- if self.exists():
- return self.remove()
- return False
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def update(self):
- self.have = self.read_current_from_device()
- if not self.should_update():
- return False
- if self.module.check_mode:
- return True
- self.update_on_device()
- return True
-
- def remove(self):
- if self.module.check_mode:
- return True
- self.remove_from_device()
- if self.exists():
- raise F5ModuleError("Failed to delete the resource.")
- return True
-
- def create(self):
- if self.want.profiles is None:
- raise F5ModuleError(
- 'Profiles parameter needs to be specified when creating transport config.'
- )
- self._set_changed_options()
- if self.module.check_mode:
- return True
- self.create_on_device()
- return True
-
-
-class GenericModuleManager(BaseManager):
- def exists(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/message-routing/generic/transport-config/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def create_on_device(self):
- params = self.changes.api_params()
- params['name'] = self.want.name
- params['partition'] = self.want.partition
- uri = "https://{0}:{1}/mgmt/tm/ltm/message-routing/generic/transport-config/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 409]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return True
-
- def update_on_device(self):
- params = self.changes.api_params()
- uri = "https://{0}:{1}/mgmt/tm/ltm/message-routing/generic/transport-config/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def remove_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/message-routing/generic/transport-config/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- response = self.client.api.delete(uri)
- if response.status == 200:
- return True
- raise F5ModuleError(response.content)
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/message-routing/generic/transport-config/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- query = '?expandSubcollections=true'
- resp = self.client.api.get(uri + query)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return ApiParameters(params=response)
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.kwargs = kwargs
-
- def version_less_than_14(self):
- version = tmos_version(self.client)
- if LooseVersion(version) < LooseVersion('14.0.0'):
- return True
- return False
-
- def exec_module(self):
- if self.version_less_than_14():
- raise F5ModuleError('Message routing is not supported on TMOS version below 14.x')
- if self.module.params['type'] == 'generic':
- manager = self.get_manager('generic')
- else:
- raise F5ModuleError(
- "Unknown type specified."
- )
- return manager.exec_module()
-
- def get_manager(self, type):
- if type == 'generic':
- return GenericModuleManager(**self.kwargs)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- name=dict(required=True),
- description=dict(),
- profiles=dict(type='list'),
- src_port=dict(type='int'),
- src_addr_translation=dict(
- type='dict',
- options=dict(
- type=dict(
- choices=['none', 'automap', 'snat']
- ),
- pool=dict(),
- ),
- required_if=[
- ['type', 'snat', ['pool']]
- ]
- ),
- rules=dict(type='list'),
- type=dict(
- choices=['generic'],
- default='generic'
- ),
- partition=dict(
- default='Common',
- fallback=(env_fallback, ['F5_PARTITION'])
- ),
- state=dict(
- default='present',
- choices=['present', 'absent']
- )
-
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode,
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_monitor_dns.py b/lib/ansible/modules/network/f5/bigip_monitor_dns.py
deleted file mode 100644
index c1af44afaf..0000000000
--- a/lib/ansible/modules/network/f5/bigip_monitor_dns.py
+++ /dev/null
@@ -1,1028 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2018, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_monitor_dns
-short_description: Manage DNS monitors on a BIG-IP
-description:
- - Manages DNS monitors on a BIG-IP.
-version_added: 2.7
-options:
- name:
- description:
- - Specifies the name of the monitor.
- type: str
- required: True
- parent:
- description:
- - The parent template of this monitor template. Once this value has
- been set, it cannot be changed. By default, this value is the C(dns)
- parent on the C(Common) partition.
- type: str
- default: /Common/dns
- description:
- description:
- - The description of the monitor.
- type: str
- interval:
- description:
- - The interval specifying how frequently the monitor instance of this
- template will run.
- - This value B(must) be less than the C(timeout) value.
- - When creating a new monitor, if this parameter is not provided, the
- default C(5) will be used.
- type: int
- up_interval:
- description:
- - Specifies the interval for the system to use to perform the health check
- when a resource is up.
- - When C(0), specifies that the system uses the interval specified in
- C(interval) to check the health of the resource.
- - When any other number, enables specification of a different interval to
- use when checking the health of a resource that is up.
- - When creating a new monitor, if this parameter is not provided, the
- default C(0) will be used.
- type: int
- timeout:
- description:
- - The number of seconds in which the node or service must respond to
- the monitor request.
- - If the target responds within the set time period, it is considered up.
- - If the target does not respond within the set time period, it is considered down.
- - You can change this number to any number you want, however, it should be 3 times the
- interval number of seconds plus 1 second.
- - If this parameter is not provided when creating a new monitor, then the default
- value will be C(16).
- type: int
- transparent:
- description:
- - Specifies whether the monitor operates in transparent mode.
- - Monitors in transparent mode can monitor pool members through firewalls.
- - When creating a new monitor, if this parameter is not provided, then the default
- value will be C(no).
- type: bool
- reverse:
- description:
- - Specifies whether the monitor operates in reverse mode.
- - When the monitor is in reverse mode, a successful receive string match
- marks the monitored object down instead of up. You can use the
- this mode only if you configure the C(receive) option.
- - This parameter is not compatible with the C(time_until_up) parameter. If
- C(time_until_up) is specified, it must be C(0). Or, if it already exists, it
- must be C(0).
- type: bool
- receive:
- description:
- - Specifies the IP address that the monitor uses from the resource record sections
- of the DNS response.
- - The IP address should be specified in the dotted-decimal notation or IPv6 notation.
- type: str
- time_until_up:
- description:
- - Specifies the amount of time in seconds after the first successful
- response before a node will be marked up.
- - A value of 0 will cause a node to be marked up immediately after a valid
- response is received from the node.
- - If this parameter is not provided when creating a new monitor, then the default
- value will be C(0).
- type: int
- manual_resume:
- description:
- - Specifies whether the system automatically changes the status of a resource
- to B(enabled) at the next successful monitor check.
- - If you set this option to C(yes), you must manually re-enable the resource
- before the system can use it for load balancing connections.
- - When creating a new monitor, if this parameter is not specified, the default
- value is C(no).
- - When C(yes), specifies that you must manually re-enable the resource after an
- unsuccessful monitor check.
- - When C(no), specifies that the system automatically changes the status of a
- resource to B(enabled) at the next successful monitor check.
- type: bool
- ip:
- description:
- - IP address part of the IP/port definition.
- - If this parameter is not provided when creating a new monitor, then the
- default value will be C(*).
- type: str
- port:
- description:
- - Port address part of the IP/port definition.
- - If this parameter is not provided when creating a new monitor, then the default
- value will be C(*).
- - Note that if specifying an IP address, a value between 1 and 65535 must be specified.
- type: str
- query_name:
- description:
- - Specifies a query name for the monitor to use in a DNS query.
- type: str
- query_type:
- description:
- - Specifies the type of DNS query that the monitor sends.
- - When creating a new monitor, if this parameter is not specified, the default
- value is C(a).
- - When C(a), specifies that the monitor will send a DNS query of type A.
- - When C(aaaa), specifies that the monitor will send a DNS query of type AAAA.
- type: str
- choices:
- - a
- - aaaa
- answer_section_contains:
- description:
- - Specifies the type of DNS query that the monitor sends.
- - When creating a new monitor, if this value is not specified, the default
- value is C(query-type).
- - When C(query-type), specifies that the response should contain at least one
- answer of which the resource record type matches the query type.
- - When C(any-type), specifies that the DNS message should contain at least one answer.
- - When C(anything), specifies that an empty answer is enough to mark the status of
- the node up.
- type: str
- choices:
- - any-type
- - anything
- - query-type
- accept_rcode:
- description:
- - Specifies the RCODE required in the response for an up status.
- - When creating a new monitor, if this parameter is not specified, the default
- value is C(no-error).
- - When C(no-error), specifies that the status of the node will be marked up if
- the received DNS message has no error.
- - When C(anything), specifies that the status of the node will be marked up
- irrespective of the RCODE in the DNS message received.
- - If this parameter is set to C(anything), it will disregard the C(receive)
- string, and nullify it if the monitor is being updated.
- type: str
- choices:
- - no-error
- - anything
- adaptive:
- description:
- - Specifies whether adaptive response time monitoring is enabled for this monitor.
- - When C(yes), the monitor determines the state of a service based on how divergent
- from the mean latency a monitor probe for that service is allowed to be.
- Also, values for the C(allowed_divergence), C(adaptive_limit), and
- and C(sampling_timespan) will be enforced.
- - When C(disabled), the monitor determines the state of a service based on the
- C(interval), C(up_interval), C(time_until_up), and C(timeout) monitor settings.
- type: bool
- allowed_divergence_type:
- description:
- - When specifying a new monitor, if C(adaptive) is C(yes), the default is
- C(relative)
- - When C(absolute), the number of milliseconds the latency of a monitor probe
- can exceed the mean latency of a monitor probe for the service being probed.
- In typical cases, if the monitor detects three probes in a row that miss the
- latency value you set, the pool member or node is marked down.
- - When C(relative), the percentage of deviation the latency of a monitor probe
- can exceed the mean latency of a monitor probe for the service being probed.
- type: str
- choices:
- - relative
- - absolute
- allowed_divergence_value:
- description:
- - When specifying a new monitor, if C(adaptive) is C(yes), and C(type) is
- C(relative), the default is C(25) percent.
- type: int
- adaptive_limit:
- description:
- - Specifies the absolute number of milliseconds that may not be exceeded by a monitor
- probe, regardless of C(allowed_divergence) setting, for a probe to be
- considered successful.
- - This value applies regardless of the value of the C(allowed_divergence) setting.
- - While this value can be configured when C(adaptive) is C(no), it will not take
- effect on the system until C(adaptive) is C(yes).
- type: int
- sampling_timespan:
- description:
- - Specifies the length, in seconds, of the probe history window that the system
- uses to calculate the mean latency and standard deviation of a monitor probe.
- - While this value can be configured when C(adaptive) is C(no), it will not take
- effect on the system until C(adaptive) is C(yes).
- type: int
- partition:
- description:
- - Device partition to manage resources on.
- type: str
- default: Common
- state:
- description:
- - When C(present), ensures that the monitor exists.
- - When C(absent), ensures the monitor is removed.
- type: str
- choices:
- - present
- - absent
- default: present
-extends_documentation_fragment: f5
-author:
- - Tim Rupp (@caphrim007)
- - Wojciech Wypior (@wojtek0806)
-'''
-
-EXAMPLES = r'''
-- name: Create a DNS monitor
- bigip_monitor_dns:
- name: DNS-UDP-V6
- interval: 2
- query_name: localhost
- query_type: aaaa
- up_interval: 5
- adaptive: no
- state: present
- provider:
- user: admin
- password: secret
- server: lb.mydomain.com
- delegate_to: localhost
-'''
-
-RETURN = r'''
-parent:
- description: New parent template of the monitor.
- returned: changed
- type: str
- sample: http
-ip:
- description: The new IP of IP/port definition.
- returned: changed
- type: str
- sample: 10.12.13.14
-interval:
- description: The new interval in which to run the monitor check.
- returned: changed
- type: int
- sample: 2
-timeout:
- description: The new timeout in which the remote system must respond to the monitor.
- returned: changed
- type: int
- sample: 10
-time_until_up:
- description: The new time in which to mark a system as up after first successful response.
- returned: changed
- type: int
- sample: 2
-adaptive:
- description: Whether adaptive is enabled or not.
- returned: changed
- type: bool
- sample: yes
-accept_rcode:
- description: RCODE required in the response for an up status.
- returned: changed
- type: str
- sample: no-error
-allowed_divergence_type:
- description: Type of divergence used for adaptive response time monitoring.
- returned: changed
- type: str
- sample: absolute
-allowed_divergence_value:
- description:
- - Value of the type of divergence used for adaptive response time monitoring.
- - May be C(percent) or C(ms) depending on whether C(relative) or C(absolute).
- returned: changed
- type: int
- sample: 25
-description:
- description: The description of the monitor.
- returned: changed
- type: str
- sample: Important Monitor
-adaptive_limit:
- description: Absolute number of milliseconds that may not be exceeded by a monitor probe.
- returned: changed
- type: int
- sample: 200
-sampling_timespan:
- description: Absolute number of milliseconds that may not be exceeded by a monitor probe.
- returned: changed
- type: int
- sample: 200
-answer_section_contains:
- description: Type of DNS query that the monitor sends.
- returned: changed
- type: str
- sample: query-type
-manual_resume:
- description:
- - Whether the system automatically changes the status of a resource to enabled at the
- next successful monitor check.
- returned: changed
- type: str
- sample: query-type
-up_interval:
- description: Interval for the system to use to perform the health check when a resource is up.
- returned: changed
- type: int
- sample: 0
-query_name:
- description: Query name for the monitor to use in a DNS query.
- returned: changed
- type: str
- sample: foo
-query_type:
- description: Type of DNS query that the monitor sends. Either C(a) or C(aaaa).
- returned: changed
- type: str
- sample: aaaa
-receive:
- description: IP address that the monitor uses from the resource record sections of the DNS response.
- returned: changed
- type: str
- sample: 2.3.2.4
-reverse:
- description: Whether the monitor operates in reverse mode.
- returned: changed
- type: bool
- sample: yes
-port:
- description:
- - Alias port or service for the monitor to check, on behalf of the pools or pool
- members with which the monitor is associated.
- returned: changed
- type: str
- sample: 80
-transparent:
- description: Whether the monitor operates in transparent mode.
- returned: changed
- type: bool
- sample: no
-'''
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.basic import env_fallback
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import fq_name
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.common import transform_name
- from library.module_utils.network.f5.common import flatten_boolean
- from library.module_utils.network.f5.ipaddress import is_valid_ip
- from library.module_utils.network.f5.ipaddress import validate_ip_v6_address
- from library.module_utils.network.f5.ipaddress import validate_ip_address
- from library.module_utils.network.f5.compare import cmp_str_with_none
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import fq_name
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.common import transform_name
- from ansible.module_utils.network.f5.common import flatten_boolean
- from ansible.module_utils.network.f5.ipaddress import is_valid_ip
- from ansible.module_utils.network.f5.ipaddress import validate_ip_v6_address
- from ansible.module_utils.network.f5.ipaddress import validate_ip_address
- from ansible.module_utils.network.f5.compare import cmp_str_with_none
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'acceptRcode': 'accept_rcode',
- 'adaptiveDivergenceType': 'allowed_divergence_type',
- 'adaptiveDivergenceValue': 'allowed_divergence_value',
- 'adaptiveLimit': 'adaptive_limit',
- 'adaptiveSamplingTimespan': 'sampling_timespan',
- 'answerContains': 'answer_section_contains',
- 'manualResume': 'manual_resume',
- 'timeUntilUp': 'time_until_up',
- 'upInterval': 'up_interval',
- 'qname': 'query_name',
- 'qtype': 'query_type',
- 'recv': 'receive',
- 'defaultsFrom': 'parent',
- }
-
- api_attributes = [
- 'adaptive',
- 'acceptRcode',
- 'adaptiveDivergenceType',
- 'adaptiveDivergenceValue',
- 'adaptiveLimit',
- 'adaptiveSamplingTimespan',
- 'answerContains',
- 'defaultsFrom',
- 'description',
- 'destination',
- 'interval',
- 'manualResume',
- 'qname',
- 'qtype',
- 'recv',
- 'reverse',
- 'timeout',
- 'timeUntilUp',
- 'transparent',
- 'upInterval',
- 'destination',
- ]
-
- returnables = [
- 'adaptive',
- 'accept_rcode',
- 'allowed_divergence_type',
- 'allowed_divergence_value',
- 'description',
- 'adaptive_limit',
- 'sampling_timespan',
- 'answer_section_contains',
- 'manual_resume',
- 'time_until_up',
- 'up_interval',
- 'query_name',
- 'query_type',
- 'receive',
- 'reverse',
- 'timeout',
- 'interval',
- 'transparent',
- 'parent',
- 'ip',
- 'port',
- ]
-
- updatables = [
- 'adaptive',
- 'accept_rcode',
- 'allowed_divergence_type',
- 'allowed_divergence_value',
- 'adaptive_limit',
- 'sampling_timespan',
- 'answer_section_contains',
- 'description',
- 'manual_resume',
- 'time_until_up',
- 'up_interval',
- 'query_name',
- 'query_type',
- 'receive',
- 'reverse',
- 'timeout',
- 'transparent',
- 'parent',
- 'destination',
- 'interval',
- ]
-
- @property
- def type(self):
- return 'dns'
-
- @property
- def destination(self):
- if self.ip is None and self.port is None:
- return None
- destination = '{0}:{1}'.format(self.ip, self.port)
- return destination
-
- @destination.setter
- def destination(self, value):
- ip, port = value.split(':')
- self._values['ip'] = ip
- self._values['port'] = port
-
- @property
- def interval(self):
- if self._values['interval'] is None:
- return None
-
- # Per BZ617284, the BIG-IP UI does not raise a warning about this.
- # So I do
- if 1 > int(self._values['interval']) > 86400:
- raise F5ModuleError(
- "Interval value must be between 1 and 86400"
- )
- return int(self._values['interval'])
-
- @property
- def timeout(self):
- if self._values['timeout'] is None:
- return None
- return int(self._values['timeout'])
-
- @property
- def ip(self):
- if self._values['ip'] is None:
- return None
- if self._values['ip'] in ['*', '0.0.0.0']:
- return '*'
- elif is_valid_ip(self._values['ip']):
- return self._values['ip']
- else:
- raise F5ModuleError(
- "The provided 'ip' parameter is not an IP address."
- )
-
- @property
- def receive(self):
- if self._values['receive'] is None:
- return None
- if self._values['receive'] == '':
- return ''
- if is_valid_ip(self._values['receive']):
- return self._values['receive']
- raise F5ModuleError(
- "The specified 'receive' parameter must be either an IPv4 or v6 address."
- )
-
- @property
- def port(self):
- if self._values['port'] is None:
- return None
- elif self._values['port'] == '*':
- return '*'
- return int(self._values['port'])
-
- @property
- def time_until_up(self):
- if self._values['time_until_up'] is None:
- return None
- return int(self._values['time_until_up'])
-
- @property
- def parent(self):
- if self._values['parent'] is None:
- return None
- result = fq_name(self.partition, self._values['parent'])
- return result
-
-
-class ApiParameters(Parameters):
- @property
- def description(self):
- if self._values['description'] in [None, 'none']:
- return None
- return self._values['description']
-
-
-class ModuleParameters(Parameters):
- @property
- def description(self):
- if self._values['description'] is None:
- return None
- elif self._values['description'] in ['none', '']:
- return ''
- return self._values['description']
-
- @property
- def manual_resume(self):
- if self._values['manual_resume'] is None:
- return None
- elif self._values['manual_resume'] is True:
- return 'enabled'
- return 'disabled'
-
- @property
- def reverse(self):
- if self._values['reverse'] is None:
- return None
- elif self._values['reverse'] is True:
- return 'enabled'
- return 'disabled'
-
- @property
- def transparent(self):
- if self._values['transparent'] is None:
- return None
- elif self._values['transparent'] is True:
- return 'enabled'
- return 'disabled'
-
- @property
- def adaptive(self):
- if self._values['adaptive'] is None:
- return None
- elif self._values['adaptive'] is True:
- return 'enabled'
- return 'disabled'
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class UsableChanges(Changes):
- pass
-
-
-class ReportableChanges(Changes):
- @property
- def manual_resume(self):
- return flatten_boolean(self._values['manual_resume'])
-
- @property
- def reverse(self):
- return flatten_boolean(self._values['reverse'])
-
- @property
- def transparent(self):
- return flatten_boolean(self._values['transparent'])
-
- @property
- def adaptive(self):
- return flatten_boolean(self._values['adaptive'])
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- @property
- def parent(self):
- if self.want.parent != self.have.parent:
- raise F5ModuleError(
- "The parent monitor cannot be changed"
- )
-
- @property
- def destination(self):
- if self.want.ip is None and self.want.port is None:
- return None
- if self.want.port is None:
- self.want.update({'port': self.have.port})
- if self.want.ip is None:
- self.want.update({'ip': self.have.ip})
-
- if self.want.port in [None, '*'] and self.want.ip != '*':
- raise F5ModuleError(
- "Specifying an IP address requires that a port number be specified"
- )
-
- if self.want.destination != self.have.destination:
- return self.want.destination
-
- @property
- def interval(self):
- if self.want.timeout is not None and self.want.interval is not None:
- if self.want.interval >= self.want.timeout:
- raise F5ModuleError(
- "Parameter 'interval' must be less than 'timeout'."
- )
- elif self.want.timeout is not None:
- if self.have.interval >= self.want.timeout:
- raise F5ModuleError(
- "Parameter 'interval' must be less than 'timeout'."
- )
- elif self.want.interval is not None:
- if self.want.interval >= self.have.timeout:
- raise F5ModuleError(
- "Parameter 'interval' must be less than 'timeout'."
- )
- if self.want.interval != self.have.interval:
- return self.want.interval
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
- @property
- def description(self):
- return cmp_str_with_none(self.want.description, self.have.description)
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(params=self.module.params)
- self.have = ApiParameters()
- self.changes = UsableChanges()
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = UsableChanges(params=changed)
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def exec_module(self):
- changed = False
- result = dict()
- state = self.want.state
-
- if state == "present":
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.client.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def present(self):
- if self.exists():
- return self.update()
- else:
- return self.create()
-
- def exists(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/monitor/dns/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def _address_type_matches_query_type(self, type, validator):
- if self.want.query_type == type and self.have.query_type == type:
- if self.want.receive is not None and validator(self.want.receive):
- return True
- if self.have.receive is not None and validator(self.have.receive):
- return True
-
- def update(self):
- self.have = self.read_current_from_device()
- if not self.should_update():
- return False
- if self.want.reverse == 'enabled':
- if not self.want.receive and not self.have.receive:
- raise F5ModuleError(
- "A 'receive' string must be specified when setting 'reverse'."
- )
- if self.want.time_until_up != 0 and self.have.time_until_up != 0:
- raise F5ModuleError(
- "Monitors with the 'reverse' attribute are not currently compatible with 'time_until_up'."
- )
- if self._address_type_matches_query_type('a', validate_ip_v6_address):
- raise F5ModuleError(
- "Monitor has a IPv6 address. Only a 'query_type' of 'aaaa' is supported for IPv6."
- )
- elif self._address_type_matches_query_type('aaaa', validate_ip_address):
- raise F5ModuleError(
- "Monitor has a IPv4 address. Only a 'query_type' of 'a' is supported for IPv4."
- )
-
- if self.want.accept_rcode == 'anything':
- if self.want.receive is not None and is_valid_ip(self.want.receive) and self.have.receive is not None:
- raise F5ModuleError(
- "No 'receive' string may be specified, or exist, when 'accept_rcode' is 'anything'."
- )
- elif self.want.receive is None and self.have.receive is not None:
- self.want.update({'receive': ''})
- if self.module.check_mode:
- return True
- self.update_on_device()
- return True
-
- def remove(self):
- if self.module.check_mode:
- return True
- self.remove_from_device()
- if self.exists():
- raise F5ModuleError("Failed to delete the resource.")
- return True
-
- def create(self):
- self._set_changed_options()
- if self.want.reverse == 'enabled':
- if self.want.time_until_up != 0:
- raise F5ModuleError(
- "Monitors with the 'reverse' attribute are not currently compatible with 'time_until_up'."
- )
- if not self.want.receive:
- raise F5ModuleError(
- "A 'receive' string must be specified when setting 'reverse'."
- )
-
- if self.want.receive is not None and validate_ip_v6_address(self.want.receive) and self.want.query_type == 'a':
- raise F5ModuleError(
- "Monitor has a IPv6 address. Only a 'query_type' of 'aaaa' is supported for IPv6."
- )
- elif self.want.receive is not None and validate_ip_address(self.want.receive) and self.want.query_type == 'aaaa':
- raise F5ModuleError(
- "Monitor has a IPv4 address. Only a 'query_type' of 'a' is supported for IPv4."
- )
-
- if self.want.accept_rcode == 'anything':
- if self.want.receive is not None and is_valid_ip(self.want.receive):
- raise F5ModuleError(
- "No 'receive' string may be specified, or exist, when 'accept_rcode' is 'anything'."
- )
- elif self.want.receive is None:
- self.want.update({'receive': ''})
-
- if self.want.query_name is None:
- raise F5ModuleError(
- "'query_name' is required when creating a new DNS monitor."
- )
- if self.module.check_mode:
- return True
- self.create_on_device()
- return True
-
- def create_on_device(self):
- params = self.changes.api_params()
- params['name'] = self.want.name
- params['partition'] = self.want.partition
- uri = "https://{0}:{1}/mgmt/tm/ltm/monitor/dns/".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def update_on_device(self):
- params = self.changes.api_params()
- uri = "https://{0}:{1}/mgmt/tm/ltm/monitor/dns/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def absent(self):
- if self.exists():
- return self.remove()
- return False
-
- def remove_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/monitor/dns/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.delete(uri)
- if resp.status == 200:
- return True
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/monitor/dns/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return ApiParameters(params=response)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- name=dict(required=True),
- parent=dict(default='/Common/dns'),
- receive=dict(),
- ip=dict(),
- description=dict(),
- port=dict(),
- interval=dict(type='int'),
- timeout=dict(type='int'),
- manual_resume=dict(type='bool'),
- reverse=dict(type='bool'),
- transparent=dict(type='bool'),
- time_until_up=dict(type='int'),
- up_interval=dict(type='int'),
- accept_rcode=dict(choices=['no-error', 'anything']),
- adaptive=dict(type='bool'),
- sampling_timespan=dict(type='int'),
- adaptive_limit=dict(type='int'),
- answer_section_contains=dict(
- choices=['any-type', 'anything', 'query-type']
- ),
- query_name=dict(),
- query_type=dict(choices=['a', 'aaaa']),
- allowed_divergence_type=dict(choices=['relative', 'absolute']),
- allowed_divergence_value=dict(type='int'),
- state=dict(
- default='present',
- choices=['present', 'absent']
- ),
- partition=dict(
- default='Common',
- fallback=(env_fallback, ['F5_PARTITION'])
- )
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode,
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_monitor_external.py b/lib/ansible/modules/network/f5/bigip_monitor_external.py
deleted file mode 100644
index 3712f11307..0000000000
--- a/lib/ansible/modules/network/f5/bigip_monitor_external.py
+++ /dev/null
@@ -1,744 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2018, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_monitor_external
-short_description: Manages external LTM monitors on a BIG-IP
-description:
- - Manages external LTM monitors on a BIG-IP.
-version_added: 2.6
-options:
- name:
- description:
- - Specifies the name of the monitor.
- type: str
- required: True
- description:
- description:
- - The description of the monitor.
- type: str
- version_added: 2.7
- parent:
- description:
- - The parent template of this monitor template. Once this value has
- been set, it cannot be changed. By default, this value is the C(http)
- parent on the C(Common) partition.
- type: str
- default: /Common/external
- arguments:
- description:
- - Specifies any command-line arguments that the script requires.
- type: str
- ip:
- description:
- - IP address part of the IP/port definition. If this parameter is not
- provided when creating a new monitor, then the default value will be
- '*'.
- type: str
- port:
- description:
- - Port address part of the IP/port definition. If this parameter is not
- provided when creating a new monitor, then the default value will be
- '*'. Note that if specifying an IP address, a value between 1 and 65535
- must be specified.
- type: str
- external_program:
- description:
- - Specifies the name of the file for the monitor to use. In order to reference
- a file, you must first import it using options on the System > File Management > External
- Monitor Program File List > Import screen. The BIG-IP system automatically
- places the file in the proper location on the file system.
- type: str
- interval:
- description:
- - The interval specifying how frequently the monitor instance of this
- template will run. If this parameter is not provided when creating
- a new monitor, then the default value will be 5. This value B(must)
- be less than the C(timeout) value.
- type: int
- timeout:
- description:
- - The number of seconds in which the node or service must respond to
- the monitor request.
- - If the target responds within the set time period, it is considered up.
- - If the target does not respond within the set time period, it is considered
- down.
- - You can change this number to any number you want, however, it should be
- 3 times the interval number of seconds plus 1 second.
- - If this parameter is not provided when creating a new monitor, then the
- default value will be C(16).
- type: int
- variables:
- description:
- - Specifies any variables that the script requires.
- - Note that double quotes in values will be suppressed.
- type: dict
- partition:
- description:
- - Device partition to manage resources on.
- type: str
- default: Common
- state:
- description:
- - When C(present), ensures that the monitor exists.
- - When C(absent), ensures the monitor is removed.
- type: str
- choices:
- - present
- - absent
- default: present
-extends_documentation_fragment: f5
-author:
- - Tim Rupp (@caphrim007)
- - Wojciech Wypior (@wojtek0806)
-'''
-
-EXAMPLES = r'''
-- name: Create an external monitor
- bigip_monitor_external:
- name: foo
- state: present
- provider:
- user: admin
- password: secret
- server: lb.mydomain.com
- delegate_to: localhost
-
-- name: Create an external monitor with variables
- bigip_monitor_external:
- name: foo
- timeout: 10
- variables:
- var1: foo
- var2: bar
- state: present
- provider:
- user: admin
- password: secret
- server: lb.mydomain.com
- delegate_to: localhost
-
-- name: Add a variable to an existing set
- bigip_monitor_external:
- name: foo
- timeout: 10
- variables:
- var1: foo
- var2: bar
- cat: dog
- state: present
- provider:
- user: admin
- password: secret
- server: lb.mydomain.com
- delegate_to: localhost
-'''
-
-RETURN = r'''
-parent:
- description: New parent template of the monitor.
- returned: changed
- type: str
- sample: external
-description:
- description: The description of the monitor.
- returned: changed
- type: str
- sample: Important Monitor
-ip:
- description: The new IP of IP/port definition.
- returned: changed
- type: str
- sample: 10.12.13.14
-interval:
- description: The new interval in which to run the monitor check.
- returned: changed
- type: int
- sample: 2
-timeout:
- description: The new timeout in which the remote system must respond to the monitor.
- returned: changed
- type: int
- sample: 10
-'''
-
-import re
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.basic import env_fallback
-from ansible.module_utils.six import iteritems
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import fq_name
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.common import transform_name
- from library.module_utils.network.f5.compare import compare_dictionary
- from library.module_utils.network.f5.ipaddress import is_valid_ip
- from library.module_utils.network.f5.compare import cmp_str_with_none
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import fq_name
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.common import transform_name
- from ansible.module_utils.network.f5.compare import compare_dictionary
- from ansible.module_utils.network.f5.ipaddress import is_valid_ip
- from ansible.module_utils.network.f5.compare import cmp_str_with_none
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'defaultsFrom': 'parent',
- 'apiRawValues': 'variables',
- 'run': 'external_program',
- 'args': 'arguments',
- }
-
- api_attributes = [
- 'defaultsFrom',
- 'interval',
- 'timeout',
- 'destination',
- 'run',
- 'args',
- 'description',
- ]
-
- returnables = [
- 'parent',
- 'ip',
- 'port',
- 'interval',
- 'timeout',
- 'variables',
- 'external_program',
- 'arguments',
- 'description',
- ]
-
- updatables = [
- 'destination',
- 'interval',
- 'timeout',
- 'variables',
- 'external_program',
- 'arguments',
- 'description',
- ]
-
- @property
- def destination(self):
- if self.ip is None and self.port is None:
- return None
- destination = '{0}:{1}'.format(self.ip, self.port)
- return destination
-
- @destination.setter
- def destination(self, value):
- ip, port = value.split(':')
- self._values['ip'] = ip
- self._values['port'] = port
-
- @property
- def interval(self):
- if self._values['interval'] is None:
- return None
-
- # Per BZ617284, the BIG-IP UI does not raise a warning about this.
- # So I do
- if 1 > int(self._values['interval']) > 86400:
- raise F5ModuleError(
- "Interval value must be between 1 and 86400"
- )
- return int(self._values['interval'])
-
- @property
- def timeout(self):
- if self._values['timeout'] is None:
- return None
- return int(self._values['timeout'])
-
- @property
- def ip(self):
- if self._values['ip'] is None:
- return None
- if self._values['ip'] in ['*', '0.0.0.0']:
- return '*'
- elif is_valid_ip(self._values['ip']):
- return self._values['ip']
- else:
- raise F5ModuleError(
- "The provided 'ip' parameter is not an IP address."
- )
-
- @property
- def port(self):
- if self._values['port'] is None:
- return None
- elif self._values['port'] == '*':
- return '*'
- return int(self._values['port'])
-
- @property
- def parent(self):
- if self._values['parent'] is None:
- return None
- result = fq_name(self.partition, self._values['parent'])
- return result
-
- @property
- def type(self):
- return 'external'
-
-
-class ApiParameters(Parameters):
- @property
- def description(self):
- if self._values['description'] in [None, 'none']:
- return None
- return self._values['description']
-
- @property
- def variables(self):
- if self._values['variables'] is None:
- return None
- pattern = r'^userDefined\s(?P<key>.*)'
- result = {}
- for k, v in iteritems(self._values['variables']):
- matches = re.match(pattern, k)
- if not matches:
- raise F5ModuleError(
- "Unable to find the variable 'key' in the API payload."
- )
- key = matches.group('key')
- result[key] = v
- return result
-
-
-class ModuleParameters(Parameters):
- @property
- def description(self):
- if self._values['description'] is None:
- return None
- elif self._values['description'] in ['none', '']:
- return ''
- return self._values['description']
-
- @property
- def variables(self):
- if self._values['variables'] is None:
- return None
- result = {}
- for k, v in iteritems(self._values['variables']):
- result[k] = str(v).replace('"', '')
- return result
-
- @property
- def external_program(self):
- if self._values['external_program'] is None:
- return None
- return fq_name(self.partition, self._values['external_program'])
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class UsableChanges(Changes):
- pass
-
-
-class ReportableChanges(Changes):
- pass
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
- @property
- def parent(self):
- if self.want.parent != self.have.parent:
- raise F5ModuleError(
- "The parent monitor cannot be changed"
- )
-
- @property
- def destination(self):
- if self.want.ip is None and self.want.port is None:
- return None
- if self.want.port is None:
- self.want.update({'port': self.have.port})
- if self.want.ip is None:
- self.want.update({'ip': self.have.ip})
-
- if self.want.port in [None, '*'] and self.want.ip != '*':
- raise F5ModuleError(
- "Specifying an IP address requires that a port number be specified"
- )
-
- if self.want.destination != self.have.destination:
- return self.want.destination
-
- @property
- def interval(self):
- if self.want.timeout is not None and self.want.interval is not None:
- if self.want.interval >= self.want.timeout:
- raise F5ModuleError(
- "Parameter 'interval' must be less than 'timeout'."
- )
- elif self.want.timeout is not None:
- if self.have.interval >= self.want.timeout:
- raise F5ModuleError(
- "Parameter 'interval' must be less than 'timeout'."
- )
- elif self.want.interval is not None:
- if self.want.interval >= self.have.timeout:
- raise F5ModuleError(
- "Parameter 'interval' must be less than 'timeout'."
- )
- if self.want.interval != self.have.interval:
- return self.want.interval
-
- @property
- def variables(self):
- if self.want.variables is None:
- return None
- if self.have.variables is None:
- return dict(
- variables=self.want.variables
- )
- result = dict()
- different = compare_dictionary(self.want.variables, self.have.variables)
- if not different:
- return None
-
- for k, v in iteritems(self.want.variables):
- if k in self.have.variables and v != self.have.variables[k]:
- result[k] = v
- elif k not in self.have.variables:
- result[k] = v
- for k, v in iteritems(self.have.variables):
- if k not in self.want.variables:
- result[k] = "none"
- if result:
- result = dict(
- variables=result
- )
- return result
-
- @property
- def description(self):
- return cmp_str_with_none(self.want.description, self.have.description)
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(params=self.module.params)
- self.have = ApiParameters()
- self.changes = UsableChanges()
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = UsableChanges(params=changed)
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def exec_module(self):
- changed = False
- result = dict()
- state = self.want.state
-
- if state == "present":
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.client.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def present(self):
- if self.exists():
- return self.update()
- else:
- return self.create()
-
- def exists(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/monitor/external/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def update(self):
- self.have = self.read_current_from_device()
- if not self.should_update():
- return False
- if self.module.check_mode:
- return True
- self.update_on_device()
- return True
-
- def remove(self):
- if self.module.check_mode:
- return True
- self.remove_from_device()
- if self.exists():
- raise F5ModuleError("Failed to delete the resource.")
- return True
-
- def create(self):
- self._set_changed_options()
- self._set_default_creation_values()
- if self.module.check_mode:
- return True
- self.create_on_device()
- return True
-
- def _set_default_creation_values(self):
- if self.want.timeout is None:
- self.want.update({'timeout': 16})
- if self.want.interval is None:
- self.want.update({'interval': 5})
- if self.want.ip is None:
- self.want.update({'ip': '*'})
- if self.want.port is None:
- self.want.update({'port': '*'})
-
- def create_on_device(self):
- params = self.changes.api_params()
- params['name'] = self.want.name
- params['partition'] = self.want.partition
- uri = "https://{0}:{1}/mgmt/tm/ltm/monitor/external/".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- if self.want.variables:
- self.set_variable_on_device(self.want.variables)
-
- def set_variable_on_device(self, commands):
- command = ' '.join(['user-defined {0} \\\"{1}\\\"'.format(k, v) for k, v in iteritems(commands)])
- command = 'tmsh modify ltm monitor external {0} {1}'.format(self.want.name, command)
- uri = "https://{0}:{1}/mgmt/tm/util/bash".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- args = dict(
- command='run',
- utilCmdArgs='-c "{0}"'.format(command)
- )
- resp = self.client.api.post(uri, json=args)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def update_on_device(self):
- params = self.changes.api_params()
- if params:
- uri = "https://{0}:{1}/mgmt/tm/ltm/monitor/external/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- if self.changes.variables:
- self.set_variable_on_device(self.changes.variables)
-
- def absent(self):
- if self.exists():
- return self.remove()
- return False
-
- def remove_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/monitor/external/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.delete(uri)
- if resp.status == 200:
- return True
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/monitor/external/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return ApiParameters(params=response)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- name=dict(required=True),
- parent=dict(default='/Common/external'),
- description=dict(),
- arguments=dict(),
- ip=dict(),
- port=dict(),
- external_program=dict(),
- interval=dict(type='int'),
- timeout=dict(type='int'),
- state=dict(
- default='present',
- choices=['present', 'absent']
- ),
- variables=dict(type='dict'),
- partition=dict(
- default='Common',
- fallback=(env_fallback, ['F5_PARTITION'])
- )
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode,
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_monitor_gateway_icmp.py b/lib/ansible/modules/network/f5/bigip_monitor_gateway_icmp.py
deleted file mode 100644
index 179e148d2a..0000000000
--- a/lib/ansible/modules/network/f5/bigip_monitor_gateway_icmp.py
+++ /dev/null
@@ -1,801 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2018, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_monitor_gateway_icmp
-short_description: Manages F5 BIG-IP LTM gateway ICMP monitors
-description:
- - Manages gateway ICMP monitors on a BIG-IP.
-version_added: 2.8
-options:
- name:
- description:
- - Monitor name.
- type: str
- required: True
- parent:
- description:
- - The parent template of this monitor template. Once this value has
- been set, it cannot be changed. By default, this value is the
- C(gateway_icmp) parent on the C(Common) partition.
- type: str
- default: /Common/gateway_icmp
- description:
- description:
- - The description of the monitor.
- type: str
- ip:
- description:
- - IP address part of the IP/port definition. If this parameter is not
- provided when creating a new monitor, then the default value will be
- '*'.
- type: str
- port:
- description:
- - Port address part of the IP/port definition. If this parameter is not
- provided when creating a new monitor, then the default value will be
- '*'. Note that if specifying an IP address, a value between 1 and 65535
- must be specified.
- type: str
- interval:
- description:
- - Specifies, in seconds, the frequency at which the system issues the
- monitor check when either the resource is down or the status of the
- resource is unknown.
- type: int
- timeout:
- description:
- - Specifies the number of seconds the target has in which to respond to
- the monitor request.
- - If the target responds within the set time period, it is considered 'up'.
- If the target does not respond within the set time period, it is considered
- 'down'. When this value is set to 0 (zero), the system uses the interval
- from the parent monitor.
- - Note that C(timeout) and C(time_until_up) combine to control when a
- resource is set to up.
- type: int
- time_until_up:
- description:
- - Specifies the number of seconds to wait after a resource first responds
- correctly to the monitor before setting the resource to 'up'.
- - During the interval, all responses from the resource must be correct.
- - When the interval expires, the resource is marked 'up'.
- - A value of 0, means that the resource is marked up immediately upon
- receipt of the first correct response.
- type: int
- up_interval:
- description:
- - Specifies the interval for the system to use to perform the health check
- when a resource is up.
- - When C(0), specifies that the system uses the interval specified in
- C(interval) to check the health of the resource.
- - When any other number, enables specification of a different interval to
- use when checking the health of a resource that is up.
- type: int
- manual_resume:
- description:
- - Specifies whether the system automatically changes the status of a resource
- to B(enabled) at the next successful monitor check.
- - If you set this option to C(yes), you must manually re-enable the resource
- before the system can use it for load balancing connections.
- - When C(yes), specifies that you must manually re-enable the resource after an
- unsuccessful monitor check.
- - When C(no), specifies that the system automatically changes the status of a
- resource to B(enabled) at the next successful monitor check.
- type: bool
- adaptive:
- description:
- - Specifies whether adaptive response time monitoring is enabled for this monitor.
- - When C(yes), the monitor determines the state of a service based on how divergent
- from the mean latency a monitor probe for that service is allowed to be.
- Also, values for the C(allowed_divergence), C(adaptive_limit), and
- and C(sampling_timespan) will be enforced.
- - When C(disabled), the monitor determines the state of a service based on the
- C(interval), C(up_interval), C(time_until_up), and C(timeout) monitor settings.
- type: bool
- allowed_divergence_type:
- description:
- - When specifying a new monitor, if C(adaptive) is C(yes), the default is
- C(relative)
- - When C(absolute), the number of milliseconds the latency of a monitor probe
- can exceed the mean latency of a monitor probe for the service being probed.
- In typical cases, if the monitor detects three probes in a row that miss the
- latency value you set, the pool member or node is marked down.
- - When C(relative), the percentage of deviation the latency of a monitor probe
- can exceed the mean latency of a monitor probe for the service being probed.
- type: str
- choices:
- - relative
- - absolute
- allowed_divergence_value:
- description:
- - When specifying a new monitor, if C(adaptive) is C(yes), and C(type) is
- C(relative), the default is C(25) percent.
- type: int
- adaptive_limit:
- description:
- - Specifies the absolute number of milliseconds that may not be exceeded by a monitor
- probe, regardless of C(allowed_divergence) setting, for a probe to be
- considered successful.
- - This value applies regardless of the value of the C(allowed_divergence) setting.
- - While this value can be configured when C(adaptive) is C(no), it will not take
- effect on the system until C(adaptive) is C(yes).
- type: int
- sampling_timespan:
- description:
- - Specifies the length, in seconds, of the probe history window that the system
- uses to calculate the mean latency and standard deviation of a monitor probe.
- - While this value can be configured when C(adaptive) is C(no), it will not take
- effect on the system until C(adaptive) is C(yes).
- type: int
- transparent:
- description:
- - Specifies whether the monitor operates in transparent mode.
- - A monitor in transparent mode directs traffic through the associated pool members
- or nodes (usually a router or firewall) to the aliased destination (that is, it
- probes the C(ip)-C(port) combination specified in the monitor).
- - If the monitor cannot successfully reach the aliased destination, the pool member
- or node through which the monitor traffic was sent is marked down.
- - When creating a new monitor, if this parameter is not provided, then the default
- value will be whatever is provided by the C(parent).
- type: bool
- partition:
- description:
- - Device partition to manage resources on.
- type: str
- default: Common
- state:
- description:
- - When C(present), ensures that the monitor exists.
- - When C(absent), ensures the monitor is removed.
- type: str
- choices:
- - present
- - absent
- default: present
-extends_documentation_fragment: f5
-author:
- - Tim Rupp (@caphrim007)
-'''
-
-EXAMPLES = r'''
-- name: Create a monitor
- bigip_monitor_gateway_icmp:
- name: gw1
- adaptive: no
- interval: 1
- time_until_up: 0
- timeout: 3
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-'''
-
-RETURN = r'''
-parent:
- description: New parent template of the monitor.
- returned: changed
- type: str
- sample: gateway-icmp
-ip:
- description: The new IP of IP/port definition.
- returned: changed
- type: str
- sample: 10.12.13.14
-interval:
- description: The new interval in which to run the monitor check.
- returned: changed
- type: int
- sample: 2
-timeout:
- description: The new timeout in which the remote system must respond to the monitor.
- returned: changed
- type: int
- sample: 10
-time_until_up:
- description: The new time in which to mark a system as up after first successful response.
- returned: changed
- type: int
- sample: 2
-adaptive:
- description: Whether adaptive is enabled or not.
- returned: changed
- type: bool
- sample: yes
-allowed_divergence_type:
- description: Type of divergence used for adaptive response time monitoring.
- returned: changed
- type: str
- sample: absolute
-allowed_divergence_value:
- description:
- - Value of the type of divergence used for adaptive response time monitoring.
- - May be C(percent) or C(ms) depending on whether C(relative) or C(absolute).
- returned: changed
- type: int
- sample: 25
-description:
- description: The description of the monitor.
- returned: changed
- type: str
- sample: Important Monitor
-adaptive_limit:
- description: Absolute number of milliseconds that may not be exceeded by a monitor probe.
- returned: changed
- type: int
- sample: 200
-sampling_timespan:
- description: Absolute number of milliseconds that may not be exceeded by a monitor probe.
- returned: changed
- type: int
- sample: 200
-up_interval:
- description: Interval for the system to use to perform the health check when a resource is up.
- returned: changed
- type: int
- sample: 0
-port:
- description:
- - Alias port or service for the monitor to check, on behalf of the pools or pool
- members with which the monitor is associated.
- returned: changed
- type: str
- sample: 80
-transparent:
- description: Whether the monitor operates in transparent mode.
- returned: changed
- type: bool
- sample: no
-'''
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.basic import env_fallback
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import fq_name
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.common import transform_name
- from library.module_utils.network.f5.common import flatten_boolean
- from library.module_utils.network.f5.ipaddress import is_valid_ip
- from library.module_utils.network.f5.compare import cmp_str_with_none
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import fq_name
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.common import transform_name
- from ansible.module_utils.network.f5.common import flatten_boolean
- from ansible.module_utils.network.f5.ipaddress import is_valid_ip
- from ansible.module_utils.network.f5.compare import cmp_str_with_none
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'adaptiveDivergenceType': 'allowed_divergence_type',
- 'adaptiveDivergenceValue': 'allowed_divergence_value',
- 'adaptiveLimit': 'adaptive_limit',
- 'adaptiveSamplingTimespan': 'sampling_timespan',
- 'timeUntilUp': 'time_until_up',
- 'upInterval': 'up_interval',
- 'defaultsFrom': 'parent',
- }
-
- api_attributes = [
- 'adaptive',
- 'adaptiveDivergenceType',
- 'adaptiveDivergenceValue',
- 'adaptiveLimit',
- 'adaptiveSamplingTimespan',
- 'defaultsFrom',
- 'description',
- 'destination',
- 'interval',
- 'manualResume',
- 'timeout',
- 'timeUntilUp',
- 'transparent',
- 'upInterval',
- 'destination',
- ]
-
- returnables = [
- 'adaptive',
- 'allowed_divergence_type',
- 'allowed_divergence_value',
- 'description',
- 'adaptive_limit',
- 'sampling_timespan',
- 'manual_resume',
- 'time_until_up',
- 'up_interval',
- 'timeout',
- 'interval',
- 'transparent',
- 'parent',
- 'ip',
- 'port',
- ]
-
- updatables = [
- 'adaptive',
- 'allowed_divergence_type',
- 'allowed_divergence_value',
- 'adaptive_limit',
- 'sampling_timespan',
- 'description',
- 'manual_resume',
- 'time_until_up',
- 'up_interval',
- 'timeout',
- 'interval',
- 'transparent',
- 'parent',
- 'destination',
- 'interval',
- ]
-
- @property
- def destination(self):
- if self.ip is None and self.port is None:
- return None
- destination = '{0}:{1}'.format(self.ip, self.port)
- return destination
-
- @destination.setter
- def destination(self, value):
- ip, port = value.split(':')
- self._values['ip'] = ip
- self._values['port'] = port
-
- @property
- def interval(self):
- if self._values['interval'] is None:
- return None
-
- # Per BZ617284, the BIG-IP UI does not raise a warning about this.
- # So I do
- if 1 > int(self._values['interval']) > 86400:
- raise F5ModuleError(
- "Interval value must be between 1 and 86400"
- )
- return int(self._values['interval'])
-
- @property
- def timeout(self):
- if self._values['timeout'] is None:
- return None
- return int(self._values['timeout'])
-
- @property
- def ip(self):
- if self._values['ip'] is None:
- return None
- if self._values['ip'] in ['*', '0.0.0.0']:
- return '*'
- elif is_valid_ip(self._values['ip']):
- return self._values['ip']
- else:
- raise F5ModuleError(
- "The provided 'ip' parameter is not an IP address."
- )
-
- @property
- def port(self):
- if self._values['port'] is None:
- return None
- elif self._values['port'] == '*':
- return '*'
- return int(self._values['port'])
-
- @property
- def time_until_up(self):
- if self._values['time_until_up'] is None:
- return None
- return int(self._values['time_until_up'])
-
- @property
- def parent(self):
- if self._values['parent'] is None:
- return None
- result = fq_name(self.partition, self._values['parent'])
- return result
-
-
-class ApiParameters(Parameters):
- @property
- def description(self):
- if self._values['description'] in [None, 'none']:
- return None
- return self._values['description']
-
-
-class ModuleParameters(Parameters):
- @property
- def description(self):
- if self._values['description'] is None:
- return None
- elif self._values['description'] in ['none', '']:
- return ''
- return self._values['description']
-
- @property
- def manual_resume(self):
- if self._values['manual_resume'] is None:
- return None
- elif self._values['manual_resume'] is True:
- return 'enabled'
- return 'disabled'
-
- @property
- def transparent(self):
- if self._values['transparent'] is None:
- return None
- elif self._values['transparent'] is True:
- return 'enabled'
- return 'disabled'
-
- @property
- def adaptive(self):
- if self._values['adaptive'] is None:
- return None
- elif self._values['adaptive'] is True:
- return 'enabled'
- return 'disabled'
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class UsableChanges(Changes):
- pass
-
-
-class ReportableChanges(Changes):
- @property
- def manual_resume(self):
- return flatten_boolean(self._values['manual_resume'])
-
- @property
- def transparent(self):
- return flatten_boolean(self._values['transparent'])
-
- @property
- def adaptive(self):
- return flatten_boolean(self._values['adaptive'])
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
- @property
- def parent(self):
- if self.want.parent != self.have.parent:
- raise F5ModuleError(
- "The parent monitor cannot be changed"
- )
-
- @property
- def destination(self):
- if self.want.ip is None and self.want.port is None:
- return None
- if self.want.port is None:
- self.want.update({'port': self.have.port})
- if self.want.ip is None:
- self.want.update({'ip': self.have.ip})
-
- if self.want.port in [None, '*'] and self.want.ip != '*':
- raise F5ModuleError(
- "Specifying an IP address requires that a port number be specified"
- )
-
- if self.want.destination != self.have.destination:
- return self.want.destination
-
- @property
- def interval(self):
- if self.want.timeout is not None and self.want.interval is not None:
- if self.want.interval >= self.want.timeout:
- raise F5ModuleError(
- "Parameter 'interval' must be less than 'timeout'."
- )
- elif self.want.timeout is not None:
- if self.have.interval >= self.want.timeout:
- raise F5ModuleError(
- "Parameter 'interval' must be less than 'timeout'."
- )
- elif self.want.interval is not None:
- if self.want.interval >= self.have.timeout:
- raise F5ModuleError(
- "Parameter 'interval' must be less than 'timeout'."
- )
- if self.want.interval != self.have.interval:
- return self.want.interval
-
- @property
- def description(self):
- return cmp_str_with_none(self.want.description, self.have.description)
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(params=self.module.params)
- self.have = ApiParameters()
- self.changes = UsableChanges()
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = UsableChanges(params=changed)
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def exec_module(self):
- changed = False
- result = dict()
- state = self.want.state
-
- if state == "present":
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.client.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def present(self):
- if self.exists():
- return self.update()
- else:
- return self.create()
-
- def exists(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/monitor/gateway-icmp/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def update(self):
- self.have = self.read_current_from_device()
- if not self.should_update():
- return False
-
- if self.module.check_mode:
- return True
- self.update_on_device()
- return True
-
- def remove(self):
- if self.module.check_mode:
- return True
- self.remove_from_device()
- if self.exists():
- raise F5ModuleError("Failed to delete the resource.")
- return True
-
- def create(self):
- self._set_changed_options()
-
- if self.module.check_mode:
- return True
- self.create_on_device()
- return True
-
- def create_on_device(self):
- params = self.changes.api_params()
- params['name'] = self.want.name
- params['partition'] = self.want.partition
- uri = "https://{0}:{1}/mgmt/tm/ltm/monitor/gateway-icmp/".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def update_on_device(self):
- params = self.changes.api_params()
- uri = "https://{0}:{1}/mgmt/tm/ltm/monitor/gateway-icmp/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def absent(self):
- if self.exists():
- return self.remove()
- return False
-
- def remove_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/monitor/gateway-icmp/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.delete(uri)
- if resp.status == 200:
- return True
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/monitor/gateway-icmp/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return ApiParameters(params=response)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- name=dict(required=True),
- parent=dict(default='/Common/gateway_icmp'),
- ip=dict(),
- description=dict(),
- port=dict(),
- interval=dict(type='int'),
- timeout=dict(type='int'),
- time_until_up=dict(type='int'),
- up_interval=dict(type='int'),
- manual_resume=dict(type='bool'),
- adaptive=dict(type='bool'),
- allowed_divergence_type=dict(choices=['relative', 'absolute']),
- allowed_divergence_value=dict(type='int'),
- adaptive_limit=dict(type='int'),
- sampling_timespan=dict(type='int'),
- transparent=dict(type='bool'),
- state=dict(
- default='present',
- choices=['present', 'absent']
- ),
- partition=dict(
- default='Common',
- fallback=(env_fallback, ['F5_PARTITION'])
- )
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode,
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_monitor_http.py b/lib/ansible/modules/network/f5/bigip_monitor_http.py
deleted file mode 100644
index e387d206fc..0000000000
--- a/lib/ansible/modules/network/f5/bigip_monitor_http.py
+++ /dev/null
@@ -1,759 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_monitor_http
-short_description: Manages F5 BIG-IP LTM http monitors
-description: Manages F5 BIG-IP LTM http monitors.
-version_added: 2.5
-options:
- name:
- description:
- - Monitor name.
- type: str
- required: True
- parent:
- description:
- - The parent template of this monitor template. Once this value has
- been set, it cannot be changed. By default, this value is the C(http)
- parent on the C(Common) partition.
- type: str
- default: /Common/http
- description:
- description:
- - The description of the monitor.
- type: str
- version_added: 2.7
- send:
- description:
- - The send string for the monitor call. When creating a new monitor, if
- this value is not provided, the default C(GET /\r\n) will be used.
- type: str
- receive:
- description:
- - The receive string for the monitor call.
- type: str
- receive_disable:
- description:
- - This setting works like C(receive), except that the system marks the node
- or pool member disabled when its response matches the C(receive_disable)
- string but not C(receive). To use this setting, you must specify both
- C(receive_disable) and C(receive).
- type: str
- ip:
- description:
- - IP address part of the IP/port definition. If this parameter is not
- provided when creating a new monitor, then the default value will be
- '*'.
- type: str
- port:
- description:
- - Port address part of the IP/port definition. If this parameter is not
- provided when creating a new monitor, then the default value will be
- '*'. Note that if specifying an IP address, a value between 1 and 65535
- must be specified.
- type: str
- interval:
- description:
- - The interval specifying how frequently the monitor instance of this
- template will run. If this parameter is not provided when creating
- a new monitor, then the default value will be 5. This value B(must)
- be less than the C(timeout) value.
- type: int
- timeout:
- description:
- - The number of seconds in which the node or service must respond to
- the monitor request. If the target responds within the set time
- period, it is considered up. If the target does not respond within
- the set time period, it is considered down. You can change this
- number to any number you want, however, it should be 3 times the
- interval number of seconds plus 1 second. If this parameter is not
- provided when creating a new monitor, then the default value will be 16.
- type: int
- time_until_up:
- description:
- - Specifies the amount of time in seconds after the first successful
- response before a node will be marked up. A value of 0 will cause a
- node to be marked up immediately after a valid response is received
- from the node. If this parameter is not provided when creating
- a new monitor, then the default value will be 0.
- type: int
- target_username:
- description:
- - Specifies the user name, if the monitored target requires authentication.
- type: str
- target_password:
- description:
- - Specifies the password, if the monitored target requires authentication.
- type: str
- reverse:
- description:
- - Specifies whether the monitor operates in reverse mode.
- - When the monitor is in reverse mode, a successful receive string match
- marks the monitored object down instead of up. You can use the
- this mode only if you configure the C(receive) option.
- - This parameter is not compatible with the C(time_until_up) parameter. If
- C(time_until_up) is specified, it must be C(0). Or, if it already exists, it
- must be C(0).
- type: bool
- version_added: 2.8
- partition:
- description:
- - Device partition to manage resources on.
- type: str
- default: Common
- version_added: 2.5
- state:
- description:
- - When C(present), ensures that the monitor exists.
- - When C(absent), ensures the monitor is removed.
- type: str
- choices:
- - present
- - absent
- default: present
- version_added: 2.5
-notes:
- - Requires BIG-IP software version >= 12
-extends_documentation_fragment: f5
-author:
- - Tim Rupp (@caphrim007)
- - Wojciech Wypior (@wojtek0806)
-'''
-
-EXAMPLES = r'''
-- name: Create HTTP Monitor
- bigip_monitor_http:
- state: present
- ip: 10.10.10.10
- name: my_http_monitor
- provider:
- server: lb.mydomain.com
- user: admin
- password: secret
- delegate_to: localhost
-
-- name: Remove HTTP Monitor
- bigip_monitor_http:
- state: absent
- name: my_http_monitor
- provider:
- server: lb.mydomain.com
- user: admin
- password: secret
- delegate_to: localhost
-
-- name: Include a username and password in the HTTP monitor
- bigip_monitor_http:
- state: absent
- name: my_http_monitor
- target_username: monitor_user
- target_password: monitor_pass
- provider:
- server: lb.mydomain.com
- user: admin
- password: secret
- delegate_to: localhost
-'''
-
-RETURN = r'''
-parent:
- description: New parent template of the monitor.
- returned: changed
- type: str
- sample: http
-description:
- description: The description of the monitor.
- returned: changed
- type: str
- sample: Important_Monitor
-ip:
- description: The new IP of IP/port definition.
- returned: changed
- type: str
- sample: 10.12.13.14
-interval:
- description: The new interval in which to run the monitor check.
- returned: changed
- type: int
- sample: 2
-timeout:
- description: The new timeout in which the remote system must respond to the monitor.
- returned: changed
- type: int
- sample: 10
-time_until_up:
- description: The new time in which to mark a system as up after first successful response.
- returned: changed
- type: int
- sample: 2
-reverse:
- description: Whether the monitor operates in reverse mode.
- returned: changed
- type: bool
- sample: yes
-'''
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.basic import env_fallback
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import fq_name
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.common import transform_name
- from library.module_utils.network.f5.common import flatten_boolean
- from library.module_utils.network.f5.ipaddress import is_valid_ip
- from library.module_utils.network.f5.compare import cmp_str_with_none
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import fq_name
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.common import transform_name
- from ansible.module_utils.network.f5.common import flatten_boolean
- from ansible.module_utils.network.f5.ipaddress import is_valid_ip
- from ansible.module_utils.network.f5.compare import cmp_str_with_none
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'timeUntilUp': 'time_until_up',
- 'defaultsFrom': 'parent',
- 'recv': 'receive',
- 'recvDisable': 'receive_disable',
- }
-
- api_attributes = [
- 'timeUntilUp',
- 'defaultsFrom',
- 'interval',
- 'timeout',
- 'recv',
- 'send',
- 'destination',
- 'username',
- 'password',
- 'recvDisable',
- 'description',
- 'reverse',
- ]
-
- returnables = [
- 'parent',
- 'send',
- 'receive',
- 'ip',
- 'port',
- 'interval',
- 'timeout',
- 'time_until_up',
- 'receive_disable',
- 'description',
- 'reverse',
- ]
-
- updatables = [
- 'destination',
- 'send',
- 'receive',
- 'interval',
- 'timeout',
- 'time_until_up',
- 'target_username',
- 'target_password',
- 'receive_disable',
- 'description',
- 'reverse',
- ]
-
- @property
- def destination(self):
- if self.ip is None and self.port is None:
- return None
- destination = '{0}:{1}'.format(self.ip, self.port)
- return destination
-
- @destination.setter
- def destination(self, value):
- ip, port = value.split(':')
- self._values['ip'] = ip
- self._values['port'] = port
-
- @property
- def interval(self):
- if self._values['interval'] is None:
- return None
-
- # Per BZ617284, the BIG-IP UI does not raise a warning about this.
- # So I do
- if 1 > int(self._values['interval']) > 86400:
- raise F5ModuleError(
- "Interval value must be between 1 and 86400"
- )
- return int(self._values['interval'])
-
- @property
- def timeout(self):
- if self._values['timeout'] is None:
- return None
- return int(self._values['timeout'])
-
- @property
- def ip(self):
- if self._values['ip'] is None:
- return None
- if self._values['ip'] in ['*', '0.0.0.0']:
- return '*'
- elif is_valid_ip(self._values['ip']):
- return self._values['ip']
- else:
- raise F5ModuleError(
- "The provided 'ip' parameter is not an IP address."
- )
-
- @property
- def port(self):
- if self._values['port'] is None:
- return None
- elif self._values['port'] == '*':
- return '*'
- return int(self._values['port'])
-
- @property
- def time_until_up(self):
- if self._values['time_until_up'] is None:
- return None
- return int(self._values['time_until_up'])
-
- @property
- def parent(self):
- if self._values['parent'] is None:
- return None
- result = fq_name(self.partition, self._values['parent'])
- return result
-
- @property
- def type(self):
- return 'http'
-
- @property
- def username(self):
- return self._values['target_username']
-
- @property
- def password(self):
- return self._values['target_password']
-
- @property
- def reverse(self):
- return flatten_boolean(self._values['reverse'])
-
-
-class ApiParameters(Parameters):
- @property
- def description(self):
- if self._values['description'] in [None, 'none']:
- return None
- return self._values['description']
-
-
-class ModuleParameters(Parameters):
- @property
- def description(self):
- if self._values['description'] is None:
- return None
- elif self._values['description'] in ['none', '']:
- return ''
- return self._values['description']
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class UsableChanges(Changes):
- @property
- def reverse(self):
- if self._values['reverse'] is None:
- return None
- elif self._values['reverse'] == 'yes':
- return 'enabled'
- return 'disabled'
-
-
-class ReportableChanges(Changes):
- @property
- def reverse(self):
- return flatten_boolean(self._values['reverse'])
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- result = self.__default(param)
- return result
-
- @property
- def parent(self):
- if self.want.parent != self.have.parent:
- raise F5ModuleError(
- "The parent monitor cannot be changed"
- )
-
- @property
- def destination(self):
- if self.want.ip is None and self.want.port is None:
- return None
- if self.want.port is None:
- self.want.update({'port': self.have.port})
- if self.want.ip is None:
- self.want.update({'ip': self.have.ip})
-
- if self.want.port in [None, '*'] and self.want.ip != '*':
- raise F5ModuleError(
- "Specifying an IP address requires that a port number be specified"
- )
-
- if self.want.destination != self.have.destination:
- return self.want.destination
-
- @property
- def interval(self):
- if self.want.timeout is not None and self.want.interval is not None:
- if self.want.interval >= self.want.timeout:
- raise F5ModuleError(
- "Parameter 'interval' must be less than 'timeout'."
- )
- elif self.want.timeout is not None:
- if self.have.interval >= self.want.timeout:
- raise F5ModuleError(
- "Parameter 'interval' must be less than 'timeout'."
- )
- elif self.want.interval is not None:
- if self.want.interval >= self.have.timeout:
- raise F5ModuleError(
- "Parameter 'interval' must be less than 'timeout'."
- )
- if self.want.interval != self.have.interval:
- return self.want.interval
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
- @property
- def description(self):
- return cmp_str_with_none(self.want.description, self.have.description)
-
- @property
- def receive(self):
- return cmp_str_with_none(self.want.receive, self.have.receive)
-
- @property
- def receive_disable(self):
- return cmp_str_with_none(self.want.receive_disable, self.have.receive_disable)
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(params=self.module.params)
- self.have = ApiParameters()
- self.changes = UsableChanges()
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = UsableChanges(params=changed)
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def exec_module(self):
- changed = False
- result = dict()
- state = self.want.state
-
- if state == "present":
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.client.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def present(self):
- if self.exists():
- return self.update()
- else:
- return self.create()
-
- def exists(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/monitor/http/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def update(self):
- self.have = self.read_current_from_device()
- if not self.should_update():
- return False
- if self.want.reverse == 'enabled':
- if not self.want.receive and not self.have.receive:
- raise F5ModuleError(
- "A 'receive' string must be specified when setting 'reverse'."
- )
- if self.want.time_until_up != 0 and self.have.time_until_up != 0:
- raise F5ModuleError(
- "Monitors with the 'reverse' attribute are not currently compatible with 'time_until_up'."
- )
- if self.module.check_mode:
- return True
- self.update_on_device()
- return True
-
- def remove(self):
- if self.module.check_mode:
- return True
- self.remove_from_device()
- if self.exists():
- raise F5ModuleError("Failed to delete the monitor.")
- return True
-
- def create(self):
- self._set_changed_options()
- if self.want.reverse == 'enabled':
- if self.want.time_until_up != 0:
- raise F5ModuleError(
- "Monitors with the 'reverse' attribute are not currently compatible with 'time_until_up'."
- )
- if not self.want.receive:
- raise F5ModuleError(
- "A 'receive' string must be specified when setting 'reverse'."
- )
- self._set_default_creation_values()
- if self.module.check_mode:
- return True
- self.create_on_device()
- return True
-
- def _set_default_creation_values(self):
- if self.want.timeout is None:
- self.want.update({'timeout': 16})
- if self.want.interval is None:
- self.want.update({'interval': 5})
- if self.want.time_until_up is None:
- self.want.update({'time_until_up': 0})
- if self.want.ip is None:
- self.want.update({'ip': '*'})
- if self.want.port is None:
- self.want.update({'port': '*'})
- if self.want.send is None:
- self.want.update({'send': 'GET /\r\n'})
-
- def create_on_device(self):
- params = self.changes.api_params()
- params['name'] = self.want.name
- params['partition'] = self.want.partition
- uri = "https://{0}:{1}/mgmt/tm/ltm/monitor/http/".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def update_on_device(self):
- params = self.changes.api_params()
- uri = "https://{0}:{1}/mgmt/tm/ltm/monitor/http/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def absent(self):
- if self.exists():
- return self.remove()
- return False
-
- def remove_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/monitor/http/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.delete(uri)
- if resp.status == 200:
- return True
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/monitor/http/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return ApiParameters(params=response)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- name=dict(required=True),
- parent=dict(default='/Common/http'),
- description=dict(),
- send=dict(),
- receive=dict(),
- receive_disable=dict(),
- ip=dict(),
- port=dict(),
- interval=dict(type='int'),
- reverse=dict(type='bool'),
- timeout=dict(type='int'),
- time_until_up=dict(type='int'),
- target_username=dict(),
- target_password=dict(no_log=True),
- state=dict(
- default='present',
- choices=['present', 'absent']
- ),
- partition=dict(
- default='Common',
- fallback=(env_fallback, ['F5_PARTITION'])
- )
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode,
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_monitor_https.py b/lib/ansible/modules/network/f5/bigip_monitor_https.py
deleted file mode 100644
index adc623124b..0000000000
--- a/lib/ansible/modules/network/f5/bigip_monitor_https.py
+++ /dev/null
@@ -1,746 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_monitor_https
-short_description: Manages F5 BIG-IP LTM https monitors
-description: Manages F5 BIG-IP LTM https monitors.
-version_added: 2.5
-options:
- name:
- description:
- - Monitor name.
- type: str
- required: True
- description:
- description:
- - The description of the monitor.
- type: str
- version_added: 2.7
- parent:
- description:
- - The parent template of this monitor template. Once this value has
- been set, it cannot be changed. By default, this value is the C(https)
- parent on the C(Common) partition.
- type: str
- default: /Common/https
- send:
- description:
- - The send string for the monitor call. When creating a new monitor, if
- this value is not provided, the default C(GET /\\r\\n) will be used.
- type: str
- receive:
- description:
- - The receive string for the monitor call.
- type: str
- receive_disable:
- description:
- - This setting works like C(receive), except that the system marks the node
- or pool member disabled when its response matches the C(receive_disable)
- string but not C(receive). To use this setting, you must specify both
- C(receive_disable) and C(receive).
- type: str
- ip:
- description:
- - IP address part of the IP/port definition. If this parameter is not
- provided when creating a new monitor, then the default value will be
- '*'.
- type: str
- port:
- description:
- - Port address part of the IP/port definition. If this parameter is not
- provided when creating a new monitor, then the default value will be
- '*'. Note that if specifying an IP address, a value between 1 and 65535
- must be specified.
- type: str
- interval:
- description:
- - The interval specifying how frequently the monitor instance of this
- template will run. If this parameter is not provided when creating
- a new monitor, then the default value will be 5. This value B(must)
- be less than the C(timeout) value.
- type: int
- timeout:
- description:
- - The number of seconds in which the node or service must respond to
- the monitor request. If the target responds within the set time
- period, it is considered up. If the target does not respond within
- the set time period, it is considered down. You can change this
- number to any number you want, however, it should be 3 times the
- interval number of seconds plus 1 second. If this parameter is not
- provided when creating a new monitor, then the default value will be 16.
- type: int
- time_until_up:
- description:
- - Specifies the amount of time in seconds after the first successful
- response before a node will be marked up. A value of 0 will cause a
- node to be marked up immediately after a valid response is received
- from the node. If this parameter is not provided when creating
- a new monitor, then the default value will be 0.
- type: int
- target_username:
- description:
- - Specifies the user name, if the monitored target requires authentication.
- type: str
- target_password:
- description:
- - Specifies the password, if the monitored target requires authentication.
- type: str
- ssl_profile:
- description:
- - Specifies the SSL profile to use for the HTTPS monitor.
- - Defining SSL profiles enables refined customization of the SSL attributes
- for an HTTPS monitor.
- - This parameter is only supported on BIG-IP versions 13.x and later.
- type: str
- version_added: 2.8
- up_interval:
- description:
- - Specifies the interval for the system to use to perform the health check
- when a resource is up.
- - When C(0), specifies that the system uses the interval specified in
- C(interval) to check the health of the resource.
- - When any other number, enables specification of a different interval to
- use when checking the health of a resource that is up.
- type: int
- version_added: 2.8
- partition:
- description:
- - Device partition to manage resources on.
- type: str
- default: Common
- state:
- description:
- - When C(present), ensures that the monitor exists.
- - When C(absent), ensures the monitor is removed.
- type: str
- choices:
- - present
- - absent
- default: present
- version_added: 2.5
-notes:
- - Requires BIG-IP software version >= 12
-extends_documentation_fragment: f5
-author:
- - Tim Rupp (@caphrim007)
- - Wojciech Wypior (@wojtek0806)
-'''
-
-EXAMPLES = r'''
-- name: Create HTTPS Monitor
- bigip_monitor_https:
- name: my_http_monitor
- state: present
- ip: 10.10.10.10
- provider:
- server: lb.mydomain.com
- user: admin
- password: secret
- delegate_to: localhost
-
-- name: Remove HTTPS Monitor
- bigip_monitor_https:
- name: my_http_monitor
- state: absent
- provider:
- server: lb.mydomain.com
- user: admin
- password: secret
- delegate_to: localhost
-'''
-
-RETURN = r'''
-parent:
- description: New parent template of the monitor.
- returned: changed
- type: str
- sample: https
-ip:
- description: The new IP of IP/port definition.
- returned: changed
- type: str
- sample: 10.12.13.14
-interval:
- description: The new interval in which to run the monitor check.
- returned: changed
- type: int
- sample: 2
-description:
- description: The description of the monitor.
- returned: changed
- type: str
- sample: Important Monitor
-timeout:
- description: The new timeout in which the remote system must respond to the monitor.
- returned: changed
- type: int
- sample: 10
-time_until_up:
- description: The new time in which to mark a system as up after first successful response.
- returned: changed
- type: int
- sample: 2
-up_interval:
- description: Interval for the system to use to perform the health check when a resource is up.
- returned: changed
- type: int
- sample: 0
-'''
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.basic import env_fallback
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import fq_name
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.common import transform_name
- from library.module_utils.network.f5.ipaddress import is_valid_ip
- from library.module_utils.network.f5.compare import cmp_str_with_none
-
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import fq_name
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.common import transform_name
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.ipaddress import is_valid_ip
- from ansible.module_utils.network.f5.compare import cmp_str_with_none
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'timeUntilUp': 'time_until_up',
- 'defaultsFrom': 'parent',
- 'recv': 'receive',
- 'recvDisable': 'receive_disable',
- 'sslProfile': 'ssl_profile',
- 'upInterval': 'up_interval',
- }
-
- api_attributes = [
- 'timeUntilUp',
- 'defaultsFrom',
- 'interval',
- 'timeout',
- 'recv',
- 'send',
- 'destination',
- 'username',
- 'password',
- 'recvDisable',
- 'description',
- 'sslProfile',
- 'upInterval',
- ]
-
- returnables = [
- 'parent',
- 'send',
- 'receive',
- 'ip',
- 'port',
- 'interval',
- 'timeout',
- 'time_until_up',
- 'receive_disable',
- 'description',
- 'ssl_profile',
- 'up_interval',
- ]
-
- updatables = [
- 'destination',
- 'send',
- 'receive',
- 'interval',
- 'timeout',
- 'time_until_up',
- 'target_username',
- 'target_password',
- 'receive_disable',
- 'description',
- 'ssl_profile',
- 'up_interval',
- ]
-
- @property
- def username(self):
- return self._values['target_username']
-
- @property
- def password(self):
- return self._values['target_password']
-
- @property
- def destination(self):
- if self.ip is None and self.port is None:
- return None
- destination = '{0}:{1}'.format(self.ip, self.port)
- return destination
-
- @destination.setter
- def destination(self, value):
- ip, port = value.split(':')
- self._values['ip'] = ip
- self._values['port'] = port
-
- @property
- def interval(self):
- if self._values['interval'] is None:
- return None
-
- # Per BZ617284, the BIG-IP UI does not raise a warning about this.
- # So I do
- if 1 > int(self._values['interval']) > 86400:
- raise F5ModuleError(
- "Interval value must be between 1 and 86400"
- )
- return int(self._values['interval'])
-
- @property
- def timeout(self):
- if self._values['timeout'] is None:
- return None
- return int(self._values['timeout'])
-
- @property
- def ip(self):
- if self._values['ip'] is None:
- return None
- elif self._values['ip'] in ['*', '0.0.0.0']:
- return '*'
- elif is_valid_ip(self._values['ip']):
- return self._values['ip']
- raise F5ModuleError(
- "The provided 'ip' parameter is not an IP address."
- )
-
- @property
- def port(self):
- if self._values['port'] is None:
- return None
- elif self._values['port'] == '*':
- return '*'
- return int(self._values['port'])
-
- @property
- def time_until_up(self):
- if self._values['time_until_up'] is None:
- return None
- return int(self._values['time_until_up'])
-
- @property
- def parent(self):
- if self._values['parent'] is None:
- return None
- result = fq_name(self.partition, self._values['parent'])
- return result
-
- @property
- def type(self):
- return 'https'
-
-
-class ApiParameters(Parameters):
- @property
- def description(self):
- if self._values['description'] in [None, 'none']:
- return None
- return self._values['description']
-
-
-class ModuleParameters(Parameters):
- @property
- def description(self):
- if self._values['description'] is None:
- return None
- elif self._values['description'] in ['none', '']:
- return ''
- return self._values['description']
-
- @property
- def ssl_profile(self):
- if self._values['ssl_profile'] is None:
- return None
- if self._values['ssl_profile'] in ['', 'none']:
- return ''
- result = fq_name(self.partition, self._values['ssl_profile'])
- return result
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class UsableChanges(Changes):
- pass
-
-
-class ReportableChanges(Changes):
- pass
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- result = self.__default(param)
- return result
-
- @property
- def parent(self):
- if self.want.parent != self.have.parent:
- raise F5ModuleError(
- "The parent monitor cannot be changed"
- )
-
- @property
- def destination(self):
- if self.want.ip is None and self.want.port is None:
- return None
- if self.want.port is None:
- self.want.update({'port': self.have.port})
- if self.want.ip is None:
- self.want.update({'ip': self.have.ip})
-
- if self.want.port in [None, '*'] and self.want.ip != '*':
- raise F5ModuleError(
- "Specifying an IP address requires that a port number be specified"
- )
-
- if self.want.destination != self.have.destination:
- return self.want.destination
-
- @property
- def interval(self):
- if self.want.timeout is not None and self.want.interval is not None:
- if self.want.interval >= self.want.timeout:
- raise F5ModuleError(
- "Parameter 'interval' must be less than 'timeout'."
- )
- elif self.want.timeout is not None:
- if self.have.interval >= self.want.timeout:
- raise F5ModuleError(
- "Parameter 'interval' must be less than 'timeout'."
- )
- elif self.want.interval is not None:
- if self.want.interval >= self.have.timeout:
- raise F5ModuleError(
- "Parameter 'interval' must be less than 'timeout'."
- )
- if self.want.interval != self.have.interval:
- return self.want.interval
-
- @property
- def ssl_profile(self):
- if self.want.ssl_profile is None:
- return None
- if self.want.ssl_profile == '' and self.have.ssl_profile is None:
- return None
- if self.want.ssl_profile != self.have.ssl_profile:
- return self.want.ssl_profile
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
- @property
- def description(self):
- return cmp_str_with_none(self.want.description, self.have.description)
-
- @property
- def receive(self):
- return cmp_str_with_none(self.want.receive, self.have.receive)
-
- @property
- def receive_disable(self):
- return cmp_str_with_none(self.want.receive_disable, self.have.receive_disable)
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(params=self.module.params)
- self.have = ApiParameters()
- self.changes = UsableChanges()
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = UsableChanges(params=changed)
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def exec_module(self):
- changed = False
- result = dict()
- state = self.want.state
-
- if state == "present":
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.client.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def present(self):
- if self.exists():
- return self.update()
- else:
- return self.create()
-
- def exists(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/monitor/https/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def update(self):
- self.have = self.read_current_from_device()
- if not self.should_update():
- return False
- if self.module.check_mode:
- return True
- self.update_on_device()
- return True
-
- def remove(self):
- if self.module.check_mode:
- return True
- self.remove_from_device()
- if self.exists():
- raise F5ModuleError("Failed to delete the resource.")
- return True
-
- def create(self):
- self._set_changed_options()
- self._set_default_creation_values()
- if self.module.check_mode:
- return True
- self.create_on_device()
- return True
-
- def _set_default_creation_values(self):
- if self.want.timeout is None:
- self.want.update({'timeout': 16})
- if self.want.interval is None:
- self.want.update({'interval': 5})
- if self.want.time_until_up is None:
- self.want.update({'time_until_up': 0})
- if self.want.ip is None:
- self.want.update({'ip': '*'})
- if self.want.port is None:
- self.want.update({'port': '*'})
- if self.want.send is None:
- self.want.update({'send': 'GET /\r\n'})
-
- def create_on_device(self):
- params = self.changes.api_params()
- params['name'] = self.want.name
- params['partition'] = self.want.partition
- uri = "https://{0}:{1}/mgmt/tm/ltm/monitor/https/".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def update_on_device(self):
- params = self.changes.api_params()
- uri = "https://{0}:{1}/mgmt/tm/ltm/monitor/https/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def absent(self):
- if self.exists():
- return self.remove()
- return False
-
- def remove_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/monitor/https/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.delete(uri)
- if resp.status == 200:
- return True
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/monitor/https/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return ApiParameters(params=response)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- name=dict(required=True),
- parent=dict(default='/Common/https'),
- description=dict(),
- send=dict(),
- receive=dict(),
- receive_disable=dict(),
- ip=dict(),
- up_interval=dict(type='int'),
- port=dict(),
- interval=dict(type='int'),
- timeout=dict(type='int'),
- time_until_up=dict(type='int'),
- target_username=dict(),
- target_password=dict(no_log=True),
- ssl_profile=dict(),
- state=dict(
- default='present',
- choices=['present', 'absent']
- ),
- partition=dict(
- default='Common',
- fallback=(env_fallback, ['F5_PARTITION'])
- )
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode,
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_monitor_ldap.py b/lib/ansible/modules/network/f5/bigip_monitor_ldap.py
deleted file mode 100644
index 841f4be7d3..0000000000
--- a/lib/ansible/modules/network/f5/bigip_monitor_ldap.py
+++ /dev/null
@@ -1,823 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2018, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_monitor_ldap
-short_description: Manages BIG-IP LDAP monitors
-description:
- - Manages BIG-IP LDAP monitors.
-version_added: 2.8
-options:
- name:
- description:
- - Monitor name.
- type: str
- required: True
- description:
- description:
- - Specifies descriptive text that identifies the monitor.
- type: str
- parent:
- description:
- - The parent template of this monitor template. Once this value has
- been set, it cannot be changed.
- - By default, this value is the C(ldap) parent on the C(Common) partition.
- type: str
- default: "/Common/ldap"
- ip:
- description:
- - IP address part of the IP/port definition. If this parameter is not
- provided when creating a new monitor, then the default value will be
- '*'.
- type: str
- port:
- description:
- - Port address part of the IP/port definition. If this parameter is not
- provided when creating a new monitor, then the default value will be
- '*'.
- - Note that if specifying an IP address, a value between 1 and 65535
- must be specified.
- type: str
- interval:
- description:
- - Specifies, in seconds, the frequency at which the system issues the
- monitor check when either the resource is down or the status of the
- resource is unknown.
- type: int
- timeout:
- description:
- - Specifies the number of seconds the target has in which to respond to
- the monitor request.
- - If the target responds within the set time period, it is considered 'up'.
- If the target does not respond within the set time period, it is considered
- 'down'. When this value is set to 0 (zero), the system uses the interval
- from the parent monitor.
- - Note that C(timeout) and C(time_until_up) combine to control when a
- resource is set to up.
- type: int
- time_until_up:
- description:
- - Specifies the number of seconds to wait after a resource first responds
- correctly to the monitor before setting the resource to 'up'.
- - During the interval, all responses from the resource must be correct.
- - When the interval expires, the resource is marked 'up'.
- - A value of 0, means that the resource is marked up immediately upon
- receipt of the first correct response.
- type: int
- up_interval:
- description:
- - Specifies the interval for the system to use to perform the health check
- when a resource is up.
- - When C(0), specifies that the system uses the interval specified in
- C(interval) to check the health of the resource.
- - When any other number, enables specification of a different interval to
- use when checking the health of a resource that is up.
- type: int
- manual_resume:
- description:
- - Specifies whether the system automatically changes the status of a resource
- to B(enabled) at the next successful monitor check.
- - If you set this option to C(yes), you must manually re-enable the resource
- before the system can use it for load balancing connections.
- - When C(yes), specifies that you must manually re-enable the resource after an
- unsuccessful monitor check.
- - When C(no), specifies that the system automatically changes the status of a
- resource to B(enabled) at the next successful monitor check.
- type: bool
- target_username:
- description:
- - Specifies the user name, if the monitored target requires authentication.
- type: str
- target_password:
- description:
- - Specifies the password, if the monitored target requires authentication.
- type: str
- base:
- description:
- - Specifies the location in the LDAP tree from which the monitor starts the
- health check.
- type: str
- filter:
- description:
- - Specifies an LDAP key for which the monitor searches.
- type: str
- security:
- description:
- - Specifies the secure protocol type for communications with the target.
- type: str
- choices:
- - none
- - ssl
- - tls
- mandatory_attributes:
- description:
- - Specifies whether the target must include attributes in its response to be
- considered up.
- type: bool
- chase_referrals:
- description:
- - Specifies whether, upon receipt of an LDAP referral entry, the target
- follows (or chases) that referral.
- type: bool
- debug:
- description:
- - Specifies whether the monitor sends error messages and additional information
- to a log file created and labeled specifically for this monitor.
- type: bool
- update_password:
- description:
- - C(always) will update passwords if the C(target_password) is specified.
- - C(on_create) will only set the password for newly created monitors.
- type: str
- choices:
- - always
- - on_create
- default: always
- partition:
- description:
- - Device partition to manage resources on.
- type: str
- default: Common
- state:
- description:
- - When C(present), ensures that the monitor exists.
- - When C(absent), ensures the monitor is removed.
- type: str
- choices:
- - present
- - absent
- default: present
-extends_documentation_fragment: f5
-author:
- - Tim Rupp (@caphrim007)
- - Greg Crosby (@crosbygw)
-'''
-
-EXAMPLES = r'''
-- name: Create a LDAP monitor
- bigip_monitor_ldap:
- name: foo
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-'''
-
-RETURN = r'''
-parent:
- description: New parent template of the monitor.
- returned: changed
- type: str
- sample: ldap
-description:
- description: The description of the monitor.
- returned: changed
- type: str
- sample: Important_Monitor
-ip:
- description: The new IP of IP/port definition.
- returned: changed
- type: str
- sample: 10.12.13.14
-interval:
- description: The new interval in which to run the monitor check.
- returned: changed
- type: int
- sample: 2
-timeout:
- description: The new timeout in which the remote system must respond to the monitor.
- returned: changed
- type: int
- sample: 10
-time_until_up:
- description: The new time in which to mark a system as up after first successful response.
- returned: changed
- type: int
- sample: 2
-security:
- description: The new Security setting of the resource.
- returned: changed
- type: str
- sample: ssl
-debug:
- description: The new Debug setting of the resource.
- returned: changed
- type: bool
- sample: yes
-mandatory_attributes:
- description: The new Mandatory Attributes setting of the resource.
- returned: changed
- type: bool
- sample: no
-chase_referrals:
- description: The new Chase Referrals setting of the resource.
- returned: changed
- type: bool
- sample: yes
-manual_resume:
- description: The new Manual Resume setting of the resource.
- returned: changed
- type: bool
- sample: no
-filter:
- description: The new LDAP Filter setting of the resource.
- returned: changed
- type: str
- sample: filter1
-base:
- description: The new LDAP Base setting of the resource.
- returned: changed
- type: str
- sample: base
-'''
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.basic import env_fallback
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import fq_name
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.common import transform_name
- from library.module_utils.network.f5.common import flatten_boolean
- from library.module_utils.network.f5.ipaddress import is_valid_ip
- from library.module_utils.network.f5.compare import cmp_str_with_none
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import fq_name
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.common import transform_name
- from ansible.module_utils.network.f5.common import flatten_boolean
- from ansible.module_utils.network.f5.ipaddress import is_valid_ip
- from ansible.module_utils.network.f5.compare import cmp_str_with_none
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'timeUntilUp': 'time_until_up',
- 'defaultsFrom': 'parent',
- 'mandatoryAttributes': 'mandatory_attributes',
- 'chaseReferrals': 'chase_referrals',
- 'manualResume': 'manual_resume',
- 'username': 'target_username',
- 'password': 'target_password',
- }
-
- api_attributes = [
- 'timeUntilUp',
- 'defaultsFrom',
- 'interval',
- 'timeout',
- 'destination',
- 'description',
- 'security',
- 'mandatoryAttributes',
- 'chaseReferrals',
- 'debug',
- 'manualResume',
- 'username',
- 'password',
- 'filter',
- 'base',
- ]
-
- returnables = [
- 'parent',
- 'ip',
- 'destination',
- 'port',
- 'interval',
- 'timeout',
- 'time_until_up',
- 'description',
- 'security',
- 'debug',
- 'mandatory_attributes',
- 'chase_referrals',
- 'manual_resume',
- 'target_username',
- 'filter',
- 'base',
- ]
-
- updatables = [
- 'destination',
- 'interval',
- 'timeout',
- 'time_until_up',
- 'description',
- 'security',
- 'debug',
- 'mandatory_attributes',
- 'chase_referrals',
- 'manual_resume',
- 'target_username',
- 'target_password',
- 'filter',
- 'base',
- ]
-
- @property
- def timeout(self):
- if self._values['timeout'] is None:
- return None
- return int(self._values['timeout'])
-
- @property
- def time_until_up(self):
- if self._values['time_until_up'] is None:
- return None
- return int(self._values['time_until_up'])
-
- @property
- def mandatory_attributes(self):
- return flatten_boolean(self._values['mandatory_attributes'])
-
- @property
- def chase_referrals(self):
- return flatten_boolean(self._values['chase_referrals'])
-
- @property
- def debug(self):
- return flatten_boolean(self._values['debug'])
-
- @property
- def manual_resume(self):
- return flatten_boolean(self._values['manual_resume'])
-
- @property
- def security(self):
- if self._values['security'] in ['none', None]:
- return ''
- return self._values['security']
-
-
-class ApiParameters(Parameters):
- @property
- def ip(self):
- ip, port = self._values['destination'].split(':')
- return ip
-
- @property
- def port(self):
- ip, port = self._values['destination'].split(':')
- try:
- return int(port)
- except ValueError:
- return port
-
- @property
- def description(self):
- if self._values['description'] in [None, 'none']:
- return None
- return self._values['description']
-
-
-class ModuleParameters(Parameters):
- @property
- def ip(self):
- if self._values['ip'] is None:
- return None
- if self._values['ip'] in ['*', '0.0.0.0']:
- return '*'
- elif is_valid_ip(self._values['ip']):
- return self._values['ip']
- else:
- raise F5ModuleError(
- "The provided 'ip' parameter is not an IP address."
- )
-
- @property
- def parent(self):
- if self._values['parent'] is None:
- return None
- result = fq_name(self.partition, self._values['parent'])
- return result
-
- @property
- def port(self):
- if self._values['port'] is None:
- return None
- elif self._values['port'] == '*':
- return '*'
- return int(self._values['port'])
-
- @property
- def destination(self):
- if self.ip is None and self.port is None:
- return None
- destination = '{0}:{1}'.format(self.ip, self.port)
- return destination
-
- @destination.setter
- def destination(self, value):
- ip, port = value.split(':')
- self._values['ip'] = ip
- self._values['port'] = port
-
- @property
- def interval(self):
- if self._values['interval'] is None:
- return None
- if 1 > int(self._values['interval']) > 86400:
- raise F5ModuleError(
- "Interval value must be between 1 and 86400"
- )
- return int(self._values['interval'])
-
- @property
- def type(self):
- return 'ldap'
-
- @property
- def description(self):
- if self._values['description'] is None:
- return None
- elif self._values['description'] in ['none', '']:
- return ''
- return self._values['description']
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class UsableChanges(Changes):
- @property
- def manual_resume(self):
- if self._values['manual_resume'] is None:
- return None
- if self._values['manual_resume'] == 'yes':
- return 'enabled'
- return 'disabled'
-
-
-class ReportableChanges(Changes):
- @property
- def manual_resume(self):
- return flatten_boolean(self._values['manual_resume'])
-
- @property
- def ip(self):
- ip, port = self._values['destination'].split(':')
- return ip
-
- @property
- def port(self):
- ip, port = self._values['destination'].split(':')
- return int(port)
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- @property
- def parent(self):
- if self.want.parent != self.have.parent:
- raise F5ModuleError(
- "The parent monitor cannot be changed"
- )
-
- @property
- def destination(self):
- if self.want.ip is None and self.want.port is None:
- return None
- if self.want.port is None:
- self.want.update({'port': self.have.port})
- if self.want.ip is None:
- self.want.update({'ip': self.have.ip})
-
- if self.want.port in [None, '*'] and self.want.ip != '*':
- raise F5ModuleError(
- "Specifying an IP address requires that a port number be specified"
- )
-
- if self.want.destination != self.have.destination:
- return self.want.destination
-
- @property
- def target_password(self):
- if self.want.target_password != self.have.target_password:
- if self.want.update_password == 'always':
- result = self.want.target_password
- return result
-
- @property
- def interval(self):
- if self.want.timeout is not None and self.want.interval is not None:
- if self.want.interval >= self.want.timeout:
- raise F5ModuleError(
- "Parameter 'interval' must be less than 'timeout'."
- )
- elif self.want.timeout is not None:
- if self.have.interval >= self.want.timeout:
- raise F5ModuleError(
- "Parameter 'interval' must be less than 'timeout'."
- )
- elif self.want.interval is not None:
- if self.want.interval >= self.have.timeout:
- raise F5ModuleError(
- "Parameter 'interval' must be less than 'timeout'."
- )
- if self.want.interval != self.have.interval:
- return self.want.interval
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
- @property
- def description(self):
- return cmp_str_with_none(self.want.description, self.have.description)
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(params=self.module.params)
- self.have = ApiParameters()
- self.changes = UsableChanges()
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = UsableChanges(params=changed)
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def exec_module(self):
- changed = False
- result = dict()
- state = self.want.state
-
- if state == "present":
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.client.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def present(self):
- if self.exists():
- return self.update()
- else:
- return self.create()
-
- def _set_default_creation_values(self):
- if self.want.ip is None:
- self.want.update({'ip': '*'})
- if self.want.port is None:
- self.want.update({'port': '*'})
-
- def exists(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/monitor/ldap/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def update(self):
- self.have = self.read_current_from_device()
- if not self.should_update():
- return False
- if self.module.check_mode:
- return True
- self.update_on_device()
- return True
-
- def remove(self):
- if self.module.check_mode:
- return True
- self.remove_from_device()
- if self.exists():
- raise F5ModuleError("Failed to delete the resource.")
- return True
-
- def create(self):
- self._set_changed_options()
- self._set_default_creation_values()
- if self.module.check_mode:
- return True
- self.create_on_device()
- return True
-
- def create_on_device(self):
- params = self.changes.api_params()
- params['name'] = self.want.name
- params['partition'] = self.want.partition
- uri = "https://{0}:{1}/mgmt/tm/ltm/monitor/ldap/".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def update_on_device(self):
- params = self.changes.api_params()
- uri = "https://{0}:{1}/mgmt/tm/ltm/monitor/ldap/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def absent(self):
- if self.exists():
- return self.remove()
- return False
-
- def remove_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/monitor/ldap/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.delete(uri)
- if resp.status == 200:
- return True
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/monitor/ldap/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return ApiParameters(params=response)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- name=dict(required=True),
- parent=dict(default='/Common/ldap'),
- ip=dict(),
- description=dict(),
- port=dict(),
- interval=dict(type='int'),
- timeout=dict(type='int'),
- target_username=dict(),
- target_password=dict(no_log=True),
- debug=dict(type='bool'),
- security=dict(
- choices=['none', 'ssl', 'tls']
- ),
- manual_resume=dict(type='bool'),
- time_until_up=dict(type='int'),
- up_interval=dict(type='int'),
- filter=dict(),
- base=dict(),
- mandatory_attributes=dict(type='bool'),
- chase_referrals=dict(type='bool'),
- update_password=dict(
- default='always',
- choices=['always', 'on_create']
- ),
- state=dict(
- default='present',
- choices=['present', 'absent']
- ),
- partition=dict(
- default='Common',
- fallback=(env_fallback, ['F5_PARTITION'])
- )
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode,
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_monitor_snmp_dca.py b/lib/ansible/modules/network/f5/bigip_monitor_snmp_dca.py
deleted file mode 100644
index d6b9358335..0000000000
--- a/lib/ansible/modules/network/f5/bigip_monitor_snmp_dca.py
+++ /dev/null
@@ -1,764 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_monitor_snmp_dca
-short_description: Manages BIG-IP SNMP data collecting agent (DCA) monitors
-description:
- - The BIG-IP has an SNMP data collecting agent (DCA) that can query remote
- SNMP agents of various types, including the UC Davis agent (UCD) and the
- Windows 2000 Server agent (WIN2000).
-version_added: 2.5
-options:
- name:
- description:
- - Monitor name.
- type: str
- required: True
- description:
- description:
- - Specifies descriptive text that identifies the monitor.
- type: str
- parent:
- description:
- - The parent template of this monitor template. Once this value has
- been set, it cannot be changed. By default, this value is the C(snmp_dca)
- parent on the C(Common) partition.
- type: str
- default: "/Common/snmp_dca"
- interval:
- description:
- - Specifies, in seconds, the frequency at which the system issues the
- monitor check when either the resource is down or the status of the
- resource is unknown. When creating a new monitor, the default is C(10).
- type: int
- timeout:
- description:
- - Specifies the number of seconds the target has in which to respond to
- the monitor request. When creating a new monitor, the default is C(30)
- seconds. If the target responds within the set time period, it is
- considered 'up'. If the target does not respond within the set time
- period, it is considered 'down'. When this value is set to 0 (zero),
- the system uses the interval from the parent monitor. Note that
- C(timeout) and C(time_until_up) combine to control when a resource is
- set to up.
- type: int
- time_until_up:
- description:
- - Specifies the number of seconds to wait after a resource first responds
- correctly to the monitor before setting the resource to 'up'. During the
- interval, all responses from the resource must be correct. When the
- interval expires, the resource is marked 'up'. A value of 0, means
- that the resource is marked up immediately upon receipt of the first
- correct response. When creating a new monitor, the default is C(0).
- type: int
- community:
- description:
- - Specifies the community name that the system must use to authenticate
- with the host server through SNMP. When creating a new monitor, the
- default value is C(public). Note that this value is case sensitive.
- type: str
- version:
- description:
- - Specifies the version of SNMP that the host server uses. When creating
- a new monitor, the default is C(v1). When C(v1), specifies that the
- host server uses SNMP version 1. When C(v2c), specifies that the host
- server uses SNMP version 2c.
- type: str
- choices:
- - v1
- - v2c
- agent_type:
- description:
- - Specifies the SNMP agent running on the monitored server. When creating
- a new monitor, the default is C(UCD) (UC-Davis).
- type: str
- choices:
- - UCD
- - WIN2000
- - GENERIC
- cpu_coefficient:
- description:
- - Specifies the coefficient that the system uses to calculate the weight
- of the CPU threshold in the dynamic ratio load balancing algorithm.
- When creating a new monitor, the default is C(1.5).
- type: str
- cpu_threshold:
- description:
- - Specifies the maximum acceptable CPU usage on the target server. When
- creating a new monitor, the default is C(80) percent.
- type: int
- memory_coefficient:
- description:
- - Specifies the coefficient that the system uses to calculate the weight
- of the memory threshold in the dynamic ratio load balancing algorithm.
- When creating a new monitor, the default is C(1.0).
- type: str
- memory_threshold:
- description:
- - Specifies the maximum acceptable memory usage on the target server.
- When creating a new monitor, the default is C(70) percent.
- type: int
- disk_coefficient:
- description:
- - Specifies the coefficient that the system uses to calculate the weight
- of the disk threshold in the dynamic ratio load balancing algorithm.
- When creating a new monitor, the default is C(2.0).
- type: str
- disk_threshold:
- description:
- - Specifies the maximum acceptable disk usage on the target server. When
- creating a new monitor, the default is C(90) percent.
- type: int
- partition:
- description:
- - Device partition to manage resources on.
- type: str
- default: Common
- state:
- description:
- - When C(present), ensures that the monitor exists.
- - When C(absent), ensures the monitor is removed.
- type: str
- choices:
- - present
- - absent
- default: present
- version_added: 2.5
-notes:
- - Requires BIG-IP software version >= 12
- - This module does not support the C(variables) option because this option
- is broken in the REST API and does not function correctly in C(tmsh); for
- example you cannot remove user-defined params. Therefore, there is no way
- to automatically configure it.
-extends_documentation_fragment: f5
-author:
- - Tim Rupp (@caphrim007)
- - Wojciech Wypior (@wojtek0806)
-'''
-
-EXAMPLES = r'''
-- name: Create SNMP DCS monitor
- bigip_monitor_snmp_dca:
- name: my_monitor
- state: present
- provider:
- server: lb.mydomain.com
- user: admin
- password: secret
- delegate_to: localhost
-
-- name: Remove TCP Echo Monitor
- bigip_monitor_snmp_dca:
- name: my_monitor
- state: absent
- provider:
- server: lb.mydomain.com
- user: admin
- password: secret
- delegate_to: localhost
-'''
-
-RETURN = r'''
-parent:
- description: New parent template of the monitor.
- returned: changed
- type: str
- sample: snmp_dca
-description:
- description: The description of the monitor.
- returned: changed
- type: str
- sample: Important Monitor
-interval:
- description: The new interval in which to run the monitor check.
- returned: changed
- type: int
- sample: 2
-timeout:
- description: The new timeout in which the remote system must respond to the monitor.
- returned: changed
- type: int
- sample: 10
-time_until_up:
- description: The new time in which to mark a system as up after first successful response.
- returned: changed
- type: int
- sample: 2
-community:
- description: The new community for the monitor.
- returned: changed
- type: str
- sample: foobar
-version:
- description: The new new SNMP version to be used by the monitor.
- returned: changed
- type: str
- sample: v2c
-agent_type:
- description: The new agent type to be used by the monitor.
- returned: changed
- type: str
- sample: UCD
-cpu_coefficient:
- description: The new CPU coefficient.
- returned: changed
- type: float
- sample: 2.4
-cpu_threshold:
- description: The new CPU threshold.
- returned: changed
- type: int
- sample: 85
-memory_coefficient:
- description: The new memory coefficient.
- returned: changed
- type: float
- sample: 6.4
-memory_threshold:
- description: The new memory threshold.
- returned: changed
- type: int
- sample: 50
-disk_coefficient:
- description: The new disk coefficient.
- returned: changed
- type: float
- sample: 10.2
-disk_threshold:
- description: The new disk threshold.
- returned: changed
- type: int
- sample: 34
-'''
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.basic import env_fallback
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import fq_name
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.common import transform_name
- from library.module_utils.network.f5.compare import cmp_str_with_none
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import fq_name
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.common import transform_name
- from ansible.module_utils.network.f5.compare import cmp_str_with_none
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'timeUntilUp': 'time_until_up',
- 'defaultsFrom': 'parent',
- 'agentType': 'agent_type',
- 'cpuCoefficient': 'cpu_coefficient',
- 'cpuThreshold': 'cpu_threshold',
- 'memoryCoefficient': 'memory_coefficient',
- 'memoryThreshold': 'memory_threshold',
- 'diskCoefficient': 'disk_coefficient',
- 'diskThreshold': 'disk_threshold',
- }
-
- api_attributes = [
- 'timeUntilUp',
- 'defaultsFrom',
- 'interval',
- 'timeout',
- 'destination',
- 'community',
- 'version',
- 'agentType',
- 'cpuCoefficient',
- 'cpuThreshold',
- 'memoryCoefficient',
- 'memoryThreshold',
- 'diskCoefficient',
- 'diskThreshold',
- 'description',
- ]
-
- returnables = [
- 'parent',
- 'ip',
- 'interval',
- 'timeout',
- 'time_until_up',
- 'description',
- 'community',
- 'version',
- 'agent_type',
- 'cpu_coefficient',
- 'cpu_threshold',
- 'memory_coefficient',
- 'memory_threshold',
- 'disk_coefficient',
- 'disk_threshold',
- ]
-
- updatables = [
- 'ip',
- 'interval',
- 'timeout',
- 'time_until_up',
- 'description',
- 'community',
- 'version',
- 'agent_type',
- 'cpu_coefficient',
- 'cpu_threshold',
- 'memory_coefficient',
- 'memory_threshold',
- 'disk_coefficient',
- 'disk_threshold',
- ]
-
- @property
- def interval(self):
- if self._values['interval'] is None:
- return None
- if 1 > int(self._values['interval']) > 86400:
- raise F5ModuleError(
- "Interval value must be between 1 and 86400"
- )
- return int(self._values['interval'])
-
- @property
- def timeout(self):
- if self._values['timeout'] is None:
- return None
- return int(self._values['timeout'])
-
- @property
- def time_until_up(self):
- if self._values['time_until_up'] is None:
- return None
- return int(self._values['time_until_up'])
-
- @property
- def parent(self):
- if self._values['parent'] is None:
- return None
- result = fq_name(self.partition, self._values['parent'])
- return result
-
- @property
- def cpu_coefficient(self):
- result = self._get_numeric_property('cpu_coefficient')
- return result
-
- @property
- def cpu_threshold(self):
- result = self._get_numeric_property('cpu_threshold')
- return result
-
- @property
- def memory_coefficient(self):
- result = self._get_numeric_property('memory_coefficient')
- return result
-
- @property
- def memory_threshold(self):
- result = self._get_numeric_property('memory_threshold')
- return result
-
- @property
- def disk_coefficient(self):
- result = self._get_numeric_property('disk_coefficient')
- return result
-
- @property
- def disk_threshold(self):
- result = self._get_numeric_property('disk_threshold')
- return result
-
- def _get_numeric_property(self, property):
- if self._values[property] is None:
- return None
- try:
- fvar = float(self._values[property])
- except ValueError:
- raise F5ModuleError(
- "Provided {0} must be a valid number".format(property)
- )
- return fvar
-
- @property
- def type(self):
- return 'snmp_dca'
-
-
-class ApiParameters(Parameters):
- @property
- def description(self):
- if self._values['description'] in [None, 'none']:
- return None
- return self._values['description']
-
-
-class ModuleParameters(Parameters):
- @property
- def description(self):
- if self._values['description'] is None:
- return None
- elif self._values['description'] in ['none', '']:
- return ''
- return self._values['description']
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class UsableChanges(Changes):
- pass
-
-
-class ReportableChanges(Changes):
- pass
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- result = self.__default(param)
- return result
-
- @property
- def parent(self):
- if self.want.parent != self.have.parent:
- raise F5ModuleError(
- "The parent monitor cannot be changed"
- )
-
- @property
- def interval(self):
- if self.want.timeout is not None and self.want.interval is not None:
- if self.want.interval >= self.want.timeout:
- raise F5ModuleError(
- "Parameter 'interval' must be less than 'timeout'."
- )
- elif self.want.timeout is not None:
- if self.have.interval >= self.want.timeout:
- raise F5ModuleError(
- "Parameter 'interval' must be less than 'timeout'."
- )
- elif self.want.interval is not None:
- if self.want.interval >= self.have.timeout:
- raise F5ModuleError(
- "Parameter 'interval' must be less than 'timeout'."
- )
- if self.want.interval != self.have.interval:
- return self.want.interval
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
- @property
- def description(self):
- return cmp_str_with_none(self.want.description, self.have.description)
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(params=self.module.params)
- self.have = ApiParameters()
- self.changes = UsableChanges()
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = UsableChanges(params=changed)
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def exec_module(self):
- changed = False
- result = dict()
- state = self.want.state
-
- if state == "present":
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.client.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def present(self):
- if self.exists():
- return self.update()
- else:
- return self.create()
-
- def exists(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/monitor/snmp-dca/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def update(self):
- self.have = self.read_current_from_device()
- if not self.should_update():
- return False
- if self.module.check_mode:
- return True
- self.update_on_device()
- return True
-
- def remove(self):
- if self.module.check_mode:
- return True
- self.remove_from_device()
- if self.exists():
- raise F5ModuleError("Failed to delete the resource.")
- return True
-
- def create(self):
- self._set_changed_options()
- self._set_default_creation_values()
- if self.module.check_mode:
- return True
- self.create_on_device()
- return True
-
- def _set_default_creation_values(self):
- if self.want.timeout is None:
- self.want.update({'timeout': 30})
- if self.want.interval is None:
- self.want.update({'interval': 10})
- if self.want.time_until_up is None:
- self.want.update({'time_until_up': 0})
- if self.want.community is None:
- self.want.update({'community': 'public'})
- if self.want.version is None:
- self.want.update({'version': 'v1'})
- if self.want.agent_type is None:
- self.want.update({'agent_type': 'UCD'})
- if self.want.cpu_coefficient is None:
- self.want.update({'cpu_coefficient': '1.5'})
- if self.want.cpu_threshold is None:
- self.want.update({'cpu_threshold': '80'})
- if self.want.memory_coefficient is None:
- self.want.update({'memory_coefficient': '1.0'})
- if self.want.memory_threshold is None:
- self.want.update({'memory_threshold': '70'})
- if self.want.disk_coefficient is None:
- self.want.update({'disk_coefficient': '2.0'})
- if self.want.disk_threshold is None:
- self.want.update({'disk_threshold': '90'})
-
- def create_on_device(self):
- params = self.changes.api_params()
- params['name'] = self.want.name
- params['partition'] = self.want.partition
- uri = "https://{0}:{1}/mgmt/tm/ltm/monitor/snmp-dca/".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def update_on_device(self):
- params = self.changes.api_params()
- uri = "https://{0}:{1}/mgmt/tm/ltm/monitor/snmp-dca/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def absent(self):
- if self.exists():
- return self.remove()
- return False
-
- def remove_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/monitor/snmp-dca/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.delete(uri)
- if resp.status == 200:
- return True
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/monitor/snmp-dca/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return ApiParameters(params=response)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- name=dict(required=True),
- description=dict(),
- parent=dict(default='/Common/snmp_dca'),
- interval=dict(type='int'),
- timeout=dict(type='int'),
- time_until_up=dict(type='int'),
- community=dict(),
- version=dict(choices=['v1', 'v2c']),
- agent_type=dict(
- choices=['UCD', 'WIN2000', 'GENERIC']
- ),
- cpu_coefficient=dict(),
- cpu_threshold=dict(type='int'),
- memory_coefficient=dict(),
- memory_threshold=dict(type='int'),
- disk_coefficient=dict(),
- disk_threshold=dict(type='int'),
- state=dict(
- default='present',
- choices=['present', 'absent']
- ),
- partition=dict(
- default='Common',
- fallback=(env_fallback, ['F5_PARTITION'])
- )
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode,
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_monitor_tcp.py b/lib/ansible/modules/network/f5/bigip_monitor_tcp.py
deleted file mode 100644
index d24f882d5e..0000000000
--- a/lib/ansible/modules/network/f5/bigip_monitor_tcp.py
+++ /dev/null
@@ -1,667 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_monitor_tcp
-short_description: Manages F5 BIG-IP LTM tcp monitors
-description: Manages F5 BIG-IP LTM tcp monitors via iControl SOAP API.
-version_added: 1.4
-options:
- name:
- description:
- - Monitor name.
- type: str
- required: True
- parent:
- description:
- - The parent template of this monitor template. Once this value has
- been set, it cannot be changed. By default, this value is the C(tcp)
- parent on the C(Common) partition.
- type: str
- default: /Common/tcp
- description:
- description:
- - The description of the monitor.
- type: str
- version_added: 2.7
- send:
- description:
- - The send string for the monitor call.
- type: str
- receive:
- description:
- - The receive string for the monitor call.
- type: str
- ip:
- description:
- - IP address part of the IP/port definition. If this parameter is not
- provided when creating a new monitor, then the default value will be
- '*'.
- - If this value is an IP address, and the C(type) is C(tcp) (the default),
- then a C(port) number must be specified.
- type: str
- port:
- description:
- - Port address part of the IP/port definition. If this parameter is not
- provided when creating a new monitor, then the default value will be
- '*'. Note that if specifying an IP address, a value between 1 and 65535
- must be specified
- - This argument is not supported for TCP Echo types.
- type: str
- interval:
- description:
- - The interval specifying how frequently the monitor instance of this
- template will run. If this parameter is not provided when creating
- a new monitor, then the default value will be 5. This value B(must)
- be less than the C(timeout) value.
- type: int
- timeout:
- description:
- - The number of seconds in which the node or service must respond to
- the monitor request. If the target responds within the set time
- period, it is considered up. If the target does not respond within
- the set time period, it is considered down. You can change this
- number to any number you want, however, it should be 3 times the
- interval number of seconds plus 1 second. If this parameter is not
- provided when creating a new monitor, then the default value will be 16.
- type: int
- time_until_up:
- description:
- - Specifies the amount of time in seconds after the first successful
- response before a node will be marked up. A value of 0 will cause a
- node to be marked up immediately after a valid response is received
- from the node. If this parameter is not provided when creating
- a new monitor, then the default value will be 0.
- type: int
- partition:
- description:
- - Device partition to manage resources on.
- type: str
- default: Common
- version_added: 2.5
- state:
- description:
- - When C(present), ensures that the monitor exists.
- - When C(absent), ensures the monitor is removed.
- type: str
- choices:
- - present
- - absent
- default: present
- version_added: 2.5
-notes:
- - Requires BIG-IP software version >= 12
-extends_documentation_fragment: f5
-author:
- - Tim Rupp (@caphrim007)
- - Wojciech Wypior (@wojtek0806)
-'''
-
-EXAMPLES = r'''
-- name: Create TCP Monitor
- bigip_monitor_tcp:
- state: present
- name: my_tcp_monitor
- send: tcp string to send
- receive: tcp string to receive
- provider:
- server: lb.mydomain.com
- user: admin
- password: secret
- delegate_to: localhost
-
-- name: Remove TCP Monitor
- bigip_monitor_tcp:
- state: absent
- name: my_tcp_monitor
- provider:
- server: lb.mydomain.com
- user: admin
- password: secret
- delegate_to: localhost
-'''
-
-RETURN = r'''
-parent:
- description: New parent template of the monitor.
- returned: changed
- type: str
- sample: tcp
-send:
- description: The new send string for this monitor.
- returned: changed
- type: str
- sample: tcp string to send
-description:
- description: The description of the monitor.
- returned: changed
- type: str
- sample: Important Monitor
-receive:
- description: The new receive string for this monitor.
- returned: changed
- type: str
- sample: tcp string to receive
-ip:
- description: The new IP of IP/port definition.
- returned: changed
- type: str
- sample: 10.12.13.14
-port:
- description: The new port of IP/port definition.
- returned: changed
- type: str
- sample: admin@root.local
-interval:
- description: The new interval in which to run the monitor check.
- returned: changed
- type: int
- sample: 2
-timeout:
- description: The new timeout in which the remote system must respond to the monitor.
- returned: changed
- type: int
- sample: 10
-time_until_up:
- description: The new time in which to mark a system as up after first successful response.
- returned: changed
- type: int
- sample: 2
-'''
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.basic import env_fallback
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import fq_name
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.common import transform_name
- from library.module_utils.network.f5.ipaddress import is_valid_ip
- from library.module_utils.network.f5.compare import cmp_str_with_none
-
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import fq_name
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.common import transform_name
- from ansible.module_utils.network.f5.ipaddress import is_valid_ip
- from ansible.module_utils.network.f5.compare import cmp_str_with_none
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'timeUntilUp': 'time_until_up',
- 'defaultsFrom': 'parent',
- 'recv': 'receive',
- }
-
- api_attributes = [
- 'timeUntilUp',
- 'defaultsFrom',
- 'interval',
- 'timeout',
- 'recv',
- 'send',
- 'destination',
- 'description',
- ]
-
- returnables = [
- 'parent',
- 'send',
- 'receive',
- 'ip',
- 'port',
- 'interval',
- 'timeout',
- 'time_until_up',
- 'description',
- ]
-
- updatables = [
- 'destination',
- 'send',
- 'receive',
- 'interval',
- 'timeout',
- 'time_until_up',
- 'description',
- ]
-
- @property
- def interval(self):
- if self._values['interval'] is None:
- return None
- if 1 > int(self._values['interval']) > 86400:
- raise F5ModuleError(
- "Interval value must be between 1 and 86400"
- )
- return int(self._values['interval'])
-
- @property
- def timeout(self):
- if self._values['timeout'] is None:
- return None
- return int(self._values['timeout'])
-
- @property
- def ip(self):
- if self._values['ip'] is None:
- return None
- if self._values['ip'] in ['*', '0.0.0.0']:
- return '*'
- if is_valid_ip(self._values['ip']):
- return self._values['ip']
- else:
- raise F5ModuleError(
- "The provided 'ip' parameter is not an IP address."
- )
-
- @property
- def time_until_up(self):
- if self._values['time_until_up'] is None:
- return None
- return int(self._values['time_until_up'])
-
- @property
- def parent(self):
- if self._values['parent'] is None:
- return None
- result = fq_name(self.partition, self._values['parent'])
- return result
-
- @property
- def port(self):
- if self._values['port'] is None:
- return None
- elif self._values['port'] == '*':
- return '*'
- return int(self._values['port'])
-
- @property
- def destination(self):
- if self.ip is None and self.port is None:
- return None
- destination = '{0}:{1}'.format(self.ip, self.port)
- return destination
-
- @destination.setter
- def destination(self, value):
- ip, port = value.split(':')
- self._values['ip'] = ip
- self._values['port'] = port
-
- @property
- def type(self):
- return 'tcp'
-
-
-class ApiParameters(Parameters):
- @property
- def description(self):
- if self._values['description'] in [None, 'none']:
- return None
- return self._values['description']
-
-
-class ModuleParameters(Parameters):
- @property
- def description(self):
- if self._values['description'] is None:
- return None
- elif self._values['description'] in ['none', '']:
- return ''
- return self._values['description']
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class UsableChanges(Changes):
- pass
-
-
-class ReportableChanges(Changes):
- pass
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- result = self.__default(param)
- return result
-
- @property
- def parent(self):
- if self.want.parent != self.have.parent:
- raise F5ModuleError(
- "The parent monitor cannot be changed"
- )
-
- @property
- def destination(self):
- if self.want.ip is None and self.want.port is None:
- return None
- if self.want.port is None:
- self.want.update({'port': self.have.port})
- if self.want.ip is None:
- self.want.update({'ip': self.have.ip})
-
- if self.want.port in [None, '*'] and self.want.ip != '*':
- raise F5ModuleError(
- "Specifying an IP address requires that a port number be specified"
- )
-
- if self.want.destination != self.have.destination:
- return self.want.destination
-
- @property
- def interval(self):
- if self.want.timeout is not None and self.want.interval is not None:
- if self.want.interval >= self.want.timeout:
- raise F5ModuleError(
- "Parameter 'interval' must be less than 'timeout'."
- )
- elif self.want.timeout is not None:
- if self.have.interval >= self.want.timeout:
- raise F5ModuleError(
- "Parameter 'interval' must be less than 'timeout'."
- )
- elif self.want.interval is not None:
- if self.want.interval >= self.have.timeout:
- raise F5ModuleError(
- "Parameter 'interval' must be less than 'timeout'."
- )
- if self.want.interval != self.have.interval:
- return self.want.interval
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
- @property
- def description(self):
- return cmp_str_with_none(self.want.description, self.have.description)
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(params=self.module.params)
- self.have = ApiParameters()
- self.changes = UsableChanges()
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = UsableChanges(params=changed)
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def exec_module(self):
- changed = False
- result = dict()
- state = self.want.state
-
- if state == "present":
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.client.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def present(self):
- if self.exists():
- return self.update()
- else:
- return self.create()
-
- def exists(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/monitor/tcp/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def update(self):
- self.have = self.read_current_from_device()
- if not self.should_update():
- return False
- if self.module.check_mode:
- return True
- self.update_on_device()
- return True
-
- def remove(self):
- if self.module.check_mode:
- return True
- self.remove_from_device()
- if self.exists():
- raise F5ModuleError("Failed to delete the resource.")
- return True
-
- def create(self):
- self._set_changed_options()
- self._set_default_creation_values()
- if self.module.check_mode:
- return True
- self.create_on_device()
- return True
-
- def _set_default_creation_values(self):
- if self.want.timeout is None:
- self.want.update({'timeout': 16})
- if self.want.interval is None:
- self.want.update({'interval': 5})
- if self.want.time_until_up is None:
- self.want.update({'time_until_up': 0})
- if self.want.ip is None:
- self.want.update({'ip': '*'})
- if self.want.port is None:
- self.want.update({'port': '*'})
-
- def create_on_device(self):
- params = self.changes.api_params()
- params['name'] = self.want.name
- params['partition'] = self.want.partition
- uri = "https://{0}:{1}/mgmt/tm/ltm/monitor/tcp/".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def update_on_device(self):
- params = self.changes.api_params()
- uri = "https://{0}:{1}/mgmt/tm/ltm/monitor/tcp/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def absent(self):
- if self.exists():
- return self.remove()
- return False
-
- def remove_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/monitor/tcp/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.delete(uri)
- if resp.status == 200:
- return True
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/monitor/tcp/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return ApiParameters(params=response)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- name=dict(required=True),
- parent=dict(default='/Common/tcp'),
- description=dict(),
- send=dict(),
- receive=dict(),
- ip=dict(),
- port=dict(),
- interval=dict(type='int'),
- timeout=dict(type='int'),
- time_until_up=dict(type='int'),
- state=dict(
- default='present',
- choices=['present', 'absent']
- ),
- partition=dict(
- default='Common',
- fallback=(env_fallback, ['F5_PARTITION'])
- )
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode,
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_monitor_tcp_echo.py b/lib/ansible/modules/network/f5/bigip_monitor_tcp_echo.py
deleted file mode 100644
index a17fe8ad57..0000000000
--- a/lib/ansible/modules/network/f5/bigip_monitor_tcp_echo.py
+++ /dev/null
@@ -1,600 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_monitor_tcp_echo
-short_description: Manages F5 BIG-IP LTM tcp echo monitors
-description: Manages F5 BIG-IP LTM tcp echo monitors.
-version_added: 2.4
-options:
- name:
- description:
- - Monitor name.
- type: str
- required: True
- parent:
- description:
- - The parent template of this monitor template. Once this value has
- been set, it cannot be changed. By default, this value is the C(tcp_echo)
- parent on the C(Common) partition.
- type: str
- default: /Common/tcp_echo
- description:
- description:
- - The description of the monitor.
- type: str
- version_added: 2.7
- ip:
- description:
- - IP address part of the IP/port definition. If this parameter is not
- provided when creating a new monitor, then the default value will be
- '*'.
- type: str
- interval:
- description:
- - The interval specifying how frequently the monitor instance of this
- template will run. If this parameter is not provided when creating
- a new monitor, then the default value will be 5. This value B(must)
- be less than the C(timeout) value.
- type: int
- timeout:
- description:
- - The number of seconds in which the node or service must respond to
- the monitor request. If the target responds within the set time
- period, it is considered up. If the target does not respond within
- the set time period, it is considered down. You can change this
- number to any number you want, however, it should be 3 times the
- interval number of seconds plus 1 second. If this parameter is not
- provided when creating a new monitor, then the default value will be 16.
- type: int
- time_until_up:
- description:
- - Specifies the amount of time in seconds after the first successful
- response before a node will be marked up. A value of 0 will cause a
- node to be marked up immediately after a valid response is received
- from the node. If this parameter is not provided when creating
- a new monitor, then the default value will be 0.
- type: int
- partition:
- description:
- - Device partition to manage resources on.
- type: str
- default: Common
- version_added: 2.5
- state:
- description:
- - When C(present), ensures that the monitor exists.
- - When C(absent), ensures the monitor is removed.
- type: str
- choices:
- - present
- - absent
- default: present
- version_added: 2.5
-notes:
- - Requires BIG-IP software version >= 12
-extends_documentation_fragment: f5
-author:
- - Tim Rupp (@caphrim007)
- - Wojciech Wypior (@wojtek0806)
-'''
-
-EXAMPLES = r'''
-- name: Create TCP Echo Monitor
- bigip_monitor_tcp_echo:
- state: present
- ip: 10.10.10.10
- name: my_tcp_monitor
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-
-- name: Remove TCP Echo Monitor
- bigip_monitor_tcp_echo:
- state: absent
- name: my_tcp_monitor
- provider:
- server: lb.mydomain.com
- user: admin
- password: secret
- delegate_to: localhost
-'''
-
-RETURN = r'''
-parent:
- description: New parent template of the monitor.
- returned: changed
- type: str
- sample: tcp
-ip:
- description: The new IP of IP/port definition.
- returned: changed
- type: str
- sample: 10.12.13.14
-description:
- description: The description of the monitor.
- returned: changed
- type: str
- sample: Important Monitor
-interval:
- description: The new interval in which to run the monitor check.
- returned: changed
- type: int
- sample: 2
-timeout:
- description: The new timeout in which the remote system must respond to the monitor.
- returned: changed
- type: int
- sample: 10
-time_until_up:
- description: The new time in which to mark a system as up after first successful response.
- returned: changed
- type: int
- sample: 2
-'''
-
-import os
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.basic import env_fallback
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.common import transform_name
- from library.module_utils.network.f5.ipaddress import is_valid_ip
- from library.module_utils.network.f5.compare import cmp_str_with_none
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.common import transform_name
- from ansible.module_utils.network.f5.ipaddress import is_valid_ip
- from ansible.module_utils.network.f5.compare import cmp_str_with_none
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'timeUntilUp': 'time_until_up',
- 'defaultsFrom': 'parent',
- }
-
- api_attributes = [
- 'timeUntilUp',
- 'defaultsFrom',
- 'interval',
- 'timeout',
- 'destination',
- 'description',
- ]
-
- returnables = [
- 'parent',
- 'ip',
- 'interval',
- 'timeout',
- 'time_until_up',
- 'description',
- ]
-
- updatables = [
- 'ip',
- 'interval',
- 'timeout',
- 'time_until_up',
- 'description',
- ]
-
- @property
- def interval(self):
- if self._values['interval'] is None:
- return None
- if 1 > int(self._values['interval']) > 86400:
- raise F5ModuleError(
- "Interval value must be between 1 and 86400"
- )
- return int(self._values['interval'])
-
- @property
- def timeout(self):
- if self._values['timeout'] is None:
- return None
- return int(self._values['timeout'])
-
- @property
- def ip(self):
- if self._values['ip'] is None:
- return None
- if self._values['ip'] in ['*', '0.0.0.0']:
- return '*'
- elif is_valid_ip(self._values['ip']):
- return self._values['ip']
- else:
- raise F5ModuleError(
- "The provided 'ip' parameter is not an IP address."
- )
-
- @property
- def destination(self):
- return self.ip
-
- @destination.setter
- def destination(self, value):
- self._values['ip'] = value
-
- @property
- def time_until_up(self):
- if self._values['time_until_up'] is None:
- return None
- return int(self._values['time_until_up'])
-
- @property
- def parent(self):
- if self._values['parent'] is None:
- return None
- if self._values['parent'].startswith('/'):
- parent = os.path.basename(self._values['parent'])
- result = '/{0}/{1}'.format(self.partition, parent)
- else:
- result = '/{0}/{1}'.format(self.partition, self._values['parent'])
- return result
-
- @property
- def type(self):
- return 'tcp_echo'
-
-
-class ApiParameters(Parameters):
- @property
- def description(self):
- if self._values['description'] in [None, 'none']:
- return None
- return self._values['description']
-
-
-class ModuleParameters(Parameters):
- @property
- def description(self):
- if self._values['description'] is None:
- return None
- elif self._values['description'] in ['none', '']:
- return ''
- return self._values['description']
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class UsableChanges(Changes):
- pass
-
-
-class ReportableChanges(Changes):
- pass
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- result = self.__default(param)
- return result
-
- @property
- def parent(self):
- if self.want.parent != self.have.parent:
- raise F5ModuleError(
- "The parent monitor cannot be changed"
- )
-
- @property
- def destination(self):
- if self.want.ip is None:
- return None
- if self.want.destination != self.have.destination:
- return self.want.destination
-
- @property
- def interval(self):
- if self.want.timeout is not None and self.want.interval is not None:
- if self.want.interval >= self.want.timeout:
- raise F5ModuleError(
- "Parameter 'interval' must be less than 'timeout'."
- )
- elif self.want.timeout is not None:
- if self.have.interval >= self.want.timeout:
- raise F5ModuleError(
- "Parameter 'interval' must be less than 'timeout'."
- )
- elif self.want.interval is not None:
- if self.want.interval >= self.have.timeout:
- raise F5ModuleError(
- "Parameter 'interval' must be less than 'timeout'."
- )
- if self.want.interval != self.have.interval:
- return self.want.interval
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
- @property
- def description(self):
- return cmp_str_with_none(self.want.description, self.have.description)
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(params=self.module.params)
- self.have = ApiParameters()
- self.changes = UsableChanges()
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = UsableChanges(params=changed)
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def exec_module(self):
- changed = False
- result = dict()
- state = self.want.state
-
- if state == "present":
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.client.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def present(self):
- if self.exists():
- return self.update()
- else:
- return self.create()
-
- def exists(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/monitor/tcp-echo/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def update(self):
- self.have = self.read_current_from_device()
- if not self.should_update():
- return False
- if self.module.check_mode:
- return True
- self.update_on_device()
- return True
-
- def remove(self):
- if self.module.check_mode:
- return True
- self.remove_from_device()
- if self.exists():
- raise F5ModuleError("Failed to delete the resource.")
- return True
-
- def create(self):
- self._set_changed_options()
- self._set_default_creation_values()
- if self.module.check_mode:
- return True
- self.create_on_device()
- return True
-
- def _set_default_creation_values(self):
- if self.want.timeout is None:
- self.want.update({'timeout': 16})
- if self.want.interval is None:
- self.want.update({'interval': 5})
- if self.want.time_until_up is None:
- self.want.update({'time_until_up': 0})
- if self.want.ip is None:
- self.want.update({'ip': '*'})
-
- def create_on_device(self):
- params = self.changes.api_params()
- params['name'] = self.want.name
- params['partition'] = self.want.partition
- uri = "https://{0}:{1}/mgmt/tm/ltm/monitor/tcp-echo/".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def update_on_device(self):
- params = self.changes.api_params()
- uri = "https://{0}:{1}/mgmt/tm/ltm/monitor/tcp-echo/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def absent(self):
- if self.exists():
- return self.remove()
- return False
-
- def remove_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/monitor/tcp-echo/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.delete(uri)
- if resp.status == 200:
- return True
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/monitor/tcp-echo/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return ApiParameters(params=response)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- name=dict(required=True),
- parent=dict(default='/Common/tcp_echo'),
- description=dict(),
- ip=dict(),
- interval=dict(type='int'),
- timeout=dict(type='int'),
- time_until_up=dict(type='int'),
- state=dict(
- default='present',
- choices=['present', 'absent']
- ),
- partition=dict(
- default='Common',
- fallback=(env_fallback, ['F5_PARTITION'])
- )
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode,
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_monitor_tcp_half_open.py b/lib/ansible/modules/network/f5/bigip_monitor_tcp_half_open.py
deleted file mode 100644
index 74d5e208e6..0000000000
--- a/lib/ansible/modules/network/f5/bigip_monitor_tcp_half_open.py
+++ /dev/null
@@ -1,651 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_monitor_tcp_half_open
-short_description: Manages F5 BIG-IP LTM tcp half-open monitors
-description: Manages F5 BIG-IP LTM tcp half-open monitors.
-version_added: 2.4
-options:
- name:
- description:
- - Monitor name.
- type: str
- required: True
- parent:
- description:
- - The parent template of this monitor template. Once this value has
- been set, it cannot be changed. By default, this value is the C(tcp_half_open)
- parent on the C(Common) partition.
- type: str
- default: /Common/tcp_half_open
- description:
- description:
- - The description of the monitor.
- type: str
- version_added: 2.7
- ip:
- description:
- - IP address part of the IP/port definition. If this parameter is not
- provided when creating a new monitor, then the default value will be
- '*'.
- - If this value is an IP address, and the C(type) is C(tcp) (the default),
- then a C(port) number must be specified.
- type: str
- port:
- description:
- - Port address part of the IP/port definition. If this parameter is not
- provided when creating a new monitor, then the default value will be
- '*'. Note that if specifying an IP address, a value between 1 and 65535
- must be specified
- type: str
- version_added: 2.5
- interval:
- description:
- - The interval specifying how frequently the monitor instance of this
- template will run. If this parameter is not provided when creating
- a new monitor, then the default value will be 5. This value B(must)
- be less than the C(timeout) value.
- type: int
- timeout:
- description:
- - The number of seconds in which the node or service must respond to
- the monitor request. If the target responds within the set time
- period, it is considered up. If the target does not respond within
- the set time period, it is considered down. You can change this
- number to any number you want, however, it should be 3 times the
- interval number of seconds plus 1 second. If this parameter is not
- provided when creating a new monitor, then the default value will be 16.
- type: int
- time_until_up:
- description:
- - Specifies the amount of time in seconds after the first successful
- response before a node will be marked up. A value of 0 will cause a
- node to be marked up immediately after a valid response is received
- from the node. If this parameter is not provided when creating
- a new monitor, then the default value will be 0.
- type: int
- partition:
- description:
- - Device partition to manage resources on.
- type: str
- default: Common
- version_added: 2.5
- state:
- description:
- - When C(present), ensures that the monitor exists.
- - When C(absent), ensures the monitor is removed.
- type: str
- choices:
- - present
- - absent
- default: present
- version_added: 2.5
-notes:
- - Requires BIG-IP software version >= 12
-extends_documentation_fragment: f5
-author:
- - Tim Rupp (@caphrim007)
- - Wojciech Wypior (@wojtek0806)
-'''
-
-EXAMPLES = r'''
-- name: Create TCP half-open Monitor
- bigip_monitor_tcp_half_open:
- state: present
- ip: 10.10.10.10
- name: my_tcp_monitor
- provider:
- server: lb.mydomain.com
- user: admin
- password: secret
- delegate_to: localhost
-
-- name: Remove TCP half-open Monitor
- bigip_monitor_tcp_half_open:
- state: absent
- name: my_tcp_monitor
- provider:
- server: lb.mydomain.com
- user: admin
- password: secret
- delegate_to: localhost
-
-- name: Add half-open monitor for all addresses, port 514
- bigip_monitor_tcp_half_open:
- port: 514
- name: my_tcp_monitor
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-'''
-
-RETURN = r'''
-parent:
- description: New parent template of the monitor.
- returned: changed
- type: str
- sample: tcp
-description:
- description: The description of the monitor.
- returned: changed
- type: str
- sample: Important Monitor
-ip:
- description: The new IP of IP/port definition.
- returned: changed
- type: str
- sample: 10.12.13.14
-interval:
- description: The new interval in which to run the monitor check.
- returned: changed
- type: int
- sample: 2
-timeout:
- description: The new timeout in which the remote system must respond to the monitor.
- returned: changed
- type: int
- sample: 10
-time_until_up:
- description: The new time in which to mark a system as up after first successful response.
- returned: changed
- type: int
- sample: 2
-'''
-
-import os
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.basic import env_fallback
-
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.common import transform_name
- from library.module_utils.network.f5.ipaddress import is_valid_ip
- from library.module_utils.network.f5.compare import cmp_str_with_none
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.common import transform_name
- from ansible.module_utils.network.f5.ipaddress import is_valid_ip
- from ansible.module_utils.network.f5.compare import cmp_str_with_none
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'timeUntilUp': 'time_until_up',
- 'defaultsFrom': 'parent',
- 'recv': 'receive',
- }
-
- api_attributes = [
- 'timeUntilUp',
- 'defaultsFrom',
- 'interval',
- 'timeout',
- 'destination',
- 'description',
- ]
-
- returnables = [
- 'parent',
- 'ip',
- 'port',
- 'interval',
- 'timeout',
- 'time_until_up',
- 'description',
- ]
-
- updatables = [
- 'destination',
- 'interval',
- 'timeout',
- 'time_until_up',
- 'description',
- ]
-
- @property
- def destination(self):
- if self.ip is None and self.port is None:
- return None
- destination = '{0}:{1}'.format(self.ip, self.port)
- return destination
-
- @destination.setter
- def destination(self, value):
- ip, port = value.split(':')
- self._values['ip'] = ip
- self._values['port'] = port
-
- @property
- def interval(self):
- if self._values['interval'] is None:
- return None
-
- # Per BZ617284, the BIG-IP UI does not raise a warning about this.
- # So I raise the error instead.
- if 1 > int(self._values['interval']) > 86400:
- raise F5ModuleError(
- "Interval value must be between 1 and 86400"
- )
- return int(self._values['interval'])
-
- @property
- def timeout(self):
- if self._values['timeout'] is None:
- return None
- return int(self._values['timeout'])
-
- @property
- def ip(self):
- if self._values['ip'] is None:
- return None
- elif self._values['ip'] in ['*', '0.0.0.0']:
- return '*'
- elif is_valid_ip(self._values['ip']):
- return self._values['ip']
- raise F5ModuleError(
- "The provided 'ip' parameter is not an IP address."
- )
-
- @property
- def port(self):
- if self._values['port'] is None:
- return None
- elif self._values['port'] == '*':
- return '*'
- return int(self._values['port'])
-
- @property
- def time_until_up(self):
- if self._values['time_until_up'] is None:
- return None
- return int(self._values['time_until_up'])
-
- @property
- def parent(self):
- if self._values['parent'] is None:
- return None
- if self._values['parent'].startswith('/'):
- parent = os.path.basename(self._values['parent'])
- result = '/{0}/{1}'.format(self.partition, parent)
- else:
- result = '/{0}/{1}'.format(self.partition, self._values['parent'])
- return result
-
- @property
- def type(self):
- return 'tcp_half_open'
-
-
-class ApiParameters(Parameters):
- @property
- def description(self):
- if self._values['description'] in [None, 'none']:
- return None
- return self._values['description']
-
-
-class ModuleParameters(Parameters):
- @property
- def description(self):
- if self._values['description'] is None:
- return None
- elif self._values['description'] in ['none', '']:
- return ''
- return self._values['description']
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class UsableChanges(Changes):
- pass
-
-
-class ReportableChanges(Changes):
- pass
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- result = self.__default(param)
- return result
-
- @property
- def parent(self):
- if self.want.parent != self.have.parent:
- raise F5ModuleError(
- "The parent monitor cannot be changed"
- )
-
- @property
- def destination(self):
- if self.want.ip is None and self.want.port is None:
- return None
- if self.want.port is None:
- self.want.update({'port': self.have.port})
- if self.want.ip is None:
- self.want.update({'ip': self.have.ip})
-
- if self.want.port in [None, '*'] and self.want.ip != '*':
- raise F5ModuleError(
- "Specifying an IP address requires that a port number be specified"
- )
-
- if self.want.destination != self.have.destination:
- return self.want.destination
-
- @property
- def interval(self):
- if self.want.timeout is not None and self.want.interval is not None:
- if self.want.interval >= self.want.timeout:
- raise F5ModuleError(
- "Parameter 'interval' must be less than 'timeout'."
- )
- elif self.want.timeout is not None:
- if self.have.interval >= self.want.timeout:
- raise F5ModuleError(
- "Parameter 'interval' must be less than 'timeout'."
- )
- elif self.want.interval is not None:
- if self.want.interval >= self.have.timeout:
- raise F5ModuleError(
- "Parameter 'interval' must be less than 'timeout'."
- )
- if self.want.interval != self.have.interval:
- return self.want.interval
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
- @property
- def description(self):
- return cmp_str_with_none(self.want.description, self.have.description)
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(params=self.module.params)
- self.have = ApiParameters()
- self.changes = UsableChanges()
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = UsableChanges(params=changed)
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def exec_module(self):
- changed = False
- result = dict()
- state = self.want.state
-
- if state == "present":
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.client.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def present(self):
- if self.exists():
- return self.update()
- else:
- return self.create()
-
- def exists(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/monitor/tcp-half-open/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def update(self):
- self.have = self.read_current_from_device()
- if not self.should_update():
- return False
- if self.module.check_mode:
- return True
- self.update_on_device()
- return True
-
- def remove(self):
- if self.module.check_mode:
- return True
- self.remove_from_device()
- if self.exists():
- raise F5ModuleError("Failed to delete the resource.")
- return True
-
- def create(self):
- self._set_changed_options()
- self._set_default_creation_values()
- if self.module.check_mode:
- return True
- self.create_on_device()
- return True
-
- def _set_default_creation_values(self):
- if self.want.timeout is None:
- self.want.update({'timeout': 16})
- if self.want.interval is None:
- self.want.update({'interval': 5})
- if self.want.time_until_up is None:
- self.want.update({'time_until_up': 0})
- if self.want.ip is None:
- self.want.update({'ip': '*'})
- if self.want.port is None:
- self.want.update({'port': '*'})
-
- def create_on_device(self):
- params = self.changes.api_params()
- params['name'] = self.want.name
- params['partition'] = self.want.partition
- uri = "https://{0}:{1}/mgmt/tm/ltm/monitor/tcp-half-open/".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def update_on_device(self):
- params = self.changes.api_params()
- uri = "https://{0}:{1}/mgmt/tm/ltm/monitor/tcp-half-open/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def absent(self):
- if self.exists():
- return self.remove()
- return False
-
- def remove_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/monitor/tcp-half-open/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.delete(uri)
- if resp.status == 200:
- return True
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/monitor/tcp-half-open/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return ApiParameters(params=response)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- name=dict(required=True),
- parent=dict(default='/Common/tcp_half_open'),
- description=dict(),
- ip=dict(),
- port=dict(),
- interval=dict(type='int'),
- timeout=dict(type='int'),
- time_until_up=dict(type='int'),
- state=dict(
- default='present',
- choices=['present', 'absent']
- ),
- partition=dict(
- default='Common',
- fallback=(env_fallback, ['F5_PARTITION'])
- )
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode,
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_monitor_udp.py b/lib/ansible/modules/network/f5/bigip_monitor_udp.py
deleted file mode 100644
index defcc18e9a..0000000000
--- a/lib/ansible/modules/network/f5/bigip_monitor_udp.py
+++ /dev/null
@@ -1,663 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_monitor_udp
-short_description: Manages F5 BIG-IP LTM udp monitors
-description: Manages F5 BIG-IP LTM udp monitors.
-version_added: 2.5
-options:
- name:
- description:
- - Monitor name.
- type: str
- required: True
- parent:
- description:
- - The parent template of this monitor template. Once this value has
- been set, it cannot be changed. By default, this value is the C(udp)
- parent on the C(Common) partition.
- type: str
- default: /Common/udp
- description:
- description:
- - The description of the monitor.
- type: str
- version_added: 2.7
- send:
- description:
- - The send string for the monitor call. When creating a new monitor, if
- this value is not provided, the default C(default send string) will be used.
- type: str
- receive:
- description:
- - The receive string for the monitor call.
- type: str
- receive_disable:
- description:
- - This setting works like C(receive), except that the system marks the node
- or pool member disabled when its response matches the C(receive_disable)
- string but not C(receive). To use this setting, you must specify both
- C(receive_disable) and C(receive).
- type: str
- ip:
- description:
- - IP address part of the IP/port definition. If this parameter is not
- provided when creating a new monitor, then the default value will be
- '*'.
- type: str
- port:
- description:
- - Port address part of the IP/port definition. If this parameter is not
- provided when creating a new monitor, then the default value will be
- '*'. Note that if specifying an IP address, a value between 1 and 65535
- must be specified.
- type: str
- interval:
- description:
- - The interval specifying how frequently the monitor instance of this
- template will run. If this parameter is not provided when creating
- a new monitor, then the default value will be 5. This value B(must)
- be less than the C(timeout) value.
- type: int
- timeout:
- description:
- - The number of seconds in which the node or service must respond to
- the monitor request. If the target responds within the set time
- period, it is considered up. If the target does not respond within
- the set time period, it is considered down. You can change this
- number to any number you want, however, it should be 3 times the
- interval number of seconds plus 1 second. If this parameter is not
- provided when creating a new monitor, then the default value will be 16.
- type: int
- time_until_up:
- description:
- - Specifies the amount of time in seconds after the first successful
- response before a node will be marked up. A value of 0 will cause a
- node to be marked up immediately after a valid response is received
- from the node. If this parameter is not provided when creating
- a new monitor, then the default value will be 0.
- type: int
- partition:
- description:
- - Device partition to manage resources on.
- type: str
- default: Common
- version_added: 2.5
- state:
- description:
- - When C(present), ensures that the monitor exists.
- - When C(absent), ensures the monitor is removed.
- type: str
- choices:
- - present
- - absent
- default: present
- version_added: 2.5
-notes:
- - Requires BIG-IP software version >= 12
-extends_documentation_fragment: f5
-author:
- - Tim Rupp (@caphrim007)
- - Wojciech Wypior (@wojtek0806)
-'''
-
-EXAMPLES = r'''
-- name: Create UDP Monitor
- bigip_monitor_udp:
- state: present
- ip: 10.10.10.10
- name: my_udp_monitor
- provider:
- server: lb.mydomain.com
- user: admin
- password: secret
- delegate_to: localhost
-
-- name: Remove UDP Monitor
- bigip_monitor_udp:
- state: absent
- name: my_udp_monitor
- provider:
- server: lb.mydomain.com
- user: admin
- password: secret
- delegate_to: localhost
-'''
-
-RETURN = r'''
-parent:
- description: New parent template of the monitor.
- returned: changed
- type: str
- sample: http
-description:
- description: The description of the monitor.
- returned: changed
- type: str
- sample: Important Monitor
-ip:
- description: The new IP of IP/port definition.
- returned: changed
- type: str
- sample: 10.12.13.14
-interval:
- description: The new interval in which to run the monitor check.
- returned: changed
- type: int
- sample: 2
-timeout:
- description: The new timeout in which the remote system must respond to the monitor.
- returned: changed
- type: int
- sample: 10
-time_until_up:
- description: The new time in which to mark a system as up after first successful response.
- returned: changed
- type: int
- sample: 2
-'''
-
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.basic import env_fallback
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import fq_name
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.common import transform_name
- from library.module_utils.network.f5.compare import cmp_str_with_none
- from library.module_utils.network.f5.ipaddress import is_valid_ip
-
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import fq_name
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.common import transform_name
- from ansible.module_utils.network.f5.compare import cmp_str_with_none
- from ansible.module_utils.network.f5.ipaddress import is_valid_ip
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'timeUntilUp': 'time_until_up',
- 'defaultsFrom': 'parent',
- 'recv': 'receive',
- }
-
- api_attributes = [
- 'timeUntilUp',
- 'defaultsFrom',
- 'interval',
- 'timeout',
- 'recv',
- 'send',
- 'destination',
- 'description',
- ]
-
- returnables = [
- 'parent',
- 'send',
- 'receive',
- 'ip',
- 'port',
- 'interval',
- 'timeout',
- 'time_until_up',
- 'description',
- ]
-
- updatables = [
- 'destination',
- 'send',
- 'receive',
- 'interval',
- 'timeout',
- 'time_until_up',
- 'description',
- ]
-
- @property
- def destination(self):
- if self.ip is None and self.port is None:
- return None
- destination = '{0}:{1}'.format(self.ip, self.port)
- return destination
-
- @destination.setter
- def destination(self, value):
- ip, port = value.split(':')
- self._values['ip'] = ip
- self._values['port'] = port
-
- @property
- def interval(self):
- if self._values['interval'] is None:
- return None
-
- # Per BZ617284, the BIG-IP UI does not raise a warning about this.
- # So I do
- if 1 > int(self._values['interval']) > 86400:
- raise F5ModuleError(
- "Interval value must be between 1 and 86400"
- )
- return int(self._values['interval'])
-
- @property
- def timeout(self):
- if self._values['timeout'] is None:
- return None
- return int(self._values['timeout'])
-
- @property
- def ip(self):
- if self._values['ip'] is None:
- return None
- if self._values['ip'] in ['*', '0.0.0.0']:
- return '*'
- elif is_valid_ip(self._values['ip']):
- return self._values['ip']
- else:
- raise F5ModuleError(
- "The provided 'ip' parameter is not an IP address."
- )
-
- @property
- def port(self):
- if self._values['port'] is None:
- return None
- elif self._values['port'] == '*':
- return '*'
- return int(self._values['port'])
-
- @property
- def time_until_up(self):
- if self._values['time_until_up'] is None:
- return None
- return int(self._values['time_until_up'])
-
- @property
- def parent(self):
- if self._values['parent'] is None:
- return None
- result = fq_name(self.partition, self._values['parent'])
- return result
-
- @property
- def type(self):
- return 'udp'
-
-
-class ApiParameters(Parameters):
- @property
- def description(self):
- if self._values['description'] in [None, 'none']:
- return None
- return self._values['description']
-
-
-class ModuleParameters(Parameters):
- @property
- def description(self):
- if self._values['description'] is None:
- return None
- elif self._values['description'] in ['none', '']:
- return ''
- return self._values['description']
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class UsableChanges(Changes):
- pass
-
-
-class ReportableChanges(Changes):
- pass
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- result = self.__default(param)
- return result
-
- @property
- def parent(self):
- if self.want.parent != self.have.parent:
- raise F5ModuleError(
- "The parent monitor cannot be changed"
- )
-
- @property
- def destination(self):
- if self.want.ip is None and self.want.port is None:
- return None
- if self.want.port is None:
- self.want.update({'port': self.have.port})
- if self.want.ip is None:
- self.want.update({'ip': self.have.ip})
-
- if self.want.port in [None, '*'] and self.want.ip != '*':
- raise F5ModuleError(
- "Specifying an IP address requires that a port number be specified"
- )
-
- if self.want.destination != self.have.destination:
- return self.want.destination
-
- @property
- def interval(self):
- if self.want.timeout is not None and self.want.interval is not None:
- if self.want.interval >= self.want.timeout:
- raise F5ModuleError(
- "Parameter 'interval' must be less than 'timeout'."
- )
- elif self.want.timeout is not None:
- if self.have.interval >= self.want.timeout:
- raise F5ModuleError(
- "Parameter 'interval' must be less than 'timeout'."
- )
- elif self.want.interval is not None:
- if self.want.interval >= self.have.timeout:
- raise F5ModuleError(
- "Parameter 'interval' must be less than 'timeout'."
- )
- if self.want.interval != self.have.interval:
- return self.want.interval
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
- @property
- def description(self):
- return cmp_str_with_none(self.want.description, self.have.description)
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(params=self.module.params)
- self.have = ApiParameters()
- self.changes = UsableChanges()
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = UsableChanges(params=changed)
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def exec_module(self):
- changed = False
- result = dict()
- state = self.want.state
-
- if state == "present":
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.client.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def present(self):
- if self.exists():
- return self.update()
- else:
- return self.create()
-
- def exists(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/monitor/udp/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def update(self):
- self.have = self.read_current_from_device()
- if not self.should_update():
- return False
- if self.module.check_mode:
- return True
- self.update_on_device()
- return True
-
- def remove(self):
- if self.module.check_mode:
- return True
- self.remove_from_device()
- if self.exists():
- raise F5ModuleError("Failed to delete the resource.")
- return True
-
- def create(self):
- self._set_changed_options()
- self._set_default_creation_values()
- if self.module.check_mode:
- return True
- self.create_on_device()
- return True
-
- def _set_default_creation_values(self):
- if self.want.timeout is None:
- self.want.update({'timeout': 16})
- if self.want.interval is None:
- self.want.update({'interval': 5})
- if self.want.time_until_up is None:
- self.want.update({'time_until_up': 0})
- if self.want.ip is None:
- self.want.update({'ip': '*'})
- if self.want.port is None:
- self.want.update({'port': '*'})
- if self.want.send is None:
- self.want.update({'send': 'default send string'})
-
- def create_on_device(self):
- params = self.changes.api_params()
- params['name'] = self.want.name
- params['partition'] = self.want.partition
- uri = "https://{0}:{1}/mgmt/tm/ltm/monitor/udp/".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def update_on_device(self):
- params = self.changes.api_params()
- uri = "https://{0}:{1}/mgmt/tm/ltm/monitor/udp/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def absent(self):
- if self.exists():
- return self.remove()
- return False
-
- def remove_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/monitor/udp/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.delete(uri)
- if resp.status == 200:
- return True
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/monitor/udp/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return ApiParameters(params=response)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- name=dict(required=True),
- parent=dict(default='/Common/udp'),
- description=dict(),
- send=dict(),
- receive=dict(),
- receive_disable=dict(required=False),
- ip=dict(),
- port=dict(),
- interval=dict(type='int'),
- timeout=dict(type='int'),
- time_until_up=dict(type='int'),
- state=dict(
- default='present',
- choices=['present', 'absent']
- ),
- partition=dict(
- default='Common',
- fallback=(env_fallback, ['F5_PARTITION'])
- )
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode,
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_node.py b/lib/ansible/modules/network/f5/bigip_node.py
deleted file mode 100644
index 856284cdae..0000000000
--- a/lib/ansible/modules/network/f5/bigip_node.py
+++ /dev/null
@@ -1,1195 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2016, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_node
-short_description: Manages F5 BIG-IP LTM nodes
-description:
- - Manages F5 BIG-IP LTM nodes.
-version_added: 1.4
-options:
- state:
- description:
- - Specifies the current state of the node. C(enabled) (All traffic
- allowed), specifies that system sends traffic to this node regardless
- of the node's state. C(disabled) (Only persistent or active connections
- allowed), Specifies that the node can handle only persistent or
- active connections. C(offline) (Only active connections allowed),
- Specifies that the node can handle only active connections. In all
- cases except C(absent), the node will be created if it does not yet
- exist.
- - Be particularly careful about changing the status of a node whose FQDN
- cannot be resolved. These situations disable your ability to change their
- C(state) to C(disabled) or C(offline). They will remain in an
- *Unavailable - Enabled* state.
- type: str
- choices:
- - present
- - absent
- - enabled
- - disabled
- - offline
- default: present
- name:
- description:
- - Specifies the name of the node.
- type: str
- required: True
- monitor_type:
- description:
- - Monitor rule type when C(monitors) is specified. When creating a new
- pool, if this value is not specified, the default of 'and_list' will
- be used.
- - Both C(single) and C(and_list) are functionally identical since BIG-IP
- considers all monitors as "a list". BIG=IP either has a list of many,
- or it has a list of one. Where they differ is in the extra guards that
- C(single) provides; namely that it only allows a single monitor.
- version_added: "1.3"
- type: str
- choices:
- - and_list
- - m_of_n
- - single
- quorum:
- description:
- - Monitor quorum value when C(monitor_type) is C(m_of_n).
- type: int
- version_added: 2.2
- monitors:
- description:
- - Specifies the health monitors that the system currently uses to
- monitor this node.
- type: list
- version_added: 2.2
- address:
- description:
- - IP address of the node. This can be either IPv4 or IPv6. When creating a
- new node, one of either C(address) or C(fqdn) must be provided. This
- parameter cannot be updated after it is set.
- type: str
- aliases:
- - ip
- - host
- version_added: 2.2
- fqdn:
- description:
- - FQDN name of the node. This can be any name that is a valid RFC 1123 DNS
- name. Therefore, the only characters that can be used are "A" to "Z",
- "a" to "z", "0" to "9", the hyphen ("-") and the period (".").
- - FQDN names must include at lease one period; delineating the host from
- the domain. ex. C(host.domain).
- - FQDN names must end with a letter or a number.
- - When creating a new node, one of either C(address) or C(fqdn) must be
- provided. This parameter cannot be updated after it is set.
- type: str
- aliases:
- - hostname
- version_added: 2.5
- fqdn_address_type:
- description:
- - Specifies whether the FQDN of the node resolves to an IPv4 or IPv6 address.
- - When creating a new node, if this parameter is not specified and C(fqdn) is
- specified, this parameter will default to C(ipv4).
- - This parameter cannot be changed after it has been set.
- type: str
- choices:
- - ipv4
- - ipv6
- - all
- version_added: 2.6
- fqdn_auto_populate:
- description:
- - Specifies whether the system automatically creates ephemeral nodes using
- the IP addresses returned by the resolution of a DNS query for a node defined
- by an FQDN.
- - When C(yes), the system generates an ephemeral node for each IP address
- returned in response to a DNS query for the FQDN of the node. Additionally,
- when a DNS response indicates the IP address of an ephemeral node no longer
- exists, the system deletes the ephemeral node.
- - When C(no), the system resolves a DNS query for the FQDN of the node with the
- single IP address associated with the FQDN.
- - When creating a new node, if this parameter is not specified and C(fqdn) is
- specified, this parameter will default to C(yes).
- - This parameter cannot be changed after it has been set.
- type: bool
- version_added: 2.6
- fqdn_up_interval:
- description:
- - Specifies the interval in which a query occurs, when the DNS server is up.
- The associated monitor attempts to probe three times, and marks the server
- down if it there is no response within the span of three times the interval
- value, in seconds.
- - This parameter accepts a value of C(ttl) to query based off of the TTL of
- the FQDN. The default TTL interval is akin to specifying C(3600).
- - When creating a new node, if this parameter is not specified and C(fqdn) is
- specified, this parameter will default to C(3600).
- type: str
- version_added: 2.6
- fqdn_down_interval:
- description:
- - Specifies the interval in which a query occurs, when the DNS server is down.
- The associated monitor continues polling as long as the DNS server is down.
- - When creating a new node, if this parameter is not specified and C(fqdn) is
- specified, this parameter will default to C(5).
- type: int
- version_added: 2.6
- description:
- description:
- - Specifies descriptive text that identifies the node.
- - You can remove a description by either specifying an empty string, or by
- specifying the special value C(none).
- type: str
- connection_limit:
- description:
- - Node connection limit. Setting this to 0 disables the limit.
- type: int
- version_added: 2.7
- rate_limit:
- description:
- - Node rate limit (connections-per-second). Setting this to 0 disables the limit.
- type: int
- version_added: 2.7
- ratio:
- description:
- - Node ratio weight. Valid values range from 1 through 100.
- - When creating a new node, if this parameter is not specified, the default of
- C(1) will be used.
- type: int
- version_added: 2.7
- dynamic_ratio:
- description:
- - The dynamic ratio number for the node. Used for dynamic ratio load balancing.
- - When creating a new node, if this parameter is not specified, the default of
- C(1) will be used.
- type: int
- version_added: 2.7
- availability_requirements:
- description:
- - Specifies, if you activate more than one health monitor, the number of health
- monitors that must receive successful responses in order for the link to be
- considered available.
- suboptions:
- type:
- description:
- - Monitor rule type when C(monitors) is specified.
- - When creating a new pool, if this value is not specified, the default of
- 'all' will be used.
- type: str
- choices:
- - all
- - at_least
- at_least:
- description:
- - Specifies the minimum number of active health monitors that must be successful
- before the link is considered up.
- - This parameter is only relevant when a C(type) of C(at_least) is used.
- - This parameter will be ignored if a type of C(all) is used.
- type: int
- type: dict
- version_added: 2.8
- partition:
- description:
- - Device partition to manage resources on.
- type: str
- default: Common
- version_added: 2.5
-extends_documentation_fragment: f5
-author:
- - Tim Rupp (@caphrim007)
- - Wojciech Wypior (@wojtek0806)
-'''
-
-EXAMPLES = r'''
-- name: Add node
- bigip_node:
- host: 10.20.30.40
- name: 10.20.30.40
- provider:
- server: lb.mydomain.com
- user: admin
- password: secret
- delegate_to: localhost
-
-- name: Add node with a single 'ping' monitor
- bigip_node:
- host: 10.20.30.40
- name: mytestserver
- monitors:
- - /Common/icmp
- provider:
- server: lb.mydomain.com
- user: admin
- password: secret
- delegate_to: localhost
-
-- name: Modify node description
- bigip_node:
- name: 10.20.30.40
- description: Our best server yet
- provider:
- server: lb.mydomain.com
- user: admin
- password: secret
- delegate_to: localhost
-
-- name: Delete node
- bigip_node:
- state: absent
- name: 10.20.30.40
- provider:
- server: lb.mydomain.com
- user: admin
- password: secret
- delegate_to: localhost
-
-- name: Force node offline
- bigip_node:
- state: disabled
- name: 10.20.30.40
- provider:
- server: lb.mydomain.com
- user: admin
- password: secret
- delegate_to: localhost
-
-- name: Add node by their FQDN
- bigip_node:
- fqdn: foo.bar.com
- name: foobar.net
- provider:
- server: lb.mydomain.com
- user: admin
- password: secret
- delegate_to: localhost
-'''
-
-RETURN = r'''
-monitor_type:
- description:
- - Changed value for the monitor_type of the node.
- returned: changed and success
- type: str
- sample: m_of_n
-quorum:
- description:
- - Changed value for the quorum of the node.
- returned: changed and success
- type: int
- sample: 1
-monitors:
- description:
- - Changed list of monitors for the node.
- returned: changed and success
- type: list
- sample: ['icmp', 'tcp_echo']
-description:
- description:
- - Changed value for the description of the node.
- returned: changed and success
- type: str
- sample: E-Commerce webserver in ORD
-session:
- description:
- - Changed value for the internal session of the node.
- returned: changed and success
- type: str
- sample: user-disabled
-state:
- description:
- - Changed value for the internal state of the node.
- returned: changed and success
- type: str
- sample: m_of_n
-'''
-
-import re
-import time
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.basic import env_fallback
-from ansible.module_utils.parsing.convert_bool import BOOLEANS_FALSE
-from ansible.module_utils.parsing.convert_bool import BOOLEANS_TRUE
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import fq_name
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.common import transform_name
- from library.module_utils.compat.ipaddress import ip_address
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import fq_name
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.common import transform_name
- from ansible.module_utils.compat.ipaddress import ip_address
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'monitor': 'monitors',
- 'connectionLimit': 'connection_limit',
- 'rateLimit': 'rate_limit'
- }
-
- api_attributes = [
- 'description',
- 'address',
- 'fqdn',
- 'ratio',
- 'connectionLimit',
- 'rateLimit',
- 'monitor',
-
- # Used for changing state
- #
- # user-enabled (enabled)
- # user-disabled (disabled)
- # user-disabled (offline)
- 'session',
-
- # Used for changing state
- # user-down (offline)
- 'state'
- ]
-
- returnables = [
- 'monitors',
- 'description',
- 'fqdn',
- 'address',
- 'session',
- 'state',
- 'fqdn_auto_populate',
- 'fqdn_address_type',
- 'fqdn_up_interval',
- 'fqdn_down_interval',
- 'fqdn_name',
- 'connection_limit',
- 'ratio',
- 'rate_limit',
- 'availability_requirements'
- ]
-
- updatables = [
- 'monitors',
- 'description',
- 'state',
- 'fqdn_up_interval',
- 'fqdn_down_interval',
- 'tmName',
- 'fqdn_auto_populate',
- 'fqdn_address_type',
- 'connection_limit',
- 'ratio',
- 'rate_limit',
- ]
-
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- return result
- except Exception:
- return result
-
- @property
- def rate_limit(self):
- if self._values['rate_limit'] is None:
- return None
- if self._values['rate_limit'] == 'disabled':
- return 0
- return int(self._values['rate_limit'])
-
-
-class Changes(Parameters):
- pass
-
-
-class UsableChanges(Changes):
- @property
- def fqdn(self):
- result = dict()
- if self._values['fqdn_up_interval'] is not None:
- result['interval'] = self._values['fqdn_up_interval']
- if self._values['fqdn_down_interval'] is not None:
- result['downInterval'] = self._values['fqdn_down_interval']
- if self._values['fqdn_auto_populate'] is not None:
- result['autopopulate'] = self._values['fqdn_auto_populate']
- if self._values['fqdn_name'] is not None:
- result['tmName'] = self._values['fqdn_name']
- if self._values['fqdn_address_type'] is not None:
- result['addressFamily'] = self._values['fqdn_address_type']
- if not result:
- return None
- return result
-
- @property
- def monitors(self):
- monitor_string = self._values['monitors']
- if monitor_string is None:
- return None
- if '{' in monitor_string and '}':
- tmp = monitor_string.strip('}').split('{')
- monitor = ''.join(tmp).rstrip()
- return monitor
- return monitor_string
-
-
-class ReportableChanges(Changes):
- @property
- def monitors(self):
- if self._values['monitors'] is None:
- return []
- try:
- result = re.findall(r'/\w+/[^\s}]+', self._values['monitors'])
- result.sort()
- return result
- except Exception:
- return self._values['monitors']
-
- @property
- def availability_requirement_type(self):
- if self._values['monitors'] is None:
- return None
- if 'min ' in self._values['monitors']:
- return 'at_least'
- else:
- return 'all'
-
- @property
- def at_least(self):
- """Returns the 'at least' value from the monitor string.
- The monitor string for a Require monitor looks like this.
- min 1 of { /Common/gateway_icmp }
- This method parses out the first of the numeric values. This values represents
- the "at_least" value that can be updated in the module.
- Returns:
- int: The at_least value if found. None otherwise.
- """
- if self._values['monitors'] is None:
- return None
- pattern = r'min\s+(?P<least>\d+)\s+of\s+'
- matches = re.search(pattern, self._values['monitors'])
- if matches is None:
- return None
- return int(matches.group('least'))
-
- @property
- def availability_requirements(self):
- if self._values['monitors'] is None:
- return None
- result = dict()
- result['type'] = self.availability_requirement_type
- result['at_least'] = self.at_least
- return result
-
-
-class ModuleParameters(Parameters):
- def _get_availability_value(self, type):
- if self._values['availability_requirements'] is None:
- return None
- if self._values['availability_requirements'][type] is None:
- return None
- return int(self._values['availability_requirements'][type])
-
- @property
- def monitors_list(self):
- if self._values['monitors'] is None:
- return []
- try:
- result = re.findall(r'/\w+/[^\s}]+', self._values['monitors'])
- except Exception:
- result = self._values['monitors']
- result.sort()
- return result
-
- @property
- def monitors(self):
- if self._values['monitors'] is None:
- return None
- if len(self._values['monitors']) == 1 and self._values['monitors'][0] == '':
- return '/Common/none'
- monitors = [fq_name(self.partition, x) for x in self.monitors_list]
- if self.availability_requirement_type == 'at_least':
- if self.at_least > len(self.monitors_list):
- raise F5ModuleError(
- "The 'at_least' value must not exceed the number of 'monitors'."
- )
- monitors = ' '.join(monitors)
- result = 'min {0} of {{ {1} }}'.format(self.at_least, monitors)
- else:
- result = ' and '.join(monitors).strip()
-
- return result
-
- @property
- def availability_requirement_type(self):
- if self._values['monitor_type']:
- if self._values['monitor_type'] in ['single', 'and_list']:
- result = 'all'
- else:
- result = 'at_least'
- self._values['availability_requirements'] = dict(type=None)
- self._values['availability_requirements']['type'] = result
- if self._values['availability_requirements'] is None:
- return None
- return self._values['availability_requirements']['type']
-
- @property
- def at_least(self):
- if self._values['quorum']:
- self._values['availability_requirements'] = dict(at_least=None)
- self._values['availability_requirements']['at_least'] = self._values['quorum']
- return self._get_availability_value('at_least')
-
- @property
- def fqdn_up_interval(self):
- if self._values['fqdn_up_interval'] is None:
- return None
- return str(self._values['fqdn_up_interval'])
-
- @property
- def fqdn_down_interval(self):
- if self._values['fqdn_down_interval'] is None:
- return None
- return str(self._values['fqdn_down_interval'])
-
- @property
- def fqdn_auto_populate(self):
- auto_populate = self._values.get('fqdn_auto_populate', None)
- if auto_populate in BOOLEANS_TRUE:
- return 'enabled'
- elif auto_populate in BOOLEANS_FALSE:
- return 'disabled'
-
- @property
- def fqdn_name(self):
- return self._values.get('fqdn', None)
-
- @property
- def fqdn(self):
- if self._values['fqdn'] is None:
- return None
- result = dict(
- addressFamily=self._values.get('fqdn_address_type', None),
- downInterval=self._values.get('fqdn_down_interval', None),
- interval=self._values.get('fqdn_up_interval', None),
- autopopulate=None,
- tmName=self._values.get('fqdn', None)
- )
- auto_populate = self._values.get('fqdn_auto_populate', None)
- if auto_populate in BOOLEANS_TRUE:
- result['autopopulate'] = 'enabled'
- elif auto_populate in BOOLEANS_FALSE:
- result['autopopulate'] = 'disabled'
- return result
-
- @property
- def description(self):
- if self._values['description'] is None:
- return None
- elif self._values['description'] in ['none', '']:
- return ''
- return self._values['description']
-
-
-class ApiParameters(Parameters):
- @property
- def fqdn_up_interval(self):
- if self._values['fqdn'] is None:
- return None
- if 'interval' in self._values['fqdn']:
- return str(self._values['fqdn']['interval'])
-
- @property
- def fqdn_down_interval(self):
- if self._values['fqdn'] is None:
- return None
- if 'downInterval' in self._values['fqdn']:
- return str(self._values['fqdn']['downInterval'])
-
- @property
- def fqdn_address_type(self):
- if self._values['fqdn'] is None:
- return None
- if 'addressFamily' in self._values['fqdn']:
- return str(self._values['fqdn']['addressFamily'])
-
- @property
- def fqdn_auto_populate(self):
- if self._values['fqdn'] is None:
- return None
- if 'autopopulate' in self._values['fqdn']:
- return str(self._values['fqdn']['autopopulate'])
-
- @property
- def description(self):
- if self._values['description'] in [None, 'none']:
- return None
- return self._values['description']
-
- @property
- def availability_requirement_type(self):
- if self._values['monitors'] is None:
- return None
- if 'min ' in self._values['monitors']:
- return 'at_least'
- else:
- return 'all'
-
- @property
- def monitors_list(self):
- if self._values['monitors'] is None:
- return []
- try:
- result = re.findall(r'/\w+/[^\s}]+', self._values['monitors'])
- except Exception:
- result = self._values['monitors']
- result.sort()
- return result
-
- @property
- def monitors(self):
- if self._values['monitors'] is None:
- return None
- if self._values['monitors'] == 'default':
- return 'default'
- monitors = [fq_name(self.partition, x) for x in self.monitors_list]
- if self.availability_requirement_type == 'at_least':
- monitors = ' '.join(monitors)
- result = 'min {0} of {{ {1} }}'.format(self.at_least, monitors)
- else:
- result = ' and '.join(monitors).strip()
- return result
-
- @property
- def at_least(self):
- """Returns the 'at least' value from the monitor string.
-
- The monitor string for a Require monitor looks like this.
-
- min 1 of { /Common/gateway_icmp }
-
- This method parses out the first of the numeric values. This values represents
- the "at_least" value that can be updated in the module.
-
- Returns:
- int: The at_least value if found. None otherwise.
- """
- if self._values['monitors'] is None:
- return None
- pattern = r'min\s+(?P<least>\d+)\s+of\s+'
- matches = re.search(pattern, self._values['monitors'])
- if matches is None:
- return None
- return matches.group('least')
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
- @property
- def monitors(self):
- if self.want.monitor_type == 'single':
- if len(self.want.monitors_list) > 1:
- raise F5ModuleError(
- "When using a 'monitor_type' of 'single', only one monitor may be provided."
- )
- elif len(self.have.monitors_list) > 1 and len(self.want.monitors_list) == 0:
- # Handle instances where there already exists many monitors, and the
- # user runs the module again specifying that the monitor_type should be
- # changed to 'single'
- raise F5ModuleError(
- "A single monitor must be specified if more than one monitor currently exists on your pool."
- )
- if self.want.monitors is None:
- return None
- if self.want.monitors == 'default' and self.have.monitors == 'default':
- return None
- if self.want.monitors == 'default' and self.have.monitors is None:
- return None
- if self.want.monitors == '/Common/none' and self.have.monitors == '/Common/none':
- return None
- if self.want.monitors == 'default' and len(self.have.monitors) > 0:
- return 'default'
- if self.have.monitors is None:
- return self.want.monitors
- if self.have.monitors != self.want.monitors:
- return self.want.monitors
-
- @property
- def state(self):
- result = None
- if self.want.state in ['present', 'enabled']:
- if self.have.session not in ['user-enabled', 'monitor-enabled']:
- result = dict(
- session='user-enabled',
- state='user-up',
- )
- elif self.want.state == 'disabled':
- if self.have.session != 'user-disabled' or self.have.state == 'user-down':
- result = dict(
- session='user-disabled',
- state='user-up'
- )
- elif self.want.state == 'offline':
- if self.have.state != 'user-down':
- result = dict(
- session='user-disabled',
- state='user-down'
- )
- return result
-
- @property
- def description(self):
- if self.want.description is None:
- return None
- if self.have.description is None and self.want.description == '':
- return None
- if self.want.description != self.have.description:
- return self.want.description
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.have = None
- self.want = ModuleParameters(params=self.module.params)
- self.changes = UsableChanges()
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = UsableChanges(params=changed)
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def _announce_deprecations(self): # lgtm [py/similar-function]
- warnings = []
- if self.want:
- warnings += self.want._values.get('__warnings', [])
- if self.have:
- warnings += self.have._values.get('__warnings', [])
- for warning in warnings:
- self.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def exec_module(self):
- changed = False
- result = dict()
- state = self.want.state
-
- try:
- if state in ['present', 'enabled', 'disabled', 'offline']:
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
- except IOError as e:
- raise F5ModuleError(str(e))
-
- changes = self.changes.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations()
- return result
-
- def present(self):
- if self.exists():
- return self.update()
- else:
- return self.create()
-
- def _check_required_creation_vars(self):
- if self.want.address is None and self.want.fqdn is None:
- raise F5ModuleError(
- "At least one of 'address' or 'fqdn' is required when creating a node"
- )
- elif self.want.address is not None and self.want.fqdn is not None:
- raise F5ModuleError(
- "Only one of 'address' or 'fqdn' can be provided when creating a node"
- )
- elif self.want.fqdn is not None:
- self.want.update(dict(address='any6'))
-
- def _munge_creation_state_for_device(self):
- # Modifying the state before sending to BIG-IP
- #
- # The 'state' must be set to None to exclude the values (accepted by this
- # module) from being sent to the BIG-IP because for specific Ansible states,
- # BIG-IP will consider those state values invalid.
- if self.want.state in ['present', 'enabled']:
- self.want.update(dict(
- session='user-enabled',
- state='user-up',
- ))
- elif self.want.state in 'disabled':
- self.want.update(dict(
- session='user-disabled',
- state='user-up'
- ))
- else:
- # State 'offline'
- # Offline state will result in the monitors stopping for the node
- self.want.update(dict(
- session='user-disabled',
-
- # only a valid state can be specified. The module's value is "offline",
- # but this is an invalid value for the BIG-IP. Therefore set it to user-down.
- state='user-down',
-
- # Even user-down wil not work when _creating_ a node, so we register another
- # want value (that is not sent to the API). This is checked for later to
- # determine if we have to PATCH the node to be offline.
- is_offline=True
- ))
-
- def create(self):
- self._check_required_creation_vars()
- self._munge_creation_state_for_device()
-
- if self.want.fqdn_auto_populate is None:
- self.want.update({'fqdn_auto_populate': True})
- if self.want.fqdn_address_type is None:
- self.want.update({'fqdn_address_type': 'ipv4'})
- if self.want.fqdn_up_interval is None:
- self.want.update({'fqdn_up_interval': 3600})
- if self.want.fqdn_down_interval is None:
- self.want.update({'fqdn_down_interval': 5})
- if self.want.ratio is None:
- self.want.update({'ratio': 1})
- if self.want.dynamic_ratio is None:
- self.want.update({'dynamic_ratio': 1})
-
- self._set_changed_options()
- if self.module.check_mode:
- return True
-
- # These are being set here because the ``create_on_device`` method
- # uses ``self.changes`` (to get formatting of parameters correct)
- # but these two parameters here cannot be changed and also it is
- # not easy to get the current versions of them for comparison.
- if self.want.address:
- self.changes.update({'address': self.want.address})
- if self.want.fqdn_up_interval is not None:
- self.changes.update({'fqdn_up_interval': self.want.fqdn_up_interval})
- if self.want.fqdn_down_interval is not None:
- self.changes.update({'fqdn_down_interval': self.want.fqdn_down_interval})
- if self.want.fqdn_auto_populate is not None:
- self.changes.update({'fqdn_auto_populate': self.want.fqdn_auto_populate})
- if self.want.fqdn_name is not None:
- self.changes.update({'fqdn_name': self.want.fqdn_name})
- if self.want.fqdn_address_type is not None:
- self.changes.update({'fqdn_address_type': self.want.fqdn_address_type})
-
- self.create_on_device()
- if not self.exists():
- raise F5ModuleError("Failed to create the node")
- # It appears that you cannot create a node in an 'offline' state, so instead
- # we update its status to offline after we create it.
- if self.want.is_offline:
- self.update_node_offline_on_device()
- return True
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def update(self):
- self.have = self.read_current_from_device()
- if not self.should_update():
- return False
-
- if self.want.fqdn_auto_populate is not None:
- if self.want.fqdn_auto_populate != self.have.fqdn_auto_populate:
- raise F5ModuleError(
- "The 'fqdn_auto_populate' parameter cannot be changed."
- )
- if self.want.fqdn_address_type is not None:
- if self.want.fqdn_address_type != self.have.fqdn_address_type:
- raise F5ModuleError(
- "The 'fqdn_address_type' parameter cannot be changed."
- )
-
- if self.module.check_mode:
- return True
-
- self.update_on_device()
- if self.want.state == 'offline':
- self.update_node_offline_on_device()
- return True
-
- def absent(self):
- if self.exists():
- return self.remove()
- return False
-
- def remove(self):
- if self.module.check_mode:
- return True
- self.remove_from_device()
- if self.exists():
- raise F5ModuleError("Failed to delete the node.")
- return True
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/node/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return ApiParameters(params=response)
-
- def exists(self): # lgtm [py/similar-function]
- uri = "https://{0}:{1}/mgmt/tm/ltm/node/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def update_node_offline_on_device(self):
- params = dict(
- session="user-disabled",
- state="user-down"
- )
- uri = "https://{0}:{1}/mgmt/tm/ltm/node/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def update_on_device(self):
- params = self.changes.api_params()
- uri = "https://{0}:{1}/mgmt/tm/ltm/node/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- if params:
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def create_on_device(self):
- params = self.changes.api_params()
- params['name'] = self.want.name
- params['partition'] = self.want.partition
- uri = "https://{0}:{1}/mgmt/tm/ltm/node/".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- self._wait_for_fqdn_checks()
-
- def _wait_for_fqdn_checks(self):
- while True:
- have = self.read_current_from_device()
- if have.state == 'fqdn-checking':
- time.sleep(1)
- else:
- break
-
- def remove_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/node/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.delete(uri)
- if resp.status == 200:
- return True
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- name=dict(required=True),
- address=dict(
- aliases=['host', 'ip']
- ),
- fqdn=dict(
- aliases=['hostname']
- ),
- description=dict(),
- state=dict(
- choices=['absent', 'present', 'enabled', 'disabled', 'offline'],
- default='present'
- ),
- partition=dict(
- default='Common',
- fallback=(env_fallback, ['F5_PARTITION'])
- ),
- fqdn_address_type=dict(
- choices=['ipv4', 'ipv6', 'all']
- ),
- fqdn_auto_populate=dict(type='bool'),
- fqdn_up_interval=dict(),
- fqdn_down_interval=dict(type='int'),
- connection_limit=dict(type='int'),
- rate_limit=dict(type='int'),
- ratio=dict(type='int'),
- dynamic_ratio=dict(type='int'),
- availability_requirements=dict(
- type='dict',
- options=dict(
- type=dict(
- choices=['all', 'at_least'],
- required=True
- ),
- at_least=dict(type='int'),
- ),
- required_if=[
- ['type', 'at_least', ['at_least']],
- ]
- ),
- monitors=dict(type='list'),
-
-
- # Deprecated parameters
- monitor_type=dict(
- choices=[
- 'and_list', 'm_of_n', 'single'
- ],
- removed_in_version=2.12,
- ),
- quorum=dict(
- type='int',
- removed_in_version=2.12,
- ),
-
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
- self.mutually_exclusive = [
- ['monitor_type', 'quorum', 'availability_requirements']
- ]
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode,
- mutually_exclusive=spec.mutually_exclusive
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_partition.py b/lib/ansible/modules/network/f5/bigip_partition.py
deleted file mode 100644
index 6a8caa0cf5..0000000000
--- a/lib/ansible/modules/network/f5/bigip_partition.py
+++ /dev/null
@@ -1,496 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_partition
-short_description: Manage BIG-IP partitions
-description:
- - Manage BIG-IP partitions.
-version_added: 2.5
-options:
- name:
- description:
- - Name of the partition
- type: str
- required: True
- description:
- description:
- - The description to attach to the Partition.
- type: str
- route_domain:
- description:
- - The default Route Domain to assign to the Partition. If no route domain
- is specified, then the default route domain for the system (typically
- zero) will be used only when creating a new partition.
- type: int
- state:
- description:
- - Whether the partition should exist or not.
- type: str
- choices:
- - present
- - absent
- default: present
-notes:
- - Requires BIG-IP software version >= 12
-extends_documentation_fragment: f5
-author:
- - Tim Rupp (@caphrim007)
- - Wojciech Wypior (@wojtek0806)
-'''
-
-EXAMPLES = r'''
-- name: Create partition "foo" using the default route domain
- bigip_partition:
- name: foo
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-
-- name: Create partition "bar" using a custom route domain
- bigip_partition:
- name: bar
- route_domain: 3
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-
-- name: Change route domain of partition "foo"
- bigip_partition:
- name: foo
- route_domain: 8
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-
-- name: Set a description for partition "foo"
- bigip_partition:
- name: foo
- description: Tenant CompanyA
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-
-- name: Delete the "foo" partition
- bigip_partition:
- name: foo
- state: absent
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-'''
-
-RETURN = r'''
-route_domain:
- description: Name of the route domain associated with the partition.
- returned: changed and success
- type: int
- sample: 0
-description:
- description: The description of the partition.
- returned: changed and success
- type: str
- sample: Example partition
-'''
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.compare import cmp_str_with_none
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.compare import cmp_str_with_none
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'defaultRouteDomain': 'route_domain',
- }
-
- api_attributes = [
- 'description',
- 'defaultRouteDomain',
- ]
-
- returnables = [
- 'description',
- 'route_domain',
- 'folder_description',
- ]
-
- updatables = [
- 'description',
- 'route_domain',
- 'folder_description',
- ]
-
-
-class ApiParameters(Parameters):
- @property
- def description(self):
- if self._values['description'] in [None, 'none']:
- return None
- return self._values['description']
-
-
-class ModuleParameters(Parameters):
- @property
- def partition(self):
- # Cannot create a partition in a partition, so nullify this
- return None
-
- @property
- def route_domain(self):
- if self._values['route_domain'] is None:
- return None
- return int(self._values['route_domain'])
-
- @property
- def description(self):
- if self._values['description'] is None:
- return None
- elif self._values['description'] in ['none', '']:
- return ''
- return self._values['description']
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class UsableChanges(Changes):
- pass
-
-
-class ReportableChanges(Changes):
- pass
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- result = self.__default(param)
- return result
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
- @property
- def description(self):
- if cmp_str_with_none(self.want.description, self.have.description) is None:
- return cmp_str_with_none(self.want.description, self.have.folder_description)
- else:
- return self.want.description
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(params=self.module.params)
- self.have = ApiParameters()
- self.changes = UsableChanges()
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.client.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = UsableChanges(params=changed)
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def exec_module(self):
- changed = False
- result = dict()
- state = self.want.state
-
- if state == "present":
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def present(self):
- if self.exists():
- return self.update()
- else:
- return self.create()
-
- def create(self):
- self._set_changed_options()
- if self.module.check_mode:
- return True
- self.create_on_device()
- if self.changes.description:
- self.update_folder_on_device()
- if not self.exists():
- raise F5ModuleError("Failed to create the partition.")
- return True
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def update(self):
- self.have = self.read_current_from_device()
- if not self.should_update():
- return False
- if self.module.check_mode:
- return True
- self.update_on_device()
- if self.changes.description:
- self.update_folder_on_device()
- return True
-
- def absent(self):
- if self.exists():
- return self.remove()
- return False
-
- def remove(self):
- if self.module.check_mode:
- return True
- self.remove_from_device()
- if self.exists():
- raise F5ModuleError("Failed to delete the partition.")
- return True
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/auth/partition/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- self.want.name
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- result = ApiParameters(params=response)
- uri = "https://{0}:{1}/mgmt/tm/sys/folder/~{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- self.want.name
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- result.update({'folder_description': response.get('description', None)})
- return result
-
- def exists(self):
- uri = "https://{0}:{1}/mgmt/tm/auth/partition/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- self.want.name
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def create_on_device(self):
- params = self.changes.api_params()
- params['name'] = self.want.name
- uri = "https://{0}:{1}/mgmt/tm/auth/partition/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403, 409]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def update_on_device(self):
- params = self.changes.api_params()
- uri = "https://{0}:{1}/mgmt/tm/auth/partition/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- self.want.name
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def update_folder_on_device(self):
- params = dict(description=self.changes.description)
- uri = "https://{0}:{1}/mgmt/tm/sys/folder/~{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- self.want.name
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def remove_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/auth/partition/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- self.want.name
- )
- resp = self.client.api.delete(uri)
- if resp.status == 200:
- return True
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- name=dict(required=True),
- description=dict(),
- route_domain=dict(type='int'),
- state=dict(
- choices=['absent', 'present'],
- default='present'
- )
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_password_policy.py b/lib/ansible/modules/network/f5/bigip_password_policy.py
deleted file mode 100644
index d291fad17a..0000000000
--- a/lib/ansible/modules/network/f5/bigip_password_policy.py
+++ /dev/null
@@ -1,439 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2018, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_password_policy
-short_description: Manages the authentication password policy on a BIG-IP
-description:
- - Manages the authentication password policy on a BIG-IP.
-version_added: 2.8
-options:
- expiration_warning:
- description:
- - Specifies the number of days before a password expires.
- - Based on this value, the BIG-IP system automatically warns users when their
- password is about to expire.
- type: int
- max_duration:
- description:
- - Specifies the maximum number of days a password is valid.
- type: int
- max_login_failures:
- description:
- - Specifies the number of consecutive unsuccessful login attempts
- that the system allows before locking out the user.
- - Specify zero (0) to disable this parameter.
- type: int
- min_duration:
- description:
- - Specifies the minimum number of days a password is valid.
- type: int
- min_length:
- description:
- - Specifies the minimum number of characters in a valid password.
- - This value must be between 6 and 255.
- type: int
- policy_enforcement:
- description:
- - Enables or disables the password policy on the BIG-IP system.
- type: bool
- required_lowercase:
- description:
- - Specifies the number of lowercase alpha characters that must be
- present in a password for the password to be valid.
- type: int
- required_numeric:
- description:
- - Specifies the number of numeric characters that must be present in
- a password for the password to be valid.
- type: int
- required_special:
- description:
- - Specifies the number of special characters that must be present in
- a password for the password to be valid.
- type: int
- required_uppercase:
- description:
- - Specifies the number of uppercase alpha characters that must be
- present in a password for the password to be valid.
- type: int
- password_memory:
- description:
- - Specifies whether the user has configured the BIG-IP system to
- remember a password on a specific computer and how many passwords
- to remember.
- type: int
-extends_documentation_fragment: f5
-author:
- - Tim Rupp (@caphrim007)
-'''
-
-EXAMPLES = r'''
-- name: Change password policy to require 2 numeric characters
- bigip_password_policy:
- required_numeric: 2
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-'''
-
-RETURN = r'''
-expiration_warning:
- description: The new expiration warning.
- returned: changed
- type: int
- sample: 7
-max_duration:
- description: The new max duration.
- returned: changed
- type: int
- sample: 99999
-max_login_failures:
- description: The new max login failures.
- returned: changed
- type: int
- sample: 0
-min_duration:
- description: The new min duration.
- returned: changed
- type: int
- sample: 0
-min_length:
- description: The new min password length.
- returned: changed
- type: int
- sample: 6
-policy_enforcement:
- description: The new policy enforcement setting.
- returned: changed
- type: bool
- sample: yes
-required_lowercase:
- description: The lowercase requirement.
- returned: changed
- type: int
- sample: 1
-required_numeric:
- description: The numeric requirement.
- returned: changed
- type: int
- sample: 2
-required_special:
- description: The special character requirement.
- returned: changed
- type: int
- sample: 1
-required_uppercase:
- description: The uppercase character requirement.
- returned: changed
- type: int
- sample: 1
-password_memory:
- description: The new number of remembered passwords
- returned: changed
- type: int
- sample: 0
-'''
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import fq_name
- from library.module_utils.network.f5.common import transform_name
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.common import flatten_boolean
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import fq_name
- from ansible.module_utils.network.f5.common import transform_name
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.common import flatten_boolean
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'expirationWarning': 'expiration_warning',
- 'maxDuration': 'max_duration',
- 'maxLoginFailures': 'max_login_failures',
- 'minDuration': 'min_duration',
- 'minimumLength': 'min_length',
- 'passwordMemory': 'password_memory',
- 'policyEnforcement': 'policy_enforcement',
- 'requiredLowercase': 'required_lowercase',
- 'requiredNumeric': 'required_numeric',
- 'requiredSpecial': 'required_special',
- 'requiredUppercase': 'required_uppercase',
- }
-
- api_attributes = [
- 'expirationWarning',
- 'maxDuration',
- 'maxLoginFailures',
- 'minDuration',
- 'minimumLength',
- 'passwordMemory',
- 'policyEnforcement',
- 'requiredLowercase',
- 'requiredNumeric',
- 'requiredSpecial',
- 'requiredUppercase',
- ]
-
- returnables = [
- 'expiration_warning',
- 'max_duration',
- 'max_login_failures',
- 'min_duration',
- 'min_length',
- 'password_memory',
- 'policy_enforcement',
- 'required_lowercase',
- 'required_numeric',
- 'required_special',
- 'required_uppercase',
- ]
-
- updatables = [
- 'expiration_warning',
- 'max_duration',
- 'max_login_failures',
- 'min_duration',
- 'min_length',
- 'password_memory',
- 'policy_enforcement',
- 'required_lowercase',
- 'required_numeric',
- 'required_special',
- 'required_uppercase',
- ]
-
- @property
- def policy_enforcement(self):
- return flatten_boolean(self._values['policy_enforcement'])
-
-
-class ApiParameters(Parameters):
- pass
-
-
-class ModuleParameters(Parameters):
- pass
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class UsableChanges(Changes):
- @property
- def policy_enforcement(self):
- if self._values['policy_enforcement'] is None:
- return None
- if self._values['policy_enforcement'] == 'yes':
- return 'enabled'
- return 'disabled'
-
-
-class ReportableChanges(Changes):
- @property
- def policy_enforcement(self):
- return flatten_boolean(self._values['policy_enforcement'])
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(params=self.module.params)
- self.have = ApiParameters()
- self.changes = UsableChanges()
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = UsableChanges(params=changed)
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.client.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def exec_module(self):
- result = dict()
-
- changed = self.present()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def present(self):
- return self.update()
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def update(self):
- self.have = self.read_current_from_device()
- if not self.should_update():
- return False
- if self.module.check_mode:
- return True
- self.update_on_device()
- return True
-
- def update_on_device(self):
- params = self.changes.api_params()
- uri = "https://{0}:{1}/mgmt/tm/auth/password-policy".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/auth/password-policy".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return ApiParameters(params=response)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- expiration_warning=dict(type='int'),
- max_duration=dict(type='int'),
- max_login_failures=dict(type='int'),
- min_duration=dict(type='int'),
- min_length=dict(type='int'),
- password_memory=dict(type='int'),
- policy_enforcement=dict(type='bool'),
- required_lowercase=dict(type='int'),
- required_numeric=dict(type='int'),
- required_special=dict(type='int'),
- required_uppercase=dict(type='int'),
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode,
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_policy.py b/lib/ansible/modules/network/f5/bigip_policy.py
deleted file mode 100644
index ea82ed8483..0000000000
--- a/lib/ansible/modules/network/f5/bigip_policy.py
+++ /dev/null
@@ -1,1128 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_policy
-short_description: Manage general policy configuration on a BIG-IP
-description:
- - Manages general policy configuration on a BIG-IP. This module is best
- used in conjunction with the C(bigip_policy_rule) module. This module
- can handle general configuration like setting the draft state of the policy,
- the description, and things unrelated to the policy rules themselves.
- It is also the first module that should be used when creating rules as
- the C(bigip_policy_rule) module requires a policy parameter.
-version_added: 2.5
-options:
- description:
- description:
- - The description to attach to the policy.
- - This parameter is only supported on versions of BIG-IP >= 12.1.0. On earlier
- versions it will simply be ignored.
- type: str
- name:
- description:
- - The name of the policy to create.
- type: str
- required: True
- state:
- description:
- - When C(state) is C(present), ensures that the policy exists and is
- published. When C(state) is C(absent), ensures that the policy is removed,
- even if it is currently drafted.
- - When C(state) is C(draft), ensures that the policy exists and is drafted.
- When modifying rules, it is required that policies first be in a draft.
- - Drafting is only supported on versions of BIG-IP >= 12.1.0. On versions
- prior to that, specifying a C(state) of C(draft) will raise an error.
- type: str
- choices:
- - present
- - absent
- - draft
- default: present
- strategy:
- description:
- - Specifies the method to determine which actions get executed in the
- case where there are multiple rules that match. When creating new
- policies, the default is C(first).
- - This module does not allow you to specify the C(best) strategy to use.
- It will choose the system default (C(/Common/best-match)) for you instead.
- type: str
- choices:
- - first
- - all
- - best
- rules:
- description:
- - Specifies a list of rules that you want associated with this policy.
- The order of this list is the order they will be evaluated by BIG-IP.
- If the specified rules do not exist (for example when creating a new
- policy) then they will be created.
- - The C(conditions) for a default rule are C(all).
- - The C(actions) for a default rule are C(ignore).
- - The C(bigip_policy_rule) module can be used to create and edit existing
- and new rules.
- type: list
- partition:
- description:
- - Device partition to manage resources on.
- type: str
- default: Common
-extends_documentation_fragment: f5
-author:
- - Tim Rupp (@caphrim007)
- - Wojciech Wypior (@wojtek0806)
-'''
-
-EXAMPLES = r'''
-- name: Create policy which is immediately published
- bigip_policy:
- name: Policy-Foo
- state: present
- provider:
- server: lb.mydomain.com
- user: admin
- password: secret
- delegate_to: localhost
-
-- name: Add a rule to the new policy - Immediately published
- bigip_policy_rule:
- policy: Policy-Foo
- name: ABC
- conditions:
- - type: http_uri
- path_starts_with:
- - /ABC
- - foo
- - bar
- path_ends_with:
- - baz
- actions:
- - forward: yes
- select: yes
- pool: pool-svrs
- provider:
- server: lb.mydomain.com
- user: admin
- password: secret
- delegate_to: localhost
-
-- name: Add multiple rules to the new policy - Added in the order they are specified
- bigip_policy_rule:
- policy: Policy-Foo
- name: "{{ item.name }}"
- conditions: "{{ item.conditions }}"
- actions: "{{ item.actions }}"
- provider:
- server: lb.mydomain.com
- user: admin
- password: secret
- delegate_to: localhost
- loop:
- - name: rule1
- actions:
- - type: forward
- pool: pool-svrs
- conditions:
- - type: http_uri
- path_starts_with: /euro
- - name: HomePage
- actions:
- - type: forward
- pool: pool-svrs
- conditions:
- - type: http_uri
- path_starts_with: /HomePage/
-
-- name: Create policy specify default rules - Immediately published
- bigip_policy:
- name: Policy-Bar
- state: present
- rules:
- - rule1
- - rule2
- - rule3
- provider:
- server: lb.mydomain.com
- user: admin
- password: secret
- delegate_to: localhost
-
-- name: Create policy specify default rules - Left in a draft
- bigip_policy:
- name: Policy-Baz
- state: draft
- rules:
- - rule1
- - rule2
- - rule3
- provider:
- server: lb.mydomain.com
- user: admin
- password: secret
- delegate_to: localhost
-'''
-
-RETURN = r'''
-strategy:
- description: The new strategy set on the policy.
- returned: changed and success
- type: int
- sample: first-match
-description:
- description:
- - The new description of the policy.
- - This value is only returned for BIG-IP devices >= 12.1.0.
- returned: changed and success
- type: str
- sample: This is my description
-rules:
- description: List of the rules, and their order, applied to the policy.
- returned: changed and success
- type: list
- sample: ['/Common/rule1', '/Common/rule2']
-'''
-import re
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.basic import env_fallback
-from distutils.version import LooseVersion
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import fq_name
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.common import transform_name
- from library.module_utils.network.f5.icontrol import tmos_version
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import fq_name
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.common import transform_name
- from ansible.module_utils.network.f5.icontrol import tmos_version
-
-
-class Parameters(AnsibleF5Parameters):
- def to_return(self):
- result = {}
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- return result
-
- @property
- def strategy(self):
- if self._values['strategy'] is None:
- return None
-
- # Look for 'first' from Ansible or REST
- elif self._values['strategy'] == 'first':
- return self._get_builtin_strategy('first')
- elif 'first-match' in self._values['strategy']:
- return str(self._values['strategy'])
-
- # Look for 'all' from Ansible or REST
- elif self._values['strategy'] == 'all':
- return self._get_builtin_strategy('all')
- elif 'all-match' in self._values['strategy']:
- return str(self._values['strategy'])
-
- else:
- # Look for 'best' from Ansible or REST
- if self._values['strategy'] == 'best':
- return self._get_builtin_strategy('best')
- elif 'best-match' in self._values['strategy']:
- return str(self._values['strategy'])
- else:
- # These are custom strategies. The strategy may include the
- # partition, but if it does not, then we add the partition
- # that is provided to the module.
- return self._get_custom_strategy_name()
-
- def _get_builtin_strategy(self, strategy):
- return '/Common/{0}-match'.format(strategy)
-
- def _get_custom_strategy_name(self):
- strategy = self._values['strategy']
- if re.match(r'(\/[a-zA-Z_0-9.-]+){2}', strategy):
- return strategy
- elif re.match(r'[a-zA-Z_0-9.-]+', strategy):
- return '/{0}/{1}'.format(self.partition, strategy)
- else:
- raise F5ModuleError(
- "The provided strategy name is invalid!"
- )
-
- @property
- def rules(self):
- if self._values['rules'] is None:
- return None
- # In case rule values are unicode (as they may be coming from the API
- result = [str(x) for x in self._values['rules']]
- return result
-
-
-class SimpleParameters(Parameters):
- api_attributes = [
- 'strategy',
- ]
-
- updatables = [
- 'strategy',
- 'rules',
- ]
-
- returnables = [
- 'strategy',
- 'rules',
- ]
-
-
-class ComplexParameters(Parameters):
- api_attributes = [
- 'strategy',
- 'description',
- ]
-
- updatables = [
- 'strategy',
- 'description',
- 'rules',
- ]
-
- returnables = [
- 'strategy',
- 'description',
- 'rules',
- ]
-
-
-class SimpleChanges(SimpleParameters):
- api_attributes = [
- 'strategy'
- ]
-
- updatables = [
- 'strategy', 'rules'
- ]
-
- returnables = [
- 'strategy', 'rules'
- ]
-
-
-class ComplexChanges(ComplexParameters):
- api_attributes = [
- 'strategy', 'description'
- ]
-
- updatables = [
- 'strategy', 'description', 'rules'
- ]
-
- returnables = [
- 'strategy', 'description', 'rules'
- ]
-
-
-class BaseManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.have = None
- self.want = Parameters(params=self.module.params)
-
- def _announce_deprecations(self):
- warnings = []
- if self.want:
- warnings += self.want._values.get('__deprecated', [])
- if self.have:
- warnings += self.have._values.get('__deprecated', [])
- for warning in warnings:
- self.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def _announce_warnings(self):
- warnings = []
- if self.want:
- warnings += self.want._values.get('__warning', [])
- if self.have:
- warnings += self.have._values.get('__warning', [])
- for warning in warnings:
- self.module.warn(warning['msg'])
-
- def present(self):
- if self.exists():
- return self.update()
- else:
- return self.create()
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def _validate_creation_parameters(self):
- if self.want.strategy is None:
- self.want.update(dict(strategy='first'))
-
- def _get_rule_names(self, rules):
- if 'items' in rules:
- rules['items'].sort(key=lambda x: x['ordinal'])
- result = [x['name'] for x in rules['items']]
- return result
- else:
- return []
-
- def _read_rule_from_device(self, rule_name, draft=False):
- if draft:
- uri = "https://{0}:{1}/mgmt/tm/ltm/policy/{2}/rules/{3}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name, sub_path='Drafts'),
- rule_name
- )
- else:
- uri = "https://{0}:{1}/mgmt/tm/ltm/policy/{2}/rules/{3}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name),
- self.want.name
- )
-
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return response['ordinal']
-
- def _create_rule_on_device(self, rule_name, idx, draft=False):
- params = dict(name=rule_name, ordinal=idx)
- if draft:
- uri = "https://{0}:{1}/mgmt/tm/ltm/policy/{2}/rules/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name, sub_path='Drafts'),
- )
- else:
- uri = "https://{0}:{1}/mgmt/tm/ltm/policy/{2}/rules/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name),
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403, 409]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def _modify_rule_on_device(self, rule_name, idx, draft=False):
- params = dict(ordinal=idx)
- if draft:
- uri = "https://{0}:{1}/mgmt/tm/ltm/policy/{2}/rules/{3}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name, sub_path='Drafts'),
- rule_name
- )
- else:
- uri = "https://{0}:{1}/mgmt/tm/ltm/policy/{2}/rules/{3}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name),
- self.want.name
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == [400, 409]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def _rule_exists_on_device(self, rule_name, draft=False):
- if draft:
- uri = "https://{0}:{1}/mgmt/tm/ltm/policy/{2}/rules/{3}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name, sub_path='Drafts'),
- rule_name
- )
- else:
- uri = "https://{0}:{1}/mgmt/tm/ltm/policy/{2}/rules/{3}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name),
- self.want.name
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def _remove_rule_on_device(self, rule_name, draft=False):
- if draft:
- uri = "https://{0}:{1}/mgmt/tm/ltm/policy/{2}/rules/{3}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name, sub_path='Drafts'),
- rule_name
- )
- else:
- uri = "https://{0}:{1}/mgmt/tm/ltm/policy/{2}/rules/{3}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name),
- self.want.name
- )
- response = self.client.api.delete(uri)
- if response.status == 200:
- return True
- raise F5ModuleError(response.content)
-
- def _upsert_policy_rules_on_device(self, draft=False):
- rules = self.changes.rules
- if rules is None:
- rules = []
- for idx, rule in enumerate(rules):
- if self._rule_exists_on_device(rule, draft):
- ordinal = self._read_rule_from_device(rule, draft)
- if int(ordinal) != idx:
- self._modify_rule_on_device(rule, idx, draft)
- else:
- self._create_rule_on_device(rule, idx, draft)
- self._remove_rule_difference(rules, draft)
-
- def _remove_rule_difference(self, rules, draft=False):
- if not rules or not self.have.rules:
- return
- have_rules = set(self.have.rules)
- want_rules = set(rules)
- removable = have_rules.difference(want_rules)
- for remove in removable:
- self._remove_rule_on_device(remove, draft)
-
-
-class SimpleManager(BaseManager):
- def __init__(self, *args, **kwargs):
- super(SimpleManager, self).__init__(**kwargs)
- self.want = SimpleParameters(params=self.module.params)
- self.have = SimpleParameters()
- self.changes = SimpleChanges()
-
- def _set_changed_options(self):
- changed = {}
- for key in SimpleParameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = SimpleChanges(params=changed)
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = SimpleParameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- changed[k] = change
- if changed:
- self.changes = SimpleChanges(params=changed)
- return True
- return False
-
- def exec_module(self):
- changed = False
- result = dict()
- state = self.want.state
-
- if state == 'draft':
- raise F5ModuleError(
- "The 'draft' status is not available on BIG-IP versions < 12.1.0"
- )
- if state == 'present':
- changed = self.present()
- elif state == 'absent':
- changed = self.absent()
-
- changes = self.changes.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations()
- self._announce_warnings()
- return result
-
- def create(self):
- self._validate_creation_parameters()
- self._set_changed_options()
- if self.module.check_mode:
- return True
- self.create_on_device()
- return True
-
- def update(self):
- self.have = self.read_current_from_device()
- if not self.should_update():
- return False
- if self.module.check_mode:
- return True
- self.update_on_device()
- return True
-
- def absent(self):
- changed = False
- if self.exists():
- changed = self.remove()
- return changed
-
- def remove(self):
- if self.module.check_mode:
- return True
- self.remove_from_device()
- if self.exists():
- raise F5ModuleError("Failed to delete the policy")
- return True
-
- def exists(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/policy/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/policy/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name),
- )
- query = "?expandSubcollections=true"
- resp = self.client.api.get(uri + query)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- rules = self._get_rule_names(response['rulesReference'])
- result = SimpleParameters(params=response)
- result.update(dict(rules=rules))
- return result
-
- def update_on_device(self):
- params = self.changes.api_params()
- if params:
- uri = "https://{0}:{1}/mgmt/tm/ltm/policy/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- self._upsert_policy_rules_on_device()
-
- def create_on_device(self):
- params = self.want.api_params()
- payload = dict(
- name=self.want.name,
- partition=self.want.partition,
- **params
- )
- uri = "https://{0}:{1}/mgmt/tm/ltm/policy/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.post(uri, json=payload)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- self._upsert_policy_rules_on_device()
-
- return True
-
- def remove_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/policy/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- response = self.client.api.delete(uri)
- if response.status == 200:
- return True
- raise F5ModuleError(response.content)
-
-
-class ComplexManager(BaseManager):
- def __init__(self, *args, **kwargs):
- super(ComplexManager, self).__init__(**kwargs)
- self.want = ComplexParameters(params=self.module.params)
- self.have = ComplexParameters()
- self.changes = ComplexChanges()
-
- def _set_changed_options(self):
- changed = {}
- for key in ComplexParameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = ComplexChanges(params=changed)
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = ComplexParameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- changed[k] = change
- if changed:
- self.changes = ComplexChanges(params=changed)
- return True
- return False
-
- def exec_module(self):
- changed = False
- result = dict()
- state = self.want.state
-
- if state in ["present", "draft"]:
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
-
- changes = self.changes.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- return result
-
- def should_update(self):
- result = self._update_changed_options()
- drafted = self.draft_status_changed()
- if any(x is True for x in [result, drafted]):
- return True
- return False
-
- def draft_status_changed(self):
- if self.draft_exists() and self.want.state == 'draft':
- drafted = False
- elif not self.draft_exists() and self.want.state == 'present':
- drafted = False
- else:
- drafted = True
- return drafted
-
- def present(self):
- if self.draft_exists() or self.policy_exists():
- return self.update()
- else:
- return self.create()
-
- def absent(self):
- changed = False
- if self.draft_exists() or self.policy_exists():
- changed = self.remove()
- return changed
-
- def remove(self):
- if self.module.check_mode:
- return True
- self.remove_from_device()
- if self.draft_exists() or self.policy_exists():
- raise F5ModuleError("Failed to delete the policy")
- return True
-
- def create(self):
- self._validate_creation_parameters()
-
- self._set_changed_options()
- if self.module.check_mode:
- return True
-
- if not self.draft_exists():
- self._create_new_policy_draft()
-
- # Because we always need to modify drafts, "creating on the device"
- # is actually identical to just updating.
- self.update_on_device()
-
- if self.want.state == 'draft':
- return True
- else:
- return self.publish()
-
- def update(self):
- self.have = self.read_current_from_device()
- if not self.should_update():
- return False
- if self.module.check_mode:
- return True
-
- if not self.draft_exists():
- self._create_existing_policy_draft()
-
- if self._update_changed_options():
- self.update_on_device()
-
- if self.want.state == 'draft':
- return True
- else:
- return self.publish()
-
- def draft_exists(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/policy/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name, sub_path='Drafts')
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def policy_exists(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/policy/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def _create_existing_policy_draft(self):
- params = dict(createDraft=True)
- uri = "https://{0}:{1}/mgmt/tm/ltm/policy/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return True
-
- def _create_new_policy_draft(self):
- params = self.want.api_params()
- payload = dict(
- name=self.want.name,
- partition=self.want.partition,
- subPath='Drafts',
- **params
- )
- uri = "https://{0}:{1}/mgmt/tm/ltm/policy/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.post(uri, json=payload)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return True
-
- def update_on_device(self):
- params = self.changes.api_params()
- if params:
- uri = "https://{0}:{1}/mgmt/tm/ltm/policy/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name, sub_path='Drafts'),
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- self._upsert_policy_rules_on_device(draft=True)
-
- def read_current_from_device(self):
- if self.draft_exists():
- uri = "https://{0}:{1}/mgmt/tm/ltm/policy/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name, sub_path='Drafts'),
- )
- else:
- uri = "https://{0}:{1}/mgmt/tm/ltm/policy/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- query = "?expandSubcollections=true"
- resp = self.client.api.get(uri + query)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- rules = self._get_rule_names(response['rulesReference'])
- result = ComplexParameters(params=response)
- result.update(dict(rules=rules))
- return result
-
- def publish(self):
- params = dict(
- name=fq_name(self.want.partition,
- self.want.name,
- sub_path='Drafts'
- ),
- command="publish"
-
- )
- uri = "https://{0}:{1}/mgmt/tm/ltm/policy/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return True
-
- def remove_policy_draft_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/policy/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name, sub_path='Drafts'),
- )
- response = self.client.api.delete(uri)
-
- if response.status == 200:
- return True
- raise F5ModuleError(response.content)
-
- def remove_policy_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/policy/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name),
- )
- response = self.client.api.delete(uri)
-
- if response.status == 200:
- return True
- raise F5ModuleError(response.content)
-
- def remove_from_device(self):
- if self.draft_exists():
- self.remove_policy_draft_from_device()
- if self.policy_exists():
- self.remove_policy_from_device()
- return True
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
- @property
- def rules(self):
- if self.want.rules != self.have.rules:
- return self.want.rules
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.kwargs = kwargs
-
- def exec_module(self):
- if self.version_is_less_than_12():
- manager = self.get_manager('simple')
- else:
- manager = self.get_manager('complex')
- return manager.exec_module()
-
- def get_manager(self, type):
- if type == 'simple':
- return SimpleManager(**self.kwargs)
- elif type == 'complex':
- return ComplexManager(**self.kwargs)
-
- def version_is_less_than_12(self):
- version = tmos_version(self.client)
- if LooseVersion(version) < LooseVersion('12.1.0'):
- return True
- else:
- return False
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- name=dict(
- required=True
- ),
- description=dict(),
- rules=dict(type='list'),
- strategy=dict(
- choices=['first', 'all', 'best']
- ),
- state=dict(
- default='present',
- choices=['absent', 'present', 'draft']
- ),
- partition=dict(
- default='Common',
- fallback=(env_fallback, ['F5_PARTITION'])
- )
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_policy_rule.py b/lib/ansible/modules/network/f5/bigip_policy_rule.py
deleted file mode 100644
index 09ebfa53d0..0000000000
--- a/lib/ansible/modules/network/f5/bigip_policy_rule.py
+++ /dev/null
@@ -1,1068 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_policy_rule
-short_description: Manage LTM policy rules on a BIG-IP
-description:
- - This module will manage LTM policy rules on a BIG-IP.
-version_added: 2.5
-options:
- description:
- description:
- - Description of the policy rule.
- type: str
- actions:
- description:
- - The actions that you want the policy rule to perform.
- - The available attributes vary by the action, however, each action requires that
- a C(type) be specified.
- - These conditions can be specified in any order. Despite them being a list, the
- BIG-IP does not treat their order as anything special.
- suboptions:
- type:
- description:
- - The action type. This value controls what below options are required.
- - When C(type) is C(forward), will associate a given C(pool), or C(virtual)
- with this rule.
- - When C(type) is C(enable), will associate a given C(asm_policy) with
- this rule.
- - When C(type) is C(ignore), will remove all existing actions from this
- rule.
- - When C(type) is C(redirect), will redirect an HTTP request to a different URL.
- type: str
- required: true
- choices:
- - forward
- - enable
- - ignore
- - redirect
- pool:
- description:
- - Pool that you want to forward traffic to.
- - This parameter is only valid with the C(forward) type.
- type: str
- virtual:
- description:
- - Virtual Server that you want to forward traffic to.
- - This parameter is only valid with the C(forward) type.
- type: str
- asm_policy:
- description:
- - ASM policy to enable.
- - This parameter is only valid with the C(enable) type.
- type: str
- location:
- description:
- - The new URL for which a redirect response will be sent.
- - A Tcl command substitution can be used for this field.
- type: str
- type: list
- policy:
- description:
- - The name of the policy that you want to associate this rule with.
- type: str
- required: True
- name:
- description:
- - The name of the rule.
- type: str
- required: True
- conditions:
- description:
- - A list of attributes that describe the condition.
- - See suboptions for details on how to construct each list entry.
- - The ordering of this list is important, the module will ensure the order is
- kept when modifying the task.
- - The suboption options listed below are not required for all condition types,
- read the description for more details.
- - These conditions can be specified in any order. Despite them being a list, the
- BIG-IP does not treat their order as anything special.
- suboptions:
- type:
- description:
- - The condition type. This value controls what below options are required.
- - When C(type) is C(http_uri), will associate a given C(path_begins_with_any)
- list of strings with which the HTTP URI should begin with. Any item in the
- list will provide a match.
- - When C(type) is C(all_traffic), will remove all existing conditions from
- this rule.
- type: str
- required: True
- choices:
- - http_uri
- - all_traffic
- - http_host
- path_begins_with_any:
- description:
- - A list of strings of characters that the HTTP URI should start with.
- - This parameter is only valid with the C(http_uri) type.
- type: str
- host_is_any:
- description:
- - A list of strings of characters that the HTTP Host should match.
- - This parameter is only valid with the C(http_host) type.
- type: str
- host_begins_with_any:
- description:
- - A list of strings of characters that the HTTP Host should start with.
- - This parameter is only valid with the C(http_host) type.
- type: str
- type: list
- state:
- description:
- - When C(present), ensures that the key is uploaded to the device. When
- C(absent), ensures that the key is removed from the device. If the key
- is currently in use, the module will not be able to remove the key.
- type: str
- choices:
- - present
- - absent
- default: present
- partition:
- description:
- - Device partition to manage resources on.
- type: str
- default: Common
-extends_documentation_fragment: f5
-requirements:
- - BIG-IP >= v12.1.0
-author:
- - Tim Rupp (@caphrim007)
- - Wojciech Wypior (@wojtek0806)
-'''
-
-EXAMPLES = r'''
-- name: Create policies
- bigip_policy:
- name: Policy-Foo
- state: present
- provider:
- server: lb.mydomain.com
- user: admin
- password: secret
- delegate_to: localhost
-
-- name: Add a rule to the new policy
- bigip_policy_rule:
- policy: Policy-Foo
- name: rule3
- conditions:
- - type: http_uri
- path_begins_with_any: /ABC
- actions:
- - type: forward
- pool: pool-svrs
- provider:
- server: lb.mydomain.com
- user: admin
- password: secret
- delegate_to: localhost
-
-- name: Add multiple rules to the new policy
- bigip_policy_rule:
- policy: Policy-Foo
- name: "{{ item.name }}"
- conditions: "{{ item.conditions }}"
- actions: "{{ item.actions }}"
- provider:
- server: lb.mydomain.com
- user: admin
- password: secret
- delegate_to: localhost
- loop:
- - name: rule1
- actions:
- - type: forward
- pool: pool-svrs
- conditions:
- - type: http_uri
- path_starts_with: /euro
- - name: rule2
- actions:
- - type: forward
- pool: pool-svrs
- conditions:
- - type: http_uri
- path_starts_with: /HomePage/
-
-- name: Remove all rules and conditions from the rule
- bigip_policy_rule:
- policy: Policy-Foo
- name: rule1
- conditions:
- - type: all_traffic
- actions:
- - type: ignore
- provider:
- server: lb.mydomain.com
- user: admin
- password: secret
- delegate_to: localhost
-'''
-
-RETURN = r'''
-actions:
- description: The new list of actions applied to the rule
- returned: changed
- type: complex
- contains:
- type:
- description: The action type
- returned: changed
- type: str
- sample: forward
- pool:
- description: Pool for forward to
- returned: changed
- type: str
- sample: foo-pool
- sample: hash/dictionary of values
-conditions:
- description: The new list of conditions applied to the rule.
- returned: changed
- type: complex
- contains:
- type:
- description: The condition type.
- returned: changed
- type: str
- sample: http_uri
- path_begins_with_any:
- description: List of strings that the URI begins with.
- returned: changed
- type: list
- sample: [foo, bar]
- sample: hash/dictionary of values
-description:
- description: The new description of the rule.
- returned: changed
- type: str
- sample: My rule
-'''
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.basic import env_fallback
-from ansible.module_utils.six import iteritems
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import fq_name
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.common import transform_name
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import fq_name
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.common import transform_name
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'actionsReference': 'actions',
- 'conditionsReference': 'conditions',
- }
- api_attributes = [
- 'description',
- 'actions',
- 'conditions',
- ]
-
- updatables = [
- 'actions',
- 'conditions',
- 'description',
- ]
-
- returnable = [
- 'description',
- ]
-
- @property
- def name(self):
- return self._values.get('name', None)
-
- @property
- def description(self):
- return self._values.get('description', None)
-
- @property
- def policy(self):
- if self._values['policy'] is None:
- return None
- return self._values['policy']
-
-
-class ApiParameters(Parameters):
- def _remove_internal_keywords(self, resource):
- items = [
- 'kind', 'generation', 'selfLink', 'poolReference', 'offset',
- ]
- for item in items:
- try:
- del resource[item]
- except KeyError:
- pass
-
- @property
- def actions(self):
- result = []
- if self._values['actions'] is None or 'items' not in self._values['actions']:
- return [dict(type='ignore')]
- for item in self._values['actions']['items']:
- action = dict()
- self._remove_internal_keywords(item)
- if 'forward' in item:
- action.update(item)
- action['type'] = 'forward'
- del action['forward']
- elif 'enable' in item:
- action.update(item)
- action['type'] = 'enable'
- del action['enable']
- elif 'redirect' in item:
- action.update(item)
- action['type'] = 'redirect'
- del action['redirect']
- result.append(action)
- result = sorted(result, key=lambda x: x['name'])
- return result
-
- @property
- def conditions(self):
- result = []
- if self._values['conditions'] is None or 'items' not in self._values['conditions']:
- return [dict(type='all_traffic')]
- for item in self._values['conditions']['items']:
- action = dict()
- self._remove_internal_keywords(item)
- if 'httpUri' in item:
- action.update(item)
- action['type'] = 'http_uri'
- del action['httpUri']
-
- # Converts to common stringiness
- #
- # The tuple set "issubset" check that happens in the Difference
- # engine does not recognize that a u'foo' and 'foo' are equal "enough"
- # to consider them a subset. Therefore, we cast everything here to
- # whatever the common stringiness is.
- if 'values' in action:
- action['values'] = [str(x) for x in action['values']]
- elif 'httpHost' in item:
- action.update(item)
- action['type'] = 'http_host'
- if 'values' in action:
- action['values'] = [str(x) for x in action['values']]
- result.append(action)
- # Names contains the index in which the rule is at.
- result = sorted(result, key=lambda x: x['name'])
- return result
-
-
-class ModuleParameters(Parameters):
- @property
- def actions(self):
- result = []
- if self._values['actions'] is None:
- return None
- for idx, item in enumerate(self._values['actions']):
- action = dict()
- if 'name' in item:
- action['name'] = str(item['name'])
- else:
- action['name'] = str(idx)
- if item['type'] == 'forward':
- self._handle_forward_action(action, item)
- elif item['type'] == 'enable':
- self._handle_enable_action(action, item)
- elif item['type'] == 'ignore':
- return [dict(type='ignore')]
- elif item['type'] == 'redirect':
- self._handle_redirect_action(action, item)
- result.append(action)
- result = sorted(result, key=lambda x: x['name'])
- return result
-
- @property
- def conditions(self):
- result = []
- if self._values['conditions'] is None:
- return None
- for idx, item in enumerate(self._values['conditions']):
- action = dict()
- if 'name' in item:
- action['name'] = str(item['name'])
- else:
- action['name'] = str(idx)
- if item['type'] == 'http_uri':
- self._handle_http_uri_condition(action, item)
- elif item['type'] == 'http_host':
- self._handle_http_host_condition(action, item)
- elif item['type'] == 'all_traffic':
- return [dict(type='all_traffic')]
- result.append(action)
- result = sorted(result, key=lambda x: x['name'])
- return result
-
- def _handle_http_host_condition(self, action, item):
- action['type'] = 'http_host'
- if 'host_begins_with_any' in item:
- if isinstance(item['host_begins_with_any'], list):
- values = item['host_begins_with_any']
- else:
- values = [item['host_begins_with_any']]
- action.update(dict(
- host=True,
- startsWith=True,
- values=values
- ))
- elif 'host_is_any' in item:
- if isinstance(item['host_is_any'], list):
- values = item['host_is_any']
- else:
- values = [item['host_is_any']]
- action.update(dict(
- equals=True,
- host=True,
- values=values
- ))
-
- def _handle_http_uri_condition(self, action, item):
- """Handle the nuances of the forwarding type
-
- Right now there is only a single type of forwarding that can be done. As that
- functionality expands, so-to will the behavior of this, and other, methods.
- Therefore, do not be surprised that the logic here is so rigid. It's deliberate.
-
- :param action:
- :param item:
- :return:
- """
- action['type'] = 'http_uri'
- if 'path_begins_with_any' not in item:
- raise F5ModuleError(
- "A 'path_begins_with_any' must be specified when the 'http_uri' type is used."
- )
- if isinstance(item['path_begins_with_any'], list):
- values = item['path_begins_with_any']
- else:
- values = [item['path_begins_with_any']]
- action.update(dict(
- path=True,
- startsWith=True,
- values=values
- ))
-
- def _handle_forward_action(self, action, item):
- """Handle the nuances of the forwarding type
-
- Right now there is only a single type of forwarding that can be done. As that
- functionality expands, so-to will the behavior of this, and other, methods.
- Therefore, do not be surprised that the logic here is so rigid. It's deliberate.
-
- :param action:
- :param item:
- :return:
- """
- action['type'] = 'forward'
- if not any(x for x in ['pool', 'virtual'] if x in item):
- raise F5ModuleError(
- "A 'pool' or 'virtual' must be specified when the 'forward' type is used."
- )
- if item.get('pool', None):
- action['pool'] = fq_name(self.partition, item['pool'])
- elif item.get('virtual', None):
- action['virtual'] = fq_name(self.partition, item['virtual'])
-
- def _handle_enable_action(self, action, item):
- """Handle the nuances of the enable type
-
- :param action:
- :param item:
- :return:
- """
- action['type'] = 'enable'
- if 'asm_policy' not in item:
- raise F5ModuleError(
- "An 'asm_policy' must be specified when the 'enable' type is used."
- )
- action.update(dict(
- policy=fq_name(self.partition, item['asm_policy']),
- asm=True
- ))
-
- def _handle_redirect_action(self, action, item):
- """Handle the nuances of the redirect type
-
- :param action:
- :param item:
- :return:
- """
- action['type'] = 'redirect'
- if 'location' not in item:
- raise F5ModuleError(
- "A 'location' must be specified when the 'redirect' type is used."
- )
- action.update(
- location=item['location'],
- httpReply=True,
- )
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class ReportableChanges(Changes):
- returnables = [
- 'description', 'actions', 'conditions'
- ]
-
- @property
- def actions(self):
- result = []
- if self._values['actions'] is None:
- return [dict(type='ignore')]
- for item in self._values['actions']:
- action = dict()
- if 'forward' in item:
- action.update(item)
- action['type'] = 'forward'
- del action['forward']
- elif 'enable' in item:
- action.update(item)
- action['type'] = 'enable'
- del action['enable']
- elif 'redirect' in item:
- action.update(item)
- action['type'] = 'redirect'
- del action['redirect']
- del action['httpReply']
- result.append(action)
- result = sorted(result, key=lambda x: x['name'])
- return result
-
- @property
- def conditions(self):
- result = []
- if self._values['conditions'] is None:
- return [dict(type='all_traffic')]
- for item in self._values['conditions']:
- action = dict()
- if 'httpUri' in item:
- action.update(item)
- action['type'] = 'http_uri'
- del action['httpUri']
- elif 'httpHost' in item:
- action.update(item)
- action['type'] = 'http_host'
- del action['httpHost']
- result.append(action)
- # Names contains the index in which the rule is at.
- result = sorted(result, key=lambda x: x['name'])
- return result
-
-
-class UsableChanges(Changes):
- @property
- def actions(self):
- if self._values['actions'] is None:
- return None
- result = []
- for action in self._values['actions']:
- if 'type' not in action:
- continue
- if action['type'] == 'forward':
- action['forward'] = True
- del action['type']
- elif action['type'] == 'enable':
- action['enable'] = True
- del action['type']
- elif action['type'] == 'ignore':
- result = []
- break
- elif action['type'] == 'redirect':
- action['httpReply'] = True
- action['redirect'] = True
- del action['type']
- result.append(action)
- return result
-
- @property
- def conditions(self):
- if self._values['conditions'] is None:
- return None
- result = []
- for condition in self._values['conditions']:
- if 'type' not in condition:
- continue
- if condition['type'] == 'http_uri':
- condition['httpUri'] = True
- del condition['type']
- elif condition['type'] == 'http_host':
- condition['httpHost'] = True
- del condition['type']
- elif condition['type'] == 'all_traffic':
- result = []
- break
- result.append(condition)
- return result
-
-
-class Difference(object):
- updatables = [
- 'actions', 'conditions', 'description'
- ]
-
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
- def to_tuple(self, items):
- result = []
- for x in items:
- tmp = [(str(k), str(v)) for k, v in iteritems(x)]
- result += tmp
- return result
-
- def _diff_complex_items(self, want, have):
- if want == [] and have is None:
- return None
- if want is None:
- return None
- w = self.to_tuple(want)
- h = self.to_tuple(have)
- if set(w).issubset(set(h)):
- return None
- else:
- return want
-
- @property
- def actions(self):
- result = self._diff_complex_items(self.want.actions, self.have.actions)
- if self._conditions_missing_default_rule_for_asm(result):
- raise F5ModuleError(
- "The 'all_traffic' condition is required when using an ASM policy in a rule's 'enable' action."
- )
- return result
-
- @property
- def conditions(self):
- result = self._diff_complex_items(self.want.conditions, self.have.conditions)
- return result
-
- def _conditions_missing_default_rule_for_asm(self, want_actions):
- if want_actions is None:
- actions = self.have.actions
- else:
- actions = want_actions
- if actions is None:
- return False
- if any(x for x in actions if x['type'] == 'enable'):
- conditions = self._diff_complex_items(self.want.conditions, self.have.conditions)
- if conditions is None:
- return False
- if any(y for y in conditions if y['type'] != 'all_traffic'):
- return True
- return False
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(params=self.module.params)
- self.have = ApiParameters()
- self.changes = UsableChanges()
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def exec_module(self):
- changed = False
- result = dict()
- state = self.want.state
-
- if state == "present":
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def present(self):
- if self.exists():
- return self.update()
- else:
- return self.create()
-
- def absent(self):
- if self.exists():
- return self.remove()
- return False
-
- def update(self):
- self.have = self.read_current_from_device()
- if not self.should_update():
- return False
- if self.module.check_mode:
- return True
- if self.draft_exists():
- redraft = True
- else:
- redraft = False
- self._create_existing_policy_draft_on_device()
- self.update_on_device()
- if redraft is False:
- self.publish_on_device()
- return True
-
- def remove(self):
- if self.module.check_mode:
- return True
- if self.draft_exists():
- redraft = True
- else:
- redraft = False
- self._create_existing_policy_draft_on_device()
- self.remove_from_device()
- if self.exists():
- raise F5ModuleError("Failed to delete the resource.")
- if redraft is False:
- self.publish_on_device()
- return True
-
- def create(self):
- self.should_update()
- if self.module.check_mode:
- return True
- if self.draft_exists():
- redraft = True
- else:
- redraft = False
- self._create_existing_policy_draft_on_device()
- self.create_on_device()
- if redraft is False:
- self.publish_on_device()
- return True
-
- def exists(self):
- if self.draft_exists():
- uri = "https://{0}:{1}/mgmt/tm/ltm/policy/{2}/rules/{3}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.policy, sub_path='Drafts'),
- self.want.name
- )
- else:
- uri = "https://{0}:{1}/mgmt/tm/ltm/policy/{2}/rules/{3}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.policy),
- self.want.name
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def draft_exists(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/policy/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.policy, sub_path='Drafts')
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def _create_existing_policy_draft_on_device(self):
- params = dict(createDraft=True)
- uri = "https://{0}:{1}/mgmt/tm/ltm/policy/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.policy)
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return True
-
- def publish_on_device(self):
- params = dict(
- name=fq_name(self.want.partition,
- self.want.policy,
- sub_path='Drafts'
- ),
- command="publish"
-
- )
- uri = "https://{0}:{1}/mgmt/tm/ltm/policy/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return True
-
- def create_on_device(self):
- params = self.changes.api_params()
- params['name'] = self.want.name
- uri = "https://{0}:{1}/mgmt/tm/ltm/policy/{2}/rules/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.policy, sub_path='Drafts'),
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return response['selfLink']
-
- def update_on_device(self):
- params = self.changes.api_params()
- uri = "https://{0}:{1}/mgmt/tm/ltm/policy/{2}/rules/{3}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.policy, sub_path='Drafts'),
- self.want.name
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def remove_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/policy/{2}/rules/{3}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.policy, sub_path='Drafts'),
- self.want.name
- )
- response = self.client.api.delete(uri)
- if response.status == 200:
- return True
- raise F5ModuleError(response.content)
-
- def read_current_from_device(self):
- if self.draft_exists():
- uri = "https://{0}:{1}/mgmt/tm/ltm/policy/{2}/rules/{3}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.policy, sub_path='Drafts'),
- self.want.name
- )
- else:
- uri = "https://{0}:{1}/mgmt/tm/ltm/policy/{2}/rules/{3}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.policy),
- self.want.name
- )
- query = "?expandSubcollections=true"
- resp = self.client.api.get(uri + query)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return ApiParameters(params=response)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- description=dict(),
- actions=dict(
- type='list',
- elements='dict',
- options=dict(
- type=dict(
- choices=[
- 'forward',
- 'enable',
- 'ignore',
- 'redirect',
- ],
- required=True
- ),
- pool=dict(),
- asm_policy=dict(),
- virtual=dict(),
- location=dict(),
- ),
- mutually_exclusive=[
- ['pool', 'asm_policy', 'virtual', 'location']
- ]
- ),
- conditions=dict(
- type='list',
- options=dict(
- type=dict(
- choices=[
- 'http_uri',
- 'http_host',
- 'all_traffic'
- ],
- required=True
- ),
- path_begins_with_any=dict(),
- host_begins_with_any=dict(),
- host_is_any=dict()
- ),
- ),
- name=dict(required=True),
- policy=dict(required=True),
- state=dict(
- default='present',
- choices=['absent', 'present']
- ),
- partition=dict(
- default='Common',
- fallback=(env_fallback, ['F5_PARTITION'])
- )
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_pool.py b/lib/ansible/modules/network/f5/bigip_pool.py
deleted file mode 100644
index 8772d785d5..0000000000
--- a/lib/ansible/modules/network/f5/bigip_pool.py
+++ /dev/null
@@ -1,1276 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_pool
-short_description: Manages F5 BIG-IP LTM pools
-description:
- - Manages F5 BIG-IP LTM pools via iControl REST API.
-version_added: 1.2
-options:
- description:
- description:
- - Specifies descriptive text that identifies the pool.
- type: str
- version_added: 2.3
- name:
- description:
- - Pool name
- type: str
- required: True
- aliases:
- - pool
- lb_method:
- description:
- - Load balancing method. When creating a new pool, if this value is not
- specified, the default of C(round-robin) will be used.
- type: str
- version_added: 1.3
- choices:
- - dynamic-ratio-member
- - dynamic-ratio-node
- - fastest-app-response
- - fastest-node
- - least-connections-member
- - least-connections-node
- - least-sessions
- - observed-member
- - observed-node
- - predictive-member
- - predictive-node
- - ratio-least-connections-member
- - ratio-least-connections-node
- - ratio-member
- - ratio-node
- - ratio-session
- - round-robin
- - weighted-least-connections-member
- - weighted-least-connections-node
- monitor_type:
- description:
- - Monitor rule type when C(monitors) is specified.
- - When creating a new pool, if this value is not specified, the default
- of 'and_list' will be used.
- - When C(single) ensures that all specified monitors are checked, but
- additionally includes checks to make sure you only specified a single
- monitor.
- - When C(and_list) ensures that B(all) monitors are checked.
- - When C(m_of_n) ensures that C(quorum) of C(monitors) are checked. C(m_of_n)
- B(requires) that a C(quorum) of 1 or greater be set either in the playbook,
- or already existing on the device.
- - Both C(single) and C(and_list) are functionally identical since BIG-IP
- considers all monitors as "a list".
- type: str
- choices:
- - and_list
- - m_of_n
- - single
- version_added: 1.3
- quorum:
- description:
- - Monitor quorum value when C(monitor_type) is C(m_of_n).
- - Quorum must be a value of 1 or greater when C(monitor_type) is C(m_of_n).
- type: int
- version_added: 1.3
- monitors:
- description:
- - Monitor template name list. If the partition is not provided as part of
- the monitor name, then the C(partition) option will be used instead.
- type: list
- version_added: 1.3
- slow_ramp_time:
- description:
- - Sets the ramp-up time (in seconds) to gradually ramp up the load on
- newly added or freshly detected up pool members.
- type: int
- version_added: 1.3
- reselect_tries:
- description:
- - Sets the number of times the system tries to contact a pool member
- after a passive failure.
- type: int
- version_added: 2.2
- service_down_action:
- description:
- - Sets the action to take when node goes down in pool.
- type: str
- choices:
- - none
- - reset
- - drop
- - reselect
- version_added: 1.3
- partition:
- description:
- - Device partition to manage resources on.
- type: str
- default: Common
- version_added: 2.5
- state:
- description:
- - When C(present), guarantees that the pool exists with the provided
- attributes.
- - When C(absent), removes the pool from the system.
- type: str
- choices:
- - absent
- - present
- default: present
- version_added: 2.5
- metadata:
- description:
- - Arbitrary key/value pairs that you can attach to a pool. This is useful in
- situations where you might want to annotate a pool to me managed by Ansible.
- - Key names will be stored as strings; this includes names that are numbers.
- - Values for all of the keys will be stored as strings; this includes values
- that are numbers.
- - Data will be persisted, not ephemeral.
- type: raw
- version_added: 2.5
- priority_group_activation:
- description:
- - Specifies whether the system load balances traffic according to the priority
- number assigned to the pool member.
- - When creating a new pool, if this parameter is not specified, the default of
- C(0) will be used.
- - To disable this setting, provide the value C(0).
- - Once you enable this setting, you can specify pool member priority when you
- create a new pool or on a pool member's properties screen.
- - The system treats same-priority pool members as a group.
- - To enable priority group activation, provide a number from C(0) to C(65535)
- that represents the minimum number of members that must be available in one
- priority group before the system directs traffic to members in a lower
- priority group.
- - When a sufficient number of members become available in the higher priority
- group, the system again directs traffic to the higher priority group.
- type: int
- aliases:
- - minimum_active_members
- version_added: 2.6
- aggregate:
- description:
- - List of pool definitions to be created, modified or removed.
- - When using C(aggregates) if one of the aggregate definitions is invalid, the aggregate run will fail,
- indicating the error it last encountered.
- - The module will C(NOT) rollback any changes it has made prior to encountering the error.
- - The module also will not indicate what changes were made prior to failure, therefore it is strongly advised
- to run the module in check mode to make basic validation, prior to module execution.
- type: list
- aliases:
- - pools
- version_added: 2.8
- replace_all_with:
- description:
- - Remove pools not defined in the C(aggregate) parameter.
- - This operation is all or none, meaning that it will stop if there are some pools
- that cannot be removed.
- type: bool
- default: no
- aliases:
- - purge
- version_added: 2.8
-notes:
- - To add members to a pool, use the C(bigip_pool_member) module. Previously, the
- C(bigip_pool) module allowed the management of members, but this has been removed
- in version 2.5 of Ansible.
-extends_documentation_fragment: f5
-author:
- - Tim Rupp (@caphrim007)
- - Wojciech Wypior (@wojtek0806)
-'''
-
-EXAMPLES = r'''
-- name: Create pool
- bigip_pool:
- state: present
- name: my-pool
- partition: Common
- lb_method: least-connections-member
- slow_ramp_time: 120
- provider:
- server: lb.mydomain.com
- user: admin
- password: secret
- delegate_to: localhost
-
-- name: Modify load balancer method
- bigip_pool:
- state: present
- name: my-pool
- partition: Common
- lb_method: round-robin
- provider:
- server: lb.mydomain.com
- user: admin
- password: secret
- delegate_to: localhost
-
-- name: Set a single monitor (with enforcement)
- bigip_pool:
- state: present
- name: my-pool
- partition: Common
- monitor_type: single
- monitors:
- - http
- provider:
- server: lb.mydomain.com
- user: admin
- password: secret
- delegate_to: localhost
-
-- name: Set a single monitor (without enforcement)
- bigip_pool:
- state: present
- name: my-pool
- partition: Common
- monitors:
- - http
- provider:
- server: lb.mydomain.com
- user: admin
- password: secret
- delegate_to: localhost
-
-- name: Set multiple monitors (all must succeed)
- bigip_pool:
- state: present
- name: my-pool
- partition: Common
- monitor_type: and_list
- monitors:
- - http
- - tcp
- provider:
- server: lb.mydomain.com
- user: admin
- password: secret
- delegate_to: localhost
-
-- name: Set multiple monitors (at least 1 must succeed)
- bigip_pool:
- state: present
- name: my-pool
- partition: Common
- monitor_type: m_of_n
- quorum: 1
- monitors:
- - http
- - tcp
- provider:
- server: lb.mydomain.com
- user: admin
- password: secret
- delegate_to: localhost
-
-- name: Delete pool
- bigip_pool:
- state: absent
- name: my-pool
- partition: Common
- provider:
- server: lb.mydomain.com
- user: admin
- password: secret
- delegate_to: localhost
-
-- name: Add metadata to pool
- bigip_pool:
- state: present
- name: my-pool
- partition: Common
- metadata:
- ansible: 2.4
- updated_at: 2017-12-20T17:50:46Z
- provider:
- server: lb.mydomain.com
- user: admin
- password: secret
- delegate_to: localhost
-
-- name: Add pools Aggregate
- bigip_pool:
- aggregate:
- - name: my-pool
- partition: Common
- lb_method: least-connections-member
- slow_ramp_time: 120
- - name: my-pool2
- partition: Common
- lb_method: least-sessions
- slow_ramp_time: 120
- - name: my-pool3
- partition: Common
- lb_method: round-robin
- slow_ramp_time: 120
- provider:
- server: lb.mydomain.com
- user: admin
- password: secret
- delegate_to: localhost
-
-- name: Add pools Aggregate, purge others
- bigip_pool:
- aggregate:
- - name: my-pool
- partition: Common
- lb_method: least-connections-member
- slow_ramp_time: 120
- - name: my-pool2
- partition: Common
- lb_method: least-sessions
- slow_ramp_time: 120
- - name: my-pool3
- partition: Common
- lb_method: round-robin
- slow_ramp_time: 120
- replace_all_with: yes
- provider:
- server: lb.mydomain.com
- user: admin
- password: secret
- delegate_to: localhost
-'''
-
-RETURN = r'''
-monitor_type:
- description: The contact that was set on the datacenter.
- returned: changed
- type: str
- sample: admin@root.local
-quorum:
- description: The quorum that was set on the pool.
- returned: changed
- type: int
- sample: 2
-monitors:
- description: Monitors set on the pool.
- returned: changed
- type: list
- sample: ['/Common/http', '/Common/gateway_icmp']
-service_down_action:
- description: Service down action that is set on the pool.
- returned: changed
- type: str
- sample: reset
-description:
- description: Description set on the pool.
- returned: changed
- type: str
- sample: Pool of web servers
-lb_method:
- description: The LB method set for the pool.
- returned: changed
- type: str
- sample: round-robin
-slow_ramp_time:
- description: The new value that is set for the slow ramp-up time.
- returned: changed
- type: int
- sample: 500
-reselect_tries:
- description: The new value that is set for the number of tries to contact member.
- returned: changed
- type: int
- sample: 10
-metadata:
- description: The new value of the pool.
- returned: changed
- type: dict
- sample: {'key1': 'foo', 'key2': 'bar'}
-priority_group_activation:
- description: The new minimum number of members to activate the priority group.
- returned: changed
- type: int
- sample: 10
-replace_all_with:
- description: Purges all non-aggregate pools from device
- returned: changed
- type: bool
- sample: yes
-'''
-
-import re
-
-from copy import deepcopy
-
-from ansible.module_utils.urls import urlparse
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.basic import env_fallback
-from ansible.module_utils.six import iteritems
-from ansible.module_utils.network.common.utils import remove_default_spec
-
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import fq_name
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.common import transform_name
- from library.module_utils.network.f5.compare import cmp_str_with_none
- from library.module_utils.network.f5.icontrol import TransactionContextManager
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import fq_name
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.common import transform_name
- from ansible.module_utils.network.f5.compare import cmp_str_with_none
- from ansible.module_utils.network.f5.icontrol import TransactionContextManager
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'loadBalancingMode': 'lb_method',
- 'slowRampTime': 'slow_ramp_time',
- 'reselectTries': 'reselect_tries',
- 'serviceDownAction': 'service_down_action',
- 'monitor': 'monitors',
- 'minActiveMembers': 'priority_group_activation',
- }
-
- api_attributes = [
- 'description',
- 'name',
- 'loadBalancingMode',
- 'monitor',
- 'slowRampTime',
- 'reselectTries',
- 'serviceDownAction',
- 'metadata',
- 'minActiveMembers',
- ]
-
- returnables = [
- 'monitor_type',
- 'quorum',
- 'monitors',
- 'service_down_action',
- 'description',
- 'lb_method',
- 'slow_ramp_time',
- 'reselect_tries',
- 'monitor',
- 'name',
- 'partition',
- 'metadata',
- 'priority_group_activation',
- ]
-
- updatables = [
- 'monitor_type',
- 'quorum',
- 'monitors',
- 'service_down_action',
- 'description',
- 'lb_method',
- 'slow_ramp_time',
- 'reselect_tries',
- 'metadata',
- 'priority_group_activation',
- ]
-
- @property
- def lb_method(self):
- lb_method = self._values['lb_method']
- if lb_method is None:
- return None
-
- spec = ArgumentSpec()
- if lb_method not in spec.lb_choice:
- raise F5ModuleError('Provided lb_method is unknown')
- return lb_method
-
- def _verify_quorum_type(self, quorum):
- try:
- if quorum is None:
- return None
- return int(quorum)
- except ValueError:
- raise F5ModuleError(
- "The specified 'quorum' must be an integer."
- )
-
- @property
- def monitors(self):
- if self._values['monitors'] is None:
- return None
- monitors = [fq_name(self.partition, x) for x in self.monitors_list]
- if self.monitor_type == 'm_of_n':
- monitors = ' '.join(monitors)
- result = 'min %s of { %s }' % (self.quorum, monitors)
- else:
- result = ' and '.join(monitors).strip()
- return result
-
- @property
- def priority_group_activation(self):
- if self._values['priority_group_activation'] is None:
- return None
- return int(self._values['priority_group_activation'])
-
-
-class ApiParameters(Parameters):
- @property
- def description(self):
- if self._values['description'] in [None, 'none']:
- return None
- return self._values['description']
-
- @property
- def quorum(self):
- if self._values['monitors'] is None:
- return None
- pattern = r'min\s+(?P<quorum>\d+)\s+of'
- matches = re.search(pattern, self._values['monitors'])
- if matches:
- quorum = matches.group('quorum')
- else:
- quorum = None
- result = self._verify_quorum_type(quorum)
- return result
-
- @property
- def monitor_type(self):
- if self._values['monitors'] is None:
- return None
- pattern = r'min\s+\d+\s+of'
- matches = re.search(pattern, self._values['monitors'])
- if matches:
- return 'm_of_n'
- else:
- return 'and_list'
-
- @property
- def monitors_list(self):
- if self._values['monitors'] is None:
- return []
- try:
- result = re.findall(r'/[\w-]+/[^\s}]+', self._values['monitors'])
- return result
- except Exception:
- return self._values['monitors']
-
- @property
- def metadata(self):
- if self._values['metadata'] is None:
- return None
- result = []
- for md in self._values['metadata']:
- tmp = dict(name=str(md['name']))
- if 'value' in md:
- tmp['value'] = str(md['value'])
- else:
- tmp['value'] = ''
- result.append(tmp)
- return result
-
-
-class ModuleParameters(Parameters):
- @property
- def description(self):
- if self._values['description'] is None:
- return None
- elif self._values['description'] in ['none', '']:
- return ''
- return self._values['description']
-
- @property
- def monitors_list(self):
- if self._values['monitors'] is None:
- return []
- return self._values['monitors']
-
- @property
- def quorum(self):
- if self._values['quorum'] is None:
- return None
- result = self._verify_quorum_type(self._values['quorum'])
- return result
-
- @property
- def monitor_type(self):
- if self._values['monitor_type'] is None:
- return None
- return self._values['monitor_type']
-
- @property
- def metadata(self):
- if self._values['metadata'] is None:
- return None
- if self._values['metadata'] == '':
- return []
- result = []
- try:
- for k, v in iteritems(self._values['metadata']):
- tmp = dict(name=str(k))
- if v:
- tmp['value'] = str(v)
- else:
- tmp['value'] = ''
- result.append(tmp)
- except AttributeError:
- raise F5ModuleError(
- "The 'metadata' parameter must be a dictionary of key/value pairs."
- )
- return result
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- for returnable in self.returnables:
- try:
- result[returnable] = getattr(self, returnable)
- except Exception:
- pass
- result = self._filter_params(result)
- return result
-
- @property
- def monitors(self):
- if self._values['monitors'] is None:
- return None
- return self._values['monitors']
-
-
-class UsableChanges(Changes):
- @property
- def monitors(self):
- monitor_string = self._values['monitors']
- if monitor_string is None:
- return None
-
- if '{' in monitor_string and '}':
- tmp = monitor_string.strip('}').split('{')
- monitor = ''.join(tmp).rstrip()
- return monitor
-
- return monitor_string
-
-
-class ReportableChanges(Changes):
- @property
- def monitors(self):
- result = sorted(re.findall(r'/[\w-]+/[^\s}]+', self._values['monitors']))
- return result
-
- @property
- def monitor_type(self):
- pattern = r'min\s+\d+\s+of'
- matches = re.search(pattern, self._values['monitors'])
- if matches:
- return 'm_of_n'
- else:
- return 'and_list'
-
- @property
- def metadata(self):
- result = dict()
- for x in self._values['metadata']:
- result[x['name']] = x['value']
- return result
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
- def to_tuple(self, items):
- result = []
- for x in items:
- tmp = [(str(k), str(v)) for k, v in iteritems(x)]
- result += tmp
- return result
-
- def _diff_complex_items(self, want, have):
- if want == [] and have is None:
- return None
- if want is None:
- return None
- w = self.to_tuple(want)
- h = self.to_tuple(have)
- if set(w).issubset(set(h)):
- return None
- else:
- return want
-
- @property
- def description(self):
- return cmp_str_with_none(self.want.description, self.have.description)
-
- def _monitors_and_quorum(self):
- if self.want.monitor_type is None:
- self.want.update(dict(monitor_type=self.have.monitor_type))
- if self.want.monitor_type == 'm_of_n':
- if self.want.quorum is None:
- self.want.update(dict(quorum=self.have.quorum))
- if self.want.quorum is None or self.want.quorum < 1:
- raise F5ModuleError(
- "Quorum value must be specified with monitor_type 'm_of_n'."
- )
- if self.want.monitors != self.have.monitors:
- return dict(
- monitors=self.want.monitors
- )
- elif self.want.monitor_type == 'and_list':
- if self.want.quorum is not None and self.want.quorum > 0:
- raise F5ModuleError(
- "Quorum values have no effect when used with 'and_list'."
- )
- if self.want.monitors != self.have.monitors:
- return dict(
- monitors=self.want.monitors
- )
- elif self.want.monitor_type == 'single':
- if len(self.want.monitors_list) > 1:
- raise F5ModuleError(
- "When using a 'monitor_type' of 'single', only one monitor may be provided."
- )
- elif len(self.have.monitors_list) > 1 and len(self.want.monitors_list) == 0:
- # Handle instances where there already exists many monitors, and the
- # user runs the module again specifying that the monitor_type should be
- # changed to 'single'
- raise F5ModuleError(
- "A single monitor must be specified if more than one monitor currently exists on your pool."
- )
- # Update to 'and_list' here because the above checks are all that need
- # to be done before we change the value back to what is expected by
- # BIG-IP.
- #
- # Remember that 'single' is nothing more than a fancy way of saying
- # "and_list plus some extra checks"
- self.want.update(dict(monitor_type='and_list'))
- if self.want.monitors != self.have.monitors:
- return dict(
- monitors=self.want.monitors
- )
-
- @property
- def monitor_type(self):
- return self._monitors_and_quorum()
-
- @property
- def quorum(self):
- return self._monitors_and_quorum()
-
- @property
- def monitors(self):
- if self.want.monitor_type is None:
- self.want.update(dict(monitor_type=self.have.monitor_type))
- if not self.want.monitors_list:
- self.want.monitors = self.have.monitors_list
- if not self.want.monitors and self.want.monitor_type is not None:
- raise F5ModuleError(
- "The 'monitors' parameter cannot be empty when 'monitor_type' parameter is specified"
- )
- if self.want.monitors != self.have.monitors:
- return self.want.monitors
-
- @property
- def metadata(self):
- if self.want.metadata is None:
- return None
- elif len(self.want.metadata) == 0 and self.have.metadata is None:
- return None
- elif len(self.want.metadata) == 0:
- return []
- elif self.have.metadata is None:
- return self.want.metadata
- result = self._diff_complex_items(self.want.metadata, self.have.metadata)
- return result
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = None
- self.have = None
- self.changes = None
- self.replace_all_with = None
- self.purge_links = list()
-
- def exec_module(self):
- wants = None
- if self.module.params['replace_all_with']:
- self.replace_all_with = True
-
- if self.module.params['aggregate']:
- wants = self.merge_defaults_for_aggregate(self.module.params)
-
- result = dict()
- changed = False
-
- if self.replace_all_with and self.purge_links:
- self.purge()
- changed = True
-
- if self.module.params['aggregate']:
- result['aggregate'] = list()
- for want in wants:
- output = self.execute(want)
- if output['changed']:
- changed = output['changed']
- result['aggregate'].append(output)
- else:
- output = self.execute(self.module.params)
- if output['changed']:
- changed = output['changed']
- result.update(output)
- if changed:
- result['changed'] = True
- return result
-
- def merge_defaults_for_aggregate(self, params):
- defaults = deepcopy(params)
- aggregate = defaults.pop('aggregate')
-
- for i, j in enumerate(aggregate):
- for k, v in iteritems(defaults):
- if k != 'replace_all_with':
- if j.get(k, None) is None and v is not None:
- aggregate[i][k] = v
-
- if self.replace_all_with:
- self.compare_aggregate_names(aggregate)
-
- return aggregate
-
- def compare_aggregate_names(self, items):
- on_device = self._read_purge_collection()
- if not on_device:
- return False
- aggregates = [item['name'] for item in items]
- collection = [item['name'] for item in on_device]
-
- diff = set(collection) - set(aggregates)
-
- if diff:
- to_purge = [item['selfLink'] for item in on_device if item['name'] in diff]
- self.purge_links.extend(to_purge)
-
- def execute(self, params=None):
- self.want = ModuleParameters(params=params)
- self.have = ApiParameters()
- self.changes = UsableChanges()
-
- changed = False
- result = dict()
- state = params['state']
-
- if state == "present":
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = UsableChanges(params=changed)
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def present(self):
- if self.exists():
- return self.update()
- else:
- return self.create()
-
- def absent(self):
- if self.exists():
- return self.remove()
- return False
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def update(self):
- self.have = self.read_current_from_device()
- if not self.should_update():
- return False
- if self.module.check_mode:
- return True
- self.update_on_device()
- return True
-
- def remove(self):
- if self.module.check_mode:
- return True
- self.remove_from_device()
- if self.exists():
- raise F5ModuleError("Failed to delete the Pool")
- return True
-
- def purge(self):
- if self.module.check_mode:
- return True
- self.purge_from_device()
- return True
-
- def create(self):
- if self.want.monitor_type is not None:
- if not self.want.monitors_list:
- raise F5ModuleError(
- "The 'monitors' parameter cannot be empty when 'monitor_type' parameter is specified"
- )
- else:
- if self.want.monitor_type is None:
- self.want.update(dict(monitor_type='and_list'))
-
- if self.want.monitor_type == 'm_of_n' and (self.want.quorum is None or self.want.quorum < 1):
- raise F5ModuleError(
- "Quorum value must be specified with monitor_type 'm_of_n'."
- )
- elif self.want.monitor_type == 'and_list' and self.want.quorum is not None and self.want.quorum > 0:
- raise F5ModuleError(
- "Quorum values have no effect when used with 'and_list'."
- )
- elif self.want.monitor_type == 'single' and len(self.want.monitors_list) > 1:
- raise F5ModuleError(
- "When using a 'monitor_type' of 'single', only one monitor may be provided"
- )
- if self.want.priority_group_activation is None:
- self.want.update({'priority_group_activation': 0})
-
- self._set_changed_options()
- if self.module.check_mode:
- return True
- self.create_on_device()
- return True
-
- def _read_purge_collection(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/pool/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
-
- query = "?$select=name,selfLink"
- resp = self.client.api.get(uri + query)
-
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- if 'items' in response:
- return response['items']
- return []
-
- def create_on_device(self):
- params = self.changes.api_params()
- params['name'] = self.want.name
- params['partition'] = self.want.partition
- uri = "https://{0}:{1}/mgmt/tm/ltm/pool/".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def update_on_device(self):
- params = self.changes.api_params()
- uri = "https://{0}:{1}/mgmt/tm/ltm/pool/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def exists(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/pool/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def remove_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/pool/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- response = self.client.api.delete(uri)
- if response.status == 200:
- return True
- raise F5ModuleError(response.content)
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/pool/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- query = '?expandSubcollections=true'
- resp = self.client.api.get(uri + query)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return ApiParameters(params=response)
-
- def _prepare_links(self, collection):
- purge_links = list()
- purge_paths = [urlparse(link).path for link in collection]
-
- for path in purge_paths:
- link = "https://{0}:{1}{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- path
- )
- purge_links.append(link)
- return purge_links
-
- def purge_from_device(self):
- links = self._prepare_links(self.purge_links)
-
- with TransactionContextManager(self.client) as transact:
- for link in links:
- resp = transact.api.delete(link)
-
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return True
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.lb_choice = [
- 'dynamic-ratio-member',
- 'dynamic-ratio-node',
- 'fastest-app-response',
- 'fastest-node',
- 'least-connections-member',
- 'least-connections-node',
- 'least-sessions',
- 'observed-member',
- 'observed-node',
- 'predictive-member',
- 'predictive-node',
- 'ratio-least-connections-member',
- 'ratio-least-connections-node',
- 'ratio-member',
- 'ratio-node',
- 'ratio-session',
- 'round-robin',
- 'weighted-least-connections-member',
- 'weighted-least-connections-node'
- ]
- self.supports_check_mode = True
- element_spec = dict(
- name=dict(
- aliases=['pool']
- ),
- lb_method=dict(
- choices=self.lb_choice
- ),
- monitor_type=dict(
- choices=[
- 'and_list', 'm_of_n', 'single'
- ]
- ),
- quorum=dict(
- type='int'
- ),
- monitors=dict(
- type='list'
- ),
- slow_ramp_time=dict(
- type='int'
- ),
- reselect_tries=dict(
- type='int'
- ),
- service_down_action=dict(
- choices=[
- 'none', 'reset',
- 'drop', 'reselect'
- ]
- ),
- description=dict(),
- metadata=dict(type='raw'),
- state=dict(
- default='present',
- choices=['present', 'absent']
- ),
- priority_group_activation=dict(
- type='int',
- aliases=['minimum_active_members']
- ),
- partition=dict(
- default='Common',
- fallback=(env_fallback, ['F5_PARTITION'])
- )
- )
-
- aggregate_spec = deepcopy(element_spec)
-
- # remove default in aggregate spec, to handle common arguments
- remove_default_spec(aggregate_spec)
-
- argument_spec = dict(
- aggregate=dict(
- type='list',
- elements='dict',
- options=aggregate_spec,
- aliases=['pools']
- ),
- partition=dict(
- default='Common',
- fallback=(env_fallback, ['F5_PARTITION'])
- ),
- replace_all_with=dict(
- default='no',
- type='bool',
- aliases=['purge']
- )
- )
-
- self.mutually_exclusive = [
- ['name', 'aggregate']
- ]
- self.required_one_of = [
- ['name', 'aggregate']
- ]
-
- self.argument_spec = {}
- self.argument_spec.update(element_spec)
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode,
- mutually_exclusive=spec.mutually_exclusive,
- required_one_of=spec.required_one_of
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_pool_member.py b/lib/ansible/modules/network/f5/bigip_pool_member.py
deleted file mode 100644
index fcd9dbe833..0000000000
--- a/lib/ansible/modules/network/f5/bigip_pool_member.py
+++ /dev/null
@@ -1,1658 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# Copyright: (c) 2013, Matt Hite <mhite@hotmail.com>
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_pool_member
-short_description: Manages F5 BIG-IP LTM pool members
-description:
- - Manages F5 BIG-IP LTM pool members via iControl SOAP API.
-version_added: 1.4
-options:
- name:
- description:
- - Name of the node to create, or re-use, when creating a new pool member.
- - This parameter is optional and, if not specified, a node name will be
- created automatically from either the specified C(address) or C(fqdn).
- - The C(enabled) state is an alias of C(present).
- type: str
- version_added: 2.6
- state:
- description:
- - Pool member state.
- type: str
- required: True
- choices:
- - present
- - absent
- - enabled
- - disabled
- - forced_offline
- default: present
- pool:
- description:
- - Pool name. This pool must exist.
- type: str
- required: True
- partition:
- description:
- - Partition to manage resources on.
- type: str
- default: Common
- address:
- description:
- - IP address of the pool member. This can be either IPv4 or IPv6. When creating a
- new pool member, one of either C(address) or C(fqdn) must be provided. This
- parameter cannot be updated after it is set.
- type: str
- aliases:
- - ip
- - host
- version_added: 2.2
- fqdn:
- description:
- - FQDN name of the pool member. This can be any name that is a valid RFC 1123 DNS
- name. Therefore, the only characters that can be used are "A" to "Z",
- "a" to "z", "0" to "9", the hyphen ("-") and the period (".").
- - FQDN names must include at lease one period; delineating the host from
- the domain. ex. C(host.domain).
- - FQDN names must end with a letter or a number.
- - When creating a new pool member, one of either C(address) or C(fqdn) must be
- provided. This parameter cannot be updated after it is set.
- type: str
- aliases:
- - hostname
- version_added: 2.6
- port:
- description:
- - Pool member port.
- - This value cannot be changed after it has been set.
- type: int
- required: True
- connection_limit:
- description:
- - Pool member connection limit. Setting this to 0 disables the limit.
- type: int
- description:
- description:
- - Pool member description.
- type: str
- rate_limit:
- description:
- - Pool member rate limit (connections-per-second). Setting this to 0
- disables the limit.
- type: int
- ratio:
- description:
- - Pool member ratio weight. Valid values range from 1 through 100.
- New pool members -- unless overridden with this value -- default
- to 1.
- type: int
- preserve_node:
- description:
- - When state is C(absent) attempts to remove the node that the pool
- member references.
- - The node will not be removed if it is still referenced by other pool
- members. If this happens, the module will not raise an error.
- - Setting this to C(yes) disables this behavior.
- type: bool
- version_added: 2.1
- priority_group:
- description:
- - Specifies a number representing the priority group for the pool member.
- - When adding a new member, the default is 0, meaning that the member has no priority.
- - To specify a priority, you must activate priority group usage when you
- create a new pool or when adding or removing pool members. When activated,
- the system load balances traffic according to the priority group number
- assigned to the pool member.
- - The higher the number, the higher the priority, so a member with a priority
- of 3 has higher priority than a member with a priority of 1.
- type: int
- version_added: 2.5
- fqdn_auto_populate:
- description:
- - Specifies whether the system automatically creates ephemeral nodes using
- the IP addresses returned by the resolution of a DNS query for a node
- defined by an FQDN.
- - When C(yes), the system generates an ephemeral node for each IP address
- returned in response to a DNS query for the FQDN of the node. Additionally,
- when a DNS response indicates the IP address of an ephemeral node no longer
- exists, the system deletes the ephemeral node.
- - When C(no), the system resolves a DNS query for the FQDN of the node
- with the single IP address associated with the FQDN.
- - When creating a new pool member, the default for this parameter is C(yes).
- - Once set this parameter cannot be changed afterwards.
- - This parameter is ignored when C(reuse_nodes) is C(yes).
- type: bool
- version_added: 2.6
- reuse_nodes:
- description:
- - Reuses node definitions if requested.
- type: bool
- default: yes
- version_added: 2.6
- monitors:
- description:
- - Specifies the health monitors that the system currently uses to monitor
- this resource.
- type: list
- version_added: 2.8
- availability_requirements:
- description:
- - Specifies, if you activate more than one health monitor, the number of health
- monitors that must receive successful responses in order for the link to be
- considered available.
- - Specifying an empty string will remove the monitors and revert to inheriting from pool (default).
- - Specifying C(none) value will remove any health monitoring from the member completely.
- suboptions:
- type:
- description:
- - Monitor rule type when C(monitors) is specified.
- - When creating a new pool, if this value is not specified, the default of
- 'all' will be used.
- type: str
- choices:
- - all
- - at_least
- at_least:
- description:
- - Specifies the minimum number of active health monitors that must be successful
- before the link is considered up.
- - This parameter is only relevant when a C(type) of C(at_least) is used.
- - This parameter will be ignored if a type of C(all) is used.
- type: int
- type: dict
- version_added: 2.8
- ip_encapsulation:
- description:
- - Specifies the IP encapsulation using either IPIP (IP encapsulation within IP,
- RFC 2003) or GRE (Generic Router Encapsulation, RFC 2784) on outbound packets
- (from BIG-IP system to server-pool member).
- - When C(none), disables IP encapsulation.
- - When C(inherit), inherits IP encapsulation setting from the member's pool.
- - When any other value, Options are None, Inherit from Pool, and Member Specific.
- type: str
- version_added: 2.8
- aggregate:
- description:
- - List of pool member definitions to be created, modified or removed.
- - When using C(aggregates) if one of the aggregate definitions is invalid, the aggregate run will fail,
- indicating the error it last encountered.
- - The module will C(NOT) rollback any changes it has made prior to encountering the error.
- - The module also will not indicate what changes were made prior to failure, therefore it is strongly advised
- to run the module in check mode to make basic validation, prior to module execution.
- type: list
- aliases:
- - members
- version_added: 2.8
- replace_all_with:
- description:
- - Remove members not defined in the C(aggregate) parameter.
- - This operation is all or none, meaning that it will stop if there are some pool members
- that cannot be removed.
- type: bool
- default: no
- aliases:
- - purge
- version_added: 2.8
-notes:
- - In previous versions of this module, which used the SDK, the C(name) parameter would act as C(fqdn) if C(address) or
- C(fqdn) were not provided.
-extends_documentation_fragment: f5
-author:
- - Tim Rupp (@caphrim007)
- - Wojciech Wypior (@wojtek0806)
-'''
-
-EXAMPLES = '''
-- name: Add pool member
- bigip_pool_member:
- pool: my-pool
- partition: Common
- host: "{{ ansible_default_ipv4['address'] }}"
- port: 80
- description: web server
- connection_limit: 100
- rate_limit: 50
- ratio: 2
- provider:
- server: lb.mydomain.com
- user: admin
- password: secret
- delegate_to: localhost
-
-- name: Modify pool member ratio and description
- bigip_pool_member:
- pool: my-pool
- partition: Common
- host: "{{ ansible_default_ipv4['address'] }}"
- port: 80
- ratio: 1
- description: nginx server
- provider:
- server: lb.mydomain.com
- user: admin
- password: secret
- delegate_to: localhost
-
-- name: Remove pool member from pool
- bigip_pool_member:
- state: absent
- pool: my-pool
- partition: Common
- host: "{{ ansible_default_ipv4['address'] }}"
- port: 80
- provider:
- server: lb.mydomain.com
- user: admin
- password: secret
- delegate_to: localhost
-
-- name: Force pool member offline
- bigip_pool_member:
- state: forced_offline
- pool: my-pool
- partition: Common
- host: "{{ ansible_default_ipv4['address'] }}"
- port: 80
- provider:
- server: lb.mydomain.com
- user: admin
- password: secret
- delegate_to: localhost
-
-- name: Create members with priority groups
- bigip_pool_member:
- pool: my-pool
- partition: Common
- host: "{{ item.address }}"
- name: "{{ item.name }}"
- priority_group: "{{ item.priority_group }}"
- port: 80
- provider:
- server: lb.mydomain.com
- user: admin
- password: secret
- delegate_to: localhost
- loop:
- - address: 1.1.1.1
- name: web1
- priority_group: 4
- - address: 2.2.2.2
- name: web2
- priority_group: 3
- - address: 3.3.3.3
- name: web3
- priority_group: 2
- - address: 4.4.4.4
- name: web4
- priority_group: 1
-
-- name: Add pool members aggregate
- bigip_pool_member:
- pool: my-pool
- aggregate:
- - host: 192.168.1.1
- partition: Common
- port: 80
- description: web server
- connection_limit: 100
- rate_limit: 50
- ratio: 2
- - host: 192.168.1.2
- partition: Common
- port: 80
- description: web server
- connection_limit: 100
- rate_limit: 50
- ratio: 2
- - host: 192.168.1.3
- partition: Common
- port: 80
- description: web server
- connection_limit: 100
- rate_limit: 50
- ratio: 2
- provider:
- server: lb.mydomain.com
- user: admin
- password: secret
- delegate_to: localhost
-
-- name: Add pool members aggregate, remove non aggregates
- bigip_pool_member:
- pool: my-pool
- aggregate:
- - host: 192.168.1.1
- partition: Common
- port: 80
- description: web server
- connection_limit: 100
- rate_limit: 50
- ratio: 2
- - host: 192.168.1.2
- partition: Common
- port: 80
- description: web server
- connection_limit: 100
- rate_limit: 50
- ratio: 2
- - host: 192.168.1.3
- partition: Common
- port: 80
- description: web server
- connection_limit: 100
- rate_limit: 50
- ratio: 2
- replace_all_with: yes
- provider:
- server: lb.mydomain.com
- user: admin
- password: secret
- delegate_to: localhost
-'''
-
-RETURN = '''
-rate_limit:
- description: The new rate limit, in connections per second, of the pool member.
- returned: changed
- type: int
- sample: 100
-connection_limit:
- description: The new connection limit of the pool member
- returned: changed
- type: int
- sample: 1000
-description:
- description: The new description of pool member.
- returned: changed
- type: str
- sample: My pool member
-ratio:
- description: The new pool member ratio weight.
- returned: changed
- type: int
- sample: 50
-priority_group:
- description: The new priority group.
- returned: changed
- type: int
- sample: 3
-fqdn_auto_populate:
- description: Whether FQDN auto population was set on the member or not.
- returned: changed
- type: bool
- sample: True
-fqdn:
- description: The FQDN of the pool member.
- returned: changed
- type: str
- sample: foo.bar.com
-address:
- description: The address of the pool member.
- returned: changed
- type: str
- sample: 1.2.3.4
-monitors:
- description: The new list of monitors for the resource.
- returned: changed
- type: list
- sample: ['/Common/monitor1', '/Common/monitor2']
-replace_all_with:
- description: Purges all non-aggregate pool members from device
- returned: changed
- type: bool
- sample: yes
-'''
-
-import os
-import re
-
-from copy import deepcopy
-
-from ansible.module_utils.urls import urlparse
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.basic import env_fallback
-from ansible.module_utils.six import iteritems
-from ansible.module_utils.network.common.utils import remove_default_spec
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import fq_name
- from library.module_utils.network.f5.common import transform_name
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.common import is_valid_hostname
- from library.module_utils.network.f5.common import flatten_boolean
- from library.module_utils.network.f5.compare import cmp_str_with_none
- from library.module_utils.network.f5.ipaddress import is_valid_ip
- from library.module_utils.network.f5.ipaddress import validate_ip_v6_address
- from library.module_utils.network.f5.icontrol import TransactionContextManager
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import fq_name
- from ansible.module_utils.network.f5.common import transform_name
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.common import is_valid_hostname
- from ansible.module_utils.network.f5.common import flatten_boolean
- from ansible.module_utils.network.f5.compare import cmp_str_with_none
- from ansible.module_utils.network.f5.ipaddress import is_valid_ip
- from ansible.module_utils.network.f5.ipaddress import validate_ip_v6_address
- from ansible.module_utils.network.f5.icontrol import TransactionContextManager
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'rateLimit': 'rate_limit',
- 'connectionLimit': 'connection_limit',
- 'priorityGroup': 'priority_group',
- 'monitor': 'monitors',
- 'inheritProfile': 'inherit_profile',
- 'profiles': 'ip_encapsulation',
- }
-
- api_attributes = [
- 'rateLimit',
- 'connectionLimit',
- 'description',
- 'ratio',
- 'priorityGroup',
- 'address',
- 'fqdn',
- 'session',
- 'state',
- 'monitor',
-
- # These two settings are for IP Encapsulation
- 'inheritProfile',
- 'profiles',
- ]
-
- returnables = [
- 'rate_limit',
- 'connection_limit',
- 'description',
- 'ratio',
- 'priority_group',
- 'fqdn_auto_populate',
- 'session',
- 'state',
- 'fqdn',
- 'address',
- 'monitors',
-
- # IP Encapsulation related
- 'inherit_profile',
- 'ip_encapsulation',
- ]
-
- updatables = [
- 'rate_limit',
- 'connection_limit',
- 'description',
- 'ratio',
- 'priority_group',
- 'fqdn_auto_populate',
- 'state',
- 'monitors',
- 'inherit_profile',
- 'ip_encapsulation',
- ]
-
-
-class ModuleParameters(Parameters):
- @property
- def full_name(self):
- delimiter = ':'
- try:
- if validate_ip_v6_address(self.full_name_dict['name']):
- delimiter = '.'
- except TypeError:
- pass
- return '{0}{1}{2}'.format(self.full_name_dict['name'], delimiter, self.port)
-
- @property
- def full_name_dict(self):
- if self._values['name'] is None:
- name = self._values['address'] if self._values['address'] else self._values['fqdn']
- else:
- name = self._values['name']
- return dict(
- name=name,
- port=self.port
- )
-
- @property
- def node_name(self):
- return self.full_name_dict['name']
-
- @property
- def fqdn_name(self):
- return self._values['fqdn']
-
- @property
- def fqdn(self):
- result = {}
- if self.fqdn_auto_populate:
- result['autopopulate'] = 'enabled'
- else:
- result['autopopulate'] = 'disabled'
- if self._values['fqdn'] is None:
- return result
- if not is_valid_hostname(self._values['fqdn']):
- raise F5ModuleError(
- "The specified 'fqdn' value of: {0} is not a valid hostname.".format(self._values['fqdn'])
- )
- result['tmName'] = self._values['fqdn']
- return result
-
- @property
- def pool(self):
- return fq_name(self.want.partition, self._values['pool'])
-
- @property
- def port(self):
- if self._values['port'] is None:
- raise F5ModuleError(
- "Port value must be specified."
- )
- if 0 > int(self._values['port']) or int(self._values['port']) > 65535:
- raise F5ModuleError(
- "Valid ports must be in range 0 - 65535"
- )
- return int(self._values['port'])
-
- @property
- def address(self):
- if self._values['address'] is None:
- return None
- elif self._values['address'] == 'any6':
- return 'any6'
- address = self._values['address'].split('%')[0]
- if is_valid_ip(address):
- return self._values['address']
- raise F5ModuleError(
- "The specified 'address' value of: {0} is not a valid IP address.".format(address)
- )
-
- @property
- def state(self):
- if self._values['state'] == 'enabled':
- return 'present'
- return self._values['state']
-
- @property
- def monitors_list(self):
- if self._values['monitors'] is None:
- return []
- try:
- result = re.findall(r'/\w+/[^\s}]+', self._values['monitors'])
- result.sort()
- return result
- except Exception:
- return self._values['monitors']
-
- @property
- def monitors(self):
- if self._values['monitors'] is None:
- return None
- if len(self._values['monitors']) == 1 and self._values['monitors'][0] == '':
- return 'default'
- if len(self._values['monitors']) == 1 and self._values['monitors'][0] == 'none':
- return '/Common/none'
- monitors = [fq_name(self.partition, x) for x in self.monitors_list]
- if self.availability_requirement_type == 'at_least':
- if self.at_least > len(self.monitors_list):
- raise F5ModuleError(
- "The 'at_least' value must not exceed the number of 'monitors'."
- )
- monitors = ' '.join(monitors)
- result = 'min {0} of {{ {1} }}'.format(self.at_least, monitors)
- else:
- result = ' and '.join(monitors).strip()
- return result
-
- @property
- def availability_requirement_type(self):
- if self._values['availability_requirements'] is None:
- return None
- return self._values['availability_requirements']['type']
-
- @property
- def at_least(self):
- return self._get_availability_value('at_least')
-
- @property
- def ip_encapsulation(self):
- if self._values['ip_encapsulation'] is None:
- return None
- if self._values['ip_encapsulation'] == 'inherit':
- return 'inherit'
- if self._values['ip_encapsulation'] in ['', 'none']:
- return ''
- return fq_name(self.partition, self._values['ip_encapsulation'])
-
- def _get_availability_value(self, type):
- if self._values['availability_requirements'] is None:
- return None
- if self._values['availability_requirements'][type] is None:
- return None
- return int(self._values['availability_requirements'][type])
-
-
-class ApiParameters(Parameters):
- @property
- def ip_encapsulation(self):
- """Returns a simple name for the tunnel.
-
- The API stores the data like so
-
- "profiles": [
- {
- "name": "gre",
- "partition": "Common",
- "nameReference": {
- "link": "https://localhost/mgmt/tm/net/tunnels/gre/~Common~gre?ver=13.1.0.7"
- }
- }
- ]
-
- This method returns that data as a simple profile name. For instance,
-
- /Common/gre
-
- This allows us to do comparisons of it in the Difference class and then,
- as needed, translate it back to the more complex form in the UsableChanges
- class.
-
- Returns:
- string: The simple form representation of the tunnel
- """
- if self._values['ip_encapsulation'] is None and self.inherit_profile == 'yes':
- return 'inherit'
- if self._values['ip_encapsulation'] is None and self.inherit_profile == 'no':
- return ''
- if self._values['ip_encapsulation'] is None:
- return None
-
- # There can be only one
- tunnel = self._values['ip_encapsulation'][0]
-
- return fq_name(tunnel['partition'], tunnel['name'])
-
- @property
- def inherit_profile(self):
- return flatten_boolean(self._values['inherit_profile'])
-
- @property
- def allow(self):
- if self._values['allow'] is None:
- return ''
- if self._values['allow'][0] == 'All':
- return 'all'
- allow = self._values['allow']
- result = list(set([str(x) for x in allow]))
- result = sorted(result)
- return result
-
- @property
- def rate_limit(self):
- if self._values['rate_limit'] is None:
- return None
- if self._values['rate_limit'] == 'disabled':
- return 0
- return int(self._values['rate_limit'])
-
- @property
- def state(self):
- if self._values['state'] in ['user-up', 'unchecked', 'fqdn-up-no-addr', 'fqdn-up'] and self._values['session'] in ['user-enabled']:
- return 'present'
- elif self._values['state'] in ['down', 'up', 'checking'] and self._values['session'] == 'monitor-enabled':
- # monitor-enabled + checking:
- # Monitor is checking to see state of pool member. For instance,
- # whether it is up or down
- #
- # monitor-enabled + down:
- # Monitor returned and determined that pool member is down.
- #
- # monitor-enabled + up
- # Monitor returned and determined that pool member is up.
- return 'present'
- elif self._values['state'] in ['user-down'] and self._values['session'] in ['user-disabled']:
- return 'forced_offline'
- else:
- return 'disabled'
-
- @property
- def availability_requirement_type(self):
- if self._values['monitors'] is None:
- return None
- if 'min ' in self._values['monitors']:
- return 'at_least'
- else:
- return 'all'
-
- @property
- def monitors_list(self):
- if self._values['monitors'] is None:
- return []
- try:
- result = re.findall(r'/\w+/[^\s}]+', self._values['monitors'])
- result.sort()
- return result
- except Exception:
- return self._values['monitors']
-
- @property
- def monitors(self):
- if self._values['monitors'] is None:
- return None
- if self._values['monitors'] == 'default':
- return 'default'
- monitors = [fq_name(self.partition, x) for x in self.monitors_list]
- if self.availability_requirement_type == 'at_least':
- monitors = ' '.join(monitors)
- result = 'min {0} of {{ {1} }}'.format(self.at_least, monitors)
- else:
- result = ' and '.join(monitors).strip()
-
- return result
-
- @property
- def at_least(self):
- """Returns the 'at least' value from the monitor string.
- The monitor string for a Require monitor looks like this.
- min 1 of { /Common/gateway_icmp }
- This method parses out the first of the numeric values. This values represents
- the "at_least" value that can be updated in the module.
- Returns:
- int: The at_least value if found. None otherwise.
- """
- if self._values['monitors'] is None:
- return None
- pattern = r'min\s+(?P<least>\d+)\s+of\s+'
- matches = re.search(pattern, self._values['monitors'])
- if matches is None:
- return None
- return matches.group('least')
-
- @property
- def fqdn_auto_populate(self):
- if self._values['fqdn'] is None:
- return None
- if 'autopopulate' in self._values['fqdn']:
- if self._values['fqdn']['autopopulate'] == 'enabled':
- return True
- return False
-
- @property
- def fqdn(self):
- if self._values['fqdn'] is None:
- return None
- if 'tmName' in self._values['fqdn']:
- return self._values['fqdn']['tmName']
-
-
-class NodeApiParameters(Parameters):
- pass
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class UsableChanges(Changes):
- @property
- def monitors(self):
- monitor_string = self._values['monitors']
- if monitor_string is None:
- return None
- if '{' in monitor_string and '}':
- tmp = monitor_string.strip('}').split('{')
- monitor = ''.join(tmp).rstrip()
- return monitor
- return monitor_string
-
-
-class ReportableChanges(Changes):
- @property
- def ssl_cipher_suite(self):
- default = ':'.join(sorted(Parameters._ciphers.split(':')))
- if self._values['ssl_cipher_suite'] == default:
- return 'default'
- else:
- return self._values['ssl_cipher_suite']
-
- @property
- def fqdn_auto_populate(self):
- if self._values['fqdn'] is None:
- return None
- if 'autopopulate' in self._values['fqdn']:
- if self._values['fqdn']['autopopulate'] == 'enabled':
- return True
- return False
-
- @property
- def fqdn(self):
- if self._values['fqdn'] is None:
- return None
- if 'tmName' in self._values['fqdn']:
- return self._values['fqdn']['tmName']
-
- @property
- def state(self):
- if self._values['state'] in ['user-up', 'unchecked', 'fqdn-up-no-addr', 'fqdn-up'] and self._values['session'] in ['user-enabled']:
- return 'present'
- elif self._values['state'] in ['down', 'up', 'checking'] and self._values['session'] == 'monitor-enabled':
- return 'present'
- elif self._values['state'] in ['user-down'] and self._values['session'] in ['user-disabled']:
- return 'forced_offline'
- else:
- return 'disabled'
-
- @property
- def monitors(self):
- if self._values['monitors'] is None:
- return []
- try:
- result = re.findall(r'/\w+/[^\s}]+', self._values['monitors'])
- result.sort()
- return result
- except Exception:
- return self._values['monitors']
-
- @property
- def availability_requirement_type(self):
- if self._values['monitors'] is None:
- return None
- if 'min ' in self._values['monitors']:
- return 'at_least'
- else:
- return 'all'
-
- @property
- def at_least(self):
- """Returns the 'at least' value from the monitor string.
- The monitor string for a Require monitor looks like this.
- min 1 of { /Common/gateway_icmp }
- This method parses out the first of the numeric values. This values represents
- the "at_least" value that can be updated in the module.
- Returns:
- int: The at_least value if found. None otherwise.
- """
- if self._values['monitors'] is None:
- return None
- pattern = r'min\s+(?P<least>\d+)\s+of\s+'
- matches = re.search(pattern, self._values['monitors'])
- if matches is None:
- return None
- return int(matches.group('least'))
-
- @property
- def availability_requirements(self):
- if self._values['monitors'] is None:
- return None
- result = dict()
- result['type'] = self.availability_requirement_type
- result['at_least'] = self.at_least
- return result
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
- @property
- def state(self):
- if self.want.state == self.have.state:
- return None
- if self.want.state == 'forced_offline':
- return {
- 'state': 'user-down',
- 'session': 'user-disabled'
- }
- elif self.want.state == 'disabled':
- return {
- 'state': 'user-up',
- 'session': 'user-disabled'
- }
- elif self.want.state in ['present', 'enabled']:
- return {
- 'state': 'user-up',
- 'session': 'user-enabled'
- }
-
- @property
- def fqdn_auto_populate(self):
- if self.want.fqdn_auto_populate is not None:
- if self.want.fqdn_auto_populate != self.have.fqdn_auto_populate:
- raise F5ModuleError(
- "The fqdn_auto_populate cannot be changed once it has been set."
- )
-
- @property
- def monitors(self):
- if self.want.monitors is None:
- return None
- if self.want.monitors == 'default' and self.have.monitors == 'default':
- return None
- if self.want.monitors == 'default' and self.have.monitors is None:
- return None
- if self.want.monitors == 'default' and len(self.have.monitors) > 0:
- return 'default'
- # this is necessary as in v12 there is a bug where returned value has a space at the end
- if self.want.monitors == '/Common/none' and self.have.monitors in ['/Common/none', '/Common/none ']:
- return None
- if self.have.monitors is None:
- return self.want.monitors
- if self.have.monitors != self.want.monitors:
- return self.want.monitors
-
- @property
- def ip_encapsulation(self):
- result = cmp_str_with_none(self.want.ip_encapsulation, self.have.ip_encapsulation)
- if result is None:
- return None
- if result == 'inherit':
- return dict(
- inherit_profile='enabled',
- ip_encapsulation=[]
- )
- elif result in ['', 'none']:
- return dict(
- inherit_profile='disabled',
- ip_encapsulation=[]
- )
- else:
- return dict(
- inherit_profile='disabled',
- ip_encapsulation=[
- dict(
- name=os.path.basename(result).strip('/'),
- partition=os.path.dirname(result)
- )
- ]
- )
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = None
- self.have = None
- self.changes = None
- self.replace_all_with = False
- self.purge_links = list()
- self.on_device = None
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = UsableChanges(params=changed)
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def exec_module(self):
- wants = None
- if self.module.params['replace_all_with']:
- self.replace_all_with = True
-
- if self.module.params['aggregate']:
- wants = self.merge_defaults_for_aggregate(self.module.params)
-
- result = dict()
- changed = False
-
- if self.replace_all_with and self.purge_links:
- self.purge()
- changed = True
-
- if self.module.params['aggregate']:
- result['aggregate'] = list()
- for want in wants:
- output = self.execute(want)
- if output['changed']:
- changed = output['changed']
- result['aggregate'].append(output)
- else:
- output = self.execute(self.module.params)
- if output['changed']:
- changed = output['changed']
- result.update(output)
- if changed:
- result['changed'] = True
- return result
-
- def merge_defaults_for_aggregate(self, params):
- defaults = deepcopy(params)
- aggregate = defaults.pop('aggregate')
-
- for i, j in enumerate(aggregate):
- for k, v in iteritems(defaults):
- if k != 'replace_all_with':
- if j.get(k, None) is None and v is not None:
- aggregate[i][k] = v
-
- if self.replace_all_with:
- self.compare_aggregate_names(aggregate)
-
- return aggregate
-
- def _filter_ephemerals(self):
- on_device = self._read_purge_collection()
- if not on_device:
- self.on_device = []
- return
- self.on_device = [member for member in on_device if member['ephemeral'] != "true"]
-
- def compare_fqdns(self, items):
- if any('fqdn' in item for item in items):
- aggregates = [item['fqdn'] for item in items if 'fqdn' in item and item['fqdn']]
- collection = [member['fqdn']['tmName'] for member in self.on_device if 'tmName' in member['fqdn']]
-
- diff = set(collection) - set(aggregates)
-
- if diff:
- fqdns = [
- member['selfLink'] for member in self.on_device if 'tmName' in member['fqdn'] and member['fqdn']['tmName'] in diff]
- self.purge_links.extend(fqdns)
- return True
- return False
- return False
-
- def compare_addresses(self, items):
- if any('address' in item for item in items):
- aggregates = [item['address'] for item in items if 'address' in item and item['address']]
- collection = [member['address'] for member in self.on_device]
- diff = set(collection) - set(aggregates)
-
- if diff:
- addresses = [item['selfLink'] for item in self.on_device if item['address'] in diff]
- self.purge_links.extend(addresses)
- return True
- return False
- return False
-
- def compare_aggregate_names(self, items):
- self._filter_ephemerals()
- if not self.on_device:
- return False
- fqdns = self.compare_fqdns(items)
- addresses = self.compare_addresses(items)
-
- if self.purge_links:
- if fqdns:
- if not addresses:
- self.purge_links.extend([item['selfLink'] for item in self.on_device if 'tmName' not in item['fqdn']])
-
- def execute(self, params=None):
- self.want = ModuleParameters(params=params)
- self.have = ApiParameters()
- self.changes = UsableChanges()
-
- changed = False
- result = dict()
- state = params['state']
-
- if state in ['present', 'enabled', 'disabled', 'forced_offline']:
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def present(self):
- if self.exists():
- return self.update()
- else:
- return self.create()
-
- def absent(self):
- if self.exists():
- return self.remove()
- elif not self.want.preserve_node and self.node_exists():
- return self.remove_node_from_device()
- return False
-
- def update(self):
- self.have = self.read_current_from_device()
- if not self.should_update():
- return False
- if self.module.check_mode:
- return True
- self.update_on_device()
- return True
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def remove(self):
- if self.module.check_mode:
- return True
- self.remove_from_device()
- if not self.want.preserve_node:
- self.remove_node_from_device()
- if self.exists():
- raise F5ModuleError("Failed to delete the resource.")
- return True
-
- def purge(self):
- if self.module.check_mode:
- return True
- if not self.pool_exist():
- raise F5ModuleError('The specified pool does not exist')
- self.purge_from_device()
- return True
-
- def create(self):
- if self.want.reuse_nodes:
- self._update_address_with_existing_nodes()
-
- if self.want.name and not any(x for x in [self.want.address, self.want.fqdn_name]):
- self._set_host_by_name()
-
- if self.want.ip_encapsulation == '':
- self.changes.update({'inherit_profile': 'enabled'})
- self.changes.update({'profiles': []})
- elif self.want.ip_encapsulation:
- # Read the current list of tunnels so that IP encapsulation
- # checking can take place.
- tunnels_gre = self.read_current_tunnels_from_device('gre')
- tunnels_ipip = self.read_current_tunnels_from_device('ipip')
- tunnels = tunnels_gre + tunnels_ipip
- if self.want.ip_encapsulation not in tunnels:
- raise F5ModuleError(
- "The specified 'ip_encapsulation' tunnel was not found on the system."
- )
- self.changes.update({'inherit_profile': 'disabled'})
-
- self._update_api_state_attributes()
- self._set_changed_options()
- if self.module.check_mode:
- return True
- self.create_on_device()
- return True
-
- def exists(self):
- if not self.pool_exist():
- raise F5ModuleError('The specified pool does not exist')
-
- uri = "https://{0}:{1}/mgmt/tm/ltm/pool/{2}/members/{3}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(name=fq_name(self.want.partition, self.want.pool)),
- transform_name(self.want.partition, self.want.full_name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def pool_exist(self):
- if self.replace_all_with:
- pool_name = transform_name(name=fq_name(self.module.params['partition'], self.module.params['pool']))
- else:
- pool_name = transform_name(name=fq_name(self.want.partition, self.want.pool))
-
- uri = "https://{0}:{1}/mgmt/tm/ltm/pool/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- pool_name
-
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def node_exists(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/node/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.node_name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def _set_host_by_name(self):
- if is_valid_ip(self.want.name):
- self.want.update({
- 'fqdn': None,
- 'address': self.want.name
- })
- else:
- if not is_valid_hostname(self.want.name):
- raise F5ModuleError(
- "'name' is neither a valid IP address or FQDN name."
- )
- self.want.update({
- 'fqdn': self.want.name,
- 'address': None
- })
-
- def _update_api_state_attributes(self):
- if self.want.state == 'forced_offline':
- self.want.update({
- 'state': 'user-down',
- 'session': 'user-disabled',
- })
- elif self.want.state == 'disabled':
- self.want.update({
- 'state': 'user-up',
- 'session': 'user-disabled',
- })
- elif self.want.state in ['present', 'enabled']:
- self.want.update({
- 'state': 'user-up',
- 'session': 'user-enabled',
- })
-
- def _update_address_with_existing_nodes(self):
- try:
- have = self.read_current_node_from_device(self.want.node_name)
-
- if self.want.fqdn_auto_populate and self.want.reuse_nodes:
- self.module.warn("'fqdn_auto_populate' is discarded in favor of the re-used node's auto-populate setting.")
- self.want.update({
- 'fqdn_auto_populate': True if have.fqdn['autopopulate'] == 'enabled' else False
- })
- if 'tmName' in have.fqdn:
- self.want.update({
- 'fqdn': have.fqdn['tmName'],
- 'address': 'any6'
- })
- else:
- self.want.update({
- 'address': have.address
- })
- except Exception:
- return None
-
- def _read_purge_collection(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/pool/{2}/members".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(name=fq_name(self.module.params['partition'], self.module.params['pool']))
- )
-
- query = '?$select=name,selfLink,fqdn,address,ephemeral'
- resp = self.client.api.get(uri + query)
-
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- if 'items' in response:
- return response['items']
- return []
-
- def create_on_device(self):
- params = self.changes.api_params()
- params['name'] = self.want.full_name
- params['partition'] = self.want.partition
- uri = "https://{0}:{1}/mgmt/tm/ltm/pool/{2}/members".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(name=fq_name(self.want.partition, self.want.pool)),
-
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def update_on_device(self):
- params = self.changes.api_params()
- uri = "https://{0}:{1}/mgmt/tm/ltm/pool/{2}/members/{3}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(name=fq_name(self.want.partition, self.want.pool)),
- transform_name(self.want.partition, self.want.full_name)
-
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def remove_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/pool/{2}/members/{3}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(name=fq_name(self.want.partition, self.want.pool)),
- transform_name(self.want.partition, self.want.full_name)
-
- )
- response = self.client.api.delete(uri)
- if response.status == 200:
- return True
- raise F5ModuleError(response.content)
-
- def remove_node_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/node/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.node_name)
- )
- response = self.client.api.delete(uri)
- if response.status == 200:
- return True
- raise F5ModuleError(response.content)
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/pool/{2}/members/{3}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(name=fq_name(self.want.partition, self.want.pool)),
- transform_name(self.want.partition, self.want.full_name)
-
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- # Read the current list of tunnels so that IP encapsulation
- # checking can take place.
- tunnels_gre = self.read_current_tunnels_from_device('gre')
- tunnels_ipip = self.read_current_tunnels_from_device('ipip')
- response['tunnels'] = tunnels_gre + tunnels_ipip
-
- return ApiParameters(params=response)
-
- def read_current_node_from_device(self, node):
- uri = "https://{0}:{1}/mgmt/tm/ltm/node/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, node)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return NodeApiParameters(params=response)
-
- def read_current_tunnels_from_device(self, tunnel_type):
- uri = "https://{0}:{1}/mgmt/tm/net/tunnels/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- tunnel_type
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- if 'items' not in response:
- return []
- return [x['fullPath'] for x in response['items']]
-
- def _prepare_links(self, collection):
- # this is to ensure no duplicates are in the provided collection
- no_dupes = list(set(collection))
- links = list()
- purge_paths = [urlparse(link).path for link in no_dupes]
-
- for path in purge_paths:
- link = "https://{0}:{1}{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- path
- )
- links.append(link)
- return links
-
- def purge_from_device(self):
- links = self._prepare_links(self.purge_links)
-
- with TransactionContextManager(self.client) as transact:
- for link in links:
- resp = transact.api.delete(link)
-
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return True
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- element_spec = dict(
- address=dict(aliases=['host', 'ip']),
- fqdn=dict(
- aliases=['hostname']
- ),
- name=dict(),
- port=dict(type='int'),
- connection_limit=dict(type='int'),
- description=dict(),
- rate_limit=dict(type='int'),
- ratio=dict(type='int'),
- preserve_node=dict(type='bool'),
- priority_group=dict(type='int'),
- state=dict(
- default='present',
- choices=['absent', 'present', 'enabled', 'disabled', 'forced_offline']
- ),
- fqdn_auto_populate=dict(type='bool'),
- reuse_nodes=dict(type='bool', default=True),
- availability_requirements=dict(
- type='dict',
- options=dict(
- type=dict(
- choices=['all', 'at_least'],
- required=True
- ),
- at_least=dict(type='int'),
- ),
- required_if=[
- ['type', 'at_least', ['at_least']],
- ]
- ),
- monitors=dict(type='list'),
- ip_encapsulation=dict(),
- partition=dict(
- default='Common',
- fallback=(env_fallback, ['F5_PARTITION'])
- ),
- )
- aggregate_spec = deepcopy(element_spec)
-
- # remove default in aggregate spec, to handle common arguments
- remove_default_spec(aggregate_spec)
-
- self.argument_spec = dict(
- aggregate=dict(
- type='list',
- elements='dict',
- options=aggregate_spec,
- aliases=['members'],
- mutually_exclusive=[
- ['address', 'fqdn']
- ],
- required_one_of=[
- ['address', 'fqdn']
- ],
- ),
- replace_all_with=dict(
- type='bool',
- aliases=['purge'],
- default='no'
- ),
- pool=dict(required=True),
- partition=dict(
- default='Common',
- fallback=(env_fallback, ['F5_PARTITION'])
- ),
- )
-
- self.argument_spec.update(element_spec)
- self.argument_spec.update(f5_argument_spec)
-
- self.mutually_exclusive = [
- ['address', 'aggregate'],
- ['fqdn', 'aggregate']
- ]
- self.required_one_of = [
- ['address', 'fqdn', 'aggregate'],
- ]
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode,
- mutually_exclusive=spec.mutually_exclusive,
- required_one_of=spec.required_one_of,
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_profile_analytics.py b/lib/ansible/modules/network/f5/bigip_profile_analytics.py
deleted file mode 100644
index 3b8f9f1c3e..0000000000
--- a/lib/ansible/modules/network/f5/bigip_profile_analytics.py
+++ /dev/null
@@ -1,761 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2018, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_profile_analytics
-short_description: Manage HTTP analytics profiles on a BIG-IP
-description:
- - Manage HTTP analytics profiles on a BIG-IP.
-version_added: 2.8
-options:
- name:
- description:
- - Specifies the name of the profile.
- type: str
- required: True
- parent:
- description:
- - Specifies the profile from which this profile inherits settings.
- - When creating a new profile, if this parameter is not specified, the default
- is the system-supplied C(analytics) profile.
- type: str
- description:
- description:
- - Description of the profile.
- type: str
- collect_geo:
- description:
- - Enables or disables the collection of the names of the countries
- from where the traffic was sent.
- type: bool
- collect_ip:
- description:
- - Enables or disables the collection of client IPs statistics.
- type: bool
- collect_max_tps_and_throughput:
- description:
- - Enables or disables the collection of maximum TPS and throughput
- for all collected entities.
- type: bool
- collect_page_load_time:
- description:
- - Enables or disables the collection of the page load time
- statistics.
- type: bool
- collect_url:
- description:
- - Enables or disables the collection of requested URL statistics.
- type: bool
- collect_user_agent:
- description:
- - Enables or disables the collection of user agents.
- type: bool
- collect_user_sessions:
- description:
- - Enables or disables the collection of the unique user sessions.
- type: bool
- collected_stats_external_logging:
- description:
- - Enables or disables the external logging of the collected
- statistics.
- type: bool
- collected_stats_internal_logging:
- description:
- - Enables or disables the internal logging of the collected
- statistics.
- type: bool
- external_logging_publisher:
- description:
- - Specifies the external logging publisher used to send statistical
- data to one or more destinations.
- type: str
- notification_by_syslog:
- description:
- - Enables or disables logging of the analytics alerts into the
- Syslog.
- type: bool
- notification_by_email:
- description:
- - Enables or disables sending the analytics alerts by email.
- type: bool
- notification_email_addresses:
- description:
- - Specifies which email addresses receive alerts by email when
- C(notification_by_email) is enabled.
- type: list
- partition:
- description:
- - Device partition to manage resources on.
- type: str
- default: Common
- state:
- description:
- - When C(present), ensures that the profile exists.
- - When C(absent), ensures the profile is removed.
- type: str
- choices:
- - present
- - absent
- default: present
-extends_documentation_fragment: f5
-author:
- - Tim Rupp (@caphrim007)
-'''
-
-EXAMPLES = r'''
-- name: Create a profile
- bigip_profile_analytics:
- name: profile1
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-'''
-
-RETURN = r'''
-param1:
- description: The new param1 value of the resource.
- returned: changed
- type: bool
- sample: true
-param2:
- description: The new param2 value of the resource.
- returned: changed
- type: str
- sample: Foo is bar
-'''
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.basic import env_fallback
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import fq_name
- from library.module_utils.network.f5.common import transform_name
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.common import flatten_boolean
- from library.module_utils.network.f5.compare import cmp_simple_list
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import fq_name
- from ansible.module_utils.network.f5.common import transform_name
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.common import flatten_boolean
- from ansible.module_utils.network.f5.compare import cmp_simple_list
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'defaultsFrom': 'parent',
- 'collectGeo': 'collect_geo',
- 'collectIp': 'collect_ip',
- 'collectMaxTpsAndThroughput': 'collect_max_tps_and_throughput',
- 'collectPageLoadTime': 'collect_page_load_time',
- 'collectUrl': 'collect_url',
- 'collectUserAgent': 'collect_user_agent',
- 'collectUserSessions': 'collect_user_sessions',
- 'collectedStatsExternalLogging': 'collected_stats_external_logging',
- 'collectedStatsInternalLogging': 'collected_stats_internal_logging',
- 'externalLoggingPublisher': 'external_logging_publisher',
- 'notificationBySyslog': 'notification_by_syslog',
- 'notificationByEmail': 'notification_by_email',
- 'notificationEmailAddresses': 'notification_email_addresses'
- }
-
- api_attributes = [
- 'description',
- 'defaultsFrom',
- 'collectGeo',
- 'collectIp',
- 'collectMaxTpsAndThroughput',
- 'collectPageLoadTime',
- 'collectUrl',
- 'collectUserAgent',
- 'collectUserSessions',
- 'collectedStatsExternalLogging',
- 'collectedStatsInternalLogging',
- 'externalLoggingPublisher',
- 'notificationBySyslog',
- 'notificationByEmail',
- 'notificationEmailAddresses',
- ]
-
- returnables = [
- 'collect_geo',
- 'collect_ip',
- 'collect_max_tps_and_throughput',
- 'collect_page_load_time',
- 'collect_url',
- 'collect_user_agent',
- 'collect_user_sessions',
- 'collected_stats_external_logging',
- 'collected_stats_internal_logging',
- 'description',
- 'external_logging_publisher',
- 'notification_by_syslog',
- 'notification_by_email',
- 'notification_email_addresses',
- 'parent',
- ]
-
- updatables = [
- 'collect_geo',
- 'collect_ip',
- 'collect_max_tps_and_throughput',
- 'collect_page_load_time',
- 'collect_url',
- 'collect_user_agent',
- 'collect_user_sessions',
- 'collected_stats_external_logging',
- 'collected_stats_internal_logging',
- 'description',
- 'external_logging_publisher',
- 'notification_by_syslog',
- 'notification_by_email',
- 'notification_email_addresses',
- 'parent',
- ]
-
- @property
- def external_logging_publisher(self):
- if self._values['external_logging_publisher'] is None:
- return None
- if self._values['external_logging_publisher'] in ['none', '']:
- return ''
- result = fq_name(self.partition, self._values['external_logging_publisher'])
- return result
-
- @property
- def collect_geo(self):
- return flatten_boolean(self._values['collect_geo'])
-
- @property
- def collect_ip(self):
- return flatten_boolean(self._values['collect_ip'])
-
- @property
- def collect_max_tps_and_throughput(self):
- return flatten_boolean(self._values['collect_max_tps_and_throughput'])
-
- @property
- def collect_page_load_time(self):
- return flatten_boolean(self._values['collect_page_load_time'])
-
- @property
- def collect_url(self):
- return flatten_boolean(self._values['collect_url'])
-
- @property
- def collect_user_agent(self):
- return flatten_boolean(self._values['collect_user_agent'])
-
- @property
- def collect_user_sessions(self):
- return flatten_boolean(self._values['collect_user_sessions'])
-
- @property
- def collected_stats_external_logging(self):
- return flatten_boolean(self._values['collected_stats_external_logging'])
-
- @property
- def collected_stats_internal_logging(self):
- return flatten_boolean(self._values['collected_stats_internal_logging'])
-
- @property
- def notification_by_syslog(self):
- return flatten_boolean(self._values['notification_by_syslog'])
-
- @property
- def notification_by_email(self):
- return flatten_boolean(self._values['notification_by_email'])
-
-
-class ApiParameters(Parameters):
- @property
- def description(self):
- if self._values['description'] in [None, 'none']:
- return None
- return self._values['description']
-
-
-class ModuleParameters(Parameters):
- @property
- def description(self):
- if self._values['description'] is None:
- return None
- elif self._values['description'] in ['none', '']:
- return ''
- return self._values['description']
-
- @property
- def parent(self):
- if self._values['parent'] is None:
- return None
- result = fq_name(self.partition, self._values['parent'])
- return result
-
- @property
- def notification_email_addresses(self):
- if self._values['notification_email_addresses'] is None:
- return None
- elif len(self._values['notification_email_addresses']) == 1 and self._values['notification_email_addresses'][0] in ['', 'none']:
- return []
- return self._values['notification_email_addresses']
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class UsableChanges(Changes):
- @property
- def collect_geo(self):
- if self._values['collect_geo'] is None:
- return None
- elif self._values['collect_geo'] == 'yes':
- return 'enabled'
- return 'disabled'
-
- @property
- def collect_ip(self):
- if self._values['collect_ip'] is None:
- return None
- elif self._values['collect_ip'] == 'yes':
- return 'enabled'
- return 'disabled'
-
- @property
- def collect_max_tps_and_throughput(self):
- if self._values['collect_max_tps_and_throughput'] is None:
- return None
- elif self._values['collect_max_tps_and_throughput'] == 'yes':
- return 'enabled'
- return 'disabled'
-
- @property
- def collect_page_load_time(self):
- if self._values['collect_page_load_time'] is None:
- return None
- elif self._values['collect_page_load_time'] == 'yes':
- return 'enabled'
- return 'disabled'
-
- @property
- def collect_url(self):
- if self._values['collect_url'] is None:
- return None
- elif self._values['collect_url'] == 'yes':
- return 'enabled'
- return 'disabled'
-
- @property
- def collect_user_agent(self):
- if self._values['collect_user_agent'] is None:
- return None
- elif self._values['collect_user_agent'] == 'yes':
- return 'enabled'
- return 'disabled'
-
- @property
- def collect_user_sessions(self):
- if self._values['collect_user_sessions'] is None:
- return None
- elif self._values['collect_user_sessions'] == 'yes':
- return 'enabled'
- return 'disabled'
-
- @property
- def collected_stats_external_logging(self):
- if self._values['collected_stats_external_logging'] is None:
- return None
- elif self._values['collected_stats_external_logging'] == 'yes':
- return 'enabled'
- return 'disabled'
-
- @property
- def collected_stats_internal_logging(self):
- if self._values['collected_stats_internal_logging'] is None:
- return None
- elif self._values['collected_stats_internal_logging'] == 'yes':
- return 'enabled'
- return 'disabled'
-
- @property
- def notification_by_syslog(self):
- if self._values['notification_by_syslog'] is None:
- return None
- elif self._values['notification_by_syslog'] == 'yes':
- return 'enabled'
- return 'disabled'
-
- @property
- def notification_by_email(self):
- if self._values['notification_by_email'] is None:
- return None
- elif self._values['notification_by_email'] == 'yes':
- return 'enabled'
- return 'disabled'
-
-
-class ReportableChanges(Changes):
- @property
- def collect_geo(self):
- return flatten_boolean(self._values['collect_geo'])
-
- @property
- def collect_ip(self):
- return flatten_boolean(self._values['collect_ip'])
-
- @property
- def collect_max_tps_and_throughput(self):
- return flatten_boolean(self._values['collect_max_tps_and_throughput'])
-
- @property
- def collect_page_load_time(self):
- return flatten_boolean(self._values['collect_page_load_time'])
-
- @property
- def collect_url(self):
- return flatten_boolean(self._values['collect_url'])
-
- @property
- def collect_user_agent(self):
- return flatten_boolean(self._values['collect_user_agent'])
-
- @property
- def collect_user_sessions(self):
- return flatten_boolean(self._values['collect_user_sessions'])
-
- @property
- def collected_stats_external_logging(self):
- return flatten_boolean(self._values['collected_stats_external_logging'])
-
- @property
- def collected_stats_internal_logging(self):
- return flatten_boolean(self._values['collected_stats_internal_logging'])
-
- @property
- def notification_by_syslog(self):
- return flatten_boolean(self._values['notification_by_syslog'])
-
- @property
- def notification_by_email(self):
- return flatten_boolean(self._values['notification_by_email'])
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
- @property
- def parent(self):
- if self.want.parent is None:
- return None
- if self.want.parent != self.have.parent:
- raise F5ModuleError(
- "The parent profile cannot be changed"
- )
-
- @property
- def description(self):
- if self.want.description is None:
- return None
- if self.have.description is None and self.want.description == '':
- return None
- if self.want.description != self.have.description:
- return self.want.description
-
- @property
- def notification_email_addresses(self):
- return cmp_simple_list(self.want.notification_email_addresses, self.have.notification_email_addresses)
-
- @property
- def external_logging_publisher(self):
- if self.want.external_logging_publisher is None:
- return None
- if self.have.external_logging_publisher is None and self.want.external_logging_publisher == '':
- return None
- if self.want.external_logging_publisher != self.have.external_logging_publisher:
- return self.want.external_logging_publisher
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(params=self.module.params)
- self.have = ApiParameters()
- self.changes = UsableChanges()
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = UsableChanges(params=changed)
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.client.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def exec_module(self):
- changed = False
- result = dict()
- state = self.want.state
-
- if state == "present":
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def present(self):
- if self.exists():
- return self.update()
- else:
- return self.create()
-
- def absent(self):
- if self.exists():
- return self.remove()
- return False
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def update(self):
- self.have = self.read_current_from_device()
- if not self.should_update():
- return False
- if self.module.check_mode:
- return True
- self.update_on_device()
- return True
-
- def remove(self):
- if self.module.check_mode:
- return True
- self.remove_from_device()
- if self.exists():
- raise F5ModuleError("Failed to delete the resource.")
- return True
-
- def create(self):
- self._set_changed_options()
- if self.module.check_mode:
- return True
- self.create_on_device()
- return True
-
- def exists(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/profile/analytics/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def create_on_device(self):
- params = self.changes.api_params()
- params['name'] = self.want.name
- params['partition'] = self.want.partition
- uri = "https://{0}:{1}/mgmt/tm/ltm/profile/analytics/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 409, 404]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return True
-
- def update_on_device(self):
- params = self.changes.api_params()
- uri = "https://{0}:{1}/mgmt/tm/ltm/profile/analytics/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 404]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def remove_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/profile/analytics/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- response = self.client.api.delete(uri)
- if response.status == 200:
- return True
- raise F5ModuleError(response.content)
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/profile/analytics/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return ApiParameters(params=response)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- name=dict(required=True),
- parent=dict(),
- description=dict(),
- collect_geo=dict(type='bool'),
- collect_ip=dict(type='bool'),
- collect_max_tps_and_throughput=dict(type='bool'),
- collect_page_load_time=dict(type='bool'),
- collect_url=dict(type='bool'),
- collect_user_agent=dict(type='bool'),
- collect_user_sessions=dict(type='bool'),
- collected_stats_external_logging=dict(type='bool'),
- collected_stats_internal_logging=dict(type='bool'),
- external_logging_publisher=dict(),
- notification_by_syslog=dict(type='bool'),
- notification_by_email=dict(type='bool'),
- notification_email_addresses=dict(type='list'),
- state=dict(
- default='present',
- choices=['present', 'absent']
- ),
- partition=dict(
- default='Common',
- fallback=(env_fallback, ['F5_PARTITION'])
- )
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode,
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_profile_client_ssl.py b/lib/ansible/modules/network/f5/bigip_profile_client_ssl.py
deleted file mode 100644
index d43cd62975..0000000000
--- a/lib/ansible/modules/network/f5/bigip_profile_client_ssl.py
+++ /dev/null
@@ -1,1117 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_profile_client_ssl
-short_description: Manages client SSL profiles on a BIG-IP
-description:
- - Manages client SSL profiles on a BIG-IP.
-version_added: 2.5
-options:
- name:
- description:
- - Specifies the name of the profile.
- type: str
- required: True
- parent:
- description:
- - The parent template of this monitor template. Once this value has
- been set, it cannot be changed. By default, this value is the C(clientssl)
- parent on the C(Common) partition.
- type: str
- default: /Common/clientssl
- ciphers:
- description:
- - Specifies the list of ciphers that the system supports. When creating a new
- profile, the default cipher list is provided by the parent profile.
- type: str
- cert_key_chain:
- description:
- - One or more certificates and keys to associate with the SSL profile. This
- option is always a list. The keys in the list dictate the details of the
- client/key/chain combination. Note that BIG-IPs can only have one of each
- type of each certificate/key type. This means that you can only have one
- RSA, one DSA, and one ECDSA per profile. If you attempt to assign two
- RSA, DSA, or ECDSA certificate/key combo, the device will reject this.
- - This list is a complex list that specifies a number of keys.
- suboptions:
- cert:
- description:
- - Specifies a cert name for use.
- type: str
- required: True
- key:
- description:
- - Contains a key name.
- type: str
- required: True
- chain:
- description:
- - Contains a certificate chain that is relevant to the certificate and key
- mentioned earlier.
- - This key is optional.
- type: str
- passphrase:
- description:
- - Contains the passphrase of the key file, should it require one.
- - Passphrases are encrypted on the remote BIG-IP device. Therefore, there is no way
- to compare them when updating a client SSL profile. Due to this, if you specify a
- passphrase, this module will always register a C(changed) event.
- type: str
- type: list
- partition:
- description:
- - Device partition to manage resources on.
- type: str
- default: Common
- version_added: 2.5
- options:
- description:
- - Options that the system uses for SSL processing in the form of a list. When
- creating a new profile, the list is provided by the parent profile.
- - When a C('') or C(none) value is provided all options for SSL processing are disabled.
- type: list
- choices:
- - netscape-reuse-cipher-change-bug
- - microsoft-big-sslv3-buffer
- - msie-sslv2-rsa-padding
- - ssleay-080-client-dh-bug
- - tls-d5-bug
- - tls-block-padding-bug
- - dont-insert-empty-fragments
- - no-ssl
- - no-dtls
- - no-session-resumption-on-renegotiation
- - no-tlsv1.1
- - no-tlsv1.2
- - no-tlsv1.3
- - single-dh-use
- - ephemeral-rsa
- - cipher-server-preference
- - tls-rollback-bug
- - no-sslv2
- - no-sslv3
- - no-tls
- - no-tlsv1
- - pkcs1-check-1
- - pkcs1-check-2
- - netscape-ca-dn-bug
- - netscape-demo-cipher-change-bug
- - "none"
- version_added: 2.7
- secure_renegotiation:
- description:
- - Specifies the method of secure renegotiations for SSL connections. When
- creating a new profile, the setting is provided by the parent profile.
- - When C(request) is set the system request secure renegotation of SSL
- connections.
- - C(require) is a default setting and when set the system permits initial SSL
- handshakes from clients but terminates renegotiations from unpatched clients.
- - The C(require-strict) setting the system requires strict renegotiation of SSL
- connections. In this mode the system refuses connections to insecure servers,
- and terminates existing SSL connections to insecure servers.
- type: str
- choices:
- - require
- - require-strict
- - request
- version_added: 2.7
- allow_non_ssl:
- description:
- - Enables or disables acceptance of non-SSL connections.
- - When creating a new profile, the setting is provided by the parent profile.
- type: bool
- version_added: 2.7
- server_name:
- description:
- - Specifies the fully qualified DNS hostname of the server used in Server Name Indication communications.
- When creating a new profile, the setting is provided by the parent profile.
- - The server name can also be a wildcard string containing the asterisk C(*) character.
- type: str
- version_added: 2.8
- sni_default:
- description:
- - Indicates that the system uses this profile as the default SSL profile when there is no match to the
- server name, or when the client provides no SNI extension support.
- - When creating a new profile, the setting is provided by the parent profile.
- - There can be only one SSL profile with this setting enabled.
- type: bool
- version_added: 2.8
- sni_require:
- description:
- - Requires that the network peers also provide SNI support, this setting only takes effect when C(sni_default) is
- set to C(true).
- - When creating a new profile, the setting is provided by the parent profile.
- type: bool
- version_added: 2.8
- strict_resume:
- description:
- - Enables or disables the resumption of SSL sessions after an unclean shutdown.
- - When creating a new profile, the setting is provided by the parent profile.
- type: bool
- version_added: 2.8
- client_certificate:
- description:
- - Specifies the way the system handles client certificates.
- - When C(ignore), specifies that the system ignores certificates from client
- systems.
- - When C(require), specifies that the system requires a client to present a
- valid certificate.
- - When C(request), specifies that the system requests a valid certificate from a
- client but always authenticate the client.
- type: str
- choices:
- - ignore
- - require
- - request
- version_added: 2.8
- client_auth_frequency:
- description:
- - Specifies the frequency of client authentication for an SSL session.
- - When C(once), specifies that the system authenticates the client once for an
- SSL session.
- - When C(always), specifies that the system authenticates the client once for an
- SSL session and also upon reuse of that session.
- type: str
- choices:
- - once
- - always
- version_added: 2.8
- renegotiation:
- description:
- - Enables or disables SSL renegotiation.
- - When creating a new profile, the setting is provided by the parent profile.
- type: bool
- version_added: 2.8
- retain_certificate:
- description:
- - When C(yes), client certificate is retained in SSL session.
- type: bool
- version_added: 2.8
- cert_auth_depth:
- description:
- - Specifies the maximum number of certificates to be traversed in a client
- certificate chain.
- type: int
- version_added: 2.8
- trusted_cert_authority:
- description:
- - Specifies a client CA that the system trusts.
- type: str
- version_added: 2.8
- advertised_cert_authority:
- description:
- - Specifies that the CAs that the system advertises to clients is being trusted
- by the profile.
- type: str
- version_added: 2.8
- client_auth_crl:
- description:
- - Specifies the name of a file containing a list of revoked client certificates.
- type: str
- version_added: 2.8
- allow_expired_crl:
- description:
- - Instructs the system to use the specified CRL file even if it has expired.
- type: bool
- version_added: 2.8
- state:
- description:
- - When C(present), ensures that the profile exists.
- - When C(absent), ensures the profile is removed.
- type: str
- choices:
- - present
- - absent
- default: present
- version_added: 2.5
-notes:
- - Requires BIG-IP software version >= 12
-extends_documentation_fragment: f5
-author:
- - Tim Rupp (@caphrim007)
- - Wojciech Wypior (@wojtek0806)
-'''
-
-EXAMPLES = r'''
-- name: Create client SSL profile
- bigip_profile_client_ssl:
- state: present
- name: my_profile
- provider:
- server: lb.mydomain.com
- user: admin
- password: secret
- delegate_to: localhost
-
-- name: Create client SSL profile with specific ciphers
- bigip_profile_client_ssl:
- state: present
- name: my_profile
- ciphers: "!SSLv3:!SSLv2:ECDHE+AES-GCM+SHA256:ECDHE-RSA-AES128-CBC-SHA"
- provider:
- server: lb.mydomain.com
- user: admin
- password: secret
- delegate_to: localhost
-
-- name: Create client SSL profile with specific SSL options
- bigip_profile_client_ssl:
- state: present
- name: my_profile
- options:
- - no-sslv2
- - no-sslv3
- provider:
- server: lb.mydomain.com
- user: admin
- password: secret
- delegate_to: localhost
-
-- name: Create client SSL profile require secure renegotiation
- bigip_profile_client_ssl:
- state: present
- name: my_profile
- secure_renegotiation: request
- provider:
- server: lb.mydomain.com
- user: admin
- password: secret
- delegate_to: localhost
-
-- name: Create a client SSL profile with a cert/key/chain setting
- bigip_profile_client_ssl:
- state: present
- name: my_profile
- cert_key_chain:
- - cert: bigip_ssl_cert1
- key: bigip_ssl_key1
- chain: bigip_ssl_cert1
- provider:
- server: lb.mydomain.com
- user: admin
- password: secret
- delegate_to: localhost
-'''
-
-RETURN = r'''
-ciphers:
- description: The ciphers applied to the profile.
- returned: changed
- type: str
- sample: "!SSLv3:!SSLv2:ECDHE+AES-GCM+SHA256:ECDHE-RSA-AES128-CBC-SHA"
-options:
- description: The list of options for SSL processing.
- returned: changed
- type: list
- sample: ['no-sslv2', 'no-sslv3']
-secure_renegotiation:
- description: The method of secure SSL renegotiation.
- returned: changed
- type: str
- sample: request
-allow_non_ssl:
- description: Acceptance of non-SSL connections.
- returned: changed
- type: bool
- sample: yes
-strict_resume:
- description: Resumption of SSL sessions after an unclean shutdown.
- returned: changed
- type: bool
- sample: yes
-renegotiation:
- description: Renegotiation of SSL sessions.
- returned: changed
- type: bool
- sample: yes
-'''
-
-import os
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.basic import env_fallback
-from ansible.module_utils.six import iteritems
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import fq_name
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.common import flatten_boolean
- from library.module_utils.network.f5.common import transform_name
- from library.module_utils.network.f5.common import is_empty_list
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import fq_name
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.common import flatten_boolean
- from ansible.module_utils.network.f5.common import transform_name
- from ansible.module_utils.network.f5.common import is_empty_list
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'certKeyChain': 'cert_key_chain',
- 'defaultsFrom': 'parent',
- 'allowNonSsl': 'allow_non_ssl',
- 'secureRenegotiation': 'secure_renegotiation',
- 'tmOptions': 'options',
- 'sniDefault': 'sni_default',
- 'sniRequire': 'sni_require',
- 'serverName': 'server_name',
- 'peerCertMode': 'client_certificate',
- 'authenticate': 'client_auth_frequency',
- 'retainCertificate': 'retain_certificate',
- 'authenticateDepth': 'cert_auth_depth',
- 'caFile': 'trusted_cert_authority',
- 'clientCertCa': 'advertised_cert_authority',
- 'crlFile': 'client_auth_crl',
- 'allowExpiredCrl': 'allow_expired_crl',
- 'strictResume': 'strict_resume',
- 'renegotiation': 'renegotiation',
- }
-
- api_attributes = [
- 'ciphers',
- 'certKeyChain',
- 'defaultsFrom',
- 'tmOptions',
- 'secureRenegotiation',
- 'allowNonSsl',
- 'sniDefault',
- 'sniRequire',
- 'serverName',
- 'peerCertMode',
- 'authenticate',
- 'retainCertificate',
- 'authenticateDepth',
- 'caFile',
- 'clientCertCa',
- 'crlFile',
- 'allowExpiredCrl',
- 'strictResume',
- 'renegotiation',
- ]
-
- returnables = [
- 'ciphers',
- 'allow_non_ssl',
- 'options',
- 'secure_renegotiation',
- 'cert_key_chain',
- 'parent',
- 'sni_default',
- 'sni_require',
- 'server_name',
- 'client_certificate',
- 'client_auth_frequency',
- 'retain_certificate',
- 'cert_auth_depth',
- 'trusted_cert_authority',
- 'advertised_cert_authority',
- 'client_auth_crl',
- 'allow_expired_crl',
- 'strict_resume',
- 'renegotiation',
- ]
-
- updatables = [
- 'ciphers',
- 'cert_key_chain',
- 'allow_non_ssl',
- 'options',
- 'secure_renegotiation',
- 'sni_default',
- 'sni_require',
- 'server_name',
- 'client_certificate',
- 'client_auth_frequency',
- 'retain_certificate',
- 'cert_auth_depth',
- 'trusted_cert_authority',
- 'advertised_cert_authority',
- 'client_auth_crl',
- 'allow_expired_crl',
- 'strict_resume',
- 'renegotiation',
- ]
-
- @property
- def retain_certificate(self):
- return flatten_boolean(self._values['retain_certificate'])
-
- @property
- def allow_expired_crl(self):
- return flatten_boolean(self._values['allow_expired_crl'])
-
-
-class ModuleParameters(Parameters):
- def _key_filename(self, name):
- if name.endswith('.key'):
- return name
- else:
- return name + '.key'
-
- def _cert_filename(self, name):
- if name.endswith('.crt'):
- return name
- else:
- return name + '.crt'
-
- def _get_chain_value(self, item):
- if 'chain' not in item or item['chain'] == 'none':
- result = 'none'
- else:
- result = self._cert_filename(fq_name(self.partition, item['chain']))
- return result
-
- @property
- def parent(self):
- if self._values['parent'] is None:
- return None
- if self._values['parent'] == 'clientssl':
- return '/Common/clientssl'
- result = fq_name(self.partition, self._values['parent'])
- return result
-
- @property
- def cert_key_chain(self):
- if self._values['cert_key_chain'] is None:
- return None
- result = []
- for item in self._values['cert_key_chain']:
- if 'key' in item and 'cert' not in item:
- raise F5ModuleError(
- "When providing a 'key', you must also provide a 'cert'"
- )
- if 'cert' in item and 'key' not in item:
- raise F5ModuleError(
- "When providing a 'cert', you must also provide a 'key'"
- )
- key = self._key_filename(item['key'])
- cert = self._cert_filename(item['cert'])
- chain = self._get_chain_value(item)
- name = os.path.basename(cert)
- filename, ex = os.path.splitext(name)
- tmp = {
- 'name': filename,
- 'cert': fq_name(self.partition, cert),
- 'key': fq_name(self.partition, key),
- 'chain': chain
- }
- if 'passphrase' in item:
- tmp['passphrase'] = item['passphrase']
- result.append(tmp)
- result = sorted(result, key=lambda x: x['name'])
- return result
-
- @property
- def allow_non_ssl(self):
- result = flatten_boolean(self._values['allow_non_ssl'])
- if result is None:
- return None
- if result == 'yes':
- return 'enabled'
- return 'disabled'
-
- @property
- def strict_resume(self):
- result = flatten_boolean(self._values['strict_resume'])
- if result is None:
- return None
- if result == 'yes':
- return 'enabled'
- return 'disabled'
-
- @property
- def renegotiation(self):
- result = flatten_boolean(self._values['renegotiation'])
- if result is None:
- return None
- if result == 'yes':
- return 'enabled'
- return 'disabled'
-
- @property
- def options(self):
- options = self._values['options']
- if options is None:
- return None
- if is_empty_list(options):
- return []
- return options
-
- @property
- def sni_require(self):
- require = flatten_boolean(self._values['sni_require'])
- default = self.sni_default
- if require is None:
- return None
- if default in [None, False]:
- if require == 'yes':
- raise F5ModuleError(
- "Cannot set 'sni_require' to {0} if 'sni_default' is set as {1}".format(require, default))
- if require == 'yes':
- return True
- else:
- return False
-
- @property
- def trusted_cert_authority(self):
- if self._values['trusted_cert_authority'] is None:
- return None
- if self._values['trusted_cert_authority'] in ['', 'none']:
- return ''
- result = fq_name(self.partition, self._values['trusted_cert_authority'])
- return result
-
- @property
- def advertised_cert_authority(self):
- if self._values['advertised_cert_authority'] is None:
- return None
- if self._values['advertised_cert_authority'] in ['', 'none']:
- return ''
- result = fq_name(self.partition, self._values['advertised_cert_authority'])
- return result
-
- @property
- def client_auth_crl(self):
- if self._values['client_auth_crl'] is None:
- return None
- if self._values['client_auth_crl'] in ['', 'none']:
- return ''
- result = fq_name(self.partition, self._values['client_auth_crl'])
- return result
-
-
-class ApiParameters(Parameters):
- @property
- def cert_key_chain(self):
- if self._values['cert_key_chain'] is None:
- return None
- result = []
- for item in self._values['cert_key_chain']:
- tmp = dict(
- name=item['name'],
- )
- for x in ['cert', 'key', 'chain', 'passphrase']:
- if x in item:
- tmp[x] = item[x]
- if 'chain' not in item:
- tmp['chain'] = 'none'
- result.append(tmp)
- result = sorted(result, key=lambda y: y['name'])
- return result
-
- @property
- def sni_default(self):
- result = self._values['sni_default']
- if result is None:
- return None
- if result == 'true':
- return True
- else:
- return False
-
- @property
- def sni_require(self):
- result = self._values['sni_require']
- if result is None:
- return None
- if result == 'true':
- return True
- else:
- return False
-
- @property
- def trusted_cert_authority(self):
- if self._values['trusted_cert_authority'] in [None, 'none']:
- return None
- return self._values['trusted_cert_authority']
-
- @property
- def advertised_cert_authority(self):
- if self._values['advertised_cert_authority'] in [None, 'none']:
- return None
- return self._values['advertised_cert_authority']
-
- @property
- def client_auth_crl(self):
- if self._values['client_auth_crl'] in [None, 'none']:
- return None
- return self._values['client_auth_crl']
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class UsableChanges(Changes):
- @property
- def retain_certificate(self):
- if self._values['retain_certificate'] is None:
- return None
- elif self._values['retain_certificate'] == 'yes':
- return 'true'
- return 'false'
-
- @property
- def allow_expired_crl(self):
- if self._values['allow_expired_crl'] is None:
- return None
- elif self._values['allow_expired_crl'] == 'yes':
- return 'enabled'
- return 'disabled'
-
-
-class ReportableChanges(Changes):
- @property
- def allow_non_ssl(self):
- if self._values['allow_non_ssl'] is None:
- return None
- elif self._values['allow_non_ssl'] == 'enabled':
- return 'yes'
- return 'no'
-
- @property
- def strict_resume(self):
- if self._values['strict_resume'] is None:
- return None
- elif self._values['strict_resume'] == 'enabled':
- return 'yes'
- return 'no'
-
- @property
- def retain_certificate(self):
- return flatten_boolean(self._values['retain_certificate'])
-
- @property
- def allow_expired_crl(self):
- return flatten_boolean(self._values['allow_expired_crl'])
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- result = self.__default(param)
- return result
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
- def to_tuple(self, items):
- result = []
- for x in items:
- tmp = [(str(k), str(v)) for k, v in iteritems(x)]
- result += tmp
- return result
-
- def _diff_complex_items(self, want, have):
- if want == [] and have is None:
- return None
- if want is None:
- return None
- w = self.to_tuple(want)
- h = self.to_tuple(have)
- if set(w).issubset(set(h)):
- return None
- else:
- return want
-
- @property
- def parent(self):
- if self.want.parent != self.have.parent:
- raise F5ModuleError(
- "The parent profile cannot be changed"
- )
-
- @property
- def cert_key_chain(self):
- result = self._diff_complex_items(self.want.cert_key_chain, self.have.cert_key_chain)
- return result
-
- @property
- def options(self):
- if self.want.options is None:
- return None
- # starting with v14 options may return as a space delimited string in curly
- # braces, eg "{ option1 option2 }", or simply "none" to indicate empty set
- if self.have.options is None or self.have.options == 'none':
- self.have.options = []
- if not isinstance(self.have.options, list):
- if self.have.options.startswith('{'):
- self.have.options = self.have.options[2:-2].split(' ')
- else:
- self.have.options = [self.have.options]
- if not self.want.options:
- # we don't want options. If we have any, indicate we should remove, else noop
- return [] if self.have.options else None
- if not self.have.options:
- return self.want.options
- if set(self.want.options) != set(self.have.options):
- return self.want.options
-
- @property
- def sni_require(self):
- if self.want.sni_require is None:
- return None
- if self.want.sni_require is False:
- if self.have.sni_default is True and self.want.sni_default is None:
- raise F5ModuleError(
- "Cannot set 'sni_require' to {0} if 'sni_default' is {1}".format(
- self.want.sni_require, self.have.sni_default)
- )
- if self.want.sni_require == self.have.sni_require:
- return None
- return self.want.sni_require
-
- @property
- def trusted_cert_authority(self):
- if self.want.trusted_cert_authority is None:
- return None
- if self.want.trusted_cert_authority == '' and self.have.trusted_cert_authority is None:
- return None
- if self.want.trusted_cert_authority != self.have.trusted_cert_authority:
- return self.want.trusted_cert_authority
-
- @property
- def advertised_cert_authority(self):
- if self.want.advertised_cert_authority is None:
- return None
- if self.want.advertised_cert_authority == '' and self.have.advertised_cert_authority is None:
- return None
- if self.want.advertised_cert_authority != self.have.advertised_cert_authority:
- return self.want.advertised_cert_authority
-
- @property
- def client_auth_crl(self):
- if self.want.client_auth_crl is None:
- return None
- if self.want.client_auth_crl == '' and self.have.client_auth_crl is None:
- return None
- if self.want.client_auth_crl != self.have.client_auth_crl:
- return self.want.client_auth_crl
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(params=self.module.params)
- self.have = ApiParameters()
- self.changes = UsableChanges()
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = UsableChanges(params=changed)
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def exec_module(self):
- changed = False
- result = dict()
- state = self.want.state
-
- if state == "present":
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.client.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def present(self):
- if self.exists():
- return self.update()
- else:
- return self.create()
-
- def exists(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/profile/client-ssl/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def update(self):
- self.have = self.read_current_from_device()
- if not self.should_update():
- return False
- if self.module.check_mode:
- return True
- self.update_on_device()
- return True
-
- def remove(self):
- if self.module.check_mode:
- return True
- self.remove_from_device()
- if self.exists():
- raise F5ModuleError("Failed to delete the resource.")
- return True
-
- def create(self):
- self._set_changed_options()
- if self.module.check_mode:
- return True
- self.create_on_device()
- return True
-
- def create_on_device(self):
- params = self.changes.api_params()
- params['name'] = self.want.name
- params['partition'] = self.want.partition
- uri = "https://{0}:{1}/mgmt/tm/ltm/profile/client-ssl/".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403, 404]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def update_on_device(self):
- params = self.changes.api_params()
- uri = "https://{0}:{1}/mgmt/tm/ltm/profile/client-ssl/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 404]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def absent(self):
- if self.exists():
- return self.remove()
- return False
-
- def remove_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/profile/client-ssl/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- response = self.client.api.delete(uri)
- if response.status == 200:
- return True
- raise F5ModuleError(response.content)
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/profile/client-ssl/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return ApiParameters(params=response)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- name=dict(required=True),
- parent=dict(default='/Common/clientssl'),
- ciphers=dict(),
- allow_non_ssl=dict(type='bool'),
- secure_renegotiation=dict(
- choices=['require', 'require-strict', 'request']
- ),
- options=dict(
- type='list',
- choices=[
- 'netscape-reuse-cipher-change-bug',
- 'microsoft-big-sslv3-buffer',
- 'msie-sslv2-rsa-padding',
- 'ssleay-080-client-dh-bug',
- 'tls-d5-bug',
- 'tls-block-padding-bug',
- 'dont-insert-empty-fragments',
- 'no-ssl',
- 'no-dtls',
- 'no-session-resumption-on-renegotiation',
- 'no-tlsv1.1',
- 'no-tlsv1.2',
- 'no-tlsv1.3',
- 'single-dh-use',
- 'ephemeral-rsa',
- 'cipher-server-preference',
- 'tls-rollback-bug',
- 'no-sslv2',
- 'no-sslv3',
- 'no-tls',
- 'no-tlsv1',
- 'pkcs1-check-1',
- 'pkcs1-check-2',
- 'netscape-ca-dn-bug',
- 'netscape-demo-cipher-change-bug',
- 'none',
- ]
- ),
- cert_key_chain=dict(
- type='list',
- options=dict(
- cert=dict(required=True),
- key=dict(required=True),
- chain=dict(),
- passphrase=dict()
- )
- ),
- state=dict(
- default='present',
- choices=['present', 'absent']
- ),
- sni_default=dict(type='bool'),
- sni_require=dict(type='bool'),
- server_name=dict(),
- client_certificate=dict(
- choices=['require', 'ignore', 'request']
- ),
- client_auth_frequency=dict(
- choices=['once', 'always']
- ),
- cert_auth_depth=dict(type='int'),
- retain_certificate=dict(type='bool'),
- trusted_cert_authority=dict(),
- advertised_cert_authority=dict(),
- client_auth_crl=dict(),
- allow_expired_crl=dict(type='bool'),
- strict_resume=dict(type='bool'),
- renegotiation=dict(type='bool'),
- partition=dict(
- default='Common',
- fallback=(env_fallback, ['F5_PARTITION'])
- )
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode,
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_profile_dns.py b/lib/ansible/modules/network/f5/bigip_profile_dns.py
deleted file mode 100644
index b3fee050df..0000000000
--- a/lib/ansible/modules/network/f5/bigip_profile_dns.py
+++ /dev/null
@@ -1,751 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_profile_dns
-short_description: Manage DNS profiles on a BIG-IP
-description:
- - Manage DNS profiles on a BIG-IP. Many DNS profiles; each with their
- own adjustments to the standard C(dns) profile. Users of this module should be aware
- that many of the adjustable knobs have no module default. Instead, the default is
- assigned by the BIG-IP system itself which, in most cases, is acceptable.
-version_added: 2.6
-options:
- name:
- description:
- - Specifies the name of the DNS profile.
- type: str
- required: True
- parent:
- description:
- - Specifies the profile from which this profile inherits settings.
- - When creating a new profile, if this parameter is not specified, the default
- is the system-supplied C(dns) profile.
- type: str
- enable_dns_express:
- description:
- - Specifies whether the DNS Express engine is enabled.
- - When creating a new profile, if this parameter is not specified, the default
- is provided by the parent profile.
- - The DNS Express engine receives zone transfers from the authoritative DNS server
- for the zone. If the C(enable_zone_transfer) setting is also C(yes) on this profile,
- the DNS Express engine also responds to zone transfer requests made by the nameservers
- configured as zone transfer clients for the DNS Express zone.
- type: bool
- enable_zone_transfer:
- description:
- - Specifies whether the system answers zone transfer requests for a DNS zone created
- on the system.
- - When creating a new profile, if this parameter is not specified, the default
- is provided by the parent profile.
- - The C(enable_dns_express) and C(enable_zone_transfer) settings on a DNS profile
- affect how the system responds to zone transfer requests.
- - When the C(enable_dns_express) and C(enable_zone_transfer) settings are both C(yes),
- if a zone transfer request matches a DNS Express zone, then DNS Express answers the
- request.
- - When the C(enable_dns_express) setting is C(no) and the C(enable_zone_transfer)
- setting is C(yes), the BIG-IP system processes zone transfer requests based on the
- last action and answers the request from local BIND or a pool member.
- type: bool
- enable_dnssec:
- description:
- - Specifies whether the system signs responses with DNSSEC keys and replies to DNSSEC
- specific queries (e.g., DNSKEY query type).
- - When creating a new profile, if this parameter is not specified, the default
- is provided by the parent profile.
- type: bool
- enable_gtm:
- description:
- - Specifies whether the system uses Global Traffic Manager to manage the response.
- - When creating a new profile, if this parameter is not specified, the default
- is provided by the parent profile.
- type: bool
- process_recursion_desired:
- description:
- - Specifies whether to process client-side DNS packets with Recursion Desired set in
- the header.
- - When creating a new profile, if this parameter is not specified, the default
- is provided by the parent profile.
- - If set to C(no), processing of the packet is subject to the unhandled-query-action
- option.
- type: bool
- use_local_bind:
- description:
- - Specifies whether the system forwards non-wide IP queries to the local BIND server
- on the BIG-IP system.
- - For best performance, disable this setting when using a DNS cache.
- - When creating a new profile, if this parameter is not specified, the default
- is provided by the parent profile.
- type: bool
- enable_dns_firewall:
- description:
- - Specifies whether DNS firewall capability is enabled.
- - When creating a new profile, if this parameter is not specified, the default
- is provided by the parent profile.
- type: bool
- enable_cache:
- description:
- - Specifies whether the system caches DNS responses.
- - When creating a new profile, if this parameter is not specified, the default
- is provided by the parent profile.
- - When C(yes), the BIG-IP system caches DNS responses handled by the virtual
- servers associated with this profile. When you enable this setting, you must
- also specify a value for C(cache_name).
- - When C(no), the BIG-IP system does not cache DNS responses handled by the
- virtual servers associated with this profile. However, the profile retains
- the association with the DNS cache in the C(cache_name) parameter. Disable
- this setting when you want to debug the system.
- type: bool
- version_added: 2.7
- cache_name:
- description:
- - Specifies the user-created cache that the system uses to cache DNS responses.
- - When you select a cache for the system to use, you must also set C(enable_dns_cache)
- to C(yes)
- type: str
- version_added: 2.7
- unhandled_query_action:
- description:
- - Specifies the action to take when a query does not match a Wide IP or a DNS Express Zone.
- - When C(allow), the BIG-IP system forwards queries to a DNS server or pool member.
- If a pool is not associated with a listener and the Use BIND Server on BIG-IP setting
- is set to Enabled, requests are forwarded to the local BIND server.
- - When C(drop), the BIG-IP system does not respond to the query.
- - When C(reject), the BIG-IP system returns the query with the REFUSED return code.
- - When C(hint), the BIG-IP system returns the query with a list of root name servers.
- - When C(no-error), the BIG-IP system returns the query with the NOERROR return code.
- - When creating a new profile, if this parameter is not specified, the default
- is provided by the parent profile.
- type: str
- choices:
- - allow
- - drop
- - reject
- - hint
- - no-error
- version_added: 2.7
- partition:
- description:
- - Device partition to manage resources on.
- type: str
- default: Common
- state:
- description:
- - When C(present), ensures that the profile exists.
- - When C(absent), ensures the profile is removed.
- type: str
- choices:
- - present
- - absent
- default: present
-extends_documentation_fragment: f5
-author:
- - Tim Rupp (@caphrim007)
-'''
-
-EXAMPLES = r'''
-- name: Create a DNS profile
- bigip_profile_dns:
- name: foo
- enable_dns_express: no
- enable_dnssec: no
- enable_gtm: no
- process_recursion_desired: no
- use_local_bind: no
- enable_dns_firewall: yes
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-'''
-
-RETURN = r'''
-enable_dns_express:
- description: Whether DNS Express is enabled on the resource or not.
- returned: changed
- type: bool
- sample: yes
-enable_zone_transfer:
- description: Whether zone transfer are enabled on the resource or not.
- returned: changed
- type: bool
- sample: no
-enable_dnssec:
- description: Whether DNSSEC is enabled on the resource or not.
- returned: changed
- type: bool
- sample: no
-enable_gtm:
- description: Whether GTM is used to manage the resource or not.
- returned: changed
- type: bool
- sample: yes
-process_recursion_desired:
- description: Whether client-side DNS packets are processed with Recursion Desired set.
- returned: changed
- type: bool
- sample: yes
-use_local_bind:
- description: Whether non-wide IP queries are forwarded to the local BIND server or not.
- returned: changed
- type: bool
- sample: no
-enable_dns_firewall:
- description: Whether DNS firewall capability is enabled or not.
- returned: changed
- type: bool
- sample: no
-enable_cache:
- description: Whether DNS caching is enabled or not.
- returned: changed
- type: bool
- sample: no
-cache_name:
- description: Name of the cache used by DNS.
- returned: changed
- type: str
- sample: /Common/cache1
-unhandled_query_action:
- description: What to do with unhandled queries
- returned: changed
- type: str
- sample: allow
-'''
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.basic import env_fallback
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import fq_name
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.common import transform_name
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import fq_name
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.common import transform_name
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'enableDnsFirewall': 'enable_dns_firewall',
- 'useLocalBind': 'use_local_bind',
- 'processRd': 'process_recursion_desired',
- 'enableGtm': 'enable_gtm',
- 'enableDnssec': 'enable_dnssec',
- 'processXfr': 'enable_zone_transfer',
- 'enableDnsExpress': 'enable_dns_express',
- 'defaultsFrom': 'parent',
- 'enableCache': 'enable_cache',
- 'cache': 'cache_name',
- 'unhandledQueryAction': 'unhandled_query_action',
- }
-
- api_attributes = [
- 'enableDnsFirewall',
- 'useLocalBind',
- 'processRd',
- 'enableGtm',
- 'enableDnssec',
- 'processXfr',
- 'enableDnsExpress',
- 'defaultsFrom',
- 'cache',
- 'enableCache',
- 'unhandledQueryAction',
- ]
-
- returnables = [
- 'enable_dns_firewall',
- 'use_local_bind',
- 'process_recursion_desired',
- 'enable_gtm',
- 'enable_dnssec',
- 'enable_zone_transfer',
- 'enable_dns_express',
- 'cache_name',
- 'enable_cache',
- 'unhandled_query_action',
- ]
-
- updatables = [
- 'enable_dns_firewall',
- 'use_local_bind',
- 'process_recursion_desired',
- 'enable_gtm',
- 'enable_dnssec',
- 'enable_zone_transfer',
- 'enable_dns_express',
- 'cache_name',
- 'enable_cache',
- 'unhandled_query_action',
- ]
-
-
-class ApiParameters(Parameters):
- @property
- def enable_dns_firewall(self):
- if self._values['enable_dns_firewall'] is None:
- return None
- if self._values['enable_dns_firewall'] == 'yes':
- return True
- return False
-
- @property
- def use_local_bind(self):
- if self._values['use_local_bind'] is None:
- return None
- if self._values['use_local_bind'] == 'yes':
- return True
- return False
-
- @property
- def process_recursion_desired(self):
- if self._values['process_recursion_desired'] is None:
- return None
- if self._values['process_recursion_desired'] == 'yes':
- return True
- return False
-
- @property
- def enable_gtm(self):
- if self._values['enable_gtm'] is None:
- return None
- if self._values['enable_gtm'] == 'yes':
- return True
- return False
-
- @property
- def enable_cache(self):
- if self._values['enable_cache'] is None:
- return None
- if self._values['enable_cache'] == 'yes':
- return True
- return False
-
- @property
- def enable_dnssec(self):
- if self._values['enable_dnssec'] is None:
- return None
- if self._values['enable_dnssec'] == 'yes':
- return True
- return False
-
- @property
- def enable_zone_transfer(self):
- if self._values['enable_zone_transfer'] is None:
- return None
- if self._values['enable_zone_transfer'] == 'yes':
- return True
- return False
-
- @property
- def enable_dns_express(self):
- if self._values['enable_dns_express'] is None:
- return None
- if self._values['enable_dns_express'] == 'yes':
- return True
- return False
-
- @property
- def unhandled_query_action(self):
- if self._values['unhandled_query_action'] is None:
- return None
- elif self._values['unhandled_query_action'] == 'noerror':
- return 'no-error'
- return self._values['unhandled_query_action']
-
-
-class ModuleParameters(Parameters):
- @property
- def parent(self):
- if self._values['parent'] is None:
- return None
- result = fq_name(self.partition, self._values['parent'])
- return result
-
- @property
- def cache_name(self):
- if self._values['cache_name'] is None:
- return None
- if self._values['cache_name'] == '':
- return ''
- result = fq_name(self.partition, self._values['cache_name'])
- return result
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class UsableChanges(Changes):
- @property
- def enable_dns_firewall(self):
- if self._values['enable_dns_firewall'] is None:
- return None
- if self._values['enable_dns_firewall']:
- return 'yes'
- return 'no'
-
- @property
- def use_local_bind(self):
- if self._values['use_local_bind'] is None:
- return None
- if self._values['use_local_bind']:
- return 'yes'
- return 'no'
-
- @property
- def process_recursion_desired(self):
- if self._values['process_recursion_desired'] is None:
- return None
- if self._values['process_recursion_desired']:
- return 'yes'
- return 'no'
-
- @property
- def enable_gtm(self):
- if self._values['enable_gtm'] is None:
- return None
- if self._values['enable_gtm']:
- return 'yes'
- return 'no'
-
- @property
- def enable_cache(self):
- if self._values['enable_cache'] is None:
- return None
- if self._values['enable_cache']:
- return 'yes'
- return 'no'
-
- @property
- def enable_dnssec(self):
- if self._values['enable_dnssec'] is None:
- return None
- if self._values['enable_dnssec']:
- return 'yes'
- return 'no'
-
- @property
- def enable_zone_transfer(self):
- if self._values['enable_zone_transfer'] is None:
- return None
- if self._values['enable_zone_transfer']:
- return 'yes'
- return 'no'
-
- @property
- def enable_dns_express(self):
- if self._values['enable_dns_express'] is None:
- return None
- if self._values['enable_dns_express']:
- return 'yes'
- return 'no'
-
- @property
- def unhandled_query_action(self):
- if self._values['unhandled_query_action'] is None:
- return None
- elif self._values['unhandled_query_action'] == 'no-error':
- return 'noerror'
- return self._values['unhandled_query_action']
-
-
-class ReportableChanges(Changes):
- pass
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(params=self.module.params)
- self.have = ApiParameters()
- self.changes = UsableChanges()
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = UsableChanges(params=changed)
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def exec_module(self):
- changed = False
- result = dict()
- state = self.want.state
-
- if state == "present":
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.client.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def present(self):
- if self.exists():
- return self.update()
- else:
- return self.create()
-
- def exists(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/profile/dns/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def update(self):
- self.have = self.read_current_from_device()
- if not self.should_update():
- return False
- if self.changes.enable_cache is True or self.have.enable_cache is True:
- if not self.have.cache_name or self.changes.cache_name == '':
- raise F5ModuleError(
- "To enable DNS cache, a DNS cache must be specified."
- )
- if self.module.check_mode:
- return True
- self.update_on_device()
- return True
-
- def remove(self):
- if self.module.check_mode:
- return True
- self.remove_from_device()
- if self.exists():
- raise F5ModuleError("Failed to delete the resource.")
- return True
-
- def create(self):
- self._set_changed_options()
- if self.want.enable_cache is True and not self.want.cache_name:
- raise F5ModuleError(
- "You must specify a 'cache_name' when creating a DNS profile that sets 'enable_cache' to 'yes'."
- )
-
- if self.module.check_mode:
- return True
- self.create_on_device()
- return True
-
- def create_on_device(self):
- params = self.changes.api_params()
- params['name'] = self.want.name
- params['partition'] = self.want.partition
- uri = "https://{0}:{1}/mgmt/tm/ltm/profile/dns/".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403, 404]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def update_on_device(self):
- params = self.changes.api_params()
- uri = "https://{0}:{1}/mgmt/tm/ltm/profile/dns/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 404]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def absent(self):
- if self.exists():
- return self.remove()
- return False
-
- def remove_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/profile/dns/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- response = self.client.api.delete(uri)
- if response.status == 200:
- return True
- raise F5ModuleError(response.content)
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/profile/dns/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return ApiParameters(params=response)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- name=dict(required=True),
- parent=dict(),
- enable_dns_express=dict(type='bool'),
- enable_zone_transfer=dict(type='bool'),
- enable_dnssec=dict(type='bool'),
- enable_gtm=dict(type='bool'),
- process_recursion_desired=dict(type='bool'),
- use_local_bind=dict(type='bool'),
- enable_dns_firewall=dict(type='bool'),
- enable_cache=dict(type='bool'),
- unhandled_query_action=dict(
- choices=['allow', 'drop', 'reject', 'hint', 'no-error']
- ),
- cache_name=dict(),
- state=dict(
- default='present',
- choices=['present', 'absent']
- ),
- partition=dict(
- default='Common',
- fallback=(env_fallback, ['F5_PARTITION'])
- )
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_profile_fastl4.py b/lib/ansible/modules/network/f5/bigip_profile_fastl4.py
deleted file mode 100644
index ce5f8deaf2..0000000000
--- a/lib/ansible/modules/network/f5/bigip_profile_fastl4.py
+++ /dev/null
@@ -1,1399 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2018, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_profile_fastl4
-short_description: Manages Fast L4 profiles
-description:
- - Manages Fast L4 profiles.
-version_added: 2.8
-options:
- name:
- description:
- - Specifies the name of the profile.
- type: str
- required: True
- parent:
- description:
- - Specifies the profile from which this profile inherits settings.
- - When creating a new profile, if this parameter is not specified, the default
- is the system-supplied C(fastL4) profile.
- type: str
- idle_timeout:
- description:
- - Specifies the length of time that a connection is idle (has no traffic) before
- the connection is eligible for deletion.
- - When creating a new profile, if this parameter is not specified, the remote
- device will choose a default value appropriate for the profile, based on its
- C(parent) profile.
- - When a number is specified, indicates the number of seconds that the TCP
- connection can remain idle before the system deletes it.
- - When C(indefinite), specifies that the system does not delete TCP connections
- regardless of how long they remain idle.
- - When C(0), or C(immediate), specifies that the system deletes connections
- immediately when they become idle.
- type: str
- client_timeout:
- description:
- - Specifies a timeout for Late Binding.
- - This is the time limit for the client to provide the application data required to
- select a back-end server. That is, this is the maximum time that the BIG-IP system
- waits for information about the sender and the target.
- - This information typically arrives at the beginning of the FIX logon packet.
- - When C(0), or C(immediate), allows for no time beyond the moment of the first packet
- transmission.
- - When C(indefinite), disables the limit. This allows the client unlimited time
- to send the sender and target information.
- type: str
- description:
- description:
- - Description of the profile.
- type: str
- explicit_flow_migration:
- description:
- - Specifies whether a qualified late-binding connection requires an explicit iRule
- command to migrate down to ePVA hardware.
- - When C(no), a late-binding connection migrates down to ePVA immediately after
- establishing the server-side connection.
- - When C(yes), this parameter stops automatic migration to ePVA, and requires that
- the iRule explicitly trigger ePVA processing by invoking the C(release_flow)
- iRule command. This allows an iRule author to control when the connection uses the
- ePVA hardware.
- type: bool
- ip_df_mode:
- description:
- - Specifies the Don't Fragment (DF) bit setting in the IP Header of the outgoing TCP packet.
- - When C(pmtu), sets the outgoing IP Header DF bit based on IP pmtu setting.
- - When C(preserve), sets the outgoing Packet's IP Header DF bit to be same as incoming IP
- Header DF bit.
- - When C(set), sets the outgoing packet's IP Header DF bit.
- - When C(clear), clears the outgoing packet's IP Header DF bit.
- type: str
- choices:
- - pmtu
- - preserve
- - set
- - clear
- ip_tos_to_client:
- description:
- - Specifies, for IP traffic passing through the system to clients, whether the system
- modifies the IP type-of-service (ToS) setting in an IP packet header.
- - May be a number between 0 and 255 (inclusive). When a number, specifies the IP ToS
- setting that the system inserts in the IP packet header.
- - When C(pass-through), specifies that the IP ToS setting remains unchanged.
- - When C(mimic), specifies that the system sets the ToS level of outgoing packets to
- the same ToS level of the most-recently received incoming packet.
- type: str
- ip_tos_to_server:
- description:
- - Specifies, for IP traffic passing through the system to back-end servers, whether
- the system modifies the IP type-of-service (ToS) setting in an IP packet header.
- - May be a number between 0 and 255 (inclusive). When a number, specifies the IP ToS
- setting that the system inserts in the IP packet header.
- - When C(pass-through), specifies that the IP ToS setting remains unchanged.
- - When C(mimic), specifies that the system sets the ToS level of outgoing packets to
- the same ToS level of the most-recently received incoming packet.
- type: str
- ip_ttl_mode:
- description:
- - Specifies the outgoing TCP packet's IP Header TTL mode.
- - When C(proxy), sets the outgoing IP Header TTL value to 255/64 for IPv4/IPv6 respectively.
- - When C(preserve), sets the outgoing IP Header TTL value to be same as the incoming
- IP Header TTL value.
- - When C(decrement), sets the outgoing IP Header TTL value to be one less than the
- incoming TTL value.
- - When C(set), sets the outgoing IP Header TTL value to a specific value(as specified
- by C(ip_ttl_v4) or C(ip_ttl_v6).
- type: str
- choices:
- - proxy
- - preserve
- - decrement
- - set
- ip_ttl_v4:
- description:
- - Specifies the outgoing packet's IP Header TTL value for IPv4 traffic.
- - Maximum TTL value that can be specified is 255.
- type: int
- ip_ttl_v6:
- description:
- - Specifies the outgoing packet's IP Header TTL value for IPv6 traffic.
- - Maximum TTL value that can be specified is 255.
- type: int
- keep_alive_interval:
- description:
- - Specifies the keep-alive probe interval, in seconds.
- type: int
- late_binding:
- description:
- - Enables intelligent selection of a back-end server or pool, using an
- iRule to make the selection.
- type: bool
- link_qos_to_client:
- description:
- - Specifies, for IP traffic passing through the system to clients,
- whether the system modifies the link quality-of-service (QoS) setting
- in an IP packet header.
- - The link QoS value prioritizes the IP packet relative to other Layer
- 2 traffic.
- - You can specify a number between 0 (lowest priority) and 7 (highest priority).
- - When a number, specifies the link QoS setting that the system inserts
- in the IP packet header.
- - When C(pass-through), specifies that the link QoS setting remains unchanged.
- type: str
- link_qos_to_server:
- description:
- - Specifies, for IP traffic passing through the system to back-end servers,
- whether the system modifies the link quality-of-service (QoS) setting
- in an IP packet header.
- - The link QoS value prioritizes the IP packet relative to other Layer
- 2 traffic.
- - You can specify a number between 0 (lowest priority) and 7 (highest priority).
- - When a number, specifies the link QoS setting that the system inserts
- in the IP packet header.
- - When C(pass-through), specifies that the link QoS setting remains unchanged.
- type: str
- loose_close:
- description:
- - When C(yes), specifies, that the system closes a loosely-initiated connection
- when the system receives the first FIN packet from either the client or the server.
- type: bool
- loose_initialization:
- description:
- - When C(yes), specifies that the system initializes a connection when it
- receives any TCP packet, rather that requiring a SYN packet for connection
- initiation.
- type: bool
- mss_override:
- description:
- - Specifies a maximum segment size (MSS) override for server-side connections.
- - Valid range is 256 to 9162 or 0 to disable.
- type: int
- reassemble_fragments:
- description:
- - When C(yes), specifies that the system reassembles IP fragments.
- type: bool
- receive_window_size:
- description:
- - Specifies the amount of data the BIG-IP system can accept without acknowledging
- the server.
- type: int
- reset_on_timeout:
- description:
- - When C(yes), specifies that the system sends a reset packet (RST) in addition
- to deleting the connection, when a connection exceeds the idle timeout value.
- type: bool
- rtt_from_client:
- description:
- - When C(yes), specifies that the system uses TCP timestamp options to measure
- the round-trip time to the client.
- type: bool
- rtt_from_server:
- description:
- - When C(yes), specifies that the system uses TCP timestamp options to measure
- the round-trip time to the server.
- type: bool
- server_sack:
- description:
- - Specifies whether the BIG-IP system processes Selective ACK (Sack) packets
- in cookie responses from the server.
- type: bool
- server_timestamp:
- description:
- - Specifies whether the BIG-IP system processes timestamp request packets in
- cookie responses from the server.
- type: bool
- syn_cookie_mss:
- description:
- - Specifies a value that overrides the SYN cookie maximum segment size (MSS)
- value in the SYN-ACK packet that is returned to the client.
- - Valid values are 0, and values from 256 through 9162.
- type: int
- tcp_close_timeout:
- description:
- - Specifies the length of time a connection can remain idle before deletion.
- type: str
- tcp_generate_isn:
- description:
- - When C(yes), specifies that the system generates initial sequence numbers
- for SYN packets, according to RFC 1948.
- type: bool
- tcp_handshake_timeout:
- description:
- - Specifies the acceptable duration for a TCP handshake, that is, the maximum
- idle time between a client synchronization (SYN) and a client acknowledgment
- (ACK). If the TCP handshake takes longer than the timeout, the system
- automatically closes the connection.
- - When a number, specifies how long the system can try to establish a TCP
- handshake before timing out.
- - When C(disabled), specifies that the system does not apply a timeout to a
- TCP handshake.
- - When C(indefinite), specifies that attempting a TCP handshake never times out.
- type: str
- tcp_strip_sack:
- description:
- - When C(yes), specifies that the system blocks a TCP selective ACK SackOK
- option from passing to the server on an initiating SYN.
- type: bool
- tcp_time_wait_timeout:
- description:
- - Specifies the number of milliseconds that a connection is in the TIME-WAIT
- state before closing.
- type: int
- tcp_timestamp_mode:
- description:
- - Specifies the action that the system should take on TCP timestamps.
- type: str
- choices:
- - preserve
- - rewrite
- - strip
- tcp_wscale_mode:
- description:
- - Specifies the action that the system should take on TCP windows.
- type: str
- choices:
- - preserve
- - rewrite
- - strip
- timeout_recovery:
- description:
- - Specifies how to handle client-timeout errors for Late Binding.
- - Timeout errors may be caused by a DoS attack or a lossy connection.
- - When C(disconnect), causes the BIG-IP system to drop the connection.
- - When C(fallback), reverts the connection to normal FastL4 load-balancing,
- based on the client's TCP header. This causes the BIG-IP system to choose
- a back-end server based only on the source address and port.
- type: str
- choices:
- - disconnect
- - fallback
- partition:
- description:
- - Device partition to manage resources on.
- type: str
- default: Common
- state:
- description:
- - When C(present), ensures that the profile exists.
- - When C(absent), ensures the profile is removed.
- type: str
- choices:
- - present
- - absent
- default: present
-extends_documentation_fragment: f5
-author:
- - Tim Rupp (@caphrim007)
-'''
-
-EXAMPLES = r'''
-- name: Create a fastL4 profile
- bigip_profile_fastl4:
- name: foo
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-'''
-
-RETURN = r'''
-client_timeout:
- description: The new client timeout value of the resource.
- returned: changed
- type: str
- sample: true
-description:
- description: The new description.
- returned: changed
- type: str
- sample: My description
-explicit_flow_migration:
- description: The new flow migration setting.
- returned: changed
- type: bool
- sample: yes
-idle_timeout:
- description: The new idle timeout setting.
- returned: changed
- type: str
- sample: 123
-ip_df_mode:
- description: The new Don't Fragment Flag (DF) setting.
- returned: changed
- type: str
- sample: clear
-ip_tos_to_client:
- description: The new IP ToS to Client setting.
- returned: changed
- type: str
- sample: 100
-ip_tos_to_server:
- description: The new IP ToS to Server setting.
- returned: changed
- type: str
- sample: 100
-ip_ttl_mode:
- description: The new Time To Live (TTL) setting.
- returned: changed
- type: str
- sample: proxy
-ip_ttl_v4:
- description: The new Time To Live (TTL) v4 setting.
- returned: changed
- type: int
- sample: 200
-ip_ttl_v6:
- description: The new Time To Live (TTL) v6 setting.
- returned: changed
- type: int
- sample: 200
-keep_alive_interval:
- description: The new TCP Keep Alive Interval setting.
- returned: changed
- type: int
- sample: 100
-late_binding:
- description: The new Late Binding setting.
- returned: changed
- type: bool
- sample: yes
-link_qos_to_client:
- description: The new Link QoS to Client setting.
- returned: changed
- type: str
- sample: pass-through
-link_qos_to_server:
- description: The new Link QoS to Server setting.
- returned: changed
- type: str
- sample: 123
-loose_close:
- description: The new Loose Close setting.
- returned: changed
- type: bool
- sample: no
-loose_initialization:
- description: The new Loose Initiation setting.
- returned: changed
- type: bool
- sample: no
-mss_override:
- description: The new Maximum Segment Size Override setting.
- returned: changed
- type: int
- sample: 300
-reassemble_fragments:
- description: The new Reassemble IP Fragments setting.
- returned: changed
- type: bool
- sample: yes
-receive_window_size:
- description: The new Receive Window setting.
- returned: changed
- type: int
- sample: 1024
-reset_on_timeout:
- description: The new Reset on Timeout setting.
- returned: changed
- type: bool
- sample: no
-rtt_from_client:
- description: The new RTT from Client setting.
- returned: changed
- type: bool
- sample: no
-rtt_from_server:
- description: The new RTT from Server setting.
- returned: changed
- type: bool
- sample: no
-server_sack:
- description: The new Server Sack setting.
- returned: changed
- type: bool
- sample: yes
-server_timestamp:
- description: The new Server Timestamp setting.
- returned: changed
- type: bool
- sample: yes
-syn_cookie_mss:
- description: The new SYN Cookie MSS setting.
- returned: changed
- type: int
- sample: 1024
-tcp_close_timeout:
- description: The new TCP Close Timeout setting.
- returned: changed
- type: str
- sample: 100
-tcp_generate_isn:
- description: The new Generate Initial Sequence Number setting.
- returned: changed
- type: bool
- sample: no
-tcp_handshake_timeout:
- description: The new TCP Handshake Timeout setting.
- returned: changed
- type: int
- sample: 5
-tcp_strip_sack:
- description: The new Strip Sack OK setting.
- returned: changed
- type: bool
- sample: no
-tcp_time_wait_timeout:
- description: The new TCP Time Wait Timeout setting.
- returned: changed
- type: int
- sample: 100
-tcp_timestamp_mode:
- description: The new TCP Timestamp Mode setting.
- returned: changed
- type: str
- sample: rewrite
-tcp_wscale_mode:
- description: The new TCP Window Scale Mode setting.
- returned: changed
- type: str
- sample: strip
-timeout_recovery:
- description: The new Timeout Recovery setting.
- returned: changed
- type: str
- sample: fallback
-'''
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.basic import env_fallback
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import fq_name
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.common import transform_name
- from library.module_utils.network.f5.common import flatten_boolean
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import fq_name
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.common import transform_name
- from ansible.module_utils.network.f5.common import flatten_boolean
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'clientTimeout': 'client_timeout',
- 'defaultsFrom': 'parent',
- 'explicitFlowMigration': 'explicit_flow_migration',
- 'idleTimeout': 'idle_timeout',
- 'ipDfMode': 'ip_df_mode',
- 'ipTosToClient': 'ip_tos_to_client',
- 'ipTosToServer': 'ip_tos_to_server',
- 'ipTtlMode': 'ip_ttl_mode',
- 'ipTtlV4': 'ip_ttl_v4',
- 'ipTtlV6': 'ip_ttl_v6',
- 'keepAliveInterval': 'keep_alive_interval',
- 'lateBinding': 'late_binding',
- 'linkQosToClient': 'link_qos_to_client',
- 'linkQosToServer': 'link_qos_to_server',
- 'looseClose': 'loose_close',
- 'looseInitialization': 'loose_initialization',
- 'mssOverride': 'mss_override',
- 'reassembleFragments': 'reassemble_fragments',
- 'receiveWindowSize': 'receive_window_size',
- 'resetOnTimeout': 'reset_on_timeout',
- 'rttFromClient': 'rtt_from_client',
- 'rttFromServer': 'rtt_from_server',
- 'serverSack': 'server_sack',
- 'serverTimestamp': 'server_timestamp',
- 'synCookieMss': 'syn_cookie_mss',
- 'tcpCloseTimeout': 'tcp_close_timeout',
- 'tcpGenerateIsn': 'tcp_generate_isn',
- 'tcpHandshakeTimeout': 'tcp_handshake_timeout',
- 'tcpStripSack': 'tcp_strip_sack',
- 'tcpTimeWaitTimeout': 'tcp_time_wait_timeout',
- 'tcpTimestampMode': 'tcp_timestamp_mode',
- 'tcpWscaleMode': 'tcp_wscale_mode',
- 'timeoutRecovery': 'timeout_recovery',
- }
-
- api_attributes = [
- 'clientTimeout',
- 'defaultsFrom',
- 'description',
- 'explicitFlowMigration',
- 'idleTimeout',
- 'ipDfMode',
- 'ipTosToClient',
- 'ipTosToServer',
- 'ipTtlMode',
- 'ipTtlV4',
- 'ipTtlV6',
- 'keepAliveInterval',
- 'lateBinding',
- 'linkQosToClient',
- 'linkQosToServer',
- 'looseClose',
- 'looseInitialization',
- 'mssOverride',
- 'reassembleFragments',
- 'receiveWindowSize',
- 'resetOnTimeout',
- 'rttFromClient',
- 'rttFromServer',
- 'serverSack',
- 'serverTimestamp',
- 'synCookieMss',
- 'tcpCloseTimeout',
- 'tcpGenerateIsn',
- 'tcpHandshakeTimeout',
- 'tcpStripSack',
- 'tcpTimeWaitTimeout',
- 'tcpTimestampMode',
- 'tcpWscaleMode',
- 'timeoutRecovery',
- ]
-
- returnables = [
- 'client_timeout',
- 'description',
- 'explicit_flow_migration',
- 'idle_timeout',
- 'ip_df_mode',
- 'ip_tos_to_client',
- 'ip_tos_to_server',
- 'ip_ttl_mode',
- 'ip_ttl_v4',
- 'ip_ttl_v6',
- 'keep_alive_interval',
- 'late_binding',
- 'link_qos_to_client',
- 'link_qos_to_server',
- 'loose_close',
- 'loose_initialization',
- 'mss_override',
- 'parent',
- 'reassemble_fragments',
- 'receive_window_size',
- 'reset_on_timeout',
- 'rtt_from_client',
- 'rtt_from_server',
- 'server_sack',
- 'server_timestamp',
- 'syn_cookie_mss',
- 'tcp_close_timeout',
- 'tcp_generate_isn',
- 'tcp_handshake_timeout',
- 'tcp_strip_sack',
- 'tcp_time_wait_timeout',
- 'tcp_timestamp_mode',
- 'tcp_wscale_mode',
- 'timeout_recovery',
- ]
-
- updatables = [
- 'client_timeout',
- 'description',
- 'explicit_flow_migration',
- 'idle_timeout',
- 'ip_df_mode',
- 'ip_tos_to_client',
- 'ip_tos_to_server',
- 'ip_ttl_mode',
- 'ip_ttl_v4',
- 'ip_ttl_v6',
- 'keep_alive_interval',
- 'late_binding',
- 'link_qos_to_client',
- 'link_qos_to_server',
- 'loose_close',
- 'loose_initialization',
- 'mss_override',
- 'parent',
- 'reassemble_fragments',
- 'receive_window_size',
- 'reset_on_timeout',
- 'rtt_from_client',
- 'rtt_from_server',
- 'server_sack',
- 'server_timestamp',
- 'syn_cookie_mss',
- 'tcp_close_timeout',
- 'tcp_generate_isn',
- 'tcp_handshake_timeout',
- 'tcp_strip_sack',
- 'tcp_time_wait_timeout',
- 'tcp_timestamp_mode',
- 'tcp_wscale_mode',
- 'timeout_recovery',
- ]
-
- @property
- def explicit_flow_migration(self):
- result = flatten_boolean(self._values['explicit_flow_migration'])
- return result
-
- @property
- def late_binding(self):
- return flatten_boolean(self._values['late_binding'])
-
- @property
- def loose_close(self):
- return flatten_boolean(self._values['loose_close'])
-
- @property
- def loose_initialization(self):
- return flatten_boolean(self._values['loose_initialization'])
-
- @property
- def reassemble_fragments(self):
- return flatten_boolean(self._values['reassemble_fragments'])
-
- @property
- def reset_on_timeout(self):
- return flatten_boolean(self._values['reset_on_timeout'])
-
- @property
- def rtt_from_client(self):
- return flatten_boolean(self._values['rtt_from_client'])
-
- @property
- def rtt_from_server(self):
- return flatten_boolean(self._values['rtt_from_server'])
-
- @property
- def server_sack(self):
- return flatten_boolean(self._values['server_sack'])
-
- @property
- def server_timestamp(self):
- return flatten_boolean(self._values['server_timestamp'])
-
- @property
- def tcp_generate_isn(self):
- return flatten_boolean(self._values['tcp_generate_isn'])
-
- @property
- def tcp_strip_sack(self):
- return flatten_boolean(self._values['tcp_strip_sack'])
-
- @property
- def tcp_close_timeout(self):
- if self._values['tcp_close_timeout'] is None:
- return None
- try:
- return int(self._values['tcp_close_timeout'])
- except ValueError:
- return self._values['tcp_close_timeout']
-
- @property
- def tcp_handshake_timeout(self):
- if self._values['tcp_handshake_timeout'] is None:
- return None
- try:
- return int(self._values['tcp_handshake_timeout'])
- except ValueError:
- if self._values['tcp_handshake_timeout'] in ['disabled', 'immediate']:
- return 0
- return self._values['tcp_handshake_timeout']
-
- @property
- def client_timeout(self):
- if self._values['client_timeout'] is None:
- return None
- try:
- return int(self._values['client_timeout'])
- except ValueError:
- if self._values['client_timeout'] == 'immediate':
- return 0
- if self._values['client_timeout'] == 'indefinite':
- return 4294967295
- return self._values['client_timeout']
-
- @property
- def parent(self):
- if self._values['parent'] is None:
- return None
- result = fq_name(self.partition, self._values['parent'])
- return result
-
-
-class ApiParameters(Parameters):
- @property
- def description(self):
- if self._values['description'] in [None, 'none']:
- return None
- return self._values['description']
-
- @property
- def idle_timeout(self):
- if self._values['idle_timeout'] is None:
- return None
- try:
- return int(self._values['idle_timeout'])
- except ValueError:
- return self._values['idle_timeout']
-
- @property
- def ip_tos_to_client(self):
- return self.transform_ip_tos('ip_tos_to_client')
-
- @property
- def ip_tos_to_server(self):
- return self.transform_ip_tos('ip_tos_to_server')
-
- @property
- def keep_alive_interval(self):
- if self._values['keep_alive_interval'] is None:
- return None
- try:
- return int(self._values['keep_alive_interval'])
- except ValueError:
- return self._values['keep_alive_interval']
-
- @property
- def link_qos_to_client(self):
- return self.transform_link_qos('link_qos_to_client')
-
- @property
- def link_qos_to_server(self):
- return self.transform_link_qos('link_qos_to_server')
-
- def transform_ip_tos(self, key):
- if self._values[key] is None:
- return None
- try:
- result = int(self._values[key])
- return result
- except ValueError:
- return self._values[key]
-
- def transform_link_qos(self, key):
- if self._values[key] is None:
- return None
- if self._values[key] == 'pass-through':
- return 'pass-through'
- if 0 <= int(self._values[key]) <= 7:
- return int(self._values[key])
-
-
-class ModuleParameters(Parameters):
- @property
- def description(self):
- if self._values['description'] is None:
- return None
- elif self._values['description'] in ['none', '']:
- return ''
- return self._values['description']
-
- @property
- def idle_timeout(self):
- if self._values['idle_timeout'] is None:
- return None
- try:
- result = int(self._values['idle_timeout'])
- if result == 0:
- return 'immediate'
- return result
- except ValueError:
- return self._values['idle_timeout']
-
- @property
- def ip_tos_to_client(self):
- return self.transform_ip_tos('ip_tos_to_client')
-
- @property
- def ip_tos_to_server(self):
- return self.transform_ip_tos('ip_tos_to_server')
-
- @property
- def ip_ttl_v4(self):
- if self._values['ip_ttl_v4'] is None:
- return None
- if 0 <= self._values['ip_ttl_v4'] <= 255:
- return int(self._values['ip_ttl_v4'])
- raise F5ModuleError(
- 'ip_ttl_v4 must be between 0 and 255'
- )
-
- @property
- def ip_ttl_v6(self):
- if self._values['ip_ttl_v6'] is None:
- return None
- if 0 <= self._values['ip_ttl_v6'] <= 255:
- return int(self._values['ip_ttl_v6'])
- raise F5ModuleError(
- 'ip_ttl_v6 must be between 0 and 255'
- )
-
- @property
- def keep_alive_interval(self):
- if self._values['keep_alive_interval'] is None:
- return None
- result = int(self._values['keep_alive_interval'])
- if result == 0:
- return 'disabled'
- return result
-
- @property
- def link_qos_to_client(self):
- result = self.transform_link_qos('link_qos_to_client')
- if result == -1:
- raise F5ModuleError(
- 'link_qos_to_client must be between 0 and 7'
- )
- return result
-
- @property
- def link_qos_to_server(self):
- result = self.transform_link_qos('link_qos_to_server')
- if result == -1:
- raise F5ModuleError(
- 'link_qos_to_server must be between 0 and 7'
- )
- return result
-
- def transform_link_qos(self, key):
- if self._values[key] is None:
- return None
- if self._values[key] == 'pass-through':
- return 'pass-through'
- if 0 <= int(self._values[key]) <= 7:
- return int(self._values[key])
- else:
- return -1
-
- def transform_ip_tos(self, key):
- if self._values[key] is None:
- return None
- try:
- result = int(self._values[key])
- return result
- except ValueError:
- if self._values[key] == 'mimic':
- return 65534
- return self._values[key]
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class UsableChanges(Changes):
- @property
- def explicit_flow_migration(self):
- if self._values['explicit_flow_migration'] == 'yes':
- return 'enabled'
- elif self._values['explicit_flow_migration'] == 'no':
- return 'disabled'
-
- @property
- def late_binding(self):
- if self._values['late_binding'] == 'yes':
- return 'enabled'
- elif self._values['late_binding'] == 'no':
- return 'disabled'
-
- @property
- def loose_close(self):
- if self._values['loose_close'] == 'yes':
- return 'enabled'
- elif self._values['loose_close'] == 'no':
- return 'disabled'
-
- @property
- def loose_initialization(self):
- if self._values['loose_initialization'] == 'yes':
- return 'enabled'
- elif self._values['loose_initialization'] == 'no':
- return 'disabled'
-
- @property
- def reassemble_fragments(self):
- if self._values['reassemble_fragments'] == 'yes':
- return 'enabled'
- elif self._values['reassemble_fragments'] == 'no':
- return 'disabled'
-
- @property
- def reset_on_timeout(self):
- if self._values['reset_on_timeout'] == 'yes':
- return 'enabled'
- elif self._values['reset_on_timeout'] == 'no':
- return 'disabled'
-
- @property
- def rtt_from_client(self):
- if self._values['rtt_from_client'] == 'yes':
- return 'enabled'
- elif self._values['rtt_from_client'] == 'no':
- return 'disabled'
-
- @property
- def rtt_from_server(self):
- if self._values['rtt_from_server'] == 'yes':
- return 'enabled'
- elif self._values['rtt_from_server'] == 'no':
- return 'disabled'
-
- @property
- def server_sack(self):
- if self._values['server_sack'] == 'yes':
- return 'enabled'
- elif self._values['server_sack'] == 'no':
- return 'disabled'
-
- @property
- def server_timestamp(self):
- if self._values['server_timestamp'] == 'yes':
- return 'enabled'
- elif self._values['server_timestamp'] == 'no':
- return 'disabled'
-
- @property
- def tcp_generate_isn(self):
- if self._values['tcp_generate_isn'] == 'yes':
- return 'enabled'
- elif self._values['tcp_generate_isn'] == 'no':
- return 'disabled'
-
- @property
- def tcp_strip_sack(self):
- if self._values['tcp_strip_sack'] == 'yes':
- return 'enabled'
- elif self._values['tcp_strip_sack'] == 'no':
- return 'disabled'
-
-
-class ReportableChanges(Changes):
- @property
- def explicit_flow_migration(self):
- result = flatten_boolean(self._values['explicit_flow_migration'])
- return result
-
- @property
- def late_binding(self):
- result = flatten_boolean(self._values['late_binding'])
- return result
-
- @property
- def loose_close(self):
- result = flatten_boolean(self._values['loose_close'])
- return result
-
- @property
- def loose_initialization(self):
- result = flatten_boolean(self._values['loose_initialization'])
- return result
-
- @property
- def reassemble_fragments(self):
- result = flatten_boolean(self._values['reassemble_fragments'])
- return result
-
- @property
- def reset_on_timeout(self):
- result = flatten_boolean(self._values['reset_on_timeout'])
- return result
-
- @property
- def rtt_from_client(self):
- result = flatten_boolean(self._values['rtt_from_client'])
- return result
-
- @property
- def rtt_from_server(self):
- result = flatten_boolean(self._values['rtt_from_server'])
- return result
-
- @property
- def server_sack(self):
- result = flatten_boolean(self._values['server_sack'])
- return result
-
- @property
- def server_timestamp(self):
- result = flatten_boolean(self._values['server_timestamp'])
- return result
-
- @property
- def tcp_generate_isn(self):
- result = flatten_boolean(self._values['tcp_generate_isn'])
- return result
-
- @property
- def tcp_strip_sack(self):
- result = flatten_boolean(self._values['tcp_strip_sack'])
- return result
-
- @property
- def ip_tos_to_client(self):
- return self.report_ip_tos('ip_tos_to_client')
-
- @property
- def ip_tos_to_server(self):
- return self.report_ip_tos('ip_tos_to_server')
-
- @property
- def keep_alive_interval(self):
- if self._values['keep_alive_interval'] is None:
- return None
- if self._values['keep_alive_interval'] == 'disabled':
- return 0
- return self._values['keep_alive_interval']
-
- @property
- def client_timeout(self):
- if self._values['client_timeout'] is None:
- return None
- try:
- return int(self._values['client_timeout'])
- except ValueError:
- if self._values['client_timeout'] == 0:
- return 'immediate'
- if self._values['client_timeout'] == 4294967295:
- return 'indefinite'
- return self._values['client_timeout']
-
- def report_ip_tos(self, key):
- if self._values[key] is None:
- return None
- if self._values[key] == 65534:
- return 'mimic'
- try:
- return int(self._values[key])
- except ValueError:
- return self._values[key]
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
- @property
- def parent(self):
- if self.want.parent != self.have.parent:
- raise F5ModuleError(
- "The parent profile cannot be changed"
- )
-
- @property
- def description(self):
- if self.want.description is None:
- return None
- if self.have.description is None and self.want.description == '':
- return None
- if self.want.description != self.have.description:
- return self.want.description
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(params=self.module.params)
- self.have = ApiParameters()
- self.changes = UsableChanges()
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = UsableChanges(params=changed)
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def exec_module(self):
- changed = False
- result = dict()
- state = self.want.state
-
- if state == "present":
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.client.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def present(self):
- if self.exists():
- return self.update()
- else:
- return self.create()
-
- def exists(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/profile/fastl4/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def update(self):
- self.have = self.read_current_from_device()
- if not self.should_update():
- return False
- if self.module.check_mode:
- return True
- self.update_on_device()
- return True
-
- def remove(self):
- if self.module.check_mode:
- return True
- self.remove_from_device()
- if self.exists():
- raise F5ModuleError("Failed to delete the resource.")
- return True
-
- def create(self):
- self._set_changed_options()
- if self.module.check_mode:
- return True
- self.create_on_device()
- return True
-
- def create_on_device(self):
- params = self.changes.api_params()
- params['name'] = self.want.name
- params['partition'] = self.want.partition
- uri = "https://{0}:{1}/mgmt/tm/ltm/profile/fastl4/".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403, 404]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def update_on_device(self):
- params = self.changes.api_params()
- uri = "https://{0}:{1}/mgmt/tm/ltm/profile/fastl4/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 404]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def absent(self):
- if self.exists():
- return self.remove()
- return False
-
- def remove_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/profile/fastl4/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- response = self.client.api.delete(uri)
- if response.status == 200:
- return True
- raise F5ModuleError(response.content)
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/profile/fastl4/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return ApiParameters(params=response)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- name=dict(required=True),
- parent=dict(),
- idle_timeout=dict(),
- client_timeout=dict(),
- description=dict(),
- explicit_flow_migration=dict(type='bool'),
- ip_df_mode=dict(
- choices=['pmtu', 'preserve', 'set', 'clear']
- ),
- ip_tos_to_client=dict(),
- ip_tos_to_server=dict(),
- ip_ttl_v4=dict(type='int'),
- ip_ttl_v6=dict(type='int'),
- ip_ttl_mode=dict(
- choices=['proxy', 'set', 'preserve', 'decrement']
- ),
- keep_alive_interval=dict(type='int'),
- late_binding=dict(type='bool'),
- link_qos_to_client=dict(),
- link_qos_to_server=dict(),
- loose_close=dict(type='bool'),
- loose_initialization=dict(type='bool'),
- mss_override=dict(type='int'),
- reassemble_fragments=dict(type='bool'),
- receive_window_size=dict(type='int'),
- reset_on_timeout=dict(type='bool'),
- rtt_from_client=dict(type='bool'),
- rtt_from_server=dict(type='bool'),
- server_sack=dict(type='bool'),
- server_timestamp=dict(type='bool'),
- syn_cookie_mss=dict(type='int'),
- tcp_close_timeout=dict(),
- tcp_generate_isn=dict(type='bool'),
- tcp_handshake_timeout=dict(),
- tcp_strip_sack=dict(type='bool'),
- tcp_time_wait_timeout=dict(type='int'),
- tcp_timestamp_mode=dict(
- choices=['preserve', 'rewrite', 'strip']
- ),
- tcp_wscale_mode=dict(
- choices=['preserve', 'rewrite', 'strip']
- ),
- timeout_recovery=dict(
- choices=['fallback', 'disconnect']
- ),
- state=dict(
- default='present',
- choices=['present', 'absent']
- ),
- partition=dict(
- default='Common',
- fallback=(env_fallback, ['F5_PARTITION'])
- )
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode,
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_profile_http.py b/lib/ansible/modules/network/f5/bigip_profile_http.py
deleted file mode 100644
index 683aadb5f9..0000000000
--- a/lib/ansible/modules/network/f5/bigip_profile_http.py
+++ /dev/null
@@ -1,1757 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2018, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_profile_http
-short_description: Manage HTTP profiles on a BIG-IP
-description:
- - Manage HTTP profiles on a BIG-IP.
-version_added: 2.7
-options:
- name:
- description:
- - Specifies the name of the profile.
- type: str
- required: True
- parent:
- description:
- - Specifies the profile from which this profile inherits settings.
- - When creating a new profile, if this parameter is not specified, the default
- is the system-supplied C(http) profile.
- type: str
- default: /Common/http
- description:
- description:
- - Description of the profile.
- type: str
- proxy_type:
- description:
- - Specifies the proxy mode for the profile.
- - When creating a new profile, if this parameter is not specified, the
- default is provided by the parent profile.
- type: str
- choices:
- - reverse
- - transparent
- - explicit
- dns_resolver:
- description:
- - Specifies the name of a configured DNS resolver, this option is mandatory when C(proxy_type)
- is set to C(explicit).
- - Format of the name can be either be prepended by partition (C(/Common/foo)), or specified
- just as an object name (C(foo)).
- - To remove the entry a value of C(none) or C('') can be set, however the profile C(proxy_type)
- must not be set as C(explicit).
- type: str
- insert_xforwarded_for:
- description:
- - When specified system inserts an X-Forwarded-For header in an HTTP request
- with the client IP address, to use with connection pooling.
- - When creating a new profile, if this parameter is not specified, the
- default is provided by the parent profile.
- type: bool
- redirect_rewrite:
- description:
- - Specifies whether the system rewrites the URIs that are part of HTTP
- redirect (3XX) responses.
- - When set to C(none) the system will not rewrite the URI in any
- HTTP redirect responses.
- - When set to C(all) the system rewrites the URI in all HTTP redirect responses.
- - When set to C(matching) the system rewrites the URI in any
- HTTP redirect responses that match the request URI.
- - When set to C(nodes) if the URI contains a node IP address instead of a host name,
- the system changes it to the virtual server address.
- - When creating a new profile, if this parameter is not specified, the
- default is provided by the parent profile.
- type: str
- choices:
- - none
- - all
- - matching
- - nodes
- encrypt_cookies:
- description:
- - Cookie names for the system to encrypt.
- - To remove the entry completely a value of C(none) or C('') should be set.
- - When creating a new profile, if this parameter is not specified, the
- default is provided by the parent profile.
- type: list
- encrypt_cookie_secret:
- description:
- - Passphrase for cookie encryption.
- - When creating a new profile, if this parameter is not specified, the
- default is provided by the parent profile.
- type: str
- update_password:
- description:
- - C(always) will update passwords if the C(encrypt_cookie_secret) is specified.
- - C(on_create) will only set the password for newly created profiles.
- type: str
- choices:
- - always
- - on_create
- default: always
- header_erase:
- description:
- - The name of a header, in an HTTP request, which the system removes from request.
- - To remove the entry completely a value of C(none) or C('') should be set.
- - The format of the header must be in C(KEY:VALUE) format, otherwise error is raised.
- - When creating a new profile, if this parameter is not specified, the
- default is provided by the parent profile.
- type: str
- version_added: 2.8
- header_insert:
- description:
- - A string that the system inserts as a header in an HTTP request.
- - To remove the entry completely a value of C(none) or C('') should be set.
- - The format of the header must be in C(KEY:VALUE) format, otherwise error is raised.
- - When creating a new profile, if this parameter is not specified, the
- default is provided by the parent profile.
- type: str
- version_added: 2.8
- server_agent_name:
- description:
- - Specifies the string used as the server name in traffic generated by BIG-IP.
- - To remove the entry completely a value of C(none) or C('') should be set.
- - When creating a new profile, if this parameter is not specified, the
- default is provided by the parent profile.
- type: str
- version_added: 2.8
- include_subdomains:
- description:
- - When set to C(yes), applies the HSTS policy to the HSTS host and its sub-domains.
- - When creating a new profile, if this parameter is not specified, the
- default is provided by the parent profile.
- type: bool
- version_added: 2.8
- maximum_age:
- description:
- - Specifies the maximum length of time, in seconds, that HSTS functionality
- requests that clients only use HTTPS to connect to the current host and
- any sub-domains of the current host's domain name.
- - The accepted value range is C(0 - 4294967295) seconds, a value of C(0) seconds
- re-enables plaintext HTTP access, while specifying C(indefinite) will set it to the maximum value.
- - When creating a new profile, if this parameter is not specified, the
- default is provided by the parent profile.
- type: str
- version_added: 2.8
- hsts_mode:
- description:
- - When set to C(yes), enables the HSTS settings.
- - When creating a new profile, if this parameter is not specified, the default is provided by the parent profile.
- type: bool
- version_added: 2.8
- accept_xff:
- description:
- - Enables or disables trusting the client IP address, and statistics from the client IP address,
- based on the request's XFF (X-forwarded-for) headers, if they exist.
- - When creating a new profile, if this parameter is not specified, the default is provided by the parent profile.
- type: bool
- version_added: 2.9
- xff_alternative_names:
- description:
- - Specifies alternative XFF headers instead of the default X-forwarded-for header.
- - When creating a new profile, if this parameter is not specified, the default is provided by the parent profile.
- type: list
- version_added: 2.9
- fallback_host:
- description:
- - Specifies an HTTP fallback host.
- - When creating a new profile, if this parameter is not specified, the default is provided by the parent profile.
- type: str
- version_added: 2.9
- fallback_status_codes:
- description:
- - Specifies one or more HTTP error codes from server responses that should trigger
- a redirection to the fallback host.
- - The accepted valid error codes are as defined by rfc2616.
- - The codes can be specified as individual items or as valid ranges e.g. C(400-417) or C(500-505).
- - Mixing response code range across error types is invalid e.g. defining C(400-505) will raise an error.
- - When creating a new profile, if this parameter is not specified, the default is provided by the parent profile.
- type: list
- version_added: 2.9
- oneconnect_transformations:
- description:
- - Enables the system to perform HTTP header transformations for the purpose of keeping server-side
- connections open. This feature requires configuration of a OneConnect profile.
- - When creating a new profile, if this parameter is not specified, the default is provided by the parent profile.
- type: bool
- version_added: 2.9
- request_chunking:
- description:
- - Specifies how to handle chunked and unchunked requests.
- - When creating a new profile, if this parameter is not specified, the default is provided by the parent profile.
- type: str
- choices:
- - rechunk
- - selective
- - preserve
- version_added: 2.9
- response_chunking:
- description:
- - Specifies how to handle chunked and unchunked responses.
- - When creating a new profile, if this parameter is not specified, the default is provided by the parent profile.
- type: str
- choices:
- - rechunk
- - selective
- - preserve
- version_added: 2.9
- enforcement:
- description:
- - Specifies protocol enforcement settings for the HTTP profile.
- - When creating a new profile, if this parameter is not specified, the default is provided by the parent profile.
- suboptions:
- truncated_redirects:
- description:
- - Specifies what happens if a truncated redirect is seen from a server.
- - If C(yes), the redirect will be forwarded to the client, otherwise the malformed HTTP
- will be silently ignored.
- - When creating a new profile, if this parameter is not specified, the default is provided
- by the parent profile.
- type: bool
- excess_client_headers:
- description:
- - Specifies the behavior when too many client headers are received.
- - If set to C(pass-through), will switch to pass through mode, when C(reject) the connection will be rejected.
- - When creating a new profile, if this parameter is not specified, the default is provided
- by the parent profile.
- type: str
- choices:
- - reject
- - pass-through
- excess_server_headers:
- description:
- - Specifies the behavior when too many server headers are received.
- - If set to C(pass-through), will switch to pass through mode, when C(reject) the connection will be rejected.
- - When creating a new profile, if this parameter is not specified, the default is provided
- by the parent profile.
- type: str
- choices:
- - reject
- - pass-through
- oversize_client_headers:
- description:
- - Specifies the behavior when too-large client headers are received.
- - If set to C(pass-through), will switch to pass through mode, when C(reject) the connection will be rejected.
- - When creating a new profile, if this parameter is not specified, the default is provided
- by the parent profile.
- type: str
- choices:
- - reject
- - pass-through
- oversize_server_headers:
- description:
- - Specifies the behavior when too-large server headers are received.
- - If set to C(pass-through), will switch to pass through mode, when C(reject) the connection will be rejected.
- - When creating a new profile, if this parameter is not specified, the default is provided
- by the parent profile.
- type: str
- choices:
- - reject
- - pass-through
- pipeline:
- description:
- - Enables HTTP/1.1 pipelining, allowing clients to make requests even when prior requests have not received
- a response.
- - In order for this to succeed, however, destination servers must include support for pipelining.
- - If set to C(pass-through), pipelined data will cause the BIG-IP to immediately switch to pass-through mode
- and disable the HTTP filter.
- - When creating a new profile, if this parameter is not specified, the default is provided
- by the parent profile.
- type: str
- choices:
- - allow
- - reject
- - pass-through
- unknown_method:
- description:
- - Specifies whether to allow, reject or switch to pass-through mode when an unknown HTTP method is parsed.
- - When creating a new profile, if this parameter is not specified, the default is provided
- by the parent profile.
- type: str
- choices:
- - allow
- - reject
- - pass-through
- max_header_count:
- description:
- - Specifies the maximum number of headers allowed in HTTP request/response.
- - The valid value range is between 16 and 4096 inclusive.
- - When set to C(default) the value of this parameter will be C(64)
- - When creating a new profile, if this parameter is not specified, the default is provided
- by the parent profile.
- type: str
- max_header_size:
- description:
- - Specifies the maximum header size specified in bytes.
- - The valid value range is between 0 and 4294967295 inclusive.
- - When set to C(default) the value of this parameter will be C(32768) bytes
- - When creating a new profile, if this parameter is not specified, the default is provided
- by the parent profile.
- type: str
- max_requests:
- description:
- - Specifies the number of requests that the system accepts on a per-connection basis.
- - The valid value range is between 0 and 4294967295 inclusive.
- - When set to C(default) the value of this parameter will be C(0), which means the system
- will not limit the number of requests per connection.
- - When creating a new profile, if this parameter is not specified, the default is provided
- by the parent profile.
- type: str
- known_methods:
- description:
- - Specifies which HTTP methods count as being known, removing RFC-defined methods from this list
- will cause the HTTP filter to not recognize them.
- - "The default list provided with the system include: C(CONNECT), C(DELETE), C(GET),
- C(HEAD), C(LOCK), C(OPTIONS), C(POST), C(PROPFIND), C(PUT), C(TRACE) ,C(UNLOCK). The list can be appended by
- by specifying C(default) keyword as one of the list elements."
- - The C(default) keyword can also be used to restore the default C(known_methods) on the system.
- - When creating a new profile, if this parameter is not specified, the default is provided
- by the parent profile.
- type: list
- type: dict
- version_added: 2.9
- sflow:
- description:
- - Specifies sFlow settings for the HTTP profile.
- - When creating a new profile, if this parameter is not specified, the default is provided by the parent profile.
- suboptions:
- poll_interval:
- description:
- - Specifies the maximum interval in seconds between two pollings.
- - The valid value range is between 0 and 4294967295 seconds inclusive.
- - For this setting to take effect the C(poll_interval_global) parameter must be set to C(no).
- - When creating a new profile, if this parameter is not specified, the default is provided
- by the parent profile.
- type: int
- poll_interval_global:
- description:
- - Specifies whether the global HTTP poll-interval setting overrides the object-level Cpoll-interval setting.
- - When creating a new profile, if this parameter is not specified, the default is provided
- by the parent profile.
- type: bool
- sampling_rate:
- description:
- - Specifies the ratio of packets observed to the samples generated. For example, a sampling rate of C(2000)
- specifies that 1 sample will be randomly generated for every 2000 packets observed.
- - The valid value range is between 0 and 4294967295 packets inclusive.
- - For this setting to take effect the C(sampling_rate_global) parameter must be set to C(no).
- - When creating a new profile, if this parameter is not specified, the default is provided
- by the parent profile.
- type: int
- sampling_rate_global:
- description:
- - Specifies whether the global HTTP sampling-rate setting overrides the object-level sampling-rate setting.
- - When creating a new profile, if this parameter is not specified, the default is provided
- by the parent profile.
- type: bool
- type: dict
- version_added: 2.9
- partition:
- description:
- - Device partition to manage resources on.
- type: str
- default: Common
- state:
- description:
- - When C(present), ensures that the profile exists.
- - When C(absent), ensures the profile is removed.
- type: str
- choices:
- - present
- - absent
- default: present
-extends_documentation_fragment: f5
-author:
- - Wojciech Wypior (@wojtek0806)
-'''
-
-EXAMPLES = r'''
-- name: Create HTTP profile
- bigip_profile_http:
- name: my_profile
- insert_xforwarded_for: yes
- redirect_rewrite: all
- state: present
- provider:
- user: admin
- password: secret
- server: lb.mydomain.com
- delegate_to: localhost
-
-- name: Remove HTTP profile
- bigip_profile_http:
- name: my_profile
- state: absent
- provider:
- server: lb.mydomain.com
- user: admin
- password: secret
- delegate_to: localhost
-
-- name: Add HTTP profile for transparent proxy
- bigip_profile_http:
- name: my_profile
- proxy_type: transparent
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-'''
-
-RETURN = r'''
-parent:
- description: Specifies the profile from which this profile inherits settings.
- returned: changed
- type: str
- sample: /Common/http
-description:
- description: Description of the profile.
- returned: changed
- type: str
- sample: My profile
-proxy_type:
- description: Specify proxy mode of the profile.
- returned: changed
- type: str
- sample: explicit
-hsts_mode:
- description: Enables the HSTS settings.
- returned: changed
- type: bool
- sample: no
-maximum_age:
- description: The maximum length of time, in seconds, that HSTS functionality requests that clients only use HTTPS.
- returned: changed
- type: str
- sample: indefinite
-include_subdomains:
- description: Applies the HSTS policy to the HSTS host and its sub-domains.
- returned: changed
- type: bool
- sample: yes
-server_agent_name:
- description: The string used as the server name in traffic generated by BIG-IP.
- returned: changed
- type: str
- sample: foobar
-header_erase:
- description: The name of a header, in an HTTP request, which the system removes from request.
- returned: changed
- type: str
- sample: FOO:BAR
-header_insert:
- description: The string that the system inserts as a header in an HTTP request.
- returned: changed
- type: str
- sample: FOO:BAR
-insert_xforwarded_for:
- description: Insert X-Forwarded-For-Header.
- returned: changed
- type: bool
- sample: yes
-redirect_rewrite:
- description: Rewrite URI that are part of 3xx responses.
- returned: changed
- type: str
- sample: all
-encrypt_cookies:
- description: Cookie names to encrypt.
- returned: changed
- type: list
- sample: ['MyCookie1', 'MyCookie2']
-dns_resolver:
- description: Configured dns resolver.
- returned: changed
- type: str
- sample: '/Common/FooBar'
-accept_xff:
- description: Enables or disables trusting the client IP address, and statistics from the client IP address.
- returned: changed
- type: bool
- sample: yes
-xff_alternative_names:
- description: Specifies alternative XFF headers instead of the default X-forwarded-for header.
- returned: changed
- type: list
- sample: ['FooBar', 'client1']
-fallback_host:
- description: Specifies an HTTP fallback host.
- returned: changed
- type: str
- sample: 'foobar.com'
-fallback_status_codes:
- description: HTTP error codes from server responses that should trigger a redirection to the fallback host.
- returned: changed
- type: list
- sample: ['400-404', '500', '501']
-oneconnect_transformations:
- description: Enables or disables HTTP header transformations.
- returned: changed
- type: bool
- sample: no
-request_chunking:
- description: Specifies how to handle chunked and unchunked requests.
- returned: changed
- type: str
- sample: rechunk
-response_chunking:
- description: Specifies how to handle chunked and unchunked responses.
- returned: changed
- type: str
- sample: rechunk
-enforcement:
- description: Specifies protocol enforcement settings for the HTTP profile.
- type: complex
- returned: changed
- contains:
- truncated_redirects:
- description: Specifies what happens if a truncated redirect is seen from a server.
- returned: changed
- type: bool
- sample: yes
- excess_server_headers:
- description: Specifies the behavior when too many server headers are received.
- returned: changed
- type: str
- sample: pass-through
- oversize_client_headers:
- description: Specifies the behavior when too-large client headers are received.
- returned: changed
- type: str
- sample: reject
- oversize_server_headers:
- description: Specifies the behavior when too-large server headers are received.
- returned: changed
- type: str
- sample: reject
- pipeline:
- description: Allows, rejects or switches to pass-through mode when dealing with pipelined data.
- returned: changed
- type: str
- sample: allow
- unknown_method:
- description: Allows, rejects or switches to pass-through mode when an unknown HTTP method is parsed.
- returned: changed
- type: str
- sample: allow
- max_header_count:
- description: The maximum number of headers allowed in HTTP request/response.
- returned: changed
- type: str
- sample: 4096
- max_header_size:
- description: The maximum header size specified in bytes.
- returned: changed
- type: str
- sample: default
- max_requests:
- description: The number of requests that the system accepts on a per-connection basis.
- returned: changed
- type: str
- sample: default
- known_methods:
- description: The list of known HTTP methods.
- returned: changed
- type: list
- sample: ['default', 'FOO', 'BAR']
- sample: hash/dictionary of values
-sflow:
- description: Specifies sFlow settings for the HTTP profile.
- type: complex
- returned: changed
- contains:
- poll_interval:
- description: Specifies the maximum interval in seconds between two pollings.
- returned: changed
- type: int
- sample: 30
- poll_interval_global:
- description: Enables/Disables overriding HTTP poll-interval setting.
- returned: changed
- type: bool
- sample: yes
- sampling_rate:
- description: Specifies the ratio of packets observed to the samples generated.
- returned: changed
- type: int
- sample: 2000
- sampling_rate_global:
- description: Enables/Disables overriding HTTP sampling-rate setting.
- returned: changed
- type: bool
- sample: yes
- sample: hash/dictionary of values
-'''
-
-import re
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.basic import env_fallback
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import fq_name
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.common import flatten_boolean
- from library.module_utils.network.f5.common import transform_name
- from library.module_utils.network.f5.compare import cmp_simple_list
- from library.module_utils.network.f5.urls import check_header_validity
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import fq_name
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.common import flatten_boolean
- from ansible.module_utils.network.f5.common import transform_name
- from ansible.module_utils.network.f5.compare import cmp_simple_list
- from ansible.module_utils.network.f5.urls import check_header_validity
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'defaultsFrom': 'parent',
- 'insertXforwardedFor': 'insert_xforwarded_for',
- 'redirectRewrite': 'redirect_rewrite',
- 'encryptCookies': 'encrypt_cookies',
- 'encryptCookieSecret': 'encrypt_cookie_secret',
- 'proxyType': 'proxy_type',
- 'explicitProxy': 'explicit_proxy',
- 'headerErase': 'header_erase',
- 'headerInsert': 'header_insert',
- 'serverAgentName': 'server_agent_name',
- 'includeSubdomains': 'include_subdomains',
- 'maximumAge': 'maximum_age',
- 'mode': 'hsts_mode',
- 'acceptXff': 'accept_xff',
- 'xffAlternativeNames': 'xff_alternative_names',
- 'fallbackHost': 'fallback_host',
- 'fallbackStatusCodes': 'fallback_status_codes',
- 'oneconnectTransformations': 'oneconnect_transformations',
- 'requestChunking': 'request_chunking',
- 'responseChunking': 'response_chunking',
- }
-
- api_attributes = [
- 'insertXforwardedFor',
- 'description',
- 'defaultsFrom',
- 'redirectRewrite',
- 'encryptCookies',
- 'encryptCookieSecret',
- 'proxyType',
- 'explicitProxy',
- 'headerErase',
- 'headerInsert',
- 'hsts',
- 'serverAgentName',
- 'acceptXff',
- 'xffAlternativeNames',
- 'fallbackHost',
- 'fallbackStatusCodes',
- 'oneconnectTransformations',
- 'requestChunking',
- 'responseChunking',
- 'enforcement',
- 'sflow',
- ]
-
- returnables = [
- 'parent',
- 'description',
- 'insert_xforwarded_for',
- 'redirect_rewrite',
- 'encrypt_cookies',
- 'proxy_type',
- 'explicit_proxy',
- 'dns_resolver',
- 'hsts_mode',
- 'maximum_age',
- 'include_subdomains',
- 'server_agent_name',
- 'header_erase',
- 'header_insert',
- 'accept_xff',
- 'xff_alternative_names',
- 'fallback_host',
- 'fallback_status_codes',
- 'oneconnect_transformations',
- 'request_chunking',
- 'response_chunking',
- 'truncated_redirects',
- 'excess_client_headers',
- 'excess_server_headers',
- 'oversize_client_headers',
- 'oversize_server_headers',
- 'pipeline',
- 'unknown_method',
- 'max_header_count',
- 'max_header_size',
- 'max_requests',
- 'known_methods',
- 'poll_interval',
- 'poll_interval_global',
- 'sampling_rate',
- 'sampling_rate_global',
- ]
-
- updatables = [
- 'description',
- 'insert_xforwarded_for',
- 'redirect_rewrite',
- 'encrypt_cookies',
- 'encrypt_cookie_secret',
- 'proxy_type',
- 'dns_resolver',
- 'hsts_mode',
- 'maximum_age',
- 'include_subdomains',
- 'server_agent_name',
- 'header_erase',
- 'header_insert',
- 'accept_xff',
- 'xff_alternative_names',
- 'fallback_host',
- 'fallback_status_codes',
- 'oneconnect_transformations',
- 'request_chunking',
- 'response_chunking',
- 'truncated_redirects',
- 'excess_client_headers',
- 'excess_server_headers',
- 'oversize_client_headers',
- 'oversize_server_headers',
- 'pipeline',
- 'unknown_method',
- 'max_header_count',
- 'max_header_size',
- 'max_requests',
- 'known_methods',
- 'poll_interval',
- 'poll_interval_global',
- 'sampling_rate',
- 'sampling_rate_global',
- ]
-
-
-class ApiParameters(Parameters):
- @property
- def poll_interval(self):
- return self._values['sflow']['pollInterval']
-
- @property
- def poll_interval_global(self):
- return self._values['sflow']['pollIntervalGlobal']
-
- @property
- def sampling_rate(self):
- return self._values['sflow']['samplingRate']
-
- @property
- def sampling_rate_global(self):
- return self._values['sflow']['samplingRateGlobal']
-
- @property
- def truncated_redirects(self):
- return self._values['enforcement']['truncatedRedirects']
-
- @property
- def excess_client_headers(self):
- return self._values['enforcement']['excessClientHeaders']
-
- @property
- def excess_server_headers(self):
- return self._values['enforcement']['excessServerHeaders']
-
- @property
- def oversize_client_headers(self):
- return self._values['enforcement']['oversizeClientHeaders']
-
- @property
- def oversize_server_headers(self):
- return self._values['enforcement']['oversizeServerHeaders']
-
- @property
- def pipeline(self):
- return self._values['enforcement']['pipeline']
-
- @property
- def unknown_method(self):
- return self._values['enforcement']['unknownMethod']
-
- @property
- def max_header_count(self):
- return self._values['enforcement']['maxHeaderCount']
-
- @property
- def max_header_size(self):
- return self._values['enforcement']['maxHeaderSize']
-
- @property
- def max_requests(self):
- return self._values['enforcement']['maxRequests']
-
- @property
- def known_methods(self):
- return self._values['enforcement'].get('knownMethods', None)
-
- @property
- def dns_resolver(self):
- if self._values['explicit_proxy'] is None:
- return None
- if 'dnsResolver' in self._values['explicit_proxy']:
- return self._values['explicit_proxy']['dnsResolver']
-
- @property
- def dns_resolver_address(self):
- if self._values['explicit_proxy'] is None:
- return None
- if 'dnsResolverReference' in self._values['explicit_proxy']:
- return self._values['explicit_proxy']['dnsResolverReference']
-
- @property
- def include_subdomains(self):
- if self._values['hsts'] is None:
- return None
- return self._values['hsts']['includeSubdomains']
-
- @property
- def hsts_mode(self):
- if self._values['hsts'] is None:
- return None
- return self._values['hsts']['mode']
-
- @property
- def maximum_age(self):
- if self._values['hsts'] is None:
- return None
- return self._values['hsts']['maximumAge']
-
-
-class ModuleParameters(Parameters):
- @property
- def accept_xff(self):
- result = flatten_boolean(self._values['accept_xff'])
- if result is None:
- return None
- if result == 'yes':
- return 'enabled'
- return 'disabled'
-
- @property
- def fallback_status_codes(self):
- if self._values['fallback_status_codes'] is None:
- return None
-
- p1 = r'(?!([4][0-1][0-7]))\d{3}'
- p2 = r'(?!(50[0-5]))\d{3}'
-
- for code in self._values['fallback_status_codes']:
- match_4xx = re.search(p1, code)
- if match_4xx:
- match_5xx = re.search(p2, code)
- if match_5xx:
- raise F5ModuleError(
- 'Invalid HTTP error code or error code range specified.'
- )
- return self._values['fallback_status_codes']
-
- @property
- def oneconnect_transformations(self):
- result = flatten_boolean(self._values['oneconnect_transformations'])
- if result is None:
- return None
- if result == 'yes':
- return 'enabled'
- return 'disabled'
-
- @property
- def proxy_type(self):
- if self._values['proxy_type'] is None:
- return None
- if self._values['proxy_type'] == 'explicit':
- if self.dns_resolver is None or self.dns_resolver == '':
- raise F5ModuleError(
- 'A proxy type cannot be set to {0} without providing DNS resolver.'.format(self._values['proxy_type'])
- )
- return self._values['proxy_type']
-
- @property
- def dns_resolver(self):
- if self._values['dns_resolver'] is None:
- return None
- if self._values['dns_resolver'] == '' or self._values['dns_resolver'] == 'none':
- return ''
- result = fq_name(self.partition, self._values['dns_resolver'])
- return result
-
- @property
- def dns_resolver_address(self):
- resolver = self.dns_resolver
- if resolver is None:
- return None
- tmp = resolver.split('/')
- link = dict(link='https://localhost/mgmt/tm/net/dns-resolver/~{0}~{1}'.format(tmp[1], tmp[2]))
- return link
-
- @property
- def insert_xforwarded_for(self):
- result = flatten_boolean(self._values['insert_xforwarded_for'])
- if result is None:
- return None
- if result == 'yes':
- return 'enabled'
- return 'disabled'
-
- @property
- def parent(self):
- if self._values['parent'] is None:
- return None
- result = fq_name(self.partition, self._values['parent'])
- return result
-
- @property
- def encrypt_cookies(self):
- if self._values['encrypt_cookies'] is None:
- return None
- if self._values['encrypt_cookies'] == [''] or self._values['encrypt_cookies'] == ['none']:
- return list()
- return self._values['encrypt_cookies']
-
- @property
- def explicit_proxy(self):
- if self.dns_resolver is None:
- return None
- result = dict(
- dnsResolver=self.dns_resolver,
- dnsResolverReference=self.dns_resolver_address
- )
- return result
-
- @property
- def include_subdomains(self):
- result = flatten_boolean(self._values['include_subdomains'])
- if result is None:
- return None
- if result == 'yes':
- return 'enabled'
- return 'disabled'
-
- @property
- def maximum_age(self):
- if self._values['maximum_age'] is None:
- return None
- if self._values['maximum_age'] == 'indefinite':
- return 4294967295
- if 0 <= int(self._values['maximum_age']) <= 4294967295:
- return int(self._values['maximum_age'])
- raise F5ModuleError(
- "Valid 'maximum_age' must be in range 0 - 4294967295, or 'indefinite'."
- )
-
- @property
- def hsts_mode(self):
- result = flatten_boolean(self._values['hsts_mode'])
- if result is None:
- return None
- if result == 'yes':
- return 'enabled'
- return 'disabled'
-
- @property
- def header_erase(self):
- header_erase = self._values['header_erase']
- if header_erase is None:
- return None
- if header_erase in ['none', '']:
- return self._values['header_erase']
- check_header_validity(header_erase)
- return header_erase
-
- @property
- def header_insert(self):
- header_insert = self._values['header_insert']
- if header_insert is None:
- return None
- if header_insert in ['none', '']:
- return self._values['header_insert']
- check_header_validity(header_insert)
- return header_insert
-
- @property
- def excess_client_headers(self):
- if self._values['enforcement'] is None:
- return None
- return self._values['enforcement']['excess_client_headers']
-
- @property
- def excess_server_headers(self):
- if self._values['enforcement'] is None:
- return None
- return self._values['enforcement']['excess_server_headers']
-
- @property
- def oversize_client_headers(self):
- if self._values['enforcement'] is None:
- return None
- return self._values['enforcement']['oversize_client_headers']
-
- @property
- def oversize_server_headers(self):
- if self._values['enforcement'] is None:
- return None
- return self._values['enforcement']['oversize_server_headers']
-
- @property
- def pipeline(self):
- if self._values['enforcement'] is None:
- return None
- return self._values['enforcement']['pipeline']
-
- @property
- def unknown_method(self):
- if self._values['enforcement'] is None:
- return None
- return self._values['enforcement']['unknown_method']
-
- @property
- def truncated_redirects(self):
- if self._values['enforcement'] is None:
- return None
- result = flatten_boolean(self._values['enforcement']['truncated_redirects'])
- if result is None:
- return None
- if result == 'yes':
- return 'enabled'
- return 'disabled'
-
- @property
- def max_header_count(self):
- if self._values['enforcement'] is None:
- return None
- if self._values['enforcement']['max_header_count'] is None:
- return None
- if self._values['enforcement']['max_header_count'] == 'default':
- return 64
- if 16 <= int(self._values['enforcement']['max_header_count']) <= 4096:
- return int(self._values['enforcement']['max_header_count'])
- raise F5ModuleError(
- "Valid 'max_header_count' must be in range 16 - 4096, or 'default'."
- )
-
- @property
- def max_header_size(self):
- if self._values['enforcement'] is None:
- return None
- if self._values['enforcement']['max_header_size'] is None:
- return None
- if self._values['enforcement']['max_header_size'] == 'default':
- return 32768
- if 0 <= int(self._values['enforcement']['max_header_size']) <= 4294967295:
- return int(self._values['enforcement']['max_header_size'])
- raise F5ModuleError(
- "Valid 'max_header_size' must be in range 0 - 4294967295, or 'default'."
- )
-
- @property
- def max_requests(self):
- if self._values['enforcement'] is None:
- return None
- if self._values['enforcement']['max_requests'] is None:
- return None
- if self._values['enforcement']['max_requests'] == 'default':
- return 0
- if 0 <= int(self._values['enforcement']['max_requests']) <= 4294967295:
- return int(self._values['enforcement']['max_requests'])
- raise F5ModuleError(
- "Valid 'max_requests' must be in range 0 - 4294967295, or 'default'."
- )
-
- @property
- def known_methods(self):
- if self._values['enforcement'] is None:
- return None
- defaults = ['CONNECT', 'DELETE', 'GET', 'HEAD', 'LOCK', 'OPTIONS', 'POST', 'PROPFIND', 'PUT', 'TRACE', 'UNLOCK']
- known = self._values['enforcement']['known_methods']
- if known is None:
- return None
- if len(known) == 1:
- if known[0] == 'default':
- return defaults
- if known[0] == '':
- return []
- if 'default' in known:
- to_return = [method for method in known if method != 'default']
- to_return.extend(defaults)
- return to_return
- result = [method for method in known]
- return result
-
- @property
- def poll_interval(self):
- if self._values['sflow'] is None:
- return None
- if self._values['sflow']['poll_interval'] is None:
- return None
- if 0 <= self._values['sflow']['poll_interval'] <= 4294967295:
- return self._values['sflow']['poll_interval']
- raise F5ModuleError(
- "Valid 'poll_interval' must be in range 0 - 4294967295 seconds."
- )
-
- @property
- def sampling_rate(self):
- if self._values['sflow'] is None:
- return None
- if self._values['sflow']['sampling_rate'] is None:
- return None
- if 0 <= self._values['sflow']['sampling_rate'] <= 4294967295:
- return self._values['sflow']['sampling_rate']
- raise F5ModuleError(
- "Valid 'sampling_rate' must be in range 0 - 4294967295 packets."
- )
-
- @property
- def poll_interval_global(self):
- if self._values['sflow'] is None:
- return None
- result = flatten_boolean(self._values['sflow']['poll_interval_global'])
- return result
-
- @property
- def sampling_rate_global(self):
- if self._values['sflow'] is None:
- return None
- result = flatten_boolean(self._values['sflow']['sampling_rate_global'])
- return result
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class UsableChanges(Changes):
- @property
- def explicit_proxy(self):
- result = dict()
- if self._values['dns_resolver'] is not None:
- result['dnsResolver'] = self._values['dns_resolver']
- if self._values['dns_resolver_address'] is not None:
- result['dnsResolverReference'] = self._values['dns_resolver_address']
- if not result:
- return None
- return result
-
- @property
- def hsts(self):
- result = dict()
- if self._values['hsts_mode'] is not None:
- result['mode'] = self._values['hsts_mode']
- if self._values['maximum_age'] is not None:
- result['maximumAge'] = self._values['maximum_age']
- if self._values['include_subdomains'] is not None:
- result['includeSubdomains'] = self._values['include_subdomains']
- if not result:
- return None
- return result
-
- @property
- def enforcement(self):
- to_filter = dict(
- excessClientHeaders=self._values['excess_client_headers'],
- excessServerHeaders=self._values['excess_server_headers'],
- knownMethods=self._values['known_methods'],
- maxHeaderCount=self._values['max_header_count'],
- maxHeaderSize=self._values['max_header_size'],
- maxRequests=self._values['max_requests'],
- oversizeClientHeaders=self._values['oversize_client_headers'],
- oversizeServerHeaders=self._values['oversize_server_headers'],
- pipeline=self._values['pipeline'],
- truncatedRedirects=self._values['truncated_redirects'],
- unknownMethod=self._values['unknown_method']
- )
- result = self._filter_params(to_filter)
- if result:
- return result
-
- @property
- def sflow(self):
- to_filter = dict(
- pollInterval=self._values['poll_interval'],
- pollIntervalGlobal=self._values['poll_interval_global'],
- samplingRate=self._values['sampling_rate'],
- samplingRateGlobal=self._values['sampling_rate_global'],
- )
- result = self._filter_params(to_filter)
- if result:
- return result
-
-
-class ReportableChanges(Changes):
- returnables = [
- 'parent',
- 'description',
- 'insert_xforwarded_for',
- 'redirect_rewrite',
- 'encrypt_cookies',
- 'proxy_type',
- 'explicit_proxy',
- 'dns_resolver',
- 'hsts_mode',
- 'maximum_age',
- 'include_subdomains',
- 'server_agent_name',
- 'header_erase',
- 'header_insert',
- 'accept_xff',
- 'xff_alternative_names',
- 'fallback_host',
- 'fallback_status_codes',
- 'oneconnect_transformations',
- 'request_chunking',
- 'response_chunking',
- 'enforcement',
- 'sflow'
- ]
-
- @property
- def insert_xforwarded_for(self):
- if self._values['insert_xforwarded_for'] is None:
- return None
- elif self._values['insert_xforwarded_for'] == 'enabled':
- return 'yes'
- return 'no'
-
- @property
- def hsts_mode(self):
- if self._values['hsts_mode'] is None:
- return None
- elif self._values['hsts_mode'] == 'enabled':
- return 'yes'
- return 'no'
-
- @property
- def include_subdomains(self):
- if self._values['include_subdomains'] is None:
- return None
- elif self._values['include_subdomains'] == 'enabled':
- return 'yes'
- return 'no'
-
- @property
- def maximum_age(self):
- if self._values['maximum_age'] is None:
- return None
- if self._values['maximum_age'] == 4294967295:
- return 'indefinite'
- return int(self._values['maximum_age'])
-
- @property
- def truncated_redirects(self):
- result = flatten_boolean(self._values['truncated_redirects'])
- return result
-
- @property
- def max_header_count(self):
- if self._values['max_header_count'] is None:
- return None
- if self._values['max_header_count'] == 64:
- return 'default'
- return str(self._values['max_header_count'])
-
- @property
- def max_header_size(self):
- if self._values['max_header_size'] is None:
- return None
- if self._values['max_header_size'] == 32768:
- return 'default'
- return str(self._values['max_header_size'])
-
- @property
- def max_requests(self):
- if self._values['max_requests'] is None:
- return None
- if self._values['max_requests'] == 0:
- return 'default'
- return str(self._values['max_requests'])
-
- @property
- def known_methods(self):
- defaults = ['CONNECT', 'DELETE', 'GET', 'HEAD', 'LOCK', 'OPTIONS', 'POST', 'PROPFIND', 'PUT', 'TRACE', 'UNLOCK']
- known = self._values['known_methods']
- if known is None:
- return None
- if not known:
- return ['']
- if set(known) == set(defaults):
- return ['default']
- if set(known).issuperset(set(defaults)):
- result = [item for item in known if item not in defaults]
- result.append('default')
- return result
- return known
-
- @property
- def enforcement(self):
- to_filter = dict(
- excess_client_headers=self._values['excess_client_headers'],
- excess_server_headers=self._values['excess_server_headers'],
- known_methods=self.known_methods,
- max_header_count=self.max_header_count,
- max_header_size=self.max_header_size,
- max_requests=self.max_requests,
- oversize_client_headers=self._values['oversize_client_headers'],
- oversize_server_headers=self._values['oversize_server_headers'],
- pipeline=self._values['pipeline'],
- truncated_redirects=self.truncated_redirects,
- unknown_method=self._values['unknown_method']
- )
- result = self._filter_params(to_filter)
- if result:
- return result
-
- @property
- def accept_xff(self):
- result = flatten_boolean(self._values['accept_xff'])
- return result
-
- @property
- def oneconnect_transformations(self):
- result = flatten_boolean(self._values['oneconnect_transformations'])
- return result
-
- @property
- def sflow(self):
- to_filter = dict(
- poll_interval=self._values['poll_interval'],
- poll_interval_global=self._values['poll_interval_global'],
- sampling_rate=self._values['sampling_rate'],
- sampling_rate_global=self._values['sampling_rate_global'],
- )
- result = self._filter_params(to_filter)
- if result:
- return result
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
- @property
- def parent(self):
- if self.want.parent != self.have.parent:
- raise F5ModuleError(
- "The parent http profile cannot be changed"
- )
-
- @property
- def dns_resolver(self):
- if self.want.dns_resolver is None:
- return None
- if self.want.dns_resolver == '':
- if self.have.dns_resolver is None or self.have.dns_resolver == 'none':
- return None
- elif self.have.proxy_type == 'explicit' and self.want.proxy_type is None:
- raise F5ModuleError(
- "DNS resolver cannot be empty or 'none' if an existing profile proxy type is set to {0}.".format(self.have.proxy_type)
- )
- elif self.have.dns_resolver is not None:
- return self.want.dns_resolver
- if self.have.dns_resolver is None:
- return self.want.dns_resolver
-
- @property
- def header_erase(self):
- if self.want.header_erase is None:
- return None
- if self.want.header_erase in ['none', '']:
- if self.have.header_erase in [None, 'none']:
- return None
- if self.want.header_erase != self.have.header_erase:
- return self.want.header_erase
-
- @property
- def header_insert(self):
- if self.want.header_insert is None:
- return None
- if self.want.header_insert in ['none', '']:
- if self.have.header_insert in [None, 'none']:
- return None
- if self.want.header_insert != self.have.header_insert:
- return self.want.header_insert
-
- @property
- def server_agent_name(self):
- if self.want.server_agent_name is None:
- return None
- if self.want.server_agent_name in ['none', '']:
- if self.have.server_agent_name in [None, 'none']:
- return None
- if self.want.server_agent_name != self.have.server_agent_name:
- return self.want.server_agent_name
-
- @property
- def encrypt_cookies(self):
- if self.want.encrypt_cookies is None:
- return None
- if self.have.encrypt_cookies in [None, []]:
- if not self.want.encrypt_cookies:
- return None
- else:
- return self.want.encrypt_cookies
- if set(self.want.encrypt_cookies) != set(self.have.encrypt_cookies):
- return self.want.encrypt_cookies
-
- @property
- def encrypt_cookie_secret(self):
- if self.want.encrypt_cookie_secret != self.have.encrypt_cookie_secret:
- if self.want.update_password == 'always':
- result = self.want.encrypt_cookie_secret
- return result
-
- @property
- def xff_alternative_names(self):
- result = cmp_simple_list(self.want.xff_alternative_names, self.have.xff_alternative_names)
- return result
-
- @property
- def fallback_status_codes(self):
- result = cmp_simple_list(self.want.fallback_status_codes, self.have.fallback_status_codes)
- return result
-
- @property
- def known_methods(self):
- result = cmp_simple_list(self.want.known_methods, self.have.known_methods)
- return result
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(params=self.module.params)
- self.have = ApiParameters()
- self.changes = UsableChanges()
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = UsableChanges(params=changed)
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def exec_module(self):
- changed = False
- result = dict()
- state = self.want.state
-
- if state == "present":
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.client.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def present(self):
- if self.exists():
- return self.update()
- else:
- return self.create()
-
- def absent(self):
- if self.exists():
- return self.remove()
- return False
-
- def update(self):
- self.have = self.read_current_from_device()
- if not self.should_update():
- return False
- if self.module.check_mode:
- return True
- self.update_on_device()
- return True
-
- def remove(self):
- if self.module.check_mode:
- return True
- self.remove_from_device()
- if self.exists():
- raise F5ModuleError("Failed to delete the resource.")
- return True
-
- def create(self):
- self._set_changed_options()
- if self.module.check_mode:
- return True
- self.create_on_device()
- return True
-
- def exists(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/profile/http/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def create_on_device(self):
- params = self.changes.api_params()
- params['name'] = self.want.name
- params['partition'] = self.want.partition
- uri = "https://{0}:{1}/mgmt/tm/ltm/profile/http/".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403, 404]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return response['selfLink']
-
- def update_on_device(self):
- params = self.changes.api_params()
- uri = "https://{0}:{1}/mgmt/tm/ltm/profile/http/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 404]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def remove_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/profile/http/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- response = self.client.api.delete(uri)
- if response.status == 200:
- return True
- raise F5ModuleError(response.content)
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/profile/http/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return ApiParameters(params=response)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- self.chunk = ['rechunk', 'selective', 'preserve']
- self.choices = ['pass-through', 'reject']
- self.select = ['allow', 'pass-through', 'reject']
- argument_spec = dict(
- name=dict(required=True),
- parent=dict(default='/Common/http'),
- description=dict(),
- accept_xff=dict(type='bool'),
- xff_alternative_names=dict(type='list'),
- fallback_host=dict(),
- fallback_status_codes=dict(type='list'),
- oneconnect_transformations=dict(type='bool'),
- request_chunking=dict(choices=self.chunk),
- response_chunking=dict(choices=self.chunk),
- proxy_type=dict(
- choices=[
- 'reverse',
- 'transparent',
- 'explicit'
- ]
- ),
- dns_resolver=dict(),
- insert_xforwarded_for=dict(type='bool'),
- redirect_rewrite=dict(
- choices=[
- 'none',
- 'all',
- 'matching',
- 'nodes'
- ]
- ),
- encrypt_cookies=dict(type='list'),
- encrypt_cookie_secret=dict(no_log=True),
- update_password=dict(
- default='always',
- choices=['always', 'on_create']
- ),
- header_erase=dict(),
- header_insert=dict(),
- server_agent_name=dict(),
- hsts_mode=dict(type='bool'),
- maximum_age=dict(),
- include_subdomains=dict(type='bool'),
- enforcement=dict(
- type='dict',
- options=dict(
- truncated_redirects=dict(type='bool'),
- excess_client_headers=dict(choices=self.choices),
- excess_server_headers=dict(choices=self.choices),
- oversize_client_headers=dict(choices=self.choices),
- oversize_server_headers=dict(choices=self.choices),
- pipeline=dict(choices=self.select),
- unknown_method=dict(choices=self.select),
- max_header_count=dict(),
- max_header_size=dict(),
- max_requests=dict(),
- known_methods=dict(type='list'),
- )
- ),
- sflow=dict(
- type='dict',
- options=dict(
- poll_interval=dict(type='int'),
- poll_interval_global=dict(type='bool'),
- sampling_rate=dict(type='int'),
- sampling_rate_global=dict(type='bool'),
- )
- ),
- state=dict(
- default='present',
- choices=['present', 'absent']
- ),
- partition=dict(
- default='Common',
- fallback=(env_fallback, ['F5_PARTITION'])
-
- )
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode,
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_profile_http2.py b/lib/ansible/modules/network/f5/bigip_profile_http2.py
deleted file mode 100644
index 32c1566f85..0000000000
--- a/lib/ansible/modules/network/f5/bigip_profile_http2.py
+++ /dev/null
@@ -1,679 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2018, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_profile_http2
-short_description: Manage HTTP2 profiles on a BIG-IP
-description:
- - Manage HTTP2 profiles on a BIG-IP.
-version_added: 2.8
-options:
- name:
- description:
- - Specifies the name of the profile.
- type: str
- required: True
- parent:
- description:
- - Specifies the profile from which this profile inherits settings.
- - When creating a new profile, if this parameter is not specified, the default
- is the system-supplied C(http2) profile.
- type: str
- default: /Common/http2
- description:
- description:
- - Description of the profile.
- type: str
- streams:
- description:
- - Specifies the number of outstanding concurrent requests that are allowed on a single HTTP/2 connection.
- - When creating a new profile, if this parameter is not specified, the default is provided by the parent profile.
- - The valid value range is C(1 - 256).
- type: int
- idle_timeout:
- description:
- - Specifies the number of seconds that an HTTP/2 connection is idly left open before being shut down.
- - When creating a new profile, if this parameter is not specified, the default is provided by the parent profile.
- type: int
- insert_header:
- description:
- - Specifies whether an HTTP header indicating the use of HTTP/2 should be inserted into the request
- that goes to the server.
- - When creating a new profile, if this parameter is not specified, the default is provided by the parent profile.
- type: bool
- insert_header_name:
- description:
- - Specifies the name of the HTTP header controlled by C(insert_header) parameter.
- - When creating a new profile, if this parameter is not specified, the default is provided by the parent profile.
- type: str
- enforce_tls_requirements:
- description:
- - Specifies whether the system requires TLS for communications between specified senders and recipients.
- - When creating a new profile, if this parameter is not specified, the default is provided by the parent profile.
- type: bool
- activation_modes:
- description:
- - Specifies what will cause an incoming connection to be handled as a HTTP/2 connection.
- - The C(alpn) and C(always) are mutually exclusive.
- - When creating a new profile, if this parameter is not specified, the default is provided by the parent profile.
- type: list
- choices:
- - alpn
- - always
- frame_size:
- description:
- - Specifies the size of data frames, in bytes, that HTTP/2 sends to the client.
- - When creating a new profile, if this parameter is not specified, the default is provided by the parent profile.
- - The valid value range in bytes is C(1024 - 16384).
- type: int
- write_size:
- description:
- - Specifies the total size of combined data frames, in bytes, that HTTP/2 sends in a single write.
- - When creating a new profile, if this parameter is not specified, the default is provided by the parent profile.
- - The valid value range in bytes is C(2048 - 32768).
- type: int
- receive_window:
- description:
- - Specifies the way that the HTTP/2 profile performs flow control.
- - When creating a new profile, if this parameter is not specified, the default is provided by the parent profile.
- - The valid value range in kilobytes is C(16 - 128).
- type: int
- header_table_size:
- description:
- - Specifies the size of the header table, in bytes.
- - When creating a new profile, if this parameter is not specified, the default is provided by the parent profile.
- - The valid value range in bytes is C(0 - 65535).
- type: int
- partition:
- description:
- - Device partition to manage resources on.
- type: str
- default: Common
- state:
- description:
- - When C(present), ensures that the profile exists.
- - When C(absent), ensures the profile is removed.
- type: str
- choices:
- - present
- - absent
- default: present
-extends_documentation_fragment: f5
-author:
- - Wojciech Wypior (@wojtek0806)
-'''
-
-EXAMPLES = r'''
-- name: Create HTTP2 profile
- bigip_profile_http2:
- name: my_profile
- insert_header: yes
- insert_header_name: FOO
- state: present
- provider:
- user: admin
- password: secret
- server: lb.mydomain.com
- delegate_to: localhost
-
-- name: Remove HTTP profile
- bigip_profile_http2:
- name: my_profile
- state: absent
- provider:
- server: lb.mydomain.com
- user: admin
- password: secret
- delegate_to: localhost
-
-- name: Add HTTP profile set activation modes
- bigip_profile_http:
- name: my_profile
- activation_modes:
- - always
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-'''
-
-RETURN = r'''
-description:
- description: Description of the profile.
- returned: changed
- type: str
- sample: My profile
-insert_header_name:
- description: Specifies the name of the HTTP2 header
- returned: changed
- type: str
- sample: X-HTTP2
-streams:
- description: The number of outstanding concurrent requests allowed on a single HTTP/2 connection
- returned: changed
- type: int
- sample: 30
-enforce_tls_requirements:
- description: pecifies whether the system requires TLS for communications.
- returned: changed
- type: bool
- sample: yes
-frame_size:
- description: The size of the data frames
- returned: changed
- type: int
- sample: 30
-activation_modes:
- description: Specifies HTTP/2 connection handling modes
- returned: changed
- type: list
- sample: ['always']
-'''
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.basic import env_fallback
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import fq_name
- from library.module_utils.network.f5.common import transform_name
- from library.module_utils.network.f5.common import flatten_boolean
- from library.module_utils.network.f5.common import is_empty_list
- from library.module_utils.network.f5.common import f5_argument_spec
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import fq_name
- from ansible.module_utils.network.f5.common import transform_name
- from ansible.module_utils.network.f5.common import flatten_boolean
- from ansible.module_utils.network.f5.common import is_empty_list
- from ansible.module_utils.network.f5.common import f5_argument_spec
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'activationModes': 'activation_modes',
- 'concurrentStreamsPerConnection': 'streams',
- 'connectionIdleTimeout': 'idle_timeout',
- 'defaultsFrom': 'parent',
- 'enforceTlsRequirements': 'enforce_tls_requirements',
- 'frameSize': 'frame_size',
- 'headerTableSize': 'header_table_size',
- 'insertHeader': 'insert_header',
- 'insertHeaderName': 'insert_header_name',
- 'receiveWindow': 'receive_window',
- 'writeSize': 'write_size',
- }
-
- api_attributes = [
- 'activationModes',
- 'concurrentStreamsPerConnection',
- 'connectionIdleTimeout',
- 'description',
- 'defaultsFrom',
- 'enforceTlsRequirements',
- 'frameSize',
- 'headerTableSize',
- 'insertHeader',
- 'insertHeaderName',
- 'receiveWindow',
- 'writeSize',
- ]
-
- returnables = [
- 'activation_modes',
- 'streams',
- 'description',
- 'idle_timeout',
- 'parent',
- 'enforce_tls_requirements',
- 'frame_size',
- 'header_table_size',
- 'insert_header',
- 'insert_header_name',
- 'receive_window',
- 'write_size',
- ]
-
- updatables = [
- 'activation_modes',
- 'streams',
- 'description',
- 'idle_timeout',
- 'parent',
- 'enforce_tls_requirements',
- 'frame_size',
- 'header_table_size',
- 'insert_header',
- 'insert_header_name',
- 'receive_window',
- 'write_size',
- ]
-
-
-class ApiParameters(Parameters):
- pass
-
-
-class ModuleParameters(Parameters):
- @property
- def parent(self):
- if self._values['parent'] is None:
- return None
- result = fq_name(self.partition, self._values['parent'])
- return result
-
- @property
- def streams(self):
- streams = self._values['streams']
- if streams is None:
- return None
- if streams < 1 or streams > 256:
- raise F5ModuleError(
- "Streams value must be between 1 and 256"
- )
- return self._values['streams']
-
- @property
- def receive_window(self):
- window = self._values['receive_window']
- if window is None:
- return None
- if window < 16 or window > 128:
- raise F5ModuleError(
- "Receive Window value must be between 16 and 128"
- )
- return self._values['receive_window']
-
- @property
- def header_table_size(self):
- header = self._values['header_table_size']
- if header is None:
- return None
- if header < 0 or header > 65535:
- raise F5ModuleError(
- "Header Table Size value must be between 0 and 65535"
- )
- return self._values['header_table_size']
-
- @property
- def write_size(self):
- write = self._values['write_size']
- if write is None:
- return None
- if write < 2048 or write > 32768:
- raise F5ModuleError(
- "Write Size value must be between 2048 and 32768"
- )
- return self._values['write_size']
-
- @property
- def frame_size(self):
- frame = self._values['frame_size']
- if frame is None:
- return None
- if frame < 1024 or frame > 16384:
- raise F5ModuleError(
- "Write Size value must be between 1024 and 16384"
- )
- return self._values['frame_size']
-
- @property
- def enforce_tls_requirements(self):
- result = flatten_boolean(self._values['enforce_tls_requirements'])
- if result is None:
- return None
- if result == 'yes':
- return 'enabled'
- return 'disabled'
-
- @property
- def insert_header(self):
- result = flatten_boolean(self._values['insert_header'])
- if result is None:
- return None
- if result == 'yes':
- return 'enabled'
- return 'disabled'
-
- @property
- def activation_modes(self):
- value = self._values['activation_modes']
- if value is None:
- return None
- if is_empty_list(value):
- raise F5ModuleError(
- "Activation Modes cannot be empty, please provide a value"
- )
- return value
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class UsableChanges(Changes):
- pass
-
-
-class ReportableChanges(Changes):
- @property
- def insert_header(self):
- if self._values['insert_header'] is None:
- return None
- elif self._values['insert_header'] == 'enabled':
- return 'yes'
- return 'no'
-
- @property
- def enforce_tls_requirements(self):
- if self._values['enforce_tls_requirements'] is None:
- return None
- elif self._values['enforce_tls_requirements'] == 'enabled':
- return 'yes'
- return 'no'
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
- @property
- def parent(self):
- if self.want.parent != self.have.parent:
- raise F5ModuleError(
- "The parent profile cannot be changed"
- )
-
- @property
- def description(self):
- if self.want.description is None:
- return None
- if self.want.description == '':
- if self.have.description is None or self.have.description == "none":
- return None
- if self.want.description != self.have.description:
- return self.want.description
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(params=self.module.params)
- self.have = ApiParameters()
- self.changes = UsableChanges()
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = UsableChanges(params=changed)
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def exec_module(self):
- changed = False
- result = dict()
- state = self.want.state
-
- if state == "present":
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.client.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def present(self):
- if self.exists():
- return self.update()
- else:
- return self.create()
-
- def absent(self):
- if self.exists():
- return self.remove()
- return False
-
- def update(self):
- self.have = self.read_current_from_device()
- if not self.should_update():
- return False
- if self.module.check_mode:
- return True
- self.update_on_device()
- return True
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def remove(self):
- if self.module.check_mode:
- return True
- self.remove_from_device()
- if self.exists():
- raise F5ModuleError("Failed to delete the resource.")
- return True
-
- def create(self):
- self._set_changed_options()
- if self.module.check_mode:
- return True
- self.create_on_device()
- return True
-
- def exists(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/profile/http2/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def create_on_device(self):
- params = self.changes.api_params()
- params['name'] = self.want.name
- params['partition'] = self.want.partition
- uri = "https://{0}:{1}/mgmt/tm/ltm/profile/http2/".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403, 404]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return response['selfLink']
-
- def update_on_device(self):
- params = self.changes.api_params()
- uri = "https://{0}:{1}/mgmt/tm/ltm/profile/http2/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 404]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def remove_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/profile/http2/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- response = self.client.api.delete(uri)
- if response.status == 200:
- return True
- raise F5ModuleError(response.content)
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/profile/http2/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return ApiParameters(params=response)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- name=dict(required=True),
- parent=dict(default='/Common/http2'),
- activation_modes=dict(
- type='list',
- choices=[
- 'alpn', 'always'
- ],
- mutually_exclusive=['always', 'alpn'],
- ),
- description=dict(),
- enforce_tls_requirements=dict(type='bool'),
- streams=dict(type='int'),
- idle_timeout=dict(type='int'),
- frame_size=dict(type='int'),
- header_table_size=dict(type='int'),
- insert_header=dict(type='bool'),
- insert_header_name=dict(),
- receive_window=dict(type='int'),
- write_size=dict(type='int'),
- state=dict(
- default='present',
- choices=['present', 'absent']
- ),
- partition=dict(
- default='Common',
- fallback=(env_fallback, ['F5_PARTITION'])
- )
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode,
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_profile_http_compression.py b/lib/ansible/modules/network/f5/bigip_profile_http_compression.py
deleted file mode 100644
index a68b883269..0000000000
--- a/lib/ansible/modules/network/f5/bigip_profile_http_compression.py
+++ /dev/null
@@ -1,542 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2018, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_profile_http_compression
-short_description: Manage HTTP compression profiles on a BIG-IP
-description:
- - Manage HTTP compression profiles on a BIG-IP.
-version_added: 2.7
-options:
- name:
- description:
- - Specifies the name of the compression profile.
- type: str
- required: True
- parent:
- description:
- - Specifies the profile from which this profile inherits settings.
- - When creating a new profile, if this parameter is not specified, the default
- is the system-supplied C(httpcompression) profile.
- type: str
- description:
- description:
- - Description of the HTTP compression profile.
- type: str
- buffer_size:
- description:
- - Maximum number of compressed bytes that the system buffers before inserting
- a Content-Length header (which specifies the compressed size) into the response.
- - When creating a new profile, if this parameter is not specified, the default
- is provided by the parent profile.
- type: int
- gzip_level:
- description:
- - Specifies the degree to which the system compresses the content.
- - Higher compression levels cause the compression process to be slower.
- - Valid values are between 1 (least compression and fastest) to 9 (most
- compression and slowest).
- type: int
- choices:
- - 1
- - 2
- - 3
- - 4
- - 5
- - 6
- - 7
- - 8
- - 9
- gzip_memory_level:
- description:
- - Number of kilobytes of memory that the system uses for internal compression
- buffers when compressing a server response.
- type: int
- choices:
- - 1
- - 2
- - 4
- - 8
- - 16
- - 32
- - 64
- - 128
- - 256
- gzip_window_size:
- description:
- - Number of kilobytes in the window size that the system uses when compressing
- a server response.
- type: int
- choices:
- - 1
- - 2
- - 4
- - 8
- - 16
- - 32
- - 64
- - 128
- partition:
- description:
- - Device partition to manage resources on.
- type: str
- default: Common
- state:
- description:
- - When C(present), ensures that the profile exists.
- - When C(absent), ensures the profile is removed.
- type: str
- choices:
- - present
- - absent
- default: present
-extends_documentation_fragment: f5
-author:
- - Tim Rupp (@caphrim007)
-'''
-
-EXAMPLES = r'''
-- name: Create an HTTP compression profile
- bigip_profile_http_compression:
- name: profile1
- description: Custom HTTP Compression Profile
- buffer_size: 131072
- gzip_level: 6
- gzip_memory_level: 16k
- gzip_window_size: 64k
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-'''
-
-RETURN = r'''
-description:
- description: The new description of the resource.
- returned: changed
- type: str
- sample: My custom profile
-buffer_size:
- description: The new buffer size of the profile.
- returned: changed
- type: int
- sample: 4096
-gzip_memory_level:
- description: The new GZIP memory level, in KB, of the profile.
- returned: changed
- type: int
- sample: 16
-gzip_level:
- description: The new GZIP level of the profile. Smaller is less compression.
- returned: changed
- type: int
- sample: 2
-gzip_window_size:
- description: The new GZIP window size, in KB, of the profile.
- returned: changed
- type: int
- sample: 64
-'''
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.basic import env_fallback
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import fq_name
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.common import transform_name
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import fq_name
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.common import transform_name
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'bufferSize': 'buffer_size',
- 'defaultsFrom': 'parent',
- 'gzipMemoryLevel': 'gzip_memory_level',
- 'gzipLevel': 'gzip_level',
- 'gzipWindowSize': 'gzip_window_size',
- }
-
- api_attributes = [
- 'description',
- 'bufferSize',
- 'defaultsFrom',
- 'gzipMemoryLevel',
- 'gzipLevel',
- 'gzipWindowSize',
- ]
-
- returnables = [
- 'description',
- 'buffer_size',
- 'gzip_memory_level',
- 'gzip_level',
- 'gzip_window_size',
- ]
-
- updatables = [
- 'description',
- 'buffer_size',
- 'gzip_memory_level',
- 'gzip_level',
- 'gzip_window_size',
- ]
-
-
-class ApiParameters(Parameters):
- @property
- def description(self):
- if self._values['description'] in [None, 'none']:
- return None
- return self._values['description']
-
- @property
- def gzip_memory_level(self):
- if self._values['gzip_memory_level'] is None:
- return None
- return self._values['gzip_memory_level'] / 1024
-
- @property
- def gzip_window_size(self):
- if self._values['gzip_window_size'] is None:
- return None
- return self._values['gzip_window_size'] / 1024
-
-
-class ModuleParameters(Parameters):
- @property
- def parent(self):
- if self._values['parent'] is None:
- return None
- result = fq_name(self.partition, self._values['parent'])
- return result
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class UsableChanges(Changes):
- @property
- def gzip_memory_level(self):
- if self._values['gzip_memory_level'] is None:
- return None
- return self._values['gzip_memory_level'] * 1024
-
- @property
- def gzip_window_size(self):
- if self._values['gzip_window_size'] is None:
- return None
- return self._values['gzip_window_size'] * 1024
-
-
-class ReportableChanges(Changes):
- @property
- def gzip_memory_level(self):
- if self._values['gzip_memory_level'] is None:
- return None
- return self._values['gzip_memory_level'] / 1024
-
- @property
- def gzip_window_size(self):
- if self._values['gzip_window_size'] is None:
- return None
- return self._values['gzip_window_size'] / 1024
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
- @property
- def parent(self):
- if self.want.parent != self.have.parent:
- raise F5ModuleError(
- "The parent profile cannot be changed"
- )
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(params=self.module.params)
- self.have = ApiParameters()
- self.changes = UsableChanges()
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = UsableChanges(params=changed)
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def exec_module(self):
- changed = False
- result = dict()
- state = self.want.state
-
- if state == "present":
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.client.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def present(self):
- if self.exists():
- return self.update()
- else:
- return self.create()
-
- def exists(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/profile/http-compression/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def update(self):
- self.have = self.read_current_from_device()
- if not self.should_update():
- return False
- if self.module.check_mode:
- return True
- self.update_on_device()
- return True
-
- def remove(self):
- if self.module.check_mode:
- return True
- self.remove_from_device()
- if self.exists():
- raise F5ModuleError("Failed to delete the resource.")
- return True
-
- def create(self):
- self._set_changed_options()
- if self.module.check_mode:
- return True
- self.create_on_device()
- return True
-
- def create_on_device(self):
- params = self.changes.api_params()
- params['name'] = self.want.name
- params['partition'] = self.want.partition
- uri = "https://{0}:{1}/mgmt/tm/ltm/profile/http-compression/".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403, 404]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def update_on_device(self):
- params = self.changes.api_params()
- uri = "https://{0}:{1}/mgmt/tm/ltm/profile/http-compression/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 404]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def absent(self):
- if self.exists():
- return self.remove()
- return False
-
- def remove_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/profile/http-compression/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.delete(uri)
- if resp.status == 200:
- return True
- raise F5ModuleError(resp.content)
-
- def read_current_from_device(self): # lgtm [py/similar-function]
- uri = "https://{0}:{1}/mgmt/tm/ltm/profile/http-compression/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return ApiParameters(params=response)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- name=dict(required=True),
- parent=dict(),
- buffer_size=dict(type='int'),
- description=dict(),
- gzip_level=dict(
- type='int',
- choices=[1, 2, 3, 4, 5, 6, 7, 8, 9]
- ),
- gzip_memory_level=dict(
- type='int',
- choices=[1, 2, 4, 8, 16, 32, 64, 128, 256]
- ),
- gzip_window_size=dict(
- type='int',
- choices=[1, 2, 4, 8, 16, 32, 64, 128]
- ),
- state=dict(
- default='present',
- choices=['present', 'absent']
- ),
- partition=dict(
- default='Common',
- fallback=(env_fallback, ['F5_PARTITION'])
- )
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode,
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_profile_oneconnect.py b/lib/ansible/modules/network/f5/bigip_profile_oneconnect.py
deleted file mode 100644
index 42e0da6f30..0000000000
--- a/lib/ansible/modules/network/f5/bigip_profile_oneconnect.py
+++ /dev/null
@@ -1,617 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2018, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_profile_oneconnect
-short_description: Manage OneConnect profiles on a BIG-IP
-description:
- - Manage OneConnect profiles on a BIG-IP.
-version_added: 2.7
-options:
- name:
- description:
- - Specifies the name of the OneConnect profile.
- type: str
- required: True
- parent:
- description:
- - Specifies the profile from which this profile inherits settings.
- - When creating a new profile, if this parameter is not specified, the default
- is the system-supplied C(oneconnect) profile.
- type: str
- source_mask:
- description:
- - Specifies a value that the system applies to the source address to determine
- its eligibility for reuse.
- - When creating a new profile, if this parameter is not specified, the
- default is provided by the parent profile.
- - The system applies the value of this setting to the server-side source address to
- determine its eligibility for reuse.
- - A mask of C(0) causes the system to share reused connections across all source
- addresses. A host mask of C(32) causes the system to share only those reused
- connections originating from the same source address.
- - When you are using a SNAT or SNAT pool, the server-side source address is
- translated first and then the OneConnect mask is applied to the translated address.
- type: str
- description:
- description:
- - Description of the profile.
- type: str
- maximum_size:
- description:
- - Specifies the maximum number of connections that the system holds in the
- connection reuse pool.
- - If the pool is already full, then a server-side connection closes after the
- response is completed.
- - When creating a new profile, if this parameter is not specified, the
- default is provided by the parent profile.
- type: int
- maximum_age:
- description:
- - Specifies the maximum number of seconds allowed for a connection in the connection
- reuse pool.
- - For any connection with an age higher than this value, the system removes that
- connection from the re-use pool.
- - When creating a new profile, if this parameter is not specified, the
- default is provided by the parent profile.
- type: int
- maximum_reuse:
- description:
- - Specifies the maximum number of times that a server-side connection can be reused.
- - When creating a new profile, if this parameter is not specified, the
- default is provided by the parent profile.
- type: int
- idle_timeout_override:
- description:
- - Specifies the number of seconds that a connection is idle before the connection
- flow is eligible for deletion.
- - When creating a new profile, if this parameter is not specified, the default
- is provided by the parent profile.
- - You may specify a number of seconds for the timeout override.
- - When C(disabled), specifies that there is no timeout override for the connection.
- - When C(indefinite), Specifies that a connection may be idle with no timeout
- override.
- type: str
- limit_type:
- description:
- - When C(none), simultaneous in-flight requests and responses over TCP connections
- to a pool member are counted toward the limit. This is the historical behavior.
- - When C(idle), idle connections will be dropped as the TCP connection limit is
- reached. For short intervals, during the overlap of the idle connection being
- dropped and the new connection being established, the TCP connection limit may
- be exceeded.
- - When C(strict), the TCP connection limit is honored with no exceptions. This means
- that idle connections will prevent new TCP connections from being made until
- they expire, even if they could otherwise be reused.
- - C(strict) is not a recommended configuration except in very special cases with
- short expiration timeouts.
- - When creating a new profile, if this parameter is not specified, the default
- is provided by the parent profile.
- type: str
- choices:
- - none
- - idle
- - strict
- share_pools:
- description:
- - Indicates that connections may be shared not only within a virtual server, but
- also among similar virtual servers
- - When C(yes), all virtual servers that use the same OneConnect and other internal
- network profiles can share connections.
- - When creating a new profile, if this parameter is not specified, the default
- is provided by the parent profile.
- type: bool
- partition:
- description:
- - Device partition to manage resources on.
- type: str
- default: Common
- state:
- description:
- - When C(present), ensures that the profile exists.
- - When C(absent), ensures the profile is removed.
- type: str
- choices:
- - present
- - absent
- default: present
-extends_documentation_fragment: f5
-author:
- - Tim Rupp (@caphrim007)
-'''
-
-EXAMPLES = r'''
-- name: Create a OneConnect profile
- bigip_profile_oneconnect:
- name: foo
- state: present
- provider:
- user: admin
- password: secret
- server: lb.mydomain.com
- delegate_to: localhost
-'''
-
-RETURN = r'''
-source_mask:
- description: Value that the system applies to the source address to determine its eligibility for reuse.
- returned: changed
- type: str
- sample: 255.255.255.255
-description:
- description: Description of the profile.
- returned: changed
- type: str
- sample: My profile
-maximum_size:
- description: Maximum number of connections that the system holds in the connection reuse pool.
- returned: changed
- type: int
- sample: 3000
-maximum_age:
- description: Maximum number of seconds allowed for a connection in the connection reuse pool.
- returned: changed
- type: int
- sample: 2000
-maximum_reuse:
- description: Maximum number of times that a server-side connection can be reused.
- returned: changed
- type: int
- sample: 1000
-idle_timeout_override:
- description: The new idle timeout override.
- returned: changed
- type: str
- sample: disabled
-limit_type:
- description: New limit type of the profile.
- returned: changed
- type: str
- sample: idle
-share_pools:
- description: Share connections among similar virtual servers.
- returned: changed
- type: bool
- sample: yes
-'''
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.basic import env_fallback
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import fq_name
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.common import transform_name
- from library.module_utils.network.f5.ipaddress import is_valid_ip
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import fq_name
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.common import transform_name
- from ansible.module_utils.network.f5.ipaddress import is_valid_ip
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'sourceMask': 'source_mask',
- 'maxSize': 'maximum_size',
- 'maxReuse': 'maximum_reuse',
- 'maxAge': 'maximum_age',
- 'defaultsFrom': 'parent',
- 'limitType': 'limit_type',
- 'idleTimeoutOverride': 'idle_timeout_override',
- 'sharePools': 'share_pools',
- }
-
- api_attributes = [
- 'sourceMask',
- 'maxSize',
- 'defaultsFrom',
- 'description',
- 'limitType',
- 'idleTimeoutOverride',
- 'maxAge',
- 'maxReuse',
- 'sharePools',
- ]
-
- returnables = [
- 'description',
- 'source_mask',
- 'maximum_size',
- 'maximum_age',
- 'maximum_reuse',
- 'limit_type',
- 'idle_timeout_override',
- 'share_pools',
- 'parent',
- ]
-
- updatables = [
- 'description',
- 'source_mask',
- 'maximum_size',
- 'maximum_age',
- 'maximum_reuse',
- 'limit_type',
- 'idle_timeout_override',
- 'share_pools',
- ]
-
-
-class ApiParameters(Parameters):
- @property
- def source_mask(self):
- if self._values['source_mask'] is None:
- return None
- elif self._values['source_mask'] == 'any':
- return 0
- return self._values['source_mask']
-
- @property
- def idle_timeout_override(self):
- if self._values['idle_timeout_override'] is None:
- return None
- try:
- return int(self._values['idle_timeout_override'])
- except ValueError:
- return self._values['idle_timeout_override']
-
-
-class ModuleParameters(Parameters):
- @property
- def parent(self):
- if self._values['parent'] is None:
- return None
- result = fq_name(self.partition, self._values['parent'])
- return result
-
- @property
- def idle_timeout_override(self):
- if self._values['idle_timeout_override'] is None:
- return None
- try:
- return int(self._values['idle_timeout_override'])
- except ValueError:
- return self._values['idle_timeout_override']
-
- @property
- def source_mask(self):
- if self._values['source_mask'] is None:
- return None
- elif self._values['source_mask'] == 'any':
- return 0
- try:
- int(self._values['source_mask'])
- raise F5ModuleError(
- "'source_mask' must not be in CIDR format."
- )
- except ValueError:
- pass
-
- if is_valid_ip(self._values['source_mask']):
- return self._values['source_mask']
-
- @property
- def share_pools(self):
- if self._values['share_pools'] is None:
- return None
- elif self._values['share_pools'] is True:
- return 'enabled'
- return 'disabled'
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class UsableChanges(Changes):
- pass
-
-
-class ReportableChanges(Changes):
- @property
- def idle_timeout_override(self):
- try:
- return int(self._values['idle_timeout_override'])
- except ValueError:
- return self._values['idle_timeout_override']
-
- @property
- def share_pools(self):
- if self._values['idle_timeout_override'] is None:
- return None
- elif self._values['idle_timeout_override'] == 'enabled':
- return 'yes'
- elif self._values['idle_timeout_override'] == 'disabled':
- return 'no'
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
- @property
- def parent(self):
- if self.want.parent != self.have.parent:
- raise F5ModuleError(
- "The parent profile cannot be changed"
- )
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(params=self.module.params)
- self.have = ApiParameters()
- self.changes = UsableChanges()
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = UsableChanges(params=changed)
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def exec_module(self):
- changed = False
- result = dict()
- state = self.want.state
-
- if state == "present":
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.client.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def present(self):
- if self.exists():
- return self.update()
- else:
- return self.create()
-
- def exists(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/profile/one-connect/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def update(self):
- self.have = self.read_current_from_device()
- if not self.should_update():
- return False
- if self.module.check_mode:
- return True
- self.update_on_device()
- return True
-
- def remove(self):
- if self.module.check_mode:
- return True
- self.remove_from_device()
- if self.exists():
- raise F5ModuleError("Failed to delete the resource.")
- return True
-
- def create(self):
- self._set_changed_options()
- if self.module.check_mode:
- return True
- self.create_on_device()
- return True
-
- def create_on_device(self):
- params = self.changes.api_params()
- params['name'] = self.want.name
- params['partition'] = self.want.partition
- uri = "https://{0}:{1}/mgmt/tm/ltm/profile/one-connect/".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403, 404]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return response['selfLink']
-
- def update_on_device(self):
- params = self.changes.api_params()
- uri = "https://{0}:{1}/mgmt/tm/ltm/profile/one-connect/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 404]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def absent(self):
- if self.exists():
- return self.remove()
- return False
-
- def remove_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/profile/one-connect/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- response = self.client.api.delete(uri)
- if response.status == 200:
- return True
- raise F5ModuleError(response.content)
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/profile/one-connect/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return ApiParameters(params=response)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- name=dict(required=True),
- description=dict(),
- parent=dict(),
- source_mask=dict(),
- maximum_size=dict(type='int'),
- maximum_reuse=dict(type='int'),
- maximum_age=dict(type='int'),
- limit_type=dict(
- choices=['none', 'idle', 'strict']
- ),
- idle_timeout_override=dict(),
- share_pools=dict(type='bool'),
- state=dict(
- default='present',
- choices=['present', 'absent']
- ),
- partition=dict(
- default='Common',
- fallback=(env_fallback, ['F5_PARTITION'])
- )
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode,
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_profile_persistence_cookie.py b/lib/ansible/modules/network/f5/bigip_profile_persistence_cookie.py
deleted file mode 100644
index 7af5ac9c5e..0000000000
--- a/lib/ansible/modules/network/f5/bigip_profile_persistence_cookie.py
+++ /dev/null
@@ -1,972 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2018, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_profile_persistence_cookie
-short_description: Manage cookie persistence profiles on BIG-IP
-description:
- - Manage cookie persistence profiles on BIG-IP.
-version_added: 2.8
-options:
- name:
- description:
- - Specifies the name of the profile.
- type: str
- required: True
- description:
- description:
- - Description of the profile.
- type: str
- parent:
- description:
- - Specifies the profile from which this profile inherits settings.
- - When creating a new profile, if this parameter is not specified, the default
- is the system-supplied C(cookie) profile.
- type: str
- default: cookie
- cookie_method:
- description:
- - Specifies the type of cookie processing that the system uses.
- - When C(hash), specifies that the server provides the cookie, which the
- system then maps consistently to a specific node. This persistence type
- requires a C(cookie_name) value.
- - When C(insert), specifies that the system inserts server information,
- in the form of a cookie, into the header of the server response.
- - When C(passive), specifies that the server provides the cookie, formatted
- with the correct server information and timeout. This persistence type
- requires a C(cookie_name) value.
- - When C(rewrite), specifies that the system intercepts the BIGipCookie
- header, sent from the server, and overwrites the name and value of that
- cookie.
- type: str
- choices:
- - hash
- - insert
- - passive
- - rewrite
- cookie_name:
- description:
- - Specifies a unique name for the cookie.
- type: str
- http_only:
- description:
- - Specifies whether the httponly attribute should be enabled or
- disabled for the inserted cookies.
- type: bool
- match_across_services:
- description:
- - When C(yes), specifies that all persistent connections from a client IP address that go
- to the same virtual IP address also go to the same node.
- - When creating a new profile, if this parameter is not specified, the
- default is provided by the parent profile.
- type: bool
- match_across_virtuals:
- description:
- - When C(yes), specifies that all persistent connections from the same client IP address
- go to the same node.
- - When creating a new profile, if this parameter is not specified, the
- default is provided by the parent profile.
- type: bool
- match_across_pools:
- description:
- - When C(yes), specifies that the system can use any pool that contains this persistence
- record.
- - When creating a new profile, if this parameter is not specified, the
- default is provided by the parent profile.
- type: bool
- cookie_encryption:
- description:
- - Specifies the way in which the cookie encryption format is used.
- - When C(disabled), generates the cookie format unencrypted.
- - When C(preferred), generate an encrypted cookie, but accepts both encrypted and unencrypted formats.
- - When C(required), cookie format must be encrypted.
- type: str
- choices:
- - disabled
- - preferred
- - required
- override_connection_limit:
- description:
- - When C(yes), specifies that the system allows you to specify that pool member connection
- limits will be overridden for persisted clients.
- - Per-virtual connection limits remain hard limits and are not overridden.
- type: bool
- encrypt_cookie_pool_name:
- description:
- - Specifies whether the pool-name in the inserted BIG-IP default cookie should be encrypted.
- type: bool
- always_send:
- description:
- - Send the cookie persistence entry on every reply, even if the
- entry has previously been supplied to the client.
- type: bool
- secure:
- description:
- - Specifies whether the secure attribute should be enabled or
- disabled for the inserted cookies.
- type: bool
- encryption_passphrase:
- description:
- - Specifies a passphrase to be used for cookie encryption.
- type: str
- update_password:
- description:
- - C(always) will allow to update passphrases if the user chooses to do so.
- C(on_create) will only set the passphrase for newly created profiles.
- type: str
- choices:
- - always
- - on_create
- default: always
- expiration:
- description:
- - Specifies the expiration time of the cookie. By default the system generates and uses session cookie.
- This cookie expires when the user session expires, that is when the browser is closed.
- suboptions:
- days:
- description:
- - Cookie expiration time in days, the value must be in range from C(0) to C(24855) days.
- type: int
- hours:
- description:
- - Cookie expiration time in hours, the value must be in the range from C(0) to C(23) hours.
- type: int
- minutes:
- description:
- - Cookie expiration time in minutes, the value must be in the range from C(0) to C(59) minutes.
- type: int
- seconds:
- description:
- - Cookie expiration time in seconds, the value must be in the range from C(0) to C(59) seconds.
- type: int
- default: 0
- type: dict
- version_added: 2.8
- partition:
- description:
- - Device partition to manage resources on.
- type: str
- default: Common
- state:
- description:
- - When C(present), ensures that the profile exists.
- - When C(absent), ensures the profile is removed.
- type: str
- choices:
- - present
- - absent
- default: present
-extends_documentation_fragment: f5
-author:
- - Tim Rupp (@caphrim007)
- - Wojciech Wypior (@wojtek0806)
-'''
-
-EXAMPLES = r'''
-- name: Create a persistence cookie profile
- bigip_profile_persistence_cookie:
- name: foo
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-- name: Create a persistence cookie profile with expiration time
- bigip_profile_persistence_cookie:
- name: foo
- expiration:
- days: 7
- hours: 12
- minutes: 30
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-'''
-
-RETURN = r'''
-cookie_name:
- description: The new Cookie Name value.
- returned: changed
- type: str
- sample: cookie1
-cookie_method:
- description: The new Cookie Method.
- returned: changed
- type: str
- sample: insert
-parent:
- description: The parent profile.
- returned: changed
- type: str
- sample: /Common/cookie
-cookie_encryption:
- description: The new Cookie Encryption type.
- returned: changed
- type: str
- sample: preferred
-match_across_pools:
- description: The new Match Across Pools value.
- returned: changed
- type: bool
- sample: yes
-match_across_services:
- description: The new Match Across Services value.
- returned: changed
- type: bool
- sample: no
-match_across_virtuals:
- description: The new Match Across Virtuals value.
- returned: changed
- type: bool
- sample: yes
-override_connection_limit:
- description: The new Override Connection Limit value.
- returned: changed
- type: bool
- sample: no
-encrypt_cookie_pool_name:
- description: The new Encrypt Cookie Pool Name value.
- returned: changed
- type: bool
- sample: yes
-always_send:
- description: The new Always Send value.
- returned: changed
- type: bool
- sample: no
-http_only:
- description: The new HTTP Only value.
- returned: changed
- type: bool
- sample: yes
-description:
- description: The new description.
- returned: changed
- type: str
- sample: My description
-secure:
- description: The new Secure Cookie value.
- returned: changed
- type: bool
- sample: no
-expiration:
- description: The expiration time of the cookie.
- returned: changed
- type: complex
- contains:
- days:
- description: Cookie expiration time in days.
- returned: changed
- type: int
- sample: 125
- hours:
- description: Cookie expiration time in hours.
- returned: changed
- type: int
- sample: 22
- minutes:
- description: Cookie expiration time in minutes.
- returned: changed
- type: int
- sample: 58
- seconds:
- description: Cookie expiration time in seconds.
- returned: changed
- type: int
- sample: 20
- sample: hash/dictionary of values
-'''
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.basic import env_fallback
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import fq_name
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.common import transform_name
- from library.module_utils.network.f5.common import flatten_boolean
- from library.module_utils.network.f5.compare import cmp_str_with_none
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import fq_name
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.common import transform_name
- from ansible.module_utils.network.f5.common import flatten_boolean
- from ansible.module_utils.network.f5.compare import cmp_str_with_none
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'cookieName': 'cookie_name',
- 'method': 'cookie_method',
- 'defaultsFrom': 'parent',
- 'cookieEncryption': 'cookie_encryption',
- 'matchAcrossPools': 'match_across_pools',
- 'matchAcrossServices': 'match_across_services',
- 'matchAcrossVirtuals': 'match_across_virtuals',
- 'overrideConnectionLimit': 'override_connection_limit',
- 'encryptCookiePoolname': 'encrypt_cookie_pool_name',
- 'alwaysSend': 'always_send',
- 'httponly': 'http_only',
- 'cookieEncryptionPassphrase': 'encryption_passphrase',
- }
-
- api_attributes = [
- 'description',
- 'cookieName',
- 'defaultsFrom',
- 'cookieEncryption',
- 'matchAcrossPools',
- 'matchAcrossServices',
- 'matchAcrossVirtuals',
- 'overrideConnectionLimit',
- 'encryptCookiePoolname',
- 'alwaysSend',
- 'httponly',
- 'secure',
- 'cookieEncryptionPassphrase',
- 'method',
- 'expiration'
- ]
-
- returnables = [
- 'cookie_name',
- 'cookie_method',
- 'parent',
- 'cookie_encryption',
- 'match_across_pools',
- 'match_across_services',
- 'match_across_virtuals',
- 'override_connection_limit',
- 'encrypt_cookie_pool_name',
- 'always_send',
- 'http_only',
- 'encryption_passphrase',
- 'description',
- 'secure',
- 'expiration',
- ]
-
- updatables = [
- 'cookie_name',
- 'cookie_method',
- 'parent',
- 'cookie_encryption',
- 'match_across_pools',
- 'match_across_services',
- 'match_across_virtuals',
- 'override_connection_limit',
- 'encrypt_cookie_pool_name',
- 'always_send',
- 'http_only',
- 'encryption_passphrase',
- 'description',
- 'secure',
- 'expiration',
- ]
-
- @property
- def encrypt_cookie_pool_name(self):
- return flatten_boolean(self._values['encrypt_cookie_pool_name'])
-
- @property
- def always_send(self):
- return flatten_boolean(self._values['always_send'])
-
- @property
- def match_across_pools(self):
- return flatten_boolean(self._values['match_across_pools'])
-
- @property
- def match_across_services(self):
- return flatten_boolean(self._values['match_across_services'])
-
- @property
- def match_across_virtuals(self):
- return flatten_boolean(self._values['match_across_virtuals'])
-
- @property
- def http_only(self):
- return flatten_boolean(self._values['http_only'])
-
- @property
- def secure(self):
- return flatten_boolean(self._values['secure'])
-
- @property
- def override_connection_limit(self):
- return flatten_boolean(self._values['override_connection_limit'])
-
-
-class ApiParameters(Parameters):
- @property
- def description(self):
- if self._values['description'] in [None, 'none']:
- return None
- return self._values['description']
-
-
-class ModuleParameters(Parameters):
- @property
- def parent(self):
- if self._values['parent'] is None:
- return None
- result = fq_name(self.partition, self._values['parent'])
- return result
-
- @property
- def description(self):
- if self._values['description'] is None:
- return None
- elif self._values['description'] in ['none', '']:
- return ''
- return self._values['description']
-
- @property
- def expiration(self):
- if self._values['expiration'] is None:
- return None
-
- days = self.days
- hours = self.hours
- minutes = self.minutes
- seconds = self.seconds
-
- if days is not None:
- if hours is None:
- raise F5ModuleError(
- "Incorrect format, 'hours' parameter is missing value."
- )
- if minutes is None:
- raise F5ModuleError(
- "Incorrect format, 'minutes' parameter is missing value."
- )
-
- expiry_time = '{0}:{1}:{2}:{3}'.format(days, hours, minutes, seconds)
- return expiry_time
-
- if hours is not None:
- if minutes is None:
- raise F5ModuleError(
- "Incorrect format, 'minutes' parameter is missing value."
- )
-
- expiry_time = '{0}:{1}:{2}'.format(hours, minutes, seconds)
- return expiry_time
-
- if minutes is not None:
- expiry_time = '{0}:{1}'.format(minutes, seconds)
- return expiry_time
-
- return str(seconds)
-
- @property
- def days(self):
- days = self._values['expiration']['days']
- if days is None:
- return None
- if days < 0 or days >= 24856:
- raise F5ModuleError(
- 'The provided value is invalid, the correct value range is: 0 - 24855 days.'
- )
- return days
-
- @property
- def hours(self):
- hours = self._values['expiration']['hours']
- if hours is None:
- return None
- if hours < 0 or hours > 23:
- raise F5ModuleError(
- 'The provided value is invalid, the correct value range is: 0 - 23 hours.'
- )
- return hours
-
- @property
- def minutes(self):
- minutes = self._values['expiration']['minutes']
- if minutes is None:
- return None
- if minutes < 0 or minutes > 59:
- raise F5ModuleError(
- 'The provided value is invalid, the correct value range is: 0 - 59 minutes.'
- )
- return minutes
-
- @property
- def seconds(self):
- seconds = self._values['expiration']['seconds']
- if seconds < 0 or seconds > 59:
- raise F5ModuleError(
- 'The provided value is invalid, the correct value range is: 0 - 59 seconds.'
- )
- return seconds
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class UsableChanges(Changes):
- @property
- def encrypt_cookie_pool_name(self):
- if self._values['encrypt_cookie_pool_name'] is None:
- return None
- elif self._values['encrypt_cookie_pool_name'] == 'yes':
- return 'enabled'
- return 'disabled'
-
- @property
- def always_send(self):
- if self._values['always_send'] is None:
- return None
- elif self._values['always_send'] == 'yes':
- return 'enabled'
- return 'disabled'
-
- @property
- def match_across_pools(self):
- if self._values['match_across_pools'] is None:
- return None
- elif self._values['match_across_pools'] == 'yes':
- return 'enabled'
- return 'disabled'
-
- @property
- def match_across_services(self):
- if self._values['match_across_services'] is None:
- return None
- elif self._values['match_across_services'] == 'yes':
- return 'enabled'
- return 'disabled'
-
- @property
- def match_across_virtuals(self):
- if self._values['match_across_virtuals'] is None:
- return None
- elif self._values['match_across_virtuals'] == 'yes':
- return 'enabled'
- return 'disabled'
-
- @property
- def http_only(self):
- if self._values['http_only'] is None:
- return None
- elif self._values['http_only'] == 'yes':
- return 'enabled'
- return 'disabled'
-
- @property
- def secure(self):
- if self._values['secure'] is None:
- return None
- elif self._values['secure'] == 'yes':
- return 'enabled'
- return 'disabled'
-
- @property
- def override_connection_limit(self):
- if self._values['override_connection_limit'] is None:
- return None
- elif self._values['override_connection_limit'] == 'yes':
- return 'enabled'
- return 'disabled'
-
-
-class ReportableChanges(Changes):
- @property
- def encrypt_cookie_pool_name(self):
- return flatten_boolean(self._values['encrypt_cookie_pool_name'])
-
- @property
- def always_send(self):
- return flatten_boolean(self._values['always_send'])
-
- @property
- def match_across_pools(self):
- return flatten_boolean(self._values['match_across_pools'])
-
- @property
- def match_across_services(self):
- return flatten_boolean(self._values['match_across_services'])
-
- @property
- def match_across_virtuals(self):
- return flatten_boolean(self._values['match_across_virtuals'])
-
- @property
- def http_only(self):
- return flatten_boolean(self._values['http_only'])
-
- @property
- def secure(self):
- return flatten_boolean(self._values['secure'])
-
- @property
- def override_connection_limit(self):
- return flatten_boolean(self._values['override_connection_limit'])
-
- @property
- def encryption_passphrase(self):
- return None
-
- @property
- def expiration(self):
- expire = self._values['expiration']
- result = dict()
-
- if expire is None:
- return None
- tmp = expire.split(':')
-
- if len(tmp) == 1:
- result['seconds'] = int(tmp[0])
- if len(tmp) == 2:
- result['minutes'] = int(tmp[0])
- result['seconds'] = int(tmp[1])
- if len(tmp) == 3:
- result['hours'] = int(tmp[0])
- result['minutes'] = int(tmp[1])
- result['seconds'] = int(tmp[2])
- if len(tmp) == 4:
- result['days'] = int(tmp[0])
- result['hours'] = int(tmp[1])
- result['minutes'] = int(tmp[2])
- result['seconds'] = int(tmp[3])
-
- return result
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
- @property
- def parent(self):
- if self.want.parent != self.have.parent:
- raise F5ModuleError(
- "The parent profile cannot be changed"
- )
-
- @property
- def description(self):
- return cmp_str_with_none(self.want.description, self.have.description)
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(params=self.module.params)
- self.have = ApiParameters()
- self.changes = UsableChanges()
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = UsableChanges(params=changed)
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def exec_module(self):
- changed = False
- result = dict()
- state = self.want.state
-
- if state == "present":
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.client.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def present(self):
- if self.exists():
- return self.update()
- else:
- return self.create()
-
- def exists(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/persistence/cookie/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def update(self):
- self.have = self.read_current_from_device()
-
- if self.want.update_password == 'always':
- self.want.update({'encryption_passphrase': self.want.encryption_passphrase})
- else:
- if self.want.encryption_passphrase:
- del self.want._values['encryption_passphrase']
-
- if not self.should_update():
- return False
- if self.module.check_mode:
- return True
- self.update_on_device()
- return True
-
- def remove(self):
- if self.module.check_mode:
- return True
- self.remove_from_device()
- if self.exists():
- raise F5ModuleError("Failed to delete the resource.")
- return True
-
- def create(self):
- self._set_changed_options()
- if self.module.check_mode:
- return True
- self.create_on_device()
- return True
-
- def create_on_device(self):
- params = self.changes.api_params()
- params['name'] = self.want.name
- params['partition'] = self.want.partition
- uri = "https://{0}:{1}/mgmt/tm/ltm/persistence/cookie/".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403, 404]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def update_on_device(self):
- params = self.changes.api_params()
- uri = "https://{0}:{1}/mgmt/tm/ltm/persistence/cookie/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 404]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def absent(self):
- if self.exists():
- return self.remove()
- return False
-
- def remove_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/persistence/cookie/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.delete(uri)
- if resp.status == 200:
- return True
- raise F5ModuleError(resp.content)
-
- def read_current_from_device(self): # lgtm [py/similar-function]
- uri = "https://{0}:{1}/mgmt/tm/ltm/persistence/cookie/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return ApiParameters(params=response)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- name=dict(required=True),
- parent=dict(default='cookie'),
- cookie_name=dict(),
- cookie_method=dict(
- choices=[
- 'hash', 'insert', 'passive', 'rewrite'
- ]
- ),
- description=dict(),
- secure=dict(type='bool'),
- http_only=dict(type='bool'),
- cookie_encryption=dict(
- choices=[
- 'disabled', 'preferred', 'required'
- ]
- ),
- always_send=dict(type='bool'),
- match_across_services=dict(type='bool'),
- match_across_virtuals=dict(type='bool'),
- match_across_pools=dict(type='bool'),
- override_connection_limit=dict(type='bool'),
- encrypt_cookie_pool_name=dict(type='bool'),
- encryption_passphrase=dict(no_log=True),
- update_password=dict(
- default='always',
- choices=['always', 'on_create']
- ),
- expiration=dict(
- type='dict',
- options=dict(
- days=dict(
- type='int'
- ),
- hours=dict(
- type='int'
- ),
- minutes=dict(
- type='int'
- ),
- seconds=dict(
- type='int',
- default=0
- )
- )
- ),
- state=dict(
- default='present',
- choices=['present', 'absent']
- ),
- partition=dict(
- default='Common',
- fallback=(env_fallback, ['F5_PARTITION'])
- )
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode,
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_profile_persistence_src_addr.py b/lib/ansible/modules/network/f5/bigip_profile_persistence_src_addr.py
deleted file mode 100644
index 47fe483252..0000000000
--- a/lib/ansible/modules/network/f5/bigip_profile_persistence_src_addr.py
+++ /dev/null
@@ -1,556 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2018, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_profile_persistence_src_addr
-short_description: Manage source address persistence profiles
-description:
- - Manages source address persistence profiles.
-version_added: 2.7
-options:
- name:
- description:
- - Specifies the name of the profile.
- type: str
- required: True
- parent:
- description:
- - Specifies the profile from which this profile inherits settings.
- - When creating a new profile, if this parameter is not specified, the default
- is the system-supplied C(source_addr) profile.
- type: str
- match_across_services:
- description:
- - When C(yes), specifies that all persistent connections from a client IP address that go
- to the same virtual IP address also go to the same node.
- - When creating a new profile, if this parameter is not specified, the
- default is provided by the parent profile.
- type: bool
- match_across_virtuals:
- description:
- - When C(yes), specifies that all persistent connections from the same client IP address
- go to the same node.
- - When creating a new profile, if this parameter is not specified, the
- default is provided by the parent profile.
- type: bool
- match_across_pools:
- description:
- - When C(yes), specifies that the system can use any pool that contains this persistence
- record.
- - When creating a new profile, if this parameter is not specified, the
- default is provided by the parent profile.
- type: bool
- hash_algorithm:
- description:
- - Specifies the algorithm the system uses for hash persistence load balancing. The hash
- result is the input for the algorithm.
- - When C(default), specifies that the system uses the index of pool members to obtain the
- hash result for the input to the algorithm.
- - When C(carp), specifies that the system uses the Cache Array Routing Protocol (CARP)
- to obtain the hash result for the input to the algorithm.
- - When creating a new profile, if this parameter is not specified, the
- default is provided by the parent profile.
- type: str
- choices:
- - default
- - carp
- entry_timeout:
- description:
- - Specifies the duration of the persistence entries.
- - When creating a new profile, if this parameter is not specified, the
- default is provided by the parent profile.
- - To specify an indefinite timeout, use the value C(indefinite).
- - If specifying a numeric timeout, the value must be between C(1) and C(4294967295).
- type: str
- override_connection_limit:
- description:
- - When C(yes), specifies that the system allows you to specify that pool member connection
- limits will be overridden for persisted clients.
- - Per-virtual connection limits remain hard limits and are not overridden.
- type: bool
- partition:
- description:
- - Device partition to manage resources on.
- type: str
- default: Common
- state:
- description:
- - When C(present), ensures that the profile exists.
- - When C(absent), ensures the profile is removed.
- type: str
- choices:
- - present
- - absent
- default: present
-extends_documentation_fragment: f5
-author:
- - Tim Rupp (@caphrim007)
-'''
-
-EXAMPLES = r'''
-- name: Create a profile
- bigip_profile_persistence_src_addr:
- name: foo
- state: present
- hash_algorithm: carp
- match_across_services: yes
- match_across_virtuals: yes
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-'''
-
-RETURN = r'''
-param1:
- description: The new param1 value of the resource.
- returned: changed
- type: bool
- sample: true
-param2:
- description: The new param2 value of the resource.
- returned: changed
- type: str
- sample: Foo is bar
-'''
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.basic import env_fallback
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import fq_name
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.common import flatten_boolean
- from library.module_utils.network.f5.common import transform_name
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import fq_name
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.common import flatten_boolean
- from ansible.module_utils.network.f5.common import transform_name
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'defaultsFrom': 'parent',
- 'hashAlgorithm': 'hash_algorithm',
- 'matchAcrossPools': 'match_across_pools',
- 'matchAcrossServices': 'match_across_services',
- 'matchAcrossVirtuals': 'match_across_virtuals',
- 'overrideConnectionLimit': 'override_connection_limit',
-
- # This timeout name needs to be overridden because 'timeout' is a connection
- # parameter and we don't want that to be the value that is always set here.
- 'timeout': 'entry_timeout'
- }
-
- api_attributes = [
- 'defaultsFrom',
- 'hashAlgorithm',
- 'matchAcrossPools',
- 'matchAcrossServices',
- 'matchAcrossVirtuals',
- 'overrideConnectionLimit',
- 'timeout',
- ]
-
- returnables = [
- 'parent',
- 'hash_algorithm',
- 'match_across_pools',
- 'match_across_services',
- 'match_across_virtuals',
- 'override_connection_limit',
- 'entry_timeout',
- ]
-
- updatables = [
- 'hash_algorithm',
- 'match_across_pools',
- 'match_across_services',
- 'match_across_virtuals',
- 'override_connection_limit',
- 'entry_timeout',
- ]
-
- @property
- def entry_timeout(self):
- if self._values['entry_timeout'] in [None, 'indefinite']:
- return self._values['entry_timeout']
- timeout = int(self._values['entry_timeout'])
- if 1 > timeout > 4294967295:
- raise F5ModuleError(
- "'timeout' value must be between 1 and 4294967295, or the value 'indefinite'."
- )
- return timeout
-
- @property
- def match_across_pools(self):
- return flatten_boolean(self._values['match_across_pools'])
-
- @property
- def match_across_services(self):
- return flatten_boolean(self._values['match_across_services'])
-
- @property
- def match_across_virtuals(self):
- return flatten_boolean(self._values['match_across_virtuals'])
-
- @property
- def override_connection_limit(self):
- return flatten_boolean(self._values['override_connection_limit'])
-
-
-class ApiParameters(Parameters):
- pass
-
-
-class ModuleParameters(Parameters):
- @property
- def parent(self):
- if self._values['parent'] is None:
- return None
- result = fq_name(self.partition, self._values['parent'])
- return result
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class UsableChanges(Changes):
- @property
- def match_across_pools(self):
- if self._values['match_across_pools'] is None:
- return None
- elif self._values['match_across_pools'] == 'yes':
- return 'enabled'
- return 'disabled'
-
- @property
- def match_across_services(self):
- if self._values['match_across_services'] is None:
- return None
- elif self._values['match_across_services'] == 'yes':
- return 'enabled'
- return 'disabled'
-
- @property
- def match_across_virtuals(self):
- if self._values['match_across_virtuals'] is None:
- return None
- elif self._values['match_across_virtuals'] == 'yes':
- return 'enabled'
- return 'disabled'
-
- @property
- def override_connection_limit(self):
- if self._values['override_connection_limit'] is None:
- return None
- elif self._values['override_connection_limit'] == 'yes':
- return 'enabled'
- return 'disabled'
-
-
-class ReportableChanges(Changes):
- @property
- def match_across_pools(self):
- return flatten_boolean(self._values['match_across_pools'])
-
- @property
- def match_across_services(self):
- return flatten_boolean(self._values['match_across_services'])
-
- @property
- def match_across_virtuals(self):
- return flatten_boolean(self._values['match_across_virtuals'])
-
- @property
- def override_connection_limit(self):
- return flatten_boolean(self._values['override_connection_limit'])
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
- @property
- def parent(self):
- if self.want.parent != self.have.parent:
- raise F5ModuleError(
- "The parent profile cannot be changed"
- )
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(params=self.module.params)
- self.have = ApiParameters()
- self.changes = UsableChanges()
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = UsableChanges(params=changed)
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def exec_module(self):
- changed = False
- result = dict()
- state = self.want.state
-
- if state == "present":
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.client.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def present(self):
- if self.exists():
- return self.update()
- else:
- return self.create()
-
- def exists(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/persistence/source-addr/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def update(self):
- self.have = self.read_current_from_device()
- if not self.should_update():
- return False
- if self.module.check_mode:
- return True
- self.update_on_device()
- return True
-
- def remove(self):
- if self.module.check_mode:
- return True
- self.remove_from_device()
- if self.exists():
- raise F5ModuleError("Failed to delete the resource.")
- return True
-
- def create(self):
- self._set_changed_options()
- if self.module.check_mode:
- return True
- self.create_on_device()
- return True
-
- def create_on_device(self):
- params = self.changes.api_params()
- params['name'] = self.want.name
- params['partition'] = self.want.partition
- uri = "https://{0}:{1}/mgmt/tm/ltm/persistence/source-addr/".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403, 404]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def update_on_device(self):
- params = self.changes.api_params()
- uri = "https://{0}:{1}/mgmt/tm/ltm/persistence/source-addr/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 404]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def absent(self):
- if self.exists():
- return self.remove()
- return False
-
- def remove_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/persistence/source-addr/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.delete(uri)
- if resp.status == 200:
- return True
- raise F5ModuleError(resp.content)
-
- def read_current_from_device(self): # lgtm [py/similar-function]
- uri = "https://{0}:{1}/mgmt/tm/ltm/persistence/source-addr/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return ApiParameters(params=response)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- name=dict(required=True),
- parent=dict(),
- match_across_services=dict(type='bool'),
- match_across_virtuals=dict(type='bool'),
- match_across_pools=dict(type='bool'),
- hash_algorithm=dict(choices=['default', 'carp']),
- entry_timeout=dict(),
- override_connection_limit=dict(type='bool'),
- state=dict(
- default='present',
- choices=['present', 'absent']
- ),
- partition=dict(
- default='Common',
- fallback=(env_fallback, ['F5_PARTITION'])
- )
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode,
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_profile_server_ssl.py b/lib/ansible/modules/network/f5/bigip_profile_server_ssl.py
deleted file mode 100644
index a82ba7a1f1..0000000000
--- a/lib/ansible/modules/network/f5/bigip_profile_server_ssl.py
+++ /dev/null
@@ -1,665 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2018, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_profile_server_ssl
-short_description: Manages server SSL profiles on a BIG-IP
-description:
- - Manages server SSL profiles on a BIG-IP.
-version_added: 2.8
-options:
- name:
- description:
- - Specifies the name of the profile.
- type: str
- required: True
- parent:
- description:
- - The parent template of this monitor template. Once this value has
- been set, it cannot be changed.
- type: str
- default: /Common/serverssl
- ciphers:
- description:
- - Specifies the list of ciphers that the system supports. When creating a new
- profile, the default cipher list is provided by the parent profile.
- type: str
- secure_renegotiation:
- description:
- - Specifies the method of secure renegotiations for SSL connections. When
- creating a new profile, the setting is provided by the parent profile.
- - When C(request) is set the system request secure renegotation of SSL
- connections.
- - C(require) is a default setting and when set the system permits initial SSL
- handshakes from clients but terminates renegotiations from unpatched clients.
- - The C(require-strict) setting the system requires strict renegotiation of SSL
- connections. In this mode the system refuses connections to insecure servers,
- and terminates existing SSL connections to insecure servers.
- type: str
- choices:
- - require
- - require-strict
- - request
- server_name:
- description:
- - Specifies the fully qualified DNS hostname of the server used in Server Name
- Indication communications. When creating a new profile, the setting is provided
- by the parent profile.
- type: str
- sni_default:
- description:
- - Indicates that the system uses this profile as the default SSL profile when there
- is no match to the server name, or when the client provides no SNI extension support.
- - When creating a new profile, the setting is provided by the parent profile.
- - There can be only one SSL profile with this setting enabled.
- type: bool
- sni_require:
- description:
- - Requires that the network peers also provide SNI support, setting only takes
- effect when C(sni_default) is C(yes).
- - When creating a new profile, the setting is provided by the parent profile.
- type: bool
- server_certificate:
- description:
- - Specifies the way the system handles server certificates.
- - When C(ignore), specifies that the system ignores certificates from server systems.
- - When C(require), specifies that the system requires a server to present a valid
- certificate.
- type: str
- choices:
- - ignore
- - require
- certificate:
- description:
- - Specifies the name of the certificate that the system uses for server-side SSL
- processing.
- type: str
- key:
- description:
- - Specifies the file name of the SSL key.
- type: str
- chain:
- description:
- - Specifies the certificates-key chain to associate with the SSL profile.
- type: str
- passphrase:
- description:
- - Specifies a passphrase used to encrypt the key.
- type: str
- update_password:
- description:
- - C(always) will allow to update passwords if the user chooses to do so.
- C(on_create) will only set the password for newly created profiles.
- type: str
- choices:
- - always
- - on_create
- default: always
- ocsp_profile:
- description:
- - Specifies the name of the OCSP profile for purpose of validating status
- of server certificate.
- type: str
- partition:
- description:
- - Device partition to manage resources on.
- type: str
- default: Common
- state:
- description:
- - When C(present), ensures that the profile exists.
- - When C(absent), ensures the profile is removed.
- type: str
- choices:
- - present
- - absent
- default: present
-extends_documentation_fragment: f5
-author:
- - Tim Rupp (@caphrim007)
-'''
-
-EXAMPLES = r'''
-- name: Create a new server SSL profile
- bigip_profile_server_ssl:
- name: foo
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-'''
-
-RETURN = r'''
-ciphers:
- description: The ciphers applied to the profile.
- returned: changed
- type: str
- sample: "!SSLv3:!SSLv2:ECDHE+AES-GCM+SHA256:ECDHE-RSA-AES128-CBC-SHA"
-secure_renegotiation:
- description: The method of secure SSL renegotiation.
- returned: changed
- type: str
- sample: request
-'''
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.basic import env_fallback
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import fq_name
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.common import flatten_boolean
- from library.module_utils.network.f5.common import transform_name
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import fq_name
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.common import flatten_boolean
- from ansible.module_utils.network.f5.common import transform_name
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'cert': 'certificate',
- 'ocsp': 'ocsp_profile',
- 'defaultsFrom': 'parent',
- 'secureRenegotiation': 'secure_renegotiation',
- 'sniDefault': 'sni_default',
- 'sniRequire': 'sni_require',
- 'serverName': 'server_name',
- 'peerCertMode': 'server_certificate',
- }
-
- api_attributes = [
- 'cert',
- 'chain',
- 'ciphers',
- 'defaultsFrom',
- 'key',
- 'ocsp',
- 'secureRenegotiation',
- 'sniDefault',
- 'sniRequire',
- 'serverName',
- 'peerCertMode',
- ]
-
- returnables = [
- 'certificate',
- 'chain',
- 'ciphers',
- 'key',
- 'ocsp_profile',
- 'secure_renegotiation',
- 'parent',
- 'sni_default',
- 'sni_require',
- 'server_name',
- 'server_certificate',
- ]
-
- updatables = [
- 'certificate',
- 'chain',
- 'ciphers',
- 'key',
- 'ocsp_profile',
- 'secure_renegotiation',
- 'sni_default',
- 'sni_require',
- 'server_name',
- 'server_certificate',
- ]
-
- @property
- def sni_default(self):
- return flatten_boolean(self._values['sni_default'])
-
- @property
- def certificate(self):
- if self._values['certificate'] is None:
- return None
- if self._values['certificate'] in ['', 'none']:
- return ''
- result = fq_name(self.partition, self._values['certificate'])
- return result
-
- @property
- def key(self):
- if self._values['key'] is None:
- return None
- if self._values['key'] in ['', 'none']:
- return ''
- result = fq_name(self.partition, self._values['key'])
- return result
-
- @property
- def chain(self):
- if self._values['chain'] is None:
- return None
- if self._values['chain'] in ['', 'none']:
- return ''
- result = fq_name(self.partition, self._values['chain'])
- return result
-
- @property
- def ocsp_profile(self):
- if self._values['ocsp_profile'] is None:
- return None
- if self._values['ocsp_profile'] in ['', 'none']:
- return ''
- result = fq_name(self.partition, self._values['ocsp_profile'])
- return result
-
-
-class ApiParameters(Parameters):
- @property
- def sni_require(self):
- return flatten_boolean(self._values['sni_require'])
-
- @property
- def server_name(self):
- if self._values['server_name'] in [None, 'none']:
- return None
- return self._values['server_name']
-
-
-class ModuleParameters(Parameters):
- @property
- def server_name(self):
- if self._values['server_name'] is None:
- return None
- if self._values['server_name'] in ['', 'none']:
- return ''
- return self._values['server_name']
-
- @property
- def parent(self):
- if self._values['parent'] is None:
- return None
- if self._values['parent'] == 'serverssl':
- return '/Common/serverssl'
- result = fq_name(self.partition, self._values['parent'])
- return result
-
- @property
- def sni_require(self):
- require = flatten_boolean(self._values['sni_require'])
- default = self.sni_default
- if require is None:
- return None
- if default in [None, 'no']:
- if require == 'yes':
- raise F5ModuleError(
- "Cannot set 'sni_require' to {0} if 'sni_default' is set as {1}".format(require, default))
- return require
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class UsableChanges(Changes):
- @property
- def sni_default(self):
- if self._values['sni_default'] is None:
- return None
- elif self._values['sni_default'] == 'yes':
- return 'true'
- else:
- return 'false'
-
- @property
- def sni_require(self):
- if self._values['sni_require'] is None:
- return None
- elif self._values['sni_require'] == 'yes':
- return 'true'
- else:
- return 'false'
-
-
-class ReportableChanges(Changes):
- @property
- def sni_default(self):
- result = flatten_boolean(self._values['sni_default'])
- return result
-
- @property
- def sni_require(self):
- result = flatten_boolean(self._values['sni_require'])
- return result
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- @property
- def parent(self):
- if self.want.parent != self.have.parent:
- raise F5ModuleError(
- "The parent profile cannot be changed"
- )
-
- @property
- def sni_require(self):
- if self.want.sni_require is None:
- return None
- if self.want.sni_require == 'no':
- if self.have.sni_default == 'yes' and self.want.sni_default is None:
- raise F5ModuleError(
- "Cannot set 'sni_require' to {0} if 'sni_default' is {1}".format(
- self.want.sni_require, self.have.sni_default
- )
- )
- if self.want.sni_require != self.have.sni_require:
- return self.want.sni_require
-
- @property
- def server_name(self):
- if self.want.server_name is None:
- return None
- if self.want.server_name == '' and self.have.server_name is None:
- return None
- if self.want.server_name != self.have.server_name:
- return self.want.server_name
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(params=self.module.params)
- self.have = ApiParameters()
- self.changes = UsableChanges()
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = UsableChanges(params=changed)
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def exec_module(self):
- changed = False
- result = dict()
- state = self.want.state
-
- if state == "present":
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.client.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def present(self):
- if self.exists():
- return self.update()
- else:
- return self.create()
-
- def exists(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/profile/server-ssl/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def update(self):
- self.have = self.read_current_from_device()
-
- if self.want.update_password == 'always':
- self.want.update({'passphrase': self.want.passphrase})
- else:
- if self.want.passphrase:
- del self.want._values['passphrase']
-
- if not self.should_update():
- return False
-
- if self.module.check_mode:
- return True
- self.update_on_device()
- return True
-
- def remove(self):
- if self.module.check_mode:
- return True
- self.remove_from_device()
- if self.exists():
- raise F5ModuleError("Failed to delete the resource.")
- return True
-
- def create(self):
- self._set_changed_options()
- if self.module.check_mode:
- return True
- self.create_on_device()
- return True
-
- def create_on_device(self):
- params = self.changes.api_params()
- params['name'] = self.want.name
- params['partition'] = self.want.partition
- uri = "https://{0}:{1}/mgmt/tm/ltm/profile/server-ssl/".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403, 404]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def update_on_device(self):
- params = self.changes.api_params()
- uri = "https://{0}:{1}/mgmt/tm/ltm/profile/server-ssl/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 404]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def absent(self):
- if self.exists():
- return self.remove()
- return False
-
- def remove_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/profile/server-ssl/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- response = self.client.api.delete(uri)
- if response.status == 200:
- return True
- raise F5ModuleError(response.content)
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/profile/server-ssl/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return ApiParameters(params=response)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- name=dict(required=True),
- certificate=dict(),
- chain=dict(),
- key=dict(),
- passphrase=dict(no_log=True),
- parent=dict(default='/Common/serverssl'),
- ciphers=dict(),
- secure_renegotiation=dict(
- choices=['require', 'require-strict', 'request']
- ),
- server_certificate=dict(
- choices=['ignore', 'require']
- ),
- state=dict(
- default='present',
- choices=['present', 'absent']
- ),
- update_password=dict(
- default='always',
- choices=['always', 'on_create']
- ),
- sni_default=dict(type='bool'),
- sni_require=dict(type='bool'),
- server_name=dict(),
- ocsp_profile=dict(),
- partition=dict(
- default='Common',
- fallback=(env_fallback, ['F5_PARTITION'])
- )
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
- self.required_together = [
- ['certificate', 'key']
- ]
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode,
- required_together=spec.required_together,
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_profile_tcp.py b/lib/ansible/modules/network/f5/bigip_profile_tcp.py
deleted file mode 100644
index e20cf08162..0000000000
--- a/lib/ansible/modules/network/f5/bigip_profile_tcp.py
+++ /dev/null
@@ -1,651 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_profile_tcp
-short_description: Manage TCP profiles on a BIG-IP
-description:
- - Manage TCP profiles on a BIG-IP. Many TCP profiles; each with their
- own adjustments to the standard C(tcp) profile. Users of this module should be aware
- that many of the adjustable knobs have no module default. Instead, the default is
- assigned by the BIG-IP system itself which, in most cases, is acceptable.
-version_added: 2.6
-options:
- name:
- description:
- - Specifies the name of the profile.
- type: str
- required: True
- parent:
- description:
- - Specifies the profile from which this profile inherits settings.
- - When creating a new profile, if this parameter is not specified, the default
- is the system-supplied C(tcp) profile.
- type: str
- idle_timeout:
- description:
- - Specifies the length of time that a connection is idle (has no traffic) before
- the connection is eligible for deletion.
- - When creating a new profile, if this parameter is not specified, the remote
- device will choose a default value appropriate for the profile, based on its
- C(parent) profile.
- - When a number is specified, indicates the number of seconds that the TCP
- connection can remain idle before the system deletes it.
- - When C(0), or C(indefinite), specifies that the system does not delete TCP connections
- regardless of how long they remain idle.
- type: str
- time_wait_recycle:
- description:
- - Specifies that connections in a TIME-WAIT state are reused, if a SYN packet,
- indicating a request for a new connection, is received.
- - When C(no), connections in a TIME-WAIT state remain unused for a specified length of time.
- - When creating a new profile, if this parameter is not specified, the default
- is provided by the parent profile.
- type: bool
- version_added: 2.7
- nagle:
- description:
- - When C(enabled) the system applies Nagle's algorithm to reduce the number of short segments on the network.
- - When C(auto), the use of Nagle's algorithm is decided based on network conditions.
- - Note that for interactive protocols such as Telnet, rlogin, or SSH, F5 recommends disabling this setting on
- high-latency networks, to improve application responsiveness.
- - When creating a new profile, if this parameter is not specified, the default is provided by the parent profile.
- type: str
- choices:
- - auto
- - enabled
- - disabled
- version_added: 2.9
- early_retransmit:
- description:
- - When C(yes) the system uses early fast retransmits to reduce the recovery time for connections that are
- receive-buffer or user-data limited.
- - When creating a new profile, if this parameter is not specified, the default is provided by the parent profile.
- type: bool
- version_added: 2.9
- proxy_options:
- description:
- - When C(yes) the system advertises an option, such as a time-stamp to the server only if it was negotiated
- with the client.
- - When creating a new profile, if this parameter is not specified, the default is provided by the parent profile.
- type: bool
- version_added: 2.9
- initial_congestion_window_size:
- description:
- - Specifies the initial congestion window size for connections to this destination. The actual window size is
- this value multiplied by the MSS for the same connection.
- - When set to C(0) the system uses the values specified in RFC2414.
- - The valid value range is 0 - 16 inclusive.
- - When creating a new profile, if this parameter is not specified, the default is provided by the parent profile.
- type: int
- version_added: 2.9
- initial_receive_window_size:
- description:
- - Specifies the initial receive window size for connections to this destination. The actual window size is
- this value multiplied by the MSS for the same connection.
- - When set to C(0) the system uses the Slow Start value.
- - The valid value range is 0 - 16 inclusive.
- - When creating a new profile, if this parameter is not specified, the default is provided by the parent profile.
- type: int
- version_added: 2.9
- syn_rto_base:
- description:
- - Specifies the initial RTO C(Retransmission TimeOut) base multiplier for SYN retransmission, in C(milliseconds).
- - This value is modified by the exponential backoff table to select the interval for subsequent retransmissions.
- - The valid value range is 0 - 5000 inclusive.
- - When creating a new profile, if this parameter is not specified, the default is provided by the parent profile.
- type: int
- version_added: 2.9
- partition:
- description:
- - Device partition to manage resources on.
- type: str
- default: Common
- state:
- description:
- - When C(present), ensures that the profile exists.
- - When C(absent), ensures the profile is removed.
- type: str
- choices:
- - present
- - absent
- default: present
-extends_documentation_fragment: f5
-author:
- - Tim Rupp (@caphrim007)
- - Wojciech Wypior (@wojtek0806)
-'''
-
-EXAMPLES = r'''
-- name: Create a TCP profile
- bigip_profile_tcp:
- name: foo
- parent: f5-tcp-progressive
- time_wait_recycle: no
- idle_timeout: 300
- state: present
- provider:
- user: admin
- password: secret
- server: lb.mydomain.com
- delegate_to: localhost
-'''
-
-RETURN = r'''
-parent:
- description: The new parent of the resource.
- returned: changed
- type: str
- sample: f5-tcp-optimized
-idle_timeout:
- description: The new idle timeout of the resource.
- returned: changed
- type: int
- sample: 100
-time_wait_recycle:
- description: Reuse connections in TIME-WAIT state.
- returned: changed
- type: bool
- sample: yes
-nagle:
- description: Specifies the use of Nagle's algorithm.
- returned: changed
- type: str
- sample: auto
-early_retransmit:
- description: Specifies the use of early fast retransmits.
- returned: changed
- type: bool
- sample: yes
-proxy_options:
- description: Specifies if that the system advertises negotiated options to the server.
- returned: changed
- type: bool
- sample: no
-initial_congestion_window_size:
- description: Specifies the initial congestion window size for connections to this destination.
- returned: changed
- type: int
- sample: 5
-initial_receive_window_size:
- description: Specifies the initial receive window size for connections to this destination.
- returned: changed
- type: int
- sample: 10
-syn_rto_base:
- description: Specifies the initial Retransmission TimeOut base multiplier for SYN retransmission.
- returned: changed
- type: int
- sample: 2000
-'''
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.basic import env_fallback
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import fq_name
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.common import flatten_boolean
- from library.module_utils.network.f5.common import transform_name
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import fq_name
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.common import flatten_boolean
- from ansible.module_utils.network.f5.common import transform_name
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'idleTimeout': 'idle_timeout',
- 'defaultsFrom': 'parent',
- 'timeWaitRecycle': 'time_wait_recycle',
- 'earlyRetransmit': 'early_retransmit',
- 'proxyOptions': 'proxy_options',
- 'initCwnd': 'initial_congestion_window_size',
- 'initRwnd': 'initial_receive_window_size',
- 'synRtoBase': 'syn_rto_base'
- }
-
- api_attributes = [
- 'idleTimeout',
- 'defaultsFrom',
- 'timeWaitRecycle',
- 'nagle',
- 'earlyRetransmit',
- 'proxyOptions',
- 'initCwnd',
- 'initRwnd',
- 'synRtoBase',
- ]
-
- returnables = [
- 'idle_timeout',
- 'parent',
- 'time_wait_recycle',
- 'nagle',
- 'early_retransmit',
- 'proxy_options',
- 'initial_congestion_window_size',
- 'initial_receive_window_size',
- 'syn_rto_base',
- ]
-
- updatables = [
- 'idle_timeout',
- 'parent',
- 'time_wait_recycle',
- 'nagle',
- 'early_retransmit',
- 'proxy_options',
- 'initial_congestion_window_size',
- 'initial_receive_window_size',
- 'syn_rto_base',
- ]
-
-
-class ApiParameters(Parameters):
- pass
-
-
-class ModuleParameters(Parameters):
- @property
- def parent(self):
- if self._values['parent'] is None:
- return None
- result = fq_name(self.partition, self._values['parent'])
- return result
-
- @property
- def idle_timeout(self):
- if self._values['idle_timeout'] is None:
- return None
- if self._values['idle_timeout'] == 'indefinite':
- return 4294967295
- return int(self._values['idle_timeout'])
-
- @property
- def time_wait_recycle(self):
- result = flatten_boolean(self._values['time_wait_recycle'])
- if result is None:
- return None
- if result == 'yes':
- return 'enabled'
- return 'disabled'
-
- @property
- def early_retransmit(self):
- result = flatten_boolean(self._values['early_retransmit'])
- if result is None:
- return None
- if result == 'yes':
- return 'enabled'
- return 'disabled'
-
- @property
- def proxy_options(self):
- result = flatten_boolean(self._values['proxy_options'])
- if result is None:
- return None
- if result == 'yes':
- return 'enabled'
- return 'disabled'
-
- @property
- def initial_congestion_window_size(self):
- if self._values['initial_congestion_window_size'] is None:
- return None
- if 0 <= self._values['initial_congestion_window_size'] <= 16:
- return self._values['initial_congestion_window_size']
- raise F5ModuleError(
- "Valid 'initial_congestion_window_size' must be in range 0 - 16 MSS units."
- )
-
- @property
- def initial_receive_window_size(self):
- if self._values['initial_receive_window_size'] is None:
- return None
- if 0 <= self._values['initial_receive_window_size'] <= 16:
- return self._values['initial_receive_window_size']
- raise F5ModuleError(
- "Valid 'initial_receive_window_size' must be in range 0 - 16 MSS units."
- )
-
- @property
- def syn_rto_base(self):
- if self._values['syn_rto_base'] is None:
- return None
- if 0 <= self._values['syn_rto_base'] <= 5000:
- return self._values['syn_rto_base']
- raise F5ModuleError(
- "Valid 'syn_rto_base' must be in range 0 - 5000 milliseconds."
- )
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class UsableChanges(Changes):
- @property
- def idle_timeout(self):
- if self._values['idle_timeout'] is None:
- return None
- if 0 <= self._values['idle_timeout'] <= 4294967295:
- return self._values['idle_timeout']
- raise F5ModuleError(
- "Valid 'idle_timeout' must be in range 1 - 4294967295, or 'indefinite'."
- )
-
-
-class ReportableChanges(Changes):
- @property
- def idle_timeout(self):
- if self._values['idle_timeout'] is None:
- return None
- if self._values['idle_timeout'] == 4294967295:
- return 'indefinite'
- return int(self._values['idle_timeout'])
-
- @property
- def time_wait_recycle(self):
- if self._values['time_wait_recycle'] is None:
- return None
- elif self._values['time_wait_recycle'] == 'enabled':
- return 'yes'
- return 'no'
-
- @property
- def early_retransmit(self):
- result = flatten_boolean(self._values['early_retransmit'])
- return result
-
- @property
- def proxy_options(self):
- result = flatten_boolean(self._values['proxy_options'])
- return result
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(params=self.module.params)
- self.have = ApiParameters()
- self.changes = UsableChanges()
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = UsableChanges(params=changed)
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def exec_module(self):
- changed = False
- result = dict()
- state = self.want.state
-
- if state == "present":
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.client.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def present(self):
- if self.exists():
- return self.update()
- else:
- return self.create()
-
- def exists(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/profile/tcp/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def update(self):
- self.have = self.read_current_from_device()
- if not self.should_update():
- return False
- if self.module.check_mode:
- return True
- self.update_on_device()
- return True
-
- def remove(self):
- if self.module.check_mode:
- return True
- self.remove_from_device()
- if self.exists():
- raise F5ModuleError("Failed to delete the resource.")
- return True
-
- def create(self):
- if self.want.parent is None:
- self.want.update({'parent': fq_name(self.want.partition, 'tcp')})
- self._set_changed_options()
- if self.module.check_mode:
- return True
- self.create_on_device()
- return True
-
- def create_on_device(self):
- params = self.changes.api_params()
- params['name'] = self.want.name
- params['partition'] = self.want.partition
- uri = "https://{0}:{1}/mgmt/tm/ltm/profile/tcp/".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403, 404]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return response['selfLink']
-
- def update_on_device(self):
- params = self.changes.api_params()
- uri = "https://{0}:{1}/mgmt/tm/ltm/profile/tcp/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 404]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def absent(self):
- if self.exists():
- return self.remove()
- return False
-
- def remove_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/profile/tcp/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- response = self.client.api.delete(uri)
- if response.status == 200:
- return True
- raise F5ModuleError(response.content)
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/profile/tcp/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return ApiParameters(params=response)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- name=dict(required=True),
- parent=dict(),
- idle_timeout=dict(),
- state=dict(
- default='present',
- choices=['present', 'absent']
- ),
- time_wait_recycle=dict(type='bool'),
- nagle=dict(
- choices=['enabled', 'disabled', 'auto']
- ),
- early_retransmit=dict(type='bool'),
- proxy_options=dict(type='bool'),
- initial_congestion_window_size=dict(type='int'),
- initial_receive_window_size=dict(type='int'),
- syn_rto_base=dict(type='int'),
- partition=dict(
- default='Common',
- fallback=(env_fallback, ['F5_PARTITION'])
- )
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode,
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_profile_udp.py b/lib/ansible/modules/network/f5/bigip_profile_udp.py
deleted file mode 100644
index e64a110a3c..0000000000
--- a/lib/ansible/modules/network/f5/bigip_profile_udp.py
+++ /dev/null
@@ -1,459 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_profile_udp
-short_description: Manage UDP profiles on a BIG-IP
-description:
- - Manage UDP profiles on a BIG-IP. Many of UDP profiles exist; each with their
- own adjustments to the standard C(udp) profile. Users of this module should be aware
- that many of the adjustable knobs have no module default. Instead, the default is
- assigned by the BIG-IP system itself which, in most cases, is acceptable.
-version_added: 2.6
-options:
- name:
- description:
- - Specifies the name of the profile.
- type: str
- required: True
- parent:
- description:
- - Specifies the profile from which this profile inherits settings.
- - When creating a new profile, if this parameter is not specified, the default
- is the system-supplied C(udp) profile.
- type: str
- idle_timeout:
- description:
- - Specifies the length of time that a connection is idle (has no traffic) before
- the connection is eligible for deletion.
- - When creating a new profile, if this parameter is not specified, the remote
- device will choose a default value appropriate for the profile, based on its
- C(parent) profile.
- - When a number is specified, indicates the number of seconds that the UDP
- connection can remain idle before the system deletes it.
- - When C(0), or C(indefinite), specifies that UDP connections can remain idle
- indefinitely.
- - When C(immediate), specifies that you do not want the UDP connection to
- remain idle, and that it is therefore immediately eligible for deletion.
- type: str
- datagram_load_balancing:
- description:
- - Specifies, when C(yes), that the system load balances UDP traffic
- packet-by-packet.
- type: bool
- partition:
- description:
- - Device partition to manage resources on.
- type: str
- default: Common
- state:
- description:
- - When C(present), ensures that the profile exists.
- - When C(absent), ensures the profile is removed.
- type: str
- choices:
- - present
- - absent
- default: present
-extends_documentation_fragment: f5
-author:
- - Tim Rupp (@caphrim007)
-'''
-
-EXAMPLES = r'''
-- name: Create a TCP profile
- bigip_profile_tcp:
- name: foo
- parent: udp
- idle_timeout: 300
- datagram_load_balancing: no
- state: present
- provider:
- user: admin
- password: secret
- server: lb.mydomain.com
- delegate_to: localhost
-'''
-
-RETURN = r'''
-parent:
- description: The new parent of the resource.
- returned: changed
- type: str
- sample: udp
-idle_timeout:
- description: The new idle timeout of the resource.
- returned: changed
- type: int
- sample: 100
-datagram_load_balancing:
- description: The new datagram load balancing setting of the resource.
- returned: changed
- type: bool
- sample: True
-'''
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.basic import env_fallback
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import fq_name
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.common import transform_name
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import fq_name
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.common import transform_name
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'datagramLoadBalancing': 'datagram_load_balancing',
- 'idleTimeout': 'idle_timeout',
- 'defaultsFrom': 'parent',
- }
-
- api_attributes = [
- 'datagramLoadBalancing',
- 'idleTimeout',
- 'defaultsFrom',
- ]
-
- returnables = [
- 'datagram_load_balancing',
- 'idle_timeout',
- 'parent',
- ]
-
- updatables = [
- 'datagram_load_balancing',
- 'idle_timeout',
- 'parent',
- ]
-
- @property
- def idle_timeout(self):
- if self._values['idle_timeout'] is None:
- return None
- if self._values['idle_timeout'] in ['indefinite', 'immediate']:
- return self._values['idle_timeout']
- return int(self._values['idle_timeout'])
-
-
-class ApiParameters(Parameters):
- @property
- def datagram_load_balancing(self):
- if self._values['datagram_load_balancing'] is None:
- return None
- if self._values['datagram_load_balancing'] == 'enabled':
- return True
- return False
-
-
-class ModuleParameters(Parameters):
- @property
- def parent(self):
- if self._values['parent'] is None:
- return None
- result = fq_name(self.partition, self._values['parent'])
- return result
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class UsableChanges(Changes):
- @property
- def datagram_load_balancing(self):
- if self._values['datagram_load_balancing'] is None:
- return None
- if self._values['datagram_load_balancing']:
- return 'enabled'
- return 'disabled'
-
-
-class ReportableChanges(Changes):
- @property
- def datagram_load_balancing(self):
- if self._values['datagram_load_balancing'] is None:
- return None
- if self._values['datagram_load_balancing'] == 'enabled':
- return True
- return False
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(params=self.module.params)
- self.have = ApiParameters()
- self.changes = UsableChanges()
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = UsableChanges(params=changed)
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def exec_module(self):
- changed = False
- result = dict()
- state = self.want.state
-
- if state == "present":
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.client.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def present(self):
- if self.exists():
- return self.update()
- else:
- return self.create()
-
- def exists(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/profile/udp/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def update(self):
- self.have = self.read_current_from_device()
- if not self.should_update():
- return False
- if self.module.check_mode:
- return True
- self.update_on_device()
- return True
-
- def remove(self):
- if self.module.check_mode:
- return True
- self.remove_from_device()
- if self.exists():
- raise F5ModuleError("Failed to delete the resource.")
- return True
-
- def create(self):
- self._set_changed_options()
- if self.module.check_mode:
- return True
- self.create_on_device()
- return True
-
- def create_on_device(self):
- params = self.changes.api_params()
- params['name'] = self.want.name
- params['partition'] = self.want.partition
- uri = "https://{0}:{1}/mgmt/tm/ltm/profile/udp/".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403, 404]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return response['selfLink']
-
- def update_on_device(self):
- params = self.changes.api_params()
- uri = "https://{0}:{1}/mgmt/tm/ltm/profile/udp/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 404]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def absent(self):
- if self.exists():
- return self.remove()
- return False
-
- def remove_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/profile/udp/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- response = self.client.api.delete(uri)
- if response.status == 200:
- return True
- raise F5ModuleError(response.content)
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/profile/udp/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return ApiParameters(params=response)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- name=dict(required=True),
- parent=dict(),
- idle_timeout=dict(),
- datagram_load_balancing=dict(type='bool'),
- state=dict(
- default='present',
- choices=['present', 'absent']
- ),
- partition=dict(
- default='Common',
- fallback=(env_fallback, ['F5_PARTITION'])
- )
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode,
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_provision.py b/lib/ansible/modules/network/f5/bigip_provision.py
deleted file mode 100644
index 7dccb949f6..0000000000
--- a/lib/ansible/modules/network/f5/bigip_provision.py
+++ /dev/null
@@ -1,1099 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['stableinterface'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_provision
-short_description: Manage BIG-IP module provisioning
-description:
- - Manage BIG-IP module provisioning. This module will only provision at the
- standard levels of Dedicated, Nominal, and Minimum.
-version_added: 2.4
-options:
- module:
- description:
- - The module to provision in BIG-IP.
- type: str
- required: True
- choices:
- - am
- - afm
- - apm
- - asm
- - avr
- - cgnat
- - fps
- - gtm
- - ilx
- - lc
- - ltm
- - mgmt
- - pem
- - sam
- - sslo
- - swg
- - urldb
- - vcmp
- aliases:
- - name
- level:
- description:
- - Sets the provisioning level for the requested modules. Changing the
- level for one module may require modifying the level of another module.
- For example, changing one module to C(dedicated) requires setting all
- others to C(none). Setting the level of a module to C(none) means that
- the module is not activated.
- - Use C(state) absent to set C(level) to none and de-provision module.
- - This parameter is not relevant to C(cgnat - pre tmos 15.0) or C(mgmt) and will not be
- applied to the C(cgnat - pre tmos 15.0) or C(mgmt) module.
- type: str
- choices:
- - dedicated
- - nominal
- - minimum
- default: nominal
- memory:
- description:
- - Sets additional memory for management module. This is in addition to
- minimum allocated RAM of 1264MB.
- - The accepted value range is C(0 - 8192). Maximum value is restricted by
- systems available RAM.
- - Specifying C(large) reserves an additional 500MB for mgmt module.
- - Specifying C(medium) reserves an additional 200MB for mgmt module.
- - Specifying C(small) reserves no additional RAM for mgmt module.
- - Use C(large) for configurations containing more than 2000 objects, or
- more specifically, for any configuration that exceeds 1000 objects
- per 2 GB of installed memory. Changing the Management C(mgmt) size
- after initial provisioning causes a reprovision operation
- type: str
- version_added: 2.9
- state:
- description:
- - The state of the provisioned module on the system. When C(present),
- guarantees that the specified module is provisioned at the requested
- level provided that there are sufficient resources on the device (such
- as physical RAM) to support the provisioned module.
- - When C(absent), de-provision the module.
- - C(absent), is not a relevant option to C(mgmt) module as module can not be de-provisioned.
- type: str
- choices:
- - present
- - absent
- default: present
-extends_documentation_fragment: f5
-author:
- - Tim Rupp (@caphrim007)
- - Greg Crosby (@crosbygw)
-'''
-
-EXAMPLES = r'''
-- name: Provision PEM at "nominal" level
- bigip_provision:
- module: pem
- level: nominal
- provider:
- server: lb.mydomain.com
- password: secret
- user: admin
- delegate_to: localhost
-
-- name: Provision a dedicated SWG. This will unprovision every other module
- bigip_provision:
- module: swg
- level: dedicated
- provider:
- server: lb.mydomain.com
- password: secret
- user: admin
- delegate_to: localhost
-
-- name: Provision mgmt with medium amount of memory.
- bigip_provision:
- module: mgmt
- memory: medium
- provider:
- server: lb.mydomain.com
- password: secret
- user: admin
- delegate_to: localhost
-'''
-
-RETURN = r'''
-level:
- description: The new provisioning level of the module.
- returned: changed
- type: str
- sample: minimum
-memory:
- description: The new provisioned amount of memory for mgmt module.
- returned: changed
- type: str
- sample: large
-'''
-
-import time
-
-from ansible.module_utils.basic import AnsibleModule
-from distutils.version import LooseVersion
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.icontrol import TransactionContextManager
- from library.module_utils.network.f5.icontrol import tmos_version
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.icontrol import TransactionContextManager
- from ansible.module_utils.network.f5.icontrol import tmos_version
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'value': 'memory',
- }
-
- api_attributes = [
- 'level',
- 'value',
- ]
-
- returnables = [
- 'level',
- 'memory',
- ]
-
- updatables = [
- 'level',
- 'cgnat',
- 'memory',
- ]
-
-
-class ApiParameters(Parameters):
- pass
-
-
-class ModuleParameters(Parameters):
-
- def _validate_memory_limit(self, limit):
- if self._values['memory'] == 'small':
- return '0'
- if self._values['memory'] == 'medium':
- return '200'
- if self._values['memory'] == 'large':
- return '500'
- if 0 <= int(limit) <= 8192:
- return str(limit)
- raise F5ModuleError(
- "Valid 'memory' must be in range 0 - 8192, 'small', 'medium', or 'large'."
- )
-
- @property
- def level(self):
- if self._values['level'] is None:
- return None
- if self._values['module'] == 'mgmt':
- return None
- if self.state == 'absent':
- return 'none'
- return str(self._values['level'])
-
- @property
- def memory(self):
- if self._values['memory'] is None:
- return None
- if self._values['module'] != 'mgmt':
- return None
- return int(self._validate_memory_limit(self._values['memory']))
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- return result
- except Exception:
- return result
-
-
-class UsableChanges(Changes):
- pass
-
-
-class ReportableChanges(Changes):
- @property
- def memory(self):
- if self._values['memory'] is None:
- return None
- if self._values['memory'] == '0':
- return 'small'
- if self._values['memory'] == '200':
- return 'medium'
- if self._values['memory'] == '500':
- return 'large'
- return str(self._values['memory'])
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- result = self.__default(param)
- return result
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
- @property
- def cgnat(self):
- if self.want.module == 'cgnat':
- if self.want.state == 'absent' and self.have.enabled is True:
- return True
- if self.want.state == 'present' and self.have.disabled is True:
- return True
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.have = None
- self.want = ModuleParameters(params=self.module.params)
- self.changes = UsableChanges()
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def exec_module(self):
- changed = False
- result = dict()
- state = self.want.state
-
- if state == "present":
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- return result
-
- def version_is_greater_or_equal_15(self):
- version = tmos_version(self.client)
- if LooseVersion(version) >= LooseVersion('15.0.0'):
- return True
- else:
- return False
-
- def present(self):
- if self.exists():
- return False
- return self.update()
-
- def exists(self):
- if self.want.module == 'cgnat' and not self.version_is_greater_or_equal_15():
- uri = "https://{0}:{1}/mgmt/tm/sys/feature-module/cgnat/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 404]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- if 'disabled' in response and response['disabled'] is True:
- return False
- elif 'enabled' in response and response['enabled'] is True:
- return True
- elif self.want.module == 'mgmt':
- uri = "https://{0}:{1}/mgmt/tm/sys/db/provision.extramb/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- if str(response['value']) != 0 and self.want.memory == 0:
- return False
- if str(response['value']) == 0 and self.want.memory == 0:
- return True
- if str(response['value']) == self.want.memory:
- return True
- return False
- try:
- for x in range(0, 5):
- uri = "https://{0}:{1}/mgmt/tm/sys/provision/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- self.want.module
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 404]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- if str(response['level']) != 'none' and self.want.level == 'none':
- return True
- if str(response['level']) == 'none' and self.want.level == 'none':
- return False
- if str(response['level']) == self.want.level:
- return True
- return False
- except Exception as ex:
- if 'not registered' in str(ex):
- return False
- time.sleep(1)
-
- def update(self):
- self.have = self.read_current_from_device()
- if not self.should_update():
- return False
- if self.module.check_mode:
- return True
- result = self.update_on_device()
- if self.want.module == 'cgnat' and not self.version_is_greater_or_equal_15():
- return result
- self._wait_for_module_provisioning()
-
- if self.want.module == 'vcmp':
- self._wait_for_reboot()
- self._wait_for_module_provisioning()
-
- if self.want.module == 'asm':
- self._wait_for_asm_ready()
- if self.want.module == 'afm':
- self._wait_for_afm_ready()
- if self.want.module == 'cgnat':
- self._wait_for_cgnat_ready()
- if self.want.module == 'mgmt':
- self._wait_for_mgmt_ready()
- return True
-
- def should_reboot(self):
- for x in range(0, 24):
- try:
- uri = "https://{0}:{1}/mgmt/tm/sys/db/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- 'provision.action'
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 404]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- if response['value'] == 'reboot':
- return True
- elif response['value'] == 'none':
- time.sleep(5)
- except Exception:
- time.sleep(5)
- return False
-
- def reboot_device(self):
- nops = 0
- last_reboot = self._get_last_reboot()
-
- try:
- params = dict(
- command="run",
- utilCmdArgs='-c "/sbin/reboot"'
- )
- uri = "https://{0}:{1}/mgmt/tm/util/bash".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- resp = self.client.api.post(uri, json=params)
-
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- if 'commandResult' in response:
- return str(response['commandResult'])
- except Exception:
- pass
-
- # Sleep a little to let rebooting take effect
- time.sleep(20)
-
- while nops < 3:
- try:
- self.client.reconnect()
- next_reboot = self._get_last_reboot()
- if next_reboot is None:
- nops = 0
- if next_reboot == last_reboot:
- nops = 0
- else:
- nops += 1
- except Exception as ex:
- # This can be caused by restjavad restarting.
- pass
- time.sleep(10)
- return None
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def update_on_device(self):
- if self.want.module == 'cgnat' and not self.version_is_greater_or_equal_15():
- if self.changes.cgnat:
- return self.provision_cgnat_on_device()
- return False
- elif self.want.level == 'dedicated' and self.want.module != 'mgmt':
- self.provision_dedicated_on_device()
- else:
- self.provision_non_dedicated_on_device()
-
- def provision_cgnat_on_device(self):
- uri = "https://{0}:{1}/mgmt/tm/sys/feature-module/cgnat/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- params = dict(enabled=True)
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 404]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return True
-
- def provision_dedicated_on_device(self):
- params = self.want.api_params()
- uri = "https://{0}:{1}/mgmt/tm/sys/provision/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 404]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- resources = [x['name'] for x in response['items'] if x['name'] != self.want.module]
-
- with TransactionContextManager(self.client) as transact:
- for resource in resources:
- target = uri + resource
- resp = transact.api.patch(target, json=dict(level='none'))
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 404]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- target = uri + self.want.module
- resp = transact.api.patch(target, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 404]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def provision_non_dedicated_on_device(self):
- params = self.want.api_params()
- if self.want.module == 'mgmt':
- uri = "https://{0}:{1}/mgmt/tm/sys/db/provision.extramb/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- else:
- uri = "https://{0}:{1}/mgmt/tm/sys/provision/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- self.want.module
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 404]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def read_current_from_device(self):
- if self.want.module == 'cgnat' and not self.version_is_greater_or_equal_15():
- uri = "https://{0}:{1}/mgmt/tm/sys/feature-module/cgnat/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 404]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- elif self.want.module == 'mgmt':
- uri = "https://{0}:{1}/mgmt/tm/sys/db/provision.extramb/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 404]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- else:
- uri = "https://{0}:{1}/mgmt/tm/sys/provision/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- self.want.module
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 404]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return ApiParameters(params=response)
-
- def absent(self):
- if self.exists():
- return self.remove()
- return False
-
- def remove(self):
- if self.module.check_mode:
- return True
- if self.want.module == 'cgnat' and not self.version_is_greater_or_equal_15():
- return self.deprovision_cgnat_on_device()
-
- self.remove_from_device()
- self._wait_for_module_provisioning()
- # For vCMP, because it has to reboot, we also wait for mcpd to become available
- # before "moving on", or else the REST API would not be available and subsequent
- # Tasks would fail.
- if self.want.module == 'vcmp':
- self._wait_for_reboot()
- self._wait_for_module_provisioning()
-
- if self.should_reboot():
- self.save_on_device()
- self.reboot_device()
- self._wait_for_module_provisioning()
-
- if self.exists():
- raise F5ModuleError("Failed to de-provision the module")
- return True
-
- def save_on_device(self):
- command = 'tmsh save sys config'
- params = dict(
- command="run",
- utilCmdArgs='-c "{0}"'.format(command)
- )
- uri = "https://{0}:{1}/mgmt/tm/util/bash".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- resp = self.client.api.post(uri, json=params)
-
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def remove_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/sys/provision/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- self.want.module
- )
- resp = self.client.api.patch(uri, json=dict(level='none'))
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def deprovision_cgnat_on_device(self):
- uri = "https://{0}:{1}/mgmt/tm/sys/feature-module/cgnat/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- params = dict(disabled=True)
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return True
-
- def _wait_for_module_provisioning(self):
- # To prevent things from running forever, the hack is to check
- # for mprov's status twice. If mprov is finished, then in most
- # cases (not ASM) the provisioning is probably ready.
- nops = 0
-
- # Sleep a little to let provisioning settle and begin properly
- time.sleep(5)
-
- while nops < 3:
- try:
- if not self._is_mprov_running_on_device():
- nops += 1
- else:
- nops = 0
- except Exception:
- # This can be caused by restjavad restarting.
- try:
- self.client.reconnect()
- except Exception:
- pass
- time.sleep(5)
-
- def _is_mprov_running_on_device(self):
- # /usr/libexec/qemu-kvm is added here to prevent vcmp provisioning
- # from never allowing the mprov provisioning to succeed.
- #
- # It turns out that the 'mprov' string is found when enabling vcmp. The
- # qemu-kvm command that is run includes it.
- #
- # For example,
- # /usr/libexec/qemu-kvm -rt-usecs 880 ... -mem-path /dev/mprov/vcmp -f5-tracing ...
- #
- try:
- command = "ps aux | grep \'[m]prov\' | grep -v /usr/libexec/qemu-kvm"
- params = dict(
- command="run",
- utilCmdArgs='-c "{0}"'.format(command)
- )
- uri = "https://{0}:{1}/mgmt/tm/util/bash".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- resp = self.client.api.post(uri, json=params)
-
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- if 'commandResult' in response:
- return True
- except Exception:
- pass
- return False
-
- def _wait_for_asm_ready(self):
- """Waits specifically for ASM
-
- On older versions, ASM can take longer to actually start up than
- all the previous checks take. This check here is specifically waiting for
- the Policies API to stop raising errors
- :return:
- """
- nops = 0
- restarted_asm = False
- while nops < 3:
- try:
- uri = "https://{0}:{1}/mgmt/tm/asm/policies/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.get(uri)
-
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- if len(response['items']) >= 0:
- nops += 1
- else:
- nops = 0
- except Exception as ex:
- if not restarted_asm:
- self._restart_asm()
- restarted_asm = True
- time.sleep(5)
-
- def _wait_for_afm_ready(self):
- """Waits specifically for AFM
-
- AFM can take longer to actually start up than all the previous checks take.
- This check here is specifically waiting for the Security API to stop raising
- errors.
- :return:
- """
- nops = 0
- while nops < 3:
- try:
- uri = "https://{0}:{1}/mgmt/tm/security/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.get(uri)
-
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- if len(response['items']) >= 0:
- nops += 1
- else:
- nops = 0
- except Exception as ex:
- pass
- time.sleep(5)
-
- def _wait_for_cgnat_ready(self):
- """Waits specifically for CGNAT
-
- Starting in TMOS 15.0 cgnat can take longer to actually start up than all the previous checks take.
- This check here is specifically waiting for a cgnat API to stop raising
- errors.
- :return:
- """
- nops = 0
- while nops < 3:
- try:
- uri = "https://{0}:{1}/mgmt/tm/ltm/lsn-pool".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.get(uri)
-
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- if len(response['items']) >= 0:
- nops += 1
- else:
- nops = 0
- except Exception as ex:
- pass
- time.sleep(5)
-
- def _wait_for_mgmt_ready(self):
- """Waits specifically for MGMT
-
- Modifying memory reserve for mgmt can take longer to actually start up than all the previous checks take.
- This check here is specifically waiting for a MGMT API to stop raising
- errors.
- :return:
- """
- nops = 0
- while nops < 3:
- try:
- uri = "https://{0}:{1}/mgmt/tm".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.get(uri)
-
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- if len(response['items']) >= 0:
- nops += 1
- else:
- nops = 0
- except Exception as ex:
- pass
- time.sleep(5)
-
- def _restart_asm(self):
- try:
- params = dict(
- command="run",
- utilCmdArgs='-c "bigstart restart asm"'
- )
- uri = "https://{0}:{1}/mgmt/tm/util/bash".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- resp = self.client.api.post(uri, json=params)
-
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- time.sleep(60)
- return True
- except Exception:
- pass
- return None
-
- def _get_last_reboot(self):
- try:
- params = dict(
- command="run",
- utilCmdArgs='-c "/usr/bin/last reboot | head -1"'
- )
- uri = "https://{0}:{1}/mgmt/tm/util/bash".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- resp = self.client.api.post(uri, json=params)
-
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- if 'commandResult' in response:
- return str(response['commandResult'])
- except Exception:
- pass
- return None
-
- def _wait_for_reboot(self):
- nops = 0
-
- last_reboot = self._get_last_reboot()
-
- # Sleep a little to let provisioning settle and begin properly
- time.sleep(5)
-
- while nops < 6:
- try:
- self.client.reconnect()
- next_reboot = self._get_last_reboot()
- if next_reboot is None:
- nops = 0
- if next_reboot == last_reboot:
- nops = 0
- else:
- nops += 1
- except Exception as ex:
- # This can be caused by restjavad restarting.
- pass
- time.sleep(10)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- module=dict(
- required=True,
- choices=[
- 'afm', 'am', 'apm', 'asm', 'avr', 'cgnat',
- 'fps', 'gtm', 'ilx', 'lc', 'ltm', 'mgmt',
- 'pem', 'sam', 'sslo', 'swg', 'urldb', 'vcmp'
- ],
- aliases=['name']
- ),
- level=dict(
- default='nominal',
- choices=['nominal', 'dedicated', 'minimum']
- ),
- memory=dict(),
- state=dict(
- default='present',
- choices=['present', 'absent']
- )
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
- self.mutually_exclusive = [
- ['parameters', 'parameters_src']
- ]
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode,
- mutually_exclusive=spec.mutually_exclusive
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_qkview.py b/lib/ansible/modules/network/f5/bigip_qkview.py
deleted file mode 100644
index 8b95e68f29..0000000000
--- a/lib/ansible/modules/network/f5/bigip_qkview.py
+++ /dev/null
@@ -1,605 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_qkview
-short_description: Manage qkviews on the device
-description:
- - Manages creating and downloading qkviews from a BIG-IP. Various
- options can be provided when creating qkviews. The qkview is important
- when dealing with F5 support. It may be required that you upload this
- qkview to the supported channels during resolution of an SRs that you
- may have opened.
-version_added: 2.4
-options:
- filename:
- description:
- - Name of the qkview to create on the remote BIG-IP.
- type: str
- default: "localhost.localdomain.qkview"
- dest:
- description:
- - Destination on your local filesystem when you want to save the qkview.
- type: path
- required: True
- asm_request_log:
- description:
- - When C(True), includes the ASM request log data. When C(False),
- excludes the ASM request log data.
- type: bool
- default: no
- max_file_size:
- description:
- - Max file size, in bytes, of the qkview to create. By default, no max
- file size is specified.
- type: int
- default: 0
- complete_information:
- description:
- - Include complete information in the qkview.
- type: bool
- default: no
- exclude_core:
- description:
- - Exclude core files from the qkview.
- type: bool
- default: no
- exclude:
- description:
- - Exclude various file from the qkview.
- type: list
- choices:
- - all
- - audit
- - secure
- - bash_history
- force:
- description:
- - If C(no), the file will only be transferred if the destination does not
- exist.
- type: bool
- default: yes
-notes:
- - This module does not include the "max time" or "restrict to blade" options.
- - If you are using this module with either Ansible Tower or Ansible AWX, you
- should be aware of how these Ansible products execute jobs in restricted
- environments. More informat can be found here
- https://clouddocs.f5.com/products/orchestration/ansible/devel/usage/module-usage-with-tower.html
-extends_documentation_fragment: f5
-author:
- - Tim Rupp (@caphrim007)
-'''
-
-EXAMPLES = r'''
-- name: Fetch a qkview from the remote device
- bigip_qkview:
- asm_request_log: yes
- exclude:
- - audit
- - secure
- dest: /tmp/localhost.localdomain.qkview
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-'''
-
-RETURN = r'''
-# only common fields returned
-'''
-
-import os
-import re
-import socket
-import ssl
-import time
-
-from ansible.module_utils.basic import AnsibleModule
-from distutils.version import LooseVersion
-
-try:
- import urlparse
-except ImportError:
- import urllib.parse as urlparse
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.common import transform_name
- from library.module_utils.network.f5.icontrol import download_file
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.common import transform_name
- from ansible.module_utils.network.f5.icontrol import download_file
-
-
-class Parameters(AnsibleF5Parameters):
- api_attributes = [
- 'asm_request_log',
- 'complete_information',
- 'exclude',
- 'exclude_core',
- 'filename_cmd',
- 'max_file_size',
- ]
-
- returnables = ['stdout', 'stdout_lines', 'warnings']
-
- @property
- def exclude(self):
- if self._values['exclude'] is None:
- return None
- exclude = ' '.join(self._values['exclude'])
- return "--exclude='{0}'".format(exclude)
-
- @property
- def exclude_raw(self):
- return self._values['exclude']
-
- @property
- def exclude_core(self):
- if self._values['exclude']:
- return '-C'
- else:
- return None
-
- @property
- def complete_information(self):
- if self._values['complete_information']:
- return '-c'
- return None
-
- @property
- def max_file_size(self):
- if self._values['max_file_size'] in [None]:
- return None
- return '-s {0}'.format(self._values['max_file_size'])
-
- @property
- def asm_request_log(self):
- if self._values['asm_request_log']:
- return '-o asm-request-log'
- return None
-
- @property
- def filename(self):
- pattern = r'^[\w\.]+$'
- filename = os.path.basename(self._values['filename'])
- if re.match(pattern, filename):
- return filename
- else:
- raise F5ModuleError(
- "The provided filename must contain word characters only."
- )
-
- @property
- def filename_cmd(self):
- return '-f {0}'.format(self.filename)
-
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
- def api_params(self):
- result = {}
- for api_attribute in self.api_attributes:
- if self.api_map is not None and api_attribute in self.api_map:
- result[api_attribute] = getattr(self, self.api_map[api_attribute])
- else:
- result[api_attribute] = getattr(self, api_attribute)
- result = self._filter_params(result)
- return result
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.kwargs = kwargs
-
- def exec_module(self):
- if self.is_version_less_than_14():
- manager = self.get_manager('madm')
- else:
- manager = self.get_manager('bulk')
- return manager.exec_module()
-
- def get_manager(self, type):
- if type == 'madm':
- return MadmLocationManager(**self.kwargs)
- elif type == 'bulk':
- return BulkLocationManager(**self.kwargs)
-
- def is_version_less_than_14(self):
- uri = "https://{0}:{1}/mgmt/tm/sys".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- version = urlparse.parse_qs(urlparse.urlparse(response['selfLink']).query)['ver'][0]
- if LooseVersion(version) < LooseVersion('14.0.0'):
- return True
- else:
- return False
-
-
-class BaseManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.have = None
- self.want = Parameters(params=self.module.params)
- self.changes = Parameters()
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = Parameters(params=changed)
-
- def exec_module(self):
- result = dict()
-
- self.present()
-
- result.update(**self.changes.to_return())
- result.update(dict(changed=False))
- return result
-
- def present(self):
- if os.path.exists(self.want.dest) and not self.want.force:
- raise F5ModuleError(
- "The specified 'dest' file already exists."
- )
- if not os.path.exists(os.path.dirname(self.want.dest)):
- raise F5ModuleError(
- "The directory of your 'dest' file does not exist."
- )
- if self.want.exclude:
- choices = ['all', 'audit', 'secure', 'bash_history']
- if not all(x in choices for x in self.want.exclude_raw):
- raise F5ModuleError(
- "The specified excludes must be in the following list: "
- "{0}".format(','.join(choices))
- )
- self.execute()
-
- def exists(self):
- params = dict(
- command='run',
- utilCmdArgs=self.remote_dir
- )
- uri = "https://{0}:{1}/mgmt/tm/util/unix-ls".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
-
- try:
- if self.want.filename in response['commandResult']:
- return True
- except KeyError:
- return False
-
- def execute(self):
- response = self.execute_on_device()
- if not response:
- raise F5ModuleError(
- "Failed to create qkview on device."
- )
-
- result = self._move_qkview_to_download()
- if not result:
- raise F5ModuleError(
- "Failed to move the file to a downloadable location"
- )
-
- self._download_file()
- if not os.path.exists(self.want.dest):
- raise F5ModuleError(
- "Failed to save the qkview to local disk"
- )
-
- self._delete_qkview()
- result = self.exists()
- if result:
- raise F5ModuleError(
- "Failed to remove the remote qkview"
- )
-
- def _delete_qkview(self):
- tpath_name = '{0}/{1}'.format(self.remote_dir, self.want.filename)
- params = dict(
- command='run',
- utilCmdArgs=tpath_name
- )
- uri = "https://{0}:{1}/mgmt/tm/util/unix-rm".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
-
- def execute_on_device(self):
- self._upsert_temporary_cli_script_on_device()
- task_id = self._create_async_task_on_device()
- self._exec_async_task_on_device(task_id)
- self._wait_for_async_task_to_finish_on_device(task_id)
- self._remove_temporary_cli_script_from_device()
- return True
-
- def _upsert_temporary_cli_script_on_device(self):
- args = {
- "name": "__ansible_mkqkview",
- "apiAnonymous": """
- proc script::run {} {
- set cmd [lreplace $tmsh::argv 0 0]; eval "exec $cmd 2> /dev/null"
- }
- """
- }
- result = self._create_temporary_cli_script_on_device(args)
- if result:
- return True
- return self._update_temporary_cli_script_on_device(args)
-
- def _create_temporary_cli_script_on_device(self, args):
- uri = "https://{0}:{1}/mgmt/tm/cli/script".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.post(uri, json=args)
- try:
- response = resp.json()
- if 'code' in response and response['code'] in [404, 409]:
- return False
- except ValueError:
- pass
- if resp.status in [404, 409]:
- return False
- return True
-
- def _update_temporary_cli_script_on_device(self, args):
- uri = "https://{0}:{1}/mgmt/tm/cli/script/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name('Common', '__ansible_mkqkview')
- )
- resp = self.client.api.put(uri, json=args)
- try:
- resp.json()
- return True
- except ValueError:
- raise F5ModuleError(
- "Failed to update temporary cli script on device."
- )
-
- def _create_async_task_on_device(self):
- """Creates an async cli script task in the REST API
-
- Returns:
- int: The ID of the task staged for running.
-
- :return:
- """
- command = ' '.join(self.want.api_params().values())
- args = {
- "command": "run",
- "name": "__ansible_mkqkview",
- "utilCmdArgs": "/usr/bin/qkview {0}".format(command)
- }
- uri = "https://{0}:{1}/mgmt/tm/task/cli/script".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.post(uri, json=args)
- try:
- response = resp.json()
- return response['_taskId']
- except ValueError:
- raise F5ModuleError(
- "Failed to create the async task on the device."
- )
-
- def _exec_async_task_on_device(self, task_id):
- args = {"_taskState": "VALIDATING"}
- uri = "https://{0}:{1}/mgmt/tm/task/cli/script/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- task_id
- )
- resp = self.client.api.put(uri, json=args)
- try:
- resp.json()
- return True
- except ValueError:
- raise F5ModuleError(
- "Failed to execute the async task on the device"
- )
-
- def _wait_for_async_task_to_finish_on_device(self, task_id):
- uri = "https://{0}:{1}/mgmt/tm/task/cli/script/{2}/result".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- task_id
- )
- while True:
- try:
- resp = self.client.api.get(uri, timeout=10)
- except (socket.timeout, ssl.SSLError):
- continue
- try:
- response = resp.json()
- except ValueError:
- # It is possible that the API call can return invalid JSON.
- # This invalid JSON appears to be just empty strings.
- continue
- if response['_taskState'] == 'FAILED':
- raise F5ModuleError(
- "qkview creation task failed unexpectedly."
- )
- if response['_taskState'] == 'COMPLETED':
- return True
- time.sleep(3)
-
- def _remove_temporary_cli_script_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/task/cli/script/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name('Common', '__ansible_mkqkview')
- )
- try:
- self.client.api.delete(uri)
- return True
- except ValueError:
- raise F5ModuleError(
- "Failed to remove the temporary cli script from the device."
- )
-
- def _move_qkview_to_download(self):
- uri = "https://{0}:{1}/mgmt/tm/util/unix-mv/".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- args = dict(
- command='run',
- utilCmdArgs='/var/tmp/{0} {1}/{0}'.format(self.want.filename, self.remote_dir)
- )
- self.client.api.post(uri, json=args)
- return True
-
-
-class BulkLocationManager(BaseManager):
- def __init__(self, *args, **kwargs):
- super(BulkLocationManager, self).__init__(**kwargs)
- self.remote_dir = '/var/config/rest/bulk'
-
- def _download_file(self):
- uri = "https://{0}:{1}/mgmt/shared/file-transfer/bulk/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- self.want.filename
- )
- download_file(self.client, uri, self.want.dest)
- if os.path.exists(self.want.dest):
- return True
- return False
-
-
-class MadmLocationManager(BaseManager):
- def __init__(self, *args, **kwargs):
- super(MadmLocationManager, self).__init__(**kwargs)
- self.remote_dir = '/var/config/rest/madm'
-
- def _download_file(self):
- uri = "https://{0}:{1}/mgmt/shared/file-transfer/madm/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- self.want.filename
- )
- download_file(self.client, uri, self.want.dest)
- if os.path.exists(self.want.dest):
- return True
- return False
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- filename=dict(
- default='localhost.localdomain.qkview'
- ),
- asm_request_log=dict(
- type='bool',
- default='no',
- ),
- max_file_size=dict(
- type='int',
- ),
- complete_information=dict(
- default='no',
- type='bool'
- ),
- exclude_core=dict(
- default="no",
- type='bool'
- ),
- force=dict(
- default=True,
- type='bool'
- ),
- exclude=dict(
- type='list',
- choices=[
- 'all', 'audit', 'secure', 'bash_history'
- ]
- ),
- dest=dict(
- type='path',
- required=True
- )
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode,
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_remote_role.py b/lib/ansible/modules/network/f5/bigip_remote_role.py
deleted file mode 100644
index 0489bfc0c9..0000000000
--- a/lib/ansible/modules/network/f5/bigip_remote_role.py
+++ /dev/null
@@ -1,553 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2018, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_remote_role
-short_description: Manage remote roles on a BIG-IP
-description:
- - Manages remote roles on a BIG-IP. Remote roles are used in situations where
- user authentication is handled off-box. Local access control to the BIG-IP
- is controlled by the defined remote role. Where-as authentication (and by
- extension, assignment to the role) is handled off-box.
-version_added: 2.7
-options:
- name:
- description:
- - Specifies the name of the remote role.
- type: str
- required: True
- line_order:
- description:
- - Specifies the order of the line in the file C(/config/bigip/auth/remoterole).
- - The LDAP and Active Directory servers read this file line by line.
- - The order of the information is important; therefore, F5 recommends that
- you set the first line at 1000. This allows you, in the future, to insert
- lines before the first line.
- - When creating a new remote role, this parameter is required.
- type: int
- attribute_string:
- description:
- - Specifies the user account attributes saved in the group, in the format
- C(cn=, ou=, dc=).
- - When creating a new remote role, this parameter is required.
- type: str
- remote_access:
- description:
- - Enables or disables remote access for the specified group of remotely
- authenticated users.
- - When creating a new remote role, if this parameter is not specified, the default
- is C(yes).
- type: bool
- assigned_role:
- description:
- - Specifies the authorization (level of access) for the account.
- - When creating a new remote role, if this parameter is not provided, the
- default is C(none).
- - The C(partition_access) parameter controls which partitions the account can
- access.
- - The chosen role may affect the partitions that one is allowed to specify.
- Specifically, roles such as C(administrator), C(auditor) and C(resource-administrator)
- required a C(partition_access) of C(all).
- - A set of pre-existing roles ship with the system. They are C(none), C(guest),
- C(operator), C(application-editor), C(manager), C(certificate-manager),
- C(irule-manager), C(user-manager), C(resource-administrator), C(auditor),
- C(administrator), C(firewall-manager).
- type: str
- partition_access:
- description:
- - Specifies the accessible partitions for the account.
- - This parameter supports the reserved names C(all) and C(Common), as well as
- specific partitions a user may access.
- - Users who have access to a partition can operate on objects in that partition,
- as determined by the permissions conferred by the user's C(assigned_role).
- - When creating a new remote role, if this parameter is not specified, the default
- is C(all).
- type: str
- terminal_access:
- description:
- - Specifies terminal-based accessibility for remote accounts not already
- explicitly assigned a user role.
- - Common values for this include C(tmsh) and C(none), however custom values
- may also be specified.
- - When creating a new remote role, if this parameter is not specified, the default
- is C(none).
- type: str
- state:
- description:
- - When C(present), guarantees that the remote role exists.
- - When C(absent), removes the remote role from the system.
- type: str
- choices:
- - absent
- - present
- default: present
-extends_documentation_fragment: f5
-author:
- - Tim Rupp (@caphrim007)
-'''
-
-EXAMPLES = r'''
-- name: Create a remote role
- bigip_remote_role:
- name: foo
- group_name: ldap_group
- line_order: 1
- attribute_string: memberOf=cn=ldap_group,cn=ldap.group,ou=ldap
- remote_access: enabled
- assigned_role: administrator
- partition_access: all
- terminal_access: none
- state: present
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-'''
-
-RETURN = r'''
-attribute_string:
- description: The new attribute string of the resource.
- returned: changed
- type: str
- sample: "memberOf=cn=ldap_group,cn=ldap.group,ou=ldap"
-terminal_access:
- description: The terminal setting of the remote role.
- returned: changed
- type: str
- sample: tmsh
-line_order:
- description: Order of the remote role for LDAP and Active Directory servers.
- returned: changed
- type: int
- sample: 1000
-assigned_role:
- description: System role that this remote role is associated with.
- returned: changed
- type: str
- sample: administrator
-partition_access:
- description: Partition that the role has access to.
- returned: changed
- type: str
- sample: all
-remote_access:
- description: Whether remote access is allowed or not.
- returned: changed
- type: bool
- sample: no
-'''
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.six import iteritems
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.common import flatten_boolean
- from library.module_utils.network.f5.common import transform_name
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.common import flatten_boolean
- from ansible.module_utils.network.f5.common import transform_name
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'attribute': 'attribute_string',
- 'console': 'terminal_access',
- 'lineOrder': 'line_order',
- 'role': 'assigned_role',
- 'userPartition': 'partition_access',
- 'deny': 'remote_access'
- }
-
- api_attributes = [
- 'attribute',
- 'console',
- 'lineOrder',
- 'role',
- 'deny',
- 'userPartition',
- ]
-
- returnables = [
- 'attribute_string',
- 'terminal_access',
- 'line_order',
- 'assigned_role',
- 'partition_access',
- 'remote_access',
- ]
-
- updatables = [
- 'attribute_string',
- 'terminal_access',
- 'line_order',
- 'assigned_role',
- 'partition_access',
- 'remote_access',
- ]
-
- role_map = {
- 'application-editor': 'applicationeditor',
- 'none': 'noaccess',
- 'certificate-manager': 'certificatemanager',
- 'irule-manager': 'irulemanager',
- 'user-manager': 'usermanager',
- 'resource-administrator': 'resourceadmin',
- 'firewall-manager': 'firewallmanager'
- }
-
-
-class ApiParameters(Parameters):
- pass
-
-
-class ModuleParameters(Parameters):
- @property
- def partition(self):
- return 'Common'
-
- @property
- def assigned_role(self):
- if self._values['assigned_role'] is None:
- return None
- return self.role_map.get(self._values['assigned_role'], self._values['assigned_role'])
-
- @property
- def terminal_access(self):
- if self._values['terminal_access'] in [None, 'tmsh']:
- return self._values['terminal_access']
- elif self._values['terminal_access'] == 'none':
- return 'disable'
- return self._values['terminal_access']
-
- @property
- def partition_access(self):
- if self._values['partition_access'] is None:
- return None
- if self._values['partition_access'] == 'all':
- return 'All'
- return self._values['partition_access']
-
- @property
- def remote_access(self):
- result = flatten_boolean(self._values['remote_access'])
- if result == 'yes':
- return 'disabled'
- elif result == 'no':
- return 'enabled'
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class UsableChanges(Changes):
- pass
-
-
-class ReportableChanges(Changes):
- @property
- def assigned_role(self):
- if self._values['assigned_role'] is None:
- return None
- rmap = dict((v, k) for k, v in iteritems(self.role_map))
- return rmap.get(self._values['assigned_role'], self._values['assigned_role'])
-
- @property
- def terminal_access(self):
- if self._values['terminal_access'] in [None, 'tmsh']:
- return self._values['terminal_access']
- elif self._values['terminal_access'] == 'disabled':
- return 'none'
- return self._values['terminal_access']
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(params=self.module.params)
- self.have = ApiParameters()
- self.changes = UsableChanges()
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = UsableChanges(params=changed)
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def exec_module(self):
- changed = False
- result = dict()
- state = self.want.state
-
- if state == "present":
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.client.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def present(self):
- if self.exists():
- return self.update()
- else:
- return self.create()
-
- def exists(self):
- uri = "https://{0}:{1}/mgmt/tm/auth/remote-role/role-info/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def update(self):
- self.have = self.read_current_from_device()
- if not self.should_update():
- return False
- if self.module.check_mode:
- return True
- self.update_on_device()
- return True
-
- def remove(self):
- if self.module.check_mode:
- return True
- self.remove_from_device()
- if self.exists():
- raise F5ModuleError("Failed to delete the resource.")
- return True
-
- def create(self):
- if self.want.partition_access is None:
- self.want.update({'partition_access': 'all'})
- if self.want.remote_access is None:
- self.want.update({'remote_access': True})
- if self.want.assigned_role is None:
- self.want.update({'assigned_role': 'none'})
- if self.want.terminal_access is None:
- self.want.update({'terminal_access': 'none'})
- self._set_changed_options()
- if self.module.check_mode:
- return True
- self.create_on_device()
- return True
-
- def create_on_device(self):
- params = self.changes.api_params()
- params['name'] = self.want.name
- uri = "https://{0}:{1}/mgmt/tm/auth/remote-role/role-info/".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def update_on_device(self):
- params = self.changes.api_params()
- uri = "https://{0}:{1}/mgmt/tm/auth/remote-role/role-info/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- if 'Once configured [All] partition, remote user group cannot' in response['message']:
- raise F5ModuleError(
- "The specified 'attribute_string' is already used in the 'all' partition."
- )
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def absent(self):
- if self.exists():
- return self.remove()
- return False
-
- def remove_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/auth/remote-role/role-info/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- response = self.client.api.delete(uri)
- if response.status == 200:
- return True
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(response.content)
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/auth/remote-role/role-info/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return ApiParameters(params=response)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- name=dict(required=True),
- line_order=dict(type='int'),
- attribute_string=dict(),
- remote_access=dict(type='bool'),
- assigned_role=dict(),
- partition_access=dict(),
- terminal_access=dict(),
- state=dict(
- default='present',
- choices=['present', 'absent']
- ),
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode,
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_remote_syslog.py b/lib/ansible/modules/network/f5/bigip_remote_syslog.py
deleted file mode 100644
index 2848629f23..0000000000
--- a/lib/ansible/modules/network/f5/bigip_remote_syslog.py
+++ /dev/null
@@ -1,467 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['stableinterface'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_remote_syslog
-short_description: Manipulate remote syslog settings on a BIG-IP
-description:
- - Manipulate remote syslog settings on a BIG-IP.
-version_added: 2.5
-options:
- remote_host:
- description:
- - Specifies the IP address, or hostname, for the remote system to
- which the system sends log messages.
- type: str
- required: True
- name:
- description:
- - Specifies the name of the syslog object.
- - This option is required when multiple C(remote_host) with the same IP
- or hostname are present on the device.
- - If C(name) is not provided C(remote_host) is used by default.
- type: str
- version_added: 2.8
- remote_port:
- description:
- - Specifies the port that the system uses to send messages to the
- remote logging server.
- - When creating a remote syslog, if this parameter is not specified, the
- default value C(514) is used.
- type: str
- local_ip:
- description:
- - Specifies the local IP address of the system that is logging. To
- provide no local IP, specify the value C(none).
- - When creating a remote syslog, if this parameter is not specified, the
- default value C(none) is used.
- type: str
- state:
- description:
- - When C(present), guarantees that the remote syslog exists with the provided
- attributes.
- - When C(absent), removes the remote syslog from the system.
- type: str
- choices:
- - absent
- - present
- default: present
-extends_documentation_fragment: f5
-author:
- - Tim Rupp (@caphrim007)
- - Wojciech Wypior (@wojtek0806)
-'''
-
-EXAMPLES = r'''
-- name: Add a remote syslog server to log to
- bigip_remote_syslog:
- remote_host: 10.10.10.10
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-
-- name: Add a remote syslog server on a non-standard port to log to
- bigip_remote_syslog:
- remote_host: 10.10.10.10
- remote_port: 1234
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-'''
-
-RETURN = r'''
-remote_port:
- description: New remote port of the remote syslog server.
- returned: changed
- type: int
- sample: 514
-local_ip:
- description: The new local IP of the remote syslog server
- returned: changed
- type: str
- sample: 10.10.10.10
-'''
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.six import iteritems
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.common import is_valid_hostname
- from library.module_utils.network.f5.common import fq_name
- from library.module_utils.network.f5.ipaddress import is_valid_ip
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.common import is_valid_hostname
- from ansible.module_utils.network.f5.common import fq_name
- from ansible.module_utils.network.f5.ipaddress import is_valid_ip
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'remotePort': 'remote_port',
- 'localIp': 'local_ip',
- 'host': 'remote_host',
- }
-
- updatables = [
- 'remote_port',
- 'local_ip',
- 'remote_host',
- 'name',
- ]
-
- returnables = [
- 'remote_port',
- 'local_ip',
- 'remote_host',
- 'name',
- 'remoteServers',
- ]
-
- api_attributes = [
- 'remotePort',
- 'localIp',
- 'host',
- 'name',
- 'remoteServers',
- ]
-
-
-class ApiParameters(Parameters):
- pass
-
-
-class ModuleParameters(Parameters):
- @property
- def remote_host(self):
- if is_valid_ip(self._values['remote_host']):
- return self._values['remote_host']
- elif is_valid_hostname(self._values['remote_host']):
- return str(self._values['remote_host'])
- raise F5ModuleError(
- "The provided 'remote_host' is not a valid IP or hostname"
- )
-
- @property
- def remote_port(self):
- if self._values['remote_port'] in [None, 'none']:
- return None
- if self._values['remote_port'] == 0:
- raise F5ModuleError(
- "The 'remote_port' value must between 1 and 65535"
- )
- return int(self._values['remote_port'])
-
- @property
- def local_ip(self):
- if self._values['local_ip'] in [None, 'none']:
- return None
- if is_valid_ip(self._values['local_ip']):
- return self._values['local_ip']
- else:
- raise F5ModuleError(
- "The provided 'local_ip' is not a valid IP address"
- )
-
- @property
- def name(self):
- if self._values['remote_host'] is None:
- return None
- if self._values['name'] is None:
- return None
- name = fq_name(self.partition, self._values['name'])
- return name
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- change = getattr(self, returnable)
- if isinstance(change, dict):
- result.update(change)
- else:
- result[returnable] = change
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class UsableChanges(Changes):
- pass
-
-
-class ReportableChanges(Changes):
- @property
- def remote_port(self):
- if self._values['remote_port'] is None:
- return None
- return int(self._values['remote_port'])
-
- @property
- def remoteServers(self):
- pass
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
- self._local_ip = None
- self._remote_port = None
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.pop('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(params=self.module.params)
- self.have = ApiParameters()
- self.changes = UsableChanges()
-
- # A list of all the syslogs queried from the API when reading current info
- # from the device. This is used when updating the API as the value that needs
- # to be updated is a list of syslogs and PATCHing a list would override any
- # default settings.
- self.syslogs = dict()
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def format_syslogs(self, syslogs):
- result = None
- for x in syslogs:
- syslog = ApiParameters(params=x)
- self.syslogs[syslog.name] = x
-
- if syslog.name == self.want.name:
- result = syslog
- elif syslog.remote_host == self.want.remote_host:
- result = syslog
-
- if not result:
- return ApiParameters()
- return result
-
- def exec_module(self):
- result = dict()
-
- changed = self.present()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def present(self):
- return self.update()
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def update(self):
- self.have = self.format_syslogs(self.read_current_from_device())
- if not self.should_update() and self.want.state != 'absent':
- return False
- if self.module.check_mode:
- return True
-
- if self.want.name is None:
- self.want.update({'name': self.want.remote_host})
-
- syslogs = [v for k, v in iteritems(self.syslogs)]
- dupes = [x for x in syslogs if x['host'] == self.want.remote_host]
- if len(dupes) > 1:
- raise F5ModuleError(
- "Multiple occurrences of hostname: {0} detected, please specify 'name' parameter". format(self.want.remote_host)
- )
-
- # A absent syslog does not appear in the list of existing syslogs
- if self.want.state == 'absent':
- if self.want.name not in self.syslogs:
- return False
-
- # At this point we know the existing syslog is not absent, so we need
- # to change it in some way.
- #
- # First, if we see that the syslog is in the current list of syslogs,
- # we are going to update it
- changes = dict(self.changes.api_params())
- if self.want.name in self.syslogs:
- self.syslogs[self.want.name].update(changes)
- else:
- # else, we are going to add it to the list of syslogs
- self.syslogs[self.want.name] = changes
-
- # Since the name attribute is not a parameter tracked in the Parameter
- # classes, we will add the name to the list of attributes so that when
- # we update the API, it creates the correct vector
- self.syslogs[self.want.name].update({'name': self.want.name})
-
- # Finally, the absent state forces us to remove the syslog from the
- # list.
- if self.want.state == 'absent':
- del self.syslogs[self.want.name]
-
- # All of the syslogs must be re-assembled into a list of dictionaries
- # so that when we PATCH the API endpoint, the syslogs list is filled
- # correctly.
- #
- # There are **not** individual API endpoints for the individual syslogs.
- # Instead, the endpoint includes a list of syslogs that is part of the
- # system config
- result = [v for k, v in iteritems(self.syslogs)]
-
- self.changes = Changes(params=dict(remoteServers=result))
- self.changes.update(self.want._values)
- self.update_on_device()
- return True
-
- def update_on_device(self):
- params = self.changes.api_params()
- params = dict(
- remoteServers=params.get('remoteServers')
- )
- uri = "https://{0}:{1}/mgmt/tm/sys/syslog/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 409]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/sys/syslog/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- result = response.get('remoteServers', [])
- return result
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- remote_host=dict(
- required=True
- ),
- remote_port=dict(),
- local_ip=dict(),
- name=dict(),
- state=dict(
- default='present',
- choices=['absent', 'present']
- )
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_remote_user.py b/lib/ansible/modules/network/f5/bigip_remote_user.py
deleted file mode 100644
index beaab5db0f..0000000000
--- a/lib/ansible/modules/network/f5/bigip_remote_user.py
+++ /dev/null
@@ -1,391 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2019, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_remote_user
-short_description: Manages default settings for remote user accounts on a BIG-IP
-description:
- - Manages default settings for remote user accounts on a BIG-IP.
-version_added: 2.9
-options:
- default_role:
- description:
- - Specifies the default role for all remote user accounts.
- - The default system value is C(no-access).
- type: str
- choices:
- - acceleration-policy-editor
- - admin
- - application-editor
- - auditor
- - certificate-manager
- - firewall-manager
- - fraud-protection-manager
- - guest
- - irule-manager
- - manager
- - no-access
- - operator
- - resource-admin
- - user-manager
- - web-application-security-administrator
- - web-application-security-editor
- default_partition:
- description:
- - Specifies the default partition for all remote user accounts.
- - The default system value is C(all) for all partitions.
- type: str
- console_access:
- description:
- - Enables or disables the default console access for all remote user accounts.
- - The default system value is C(disabled).
- type: bool
- description:
- description:
- - User defined description.
- type: str
-extends_documentation_fragment: f5
-author:
- - Wojciech Wypior (@wojtek0806)
-'''
-
-EXAMPLES = r'''
-- name: Modify default partition and console access
- bigip_remote_user:
- default_partition: Common
- console_access: yes
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-
-- name: Modify default role, partition and console access
- bigip_remote_user:
- default_partition: Common
- default_role: manager
- console_access: yes
- description: "Changed new settings"
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-
-- name: Revert to default settings
- bigip_remote_user:
- default_partition: all
- default_role: "no-access"
- console_access: no
- description: ""
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-'''
-
-RETURN = r'''
-default_role:
- description: The default role for all remote user accounts.
- returned: changed
- type: str
- sample: auditor
-default_partition:
- description: The default partition for all remote user accounts.
- returned: changed
- type: str
- sample: Common
-console_access:
- description: The default console access for all remote user accounts
- returned: changed
- type: bool
- sample: no
-description:
- description: The user defined description.
- returned: changed
- type: str
- sample: Foo is bar
-'''
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.common import flatten_boolean
- from library.module_utils.network.f5.compare import cmp_str_with_none
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.common import flatten_boolean
- from ansible.module_utils.network.f5.compare import cmp_str_with_none
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'defaultPartition': 'default_partition',
- 'defaultRole': 'default_role',
- 'remoteConsoleAccess': 'console_access',
- }
-
- api_attributes = [
- 'defaultPartition',
- 'defaultRole',
- 'description',
- 'remoteConsoleAccess',
-
- ]
-
- returnables = [
- 'default_partition',
- 'default_role',
- 'console_access',
- 'description',
- ]
-
- updatables = [
- 'default_partition',
- 'default_role',
- 'console_access',
- 'description',
- ]
-
-
-class ApiParameters(Parameters):
- pass
-
-
-class ModuleParameters(Parameters):
- @property
- def console_access(self):
- result = flatten_boolean(self._values['console_access'])
- if result == 'yes':
- return 'tmsh'
- if result == 'no':
- return 'disabled'
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class UsableChanges(Changes):
- pass
-
-
-class ReportableChanges(Changes):
- @property
- def console_access(self):
- if self._values['console_access'] is None:
- return None
- if self._values['console_access'] == 'tmsh':
- return 'yes'
- if self._values['console_access'] == 'disabled':
- return 'no'
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
- @property
- def description(self):
- result = cmp_str_with_none(self.want.description, self.have.description)
- return result
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(params=self.module.params)
- self.have = ApiParameters()
- self.changes = UsableChanges()
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.client.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def exec_module(self):
- result = dict()
-
- changed = self.update()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def update(self):
- self.have = self.read_current_from_device()
- if not self.should_update():
- return False
- if self.module.check_mode:
- return True
- self.update_on_device()
- return True
-
- def update_on_device(self):
- params = self.changes.api_params()
- uri = "https://{0}:{1}/mgmt/tm/auth/remote-user/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/auth/remote-user/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return ApiParameters(params=response)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- self.choices = [
- 'acceleration-policy-editor',
- 'admin',
- 'application-editor',
- 'auditor',
- 'certificate-manager',
- 'firewall-manager',
- 'fraud-protection-manager',
- 'guest',
- 'irule-manager',
- 'manager',
- 'no-access',
- 'operator',
- 'resource-admin',
- 'user-manager',
- 'web-application-security-administrator',
- 'web-application-security-editor'
- ]
- argument_spec = dict(
- default_role=dict(
- choices=self.choices
- ),
- default_partition=dict(),
- console_access=dict(type='bool'),
- description=dict()
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
- self.required_one_of = [
- ['default_role', 'default_partition']
- ]
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode,
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_routedomain.py b/lib/ansible/modules/network/f5/bigip_routedomain.py
deleted file mode 100644
index caf680f318..0000000000
--- a/lib/ansible/modules/network/f5/bigip_routedomain.py
+++ /dev/null
@@ -1,731 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2016, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_routedomain
-short_description: Manage route domains on a BIG-IP
-description:
- - Manage route domains on a BIG-IP.
-version_added: 2.2
-options:
- name:
- description:
- - The name of the route domain.
- type: str
- version_added: 2.5
- bwc_policy:
- description:
- - The bandwidth controller for the route domain.
- type: str
- connection_limit:
- description:
- - The maximum number of concurrent connections allowed for the
- route domain. Setting this to C(0) turns off connection limits.
- type: int
- description:
- description:
- - Specifies descriptive text that identifies the route domain.
- type: str
- flow_eviction_policy:
- description:
- - The eviction policy to use with this route domain. Apply an eviction
- policy to provide customized responses to flow overflows and slow
- flows on the route domain.
- type: str
- id:
- description:
- - The unique identifying integer representing the route domain.
- - This field is required when creating a new route domain.
- - In version 2.5, this value is no longer used to reference a route domain when
- making modifications to it (for instance during update and delete operations).
- Instead, the C(name) parameter is used. In version 2.6, the C(name) value will
- become a required parameter.
- type: int
- parent:
- description:
- - Specifies the route domain the system searches when it cannot
- find a route in the configured domain.
- type: str
- partition:
- description:
- - Partition to create the route domain on. Partitions cannot be updated
- once they are created.
- type: str
- default: Common
- version_added: 2.5
- routing_protocol:
- description:
- - Dynamic routing protocols for the system to use in the route domain.
- type: list
- choices:
- - none
- - BFD
- - BGP
- - IS-IS
- - OSPFv2
- - OSPFv3
- - PIM
- - RIP
- - RIPng
- service_policy:
- description:
- - Service policy to associate with the route domain.
- type: str
- state:
- description:
- - Whether the route domain should exist or not.
- type: str
- choices:
- - present
- - absent
- default: present
- strict:
- description:
- - Specifies whether the system enforces cross-routing restrictions or not.
- type: bool
- vlans:
- description:
- - VLANs for the system to use in the route domain.
- type: list
- fw_enforced_policy:
- description:
- - Specifies AFM policy to be attached to route domain.
- type: str
- version_added: 2.8
-extends_documentation_fragment: f5
-author:
- - Tim Rupp (@caphrim007)
- - Wojciech Wypior (@wojtek0806)
-'''
-
-EXAMPLES = r'''
-- name: Create a route domain
- bigip_routedomain:
- name: foo
- id: 1234
- state: present
- provider:
- user: admin
- password: secret
- server: lb.mydomain.com
- delegate_to: localhost
-
-- name: Set VLANs on the route domain
- bigip_routedomain:
- name: bar
- state: present
- vlans:
- - net1
- - foo
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-'''
-
-RETURN = r'''
-id:
- description: The ID of the route domain that was changed.
- returned: changed
- type: int
- sample: 2
-description:
- description: The description of the route domain.
- returned: changed
- type: str
- sample: route domain foo
-strict:
- description: The new strict isolation setting.
- returned: changed
- type: str
- sample: enabled
-parent:
- description: The new parent route domain.
- returned: changed
- type: int
- sample: 0
-vlans:
- description: List of new VLANs the route domain is applied to.
- returned: changed
- type: list
- sample: ['/Common/http-tunnel', '/Common/socks-tunnel']
-routing_protocol:
- description: List of routing protocols applied to the route domain.
- returned: changed
- type: list
- sample: ['bfd', 'bgp']
-bwc_policy:
- description: The new bandwidth controller.
- returned: changed
- type: str
- sample: /Common/foo
-connection_limit:
- description: The new connection limit for the route domain.
- returned: changed
- type: int
- sample: 100
-flow_eviction_policy:
- description: The new eviction policy to use with this route domain.
- returned: changed
- type: str
- sample: /Common/default-eviction-policy
-service_policy:
- description: The new service policy to use with this route domain.
- returned: changed
- type: str
- sample: /Common-my-service-policy
-fw_enforced_policy:
- description: Specfies AFM policy to be attached to route domain.
- returned: changed
- type: str
- sample: /Common/afm-blocking-policy
-'''
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.basic import env_fallback
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import fq_name
- from library.module_utils.network.f5.common import transform_name
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.compare import cmp_simple_list
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import fq_name
- from ansible.module_utils.network.f5.common import transform_name
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.compare import cmp_simple_list
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'connectionLimit': 'connection_limit',
- 'servicePolicy': 'service_policy',
- 'bwcPolicy': 'bwc_policy',
- 'flowEvictionPolicy': 'flow_eviction_policy',
- 'routingProtocol': 'routing_protocol',
- 'fwEnforcedPolicy': 'fw_enforced_policy',
- 'fwEnforcedPolicyReference': 'fw_policy_link',
- }
-
- api_attributes = [
- 'connectionLimit',
- 'description',
- 'strict',
- 'parent',
- 'servicePolicy',
- 'bwcPolicy',
- 'flowEvictionPolicy',
- 'routingProtocol',
- 'vlans',
- 'id',
- 'fwEnforcedPolicy',
- 'fwEnforcedPolicyReference',
- ]
-
- returnables = [
- 'description',
- 'strict',
- 'parent',
- 'service_policy',
- 'bwc_policy',
- 'flow_eviction_policy',
- 'routing_protocol',
- 'vlans',
- 'connection_limit',
- 'id',
- ]
-
- updatables = [
- 'description',
- 'strict',
- 'parent',
- 'service_policy',
- 'bwc_policy',
- 'flow_eviction_policy',
- 'routing_protocol',
- 'vlans',
- 'connection_limit',
- 'id',
- 'fw_enforced_policy',
- 'fw_policy_link',
- ]
-
- @property
- def connection_limit(self):
- if self._values['connection_limit'] is None:
- return None
- return int(self._values['connection_limit'])
-
- @property
- def id(self):
- if self._values['id'] is None:
- return None
- return int(self._values['id'])
-
-
-class ApiParameters(Parameters):
- @property
- def strict(self):
- if self._values['strict'] is None:
- return None
- if self._values['strict'] == 'enabled':
- return True
- return False
-
- @property
- def domains(self):
- domains = self.read_domains_from_device()
- result = [x['fullPath'] for x in domains['items']]
- return result
-
- def read_domains_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/net/route-domain/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return response
-
-
-class ModuleParameters(Parameters):
- @property
- def bwc_policy(self):
- if self._values['bwc_policy'] is None:
- return None
- return fq_name(self.partition, self._values['bwc_policy'])
-
- @property
- def flow_eviction_policy(self):
- if self._values['flow_eviction_policy'] is None:
- return None
- return fq_name(self.partition, self._values['flow_eviction_policy'])
-
- @property
- def service_policy(self):
- if self._values['service_policy'] is None:
- return None
- return fq_name(self.partition, self._values['service_policy'])
-
- @property
- def parent(self):
- if self._values['parent'] is None:
- return None
- result = fq_name(self.partition, self._values['parent'])
- return result
-
- @property
- def vlans(self):
- if self._values['vlans'] is None:
- return None
- if len(self._values['vlans']) == 1 and self._values['vlans'][0] == '':
- return ''
- return [fq_name(self.partition, x) for x in self._values['vlans']]
-
- @property
- def name(self):
- if self._values['name'] is None:
- return str(self.id)
- return self._values['name']
-
- @property
- def routing_protocol(self):
- if self._values['routing_protocol'] is None:
- return None
- if len(self._values['routing_protocol']) == 1 and self._values['routing_protocol'][0] in ['', 'none']:
- return ''
- return self._values['routing_protocol']
-
- @property
- def fw_enforced_policy(self):
- if self._values['fw_enforced_policy'] is None:
- return None
- if self._values['fw_enforced_policy'] in ['none', '']:
- return None
- name = self._values['fw_enforced_policy']
- return fq_name(self.partition, name)
-
- @property
- def fw_policy_link(self):
- policy = self.fw_enforced_policy
- if policy is None:
- return None
- tmp = policy.split('/')
- link = dict(link='https://localhost/mgmt/tm/security/firewall/policy/~{0}~{1}'.format(tmp[1], tmp[2]))
- return link
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class UsableChanges(Changes):
- @property
- def strict(self):
- if self._values['strict'] is None:
- return None
- if self._values['strict']:
- return 'enabled'
- return 'disabled'
-
-
-class ReportableChanges(Changes):
- @property
- def strict(self):
- if self._values['strict'] is None:
- return None
- if self._values['strict'] == 'enabled':
- return 'yes'
- return 'no'
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
- @property
- def routing_protocol(self):
- return cmp_simple_list(self.want.routing_protocol, self.have.routing_protocol)
-
- @property
- def vlans(self):
- return cmp_simple_list(self.want.vlans, self.have.vlans)
-
- @property
- def fw_policy_link(self):
- if self.want.fw_enforced_policy is None:
- return None
- if self.want.fw_enforced_policy == self.have.fw_enforced_policy:
- return None
- if self.want.fw_policy_link != self.have.fw_policy_link:
- return self.want.fw_policy_link
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(params=self.module.params, client=self.client)
- self.have = ApiParameters(client=self.client)
- self.changes = UsableChanges()
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = UsableChanges(params=changed)
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def exec_module(self):
- changed = False
- result = dict()
- state = self.want.state
-
- if state == "present":
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.client.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def present(self):
- if self.exists():
- return self.update()
- else:
- return self.create()
-
- def absent(self):
- if self.exists():
- return self.remove()
- return False
-
- def update(self):
- self.have = self.read_current_from_device()
- if not self.should_update():
- return False
- if self.want.parent and self.want.parent not in self.have.domains:
- raise F5ModuleError(
- "The parent route domain was not found."
- )
- if self.module.check_mode:
- return True
- self.update_on_device()
- return True
-
- def remove(self):
- if self.module.check_mode:
- return True
- self.remove_from_device()
- if self.exists():
- raise F5ModuleError("Failed to delete the resource.")
- return True
-
- def create(self):
- if self.want.id is None:
- raise F5ModuleError(
- "The 'id' parameter is required when creating new route domains."
- )
- if self.want.parent and self.want.parent not in self.have.domains:
- raise F5ModuleError(
- "The parent route domain was not found."
- )
- self._set_changed_options()
- if self.module.check_mode:
- return True
- self.create_on_device()
- return True
-
- def exists(self):
- uri = "https://{0}:{1}/mgmt/tm/net/route-domain/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name),
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def create_on_device(self):
- params = self.changes.api_params()
- params['name'] = self.want.name
- params['partition'] = self.want.partition
- uri = "https://{0}:{1}/mgmt/tm/net/route-domain/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- if self.want.fw_enforced_policy:
- payload = dict(
- fwEnforcedPolicy=self.want.fw_enforced_policy,
- fwEnforcedPolicyReference=self.want.fw_policy_link
- )
- uri = "https://{0}:{1}/mgmt/tm/net/route-domain/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name),
- )
- resp = self.client.api.patch(uri, json=payload)
-
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return True
-
- def update_on_device(self):
- params = self.changes.api_params()
- uri = "https://{0}:{1}/mgmt/tm/net/route-domain/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name),
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def remove_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/net/route-domain/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name),
- )
- response = self.client.api.delete(uri)
- if response.status == 200:
- return True
- raise F5ModuleError(response.content)
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/net/route-domain/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name),
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return ApiParameters(params=response, client=self.client)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- name=dict(),
- id=dict(type='int'),
- description=dict(),
- strict=dict(type='bool'),
- parent=dict(),
- vlans=dict(type='list'),
- routing_protocol=dict(
- type='list',
- choices=['BFD', 'BGP', 'IS-IS', 'OSPFv2', 'OSPFv3', 'PIM', 'RIP', 'RIPng', 'none']
- ),
- bwc_policy=dict(),
- connection_limit=dict(type='int'),
- flow_eviction_policy=dict(),
- service_policy=dict(),
- fw_enforced_policy=dict(),
- partition=dict(
- default='Common',
- fallback=(env_fallback, ['F5_PARTITION'])
- ),
- state=dict(
- default='present',
- choices=['present', 'absent']
- )
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
- self.required_one_of = [
- ['name', 'id']
- ]
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode,
- required_one_of=spec.required_one_of
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_selfip.py b/lib/ansible/modules/network/f5/bigip_selfip.py
deleted file mode 100644
index 2f2bc5f648..0000000000
--- a/lib/ansible/modules/network/f5/bigip_selfip.py
+++ /dev/null
@@ -1,853 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2016, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['stableinterface'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_selfip
-short_description: Manage Self-IPs on a BIG-IP system
-description:
- - Manage Self-IPs on a BIG-IP system.
-version_added: 2.2
-options:
- address:
- description:
- - The IP addresses for the new self IP. This value is ignored upon update
- as addresses themselves cannot be changed after they are created.
- - This value is required when creating new self IPs.
- type: str
- allow_service:
- description:
- - Configure port lockdown for the Self IP. By default, the Self IP has a
- "default deny" policy. This can be changed to allow TCP and UDP ports
- as well as specific protocols. This list should contain C(protocol):C(port)
- values.
- type: list
- name:
- description:
- - The self IP to create.
- - If this parameter is not specified, then it will default to the value supplied
- in the C(address) parameter.
- type: str
- required: True
- description:
- description:
- - Description of the traffic selector.
- type: str
- version_added: 2.8
- netmask:
- description:
- - The netmask for the self IP. When creating a new Self IP, this value
- is required.
- type: str
- state:
- description:
- - When C(present), guarantees that the Self-IP exists with the provided
- attributes.
- - When C(absent), removes the Self-IP from the system.
- type: str
- choices:
- - absent
- - present
- default: present
- traffic_group:
- description:
- - The traffic group for the Self IP addresses in an active-active,
- redundant load balancer configuration. When creating a new Self IP, if
- this value is not specified, the default of C(/Common/traffic-group-local-only)
- will be used.
- type: str
- vlan:
- description:
- - The VLAN that the new self IPs will be on. When creating a new Self
- IP, this value is required.
- type: str
- route_domain:
- description:
- - The route domain id of the system. When creating a new Self IP, if
- this value is not specified, a default value of C(0) will be used.
- - This value cannot be changed after it is set.
- type: int
- version_added: 2.3
- partition:
- description:
- - Device partition to manage resources on. You can set different partitions
- for Self IPs, but the address used may not match any other address used
- by a Self IP. In that sense, Self IPs are not isolated by partitions as
- other resources on a BIG-IP are.
- type: str
- default: Common
- version_added: 2.5
-extends_documentation_fragment: f5
-author:
- - Tim Rupp (@caphrim007)
- - Wojciech Wypior (@wojtek0806)
-'''
-
-EXAMPLES = r'''
-- name: Create Self IP
- bigip_selfip:
- address: 10.10.10.10
- name: self1
- netmask: 255.255.255.0
- vlan: vlan1
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-
-- name: Create Self IP with a Route Domain
- bigip_selfip:
- name: self1
- address: 10.10.10.10
- netmask: 255.255.255.0
- vlan: vlan1
- route_domain: 10
- allow_service: default
- provider:
- server: lb.mydomain.com
- user: admin
- password: secret
- delegate_to: localhost
-
-- name: Delete Self IP
- bigip_selfip:
- name: self1
- state: absent
- provider:
- user: admin
- password: secret
- server: lb.mydomain.com
- delegate_to: localhost
-
-- name: Allow management web UI to be accessed on this Self IP
- bigip_selfip:
- name: self1
- state: absent
- allow_service:
- - tcp:443
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-
-- name: Allow HTTPS and SSH access to this Self IP
- bigip_selfip:
- name: self1
- state: absent
- allow_service:
- - tcp:443
- - tcp:22
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-
-- name: Allow all services access to this Self IP
- bigip_selfip:
- name: self1
- state: absent
- allow_service:
- - all
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-
-- name: Allow only GRE and IGMP protocols access to this Self IP
- bigip_selfip:
- name: self1
- state: absent
- allow_service:
- - gre:0
- - igmp:0
- provider:
- user: admin
- password: secret
- server: lb.mydomain.com
- delegate_to: localhost
-
-- name: Allow all TCP, but no other protocols access to this Self IP
- bigip_selfip:
- name: self1
- state: absent
- allow_service:
- - tcp:0
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-'''
-
-RETURN = r'''
-allow_service:
- description: Services that allowed via this Self IP
- returned: changed
- type: list
- sample: ['igmp:0','tcp:22','udp:53']
-address:
- description: The address for the Self IP
- returned: changed
- type: str
- sample: 192.0.2.10
-name:
- description: The name of the Self IP
- returned: created
- type: str
- sample: self1
-netmask:
- description: The netmask of the Self IP
- returned: changed
- type: str
- sample: 255.255.255.0
-traffic_group:
- description: The traffic group that the Self IP is a member of
- returned: changed
- type: str
- sample: traffic-group-local-only
-vlan:
- description: The VLAN set on the Self IP
- returned: changed
- type: str
- sample: vlan1
-'''
-
-import re
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.basic import env_fallback
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import fq_name
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.common import transform_name
- from library.module_utils.network.f5.ipaddress import is_valid_ip
- from library.module_utils.network.f5.ipaddress import ipv6_netmask_to_cidr
- from library.module_utils.compat.ipaddress import ip_address
- from library.module_utils.compat.ipaddress import ip_network
- from library.module_utils.compat.ipaddress import ip_interface
- from library.module_utils.network.f5.compare import cmp_str_with_none
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import fq_name
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.common import transform_name
- from ansible.module_utils.network.f5.ipaddress import is_valid_ip
- from ansible.module_utils.network.f5.ipaddress import ipv6_netmask_to_cidr
- from ansible.module_utils.compat.ipaddress import ip_address
- from ansible.module_utils.compat.ipaddress import ip_network
- from ansible.module_utils.compat.ipaddress import ip_interface
- from ansible.module_utils.network.f5.compare import cmp_str_with_none
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'trafficGroup': 'traffic_group',
- 'allowService': 'allow_service',
- }
-
- updatables = [
- 'traffic_group',
- 'allow_service',
- 'vlan',
- 'netmask',
- 'address',
- 'description',
- ]
-
- returnables = [
- 'traffic_group',
- 'allow_service',
- 'vlan',
- 'route_domain',
- 'netmask',
- 'address',
- 'description',
- ]
-
- api_attributes = [
- 'trafficGroup',
- 'allowService',
- 'vlan',
- 'address',
- 'description',
- ]
-
- @property
- def vlan(self):
- if self._values['vlan'] is None:
- return None
- return fq_name(self.partition, self._values['vlan'])
-
-
-class ModuleParameters(Parameters):
- @property
- def address(self):
- address = "{0}%{1}/{2}".format(
- self.ip, self.route_domain, self.netmask
- )
- return address
-
- @property
- def ip(self):
- if self._values['address'] is None:
- return None
- if is_valid_ip(self._values['address']):
- return self._values['address']
- else:
- raise F5ModuleError(
- 'The provided address is not a valid IP address'
- )
-
- @property
- def traffic_group(self):
- if self._values['traffic_group'] is None:
- return None
- return fq_name(self.partition, self._values['traffic_group'])
-
- @property
- def route_domain(self):
- if self._values['route_domain'] is None:
- return None
- result = int(self._values['route_domain'])
- return result
-
- @property
- def netmask(self):
- if self._values['netmask'] is None:
- return None
- result = -1
- try:
- result = int(self._values['netmask'])
- if 0 < result < 256:
- pass
- except ValueError:
- if is_valid_ip(self._values['netmask']):
- addr = ip_address(u'{0}'.format(str(self._values['netmask'])))
- if addr.version == 4:
- ip = ip_network(u'0.0.0.0/%s' % str(self._values['netmask']))
- result = ip.prefixlen
- else:
- result = ipv6_netmask_to_cidr(self._values['netmask'])
- if result < 0:
- raise F5ModuleError(
- 'The provided netmask {0} is neither in IP or CIDR format'.format(result)
- )
- return result
-
- @property
- def allow_service(self):
- """Verifies that a supplied service string has correct format
-
- The string format for port lockdown is PROTOCOL:PORT. This method
- will verify that the provided input matches the allowed protocols
- and the port ranges before submitting to BIG-IP.
-
- The only allowed exceptions to this rule are the following values
-
- * all
- * default
- * none
-
- These are special cases that are handled differently in the API.
- "all" is set as a string, "default" is set as a one item list, and
- "none" removes the key entirely from the REST API.
-
- :raises F5ModuleError:
- """
- if self._values['allow_service'] is None:
- return None
- result = []
- allowed_protocols = [
- 'eigrp', 'egp', 'gre', 'icmp', 'igmp', 'igp', 'ipip',
- 'l2tp', 'ospf', 'pim', 'tcp', 'udp'
- ]
- special_protocols = [
- 'all', 'none', 'default'
- ]
- for svc in self._values['allow_service']:
- if svc in special_protocols:
- result = [svc]
- break
- elif svc in allowed_protocols:
- full_service = '{0}:0'.format(svc)
- result.append(full_service)
- else:
- tmp = svc.split(':')
- if tmp[0] not in allowed_protocols:
- raise F5ModuleError(
- "The provided protocol '%s' is invalid" % (tmp[0])
- )
- try:
- port = int(tmp[1])
- except Exception:
- raise F5ModuleError(
- "The provided port '%s' is not a number" % (tmp[1])
- )
-
- if port < 0 or port > 65535:
- raise F5ModuleError(
- "The provided port '{0}' must be between 0 and 65535".format(port)
- )
- else:
- result.append(svc)
- result = sorted(list(set(result)))
- return result
-
- @property
- def description(self):
- if self._values['description'] is None:
- return None
- elif self._values['description'] in ['none', '']:
- return ''
- return self._values['description']
-
-
-class ApiParameters(Parameters):
- @property
- def allow_service(self):
- if self._values['allow_service'] is None:
- return None
- if self._values['allow_service'] == 'all':
- self._values['allow_service'] = ['all']
- return sorted(self._values['allow_service'])
-
- @property
- def destination_ip(self):
- if self._values['address'] is None:
- return None
- try:
- pattern = r'(?P<rd>%[0-9]+)'
- addr = re.sub(pattern, '', self._values['address'])
- ip = ip_interface(u'{0}'.format(addr))
- return ip.with_prefixlen
- except ValueError:
- raise F5ModuleError(
- "The provided destination is not an IP address"
- )
-
- @property
- def netmask(self):
- ip = ip_interface(self.destination_ip)
- return int(ip.network.prefixlen)
-
- @property
- def ip(self):
- result = ip_interface(self.destination_ip)
- return str(result.ip)
-
- @property
- def description(self):
- if self._values['description'] in [None, 'none']:
- return None
- return self._values['description']
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class UsableChanges(Changes):
- @property
- def allow_service(self):
- if self._values['allow_service'] is None:
- return None
- if self._values['allow_service'] == ['all']:
- return 'all'
- return sorted(self._values['allow_service'])
-
-
-class ReportableChanges(Changes):
- pass
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
- @property
- def address(self):
- return None
-
- @property
- def allow_service(self):
- """Returns services formatted for consumption by f5-sdk update
-
- The BIG-IP endpoint for services takes different values depending on
- what you want the "allowed services" to be. It can be any of the
- following
-
- - a list containing "protocol:port" values
- - the string "all"
- - a null value, or None
-
- This is a convenience function to massage the values the user has
- supplied so that they are formatted in such a way that BIG-IP will
- accept them and apply the specified policy.
- """
- if self.want.allow_service is None:
- return None
- result = self.want.allow_service
- if result[0] == 'none' and self.have.allow_service is None:
- return None
- elif self.have.allow_service is None:
- return result
- elif result[0] == 'all' and self.have.allow_service[0] != 'all':
- return ['all']
- elif result[0] == 'none':
- return []
- elif set(self.want.allow_service) != set(self.have.allow_service):
- return result
-
- @property
- def netmask(self):
- if self.want.netmask is None:
- return None
- ip = self.have.ip
- if is_valid_ip(ip):
- if self.want.route_domain is not None:
- want = "{0}%{1}/{2}".format(ip, self.want.route_domain, self.want.netmask)
- have = "{0}%{1}/{2}".format(ip, self.want.route_domain, self.have.netmask)
- elif self.have.route_domain is not None:
- want = "{0}%{1}/{2}".format(ip, self.have.route_domain, self.want.netmask)
- have = "{0}%{1}/{2}".format(ip, self.have.route_domain, self.have.netmask)
- else:
- want = "{0}/{1}".format(ip, self.want.netmask)
- have = "{0}/{1}".format(ip, self.have.netmask)
- if want != have:
- return want
- else:
- raise F5ModuleError(
- 'The provided address/netmask value "{0}" was invalid'.format(self.have.ip)
- )
-
- @property
- def traffic_group(self):
- if self.want.traffic_group != self.have.traffic_group:
- return self.want.traffic_group
-
- @property
- def description(self):
- return cmp_str_with_none(self.want.description, self.have.description)
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.have = None
- self.want = ModuleParameters(params=self.module.params)
- self.changes = UsableChanges()
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = UsableChanges(params=changed)
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = ApiParameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if k in ['netmask']:
- changed['address'] = change
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.client.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def exec_module(self):
- changed = False
- result = dict()
- state = self.want.state
-
- if state == "present":
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def present(self):
- if self.exists():
- changed = self.update()
- else:
- changed = self.create()
- return changed
-
- def absent(self):
- changed = False
- if self.exists():
- changed = self.remove()
- return changed
-
- def remove(self):
- if self.module.check_mode:
- return True
- self.remove_from_device()
- if self.exists():
- raise F5ModuleError("Failed to delete the Self IP")
- return True
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def update(self):
- self.have = self.read_current_from_device()
- if not self.should_update():
- return False
- if self.module.check_mode:
- return True
- self.update_on_device()
- return True
-
- def create(self):
- if self.want.address is None or self.want.netmask is None:
- raise F5ModuleError(
- 'An address and a netmask must be specified'
- )
- if self.want.vlan is None:
- raise F5ModuleError(
- 'A VLAN name must be specified'
- )
- if self.want.route_domain is None:
- rd = self.read_partition_default_route_domain_from_device()
- self.want.update({'route_domain': rd})
-
- if self.want.traffic_group is None:
- self.want.update({'traffic_group': '/Common/traffic-group-local-only'})
- if self.want.route_domain is None:
- self.want.update({'route_domain': 0})
- if self.want.allow_service:
- if 'all' in self.want.allow_service:
- self.want.update(dict(allow_service=['all']))
- elif 'none' in self.want.allow_service:
- self.want.update(dict(allow_service=[]))
- elif 'default' in self.want.allow_service:
- self.want.update(dict(allow_service=['default']))
- self._set_changed_options()
- if self.module.check_mode:
- return True
- self.create_on_device()
- if self.exists():
- return True
- else:
- raise F5ModuleError("Failed to create the Self IP")
-
- def exists(self):
- uri = "https://{0}:{1}/mgmt/tm/net/self/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def create_on_device(self):
- params = self.changes.api_params()
- params['name'] = self.want.name
- params['partition'] = self.want.partition
- uri = "https://{0}:{1}/mgmt/tm/net/self/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def update_on_device(self):
- params = self.changes.api_params()
- uri = "https://{0}:{1}/mgmt/tm/net/self/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def remove_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/net/self/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.delete(uri)
- if resp.status == 200:
- return True
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/net/self/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return ApiParameters(params=response)
-
- def read_partition_default_route_domain_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/auth/partition/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- self.want.partition
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return int(response['defaultRouteDomain'])
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- address=dict(),
- allow_service=dict(type='list'),
- name=dict(required=True),
- netmask=dict(),
- traffic_group=dict(),
- vlan=dict(),
- route_domain=dict(type='int'),
- description=dict(),
- state=dict(
- default='present',
- choices=['present', 'absent']
- ),
- partition=dict(
- default='Common',
- fallback=(env_fallback, ['F5_PARTITION'])
- )
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_service_policy.py b/lib/ansible/modules/network/f5/bigip_service_policy.py
deleted file mode 100644
index 66ec65b97c..0000000000
--- a/lib/ansible/modules/network/f5/bigip_service_policy.py
+++ /dev/null
@@ -1,440 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_service_policy
-short_description: Manages service policies on a BIG-IP.
-description:
- - Service policies allow you to configure timers and port misuse rules,
- if enabled, on a per rule or per context basis.
-version_added: 2.6
-options:
- name:
- description:
- - Name of the service policy.
- required: True
- type: str
- description:
- description:
- - Description of the service policy.
- type: str
- timer_policy:
- description:
- - The timer policy to attach to the service policy.
- type: str
- port_misuse_policy:
- description:
- - The port misuse policy to attach to the service policy.
- - Requires that C(afm) be provisioned to use. If C(afm) is not provisioned, this parameter
- will be ignored.
- type: str
- state:
- description:
- - Whether the resource should exist or not.
- type: str
- choices:
- - present
- - absent
- default: present
- partition:
- description:
- - Device partition to manage resources on.
- type: str
- default: Common
-extends_documentation_fragment: f5
-author:
- - Tim Rupp (@caphrim007)
- - Wojciech Wypior (@wojtek0806)
-'''
-
-EXAMPLES = r'''
-- name: Create a service policy
- bigip_service_policy:
- name: foo
- timer_policy: timer1
- port_misuse_policy: misuse1
- timer_policy_enabled: yes
- port_misuse_policy_enabled: yes
- state: present
- provider:
- user: admin
- password: secret
- server: lb.mydomain.com
- delegate_to: localhost
-'''
-
-RETURN = r'''
-timer_policy:
- description: The new timer policy attached to the resource.
- returned: changed
- type: str
- sample: /Common/timer1
-port_misuse_policy:
- description: The new port misuse policy attached to the resource.
- returned: changed
- type: str
- sample: /Common/misuse1
-description:
- description: New description of the resource.
- returned: changed
- type: str
- sample: My service policy description
-'''
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.basic import env_fallback
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.common import fq_name
- from library.module_utils.network.f5.common import transform_name
- from library.module_utils.network.f5.icontrol import module_provisioned
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.common import fq_name
- from ansible.module_utils.network.f5.common import transform_name
- from ansible.module_utils.network.f5.icontrol import module_provisioned
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'portMisusePolicy': 'port_misuse_policy',
- 'timerPolicy': 'timer_policy',
- }
-
- api_attributes = [
- 'description',
- 'timerPolicy',
- 'portMisusePolicy',
- ]
-
- returnables = [
- 'description',
- 'timer_policy',
- 'port_misuse_policy',
- ]
-
- updatables = [
- 'description',
- 'timer_policy',
- 'port_misuse_policy',
- ]
-
-
-class ApiParameters(Parameters):
- pass
-
-
-class ModuleParameters(Parameters):
- @property
- def timer_policy(self):
- if self._values['timer_policy'] is None:
- return None
- if self._values['timer_policy'] == '':
- return ''
- return fq_name(self.partition, self._values['timer_policy'])
-
- @property
- def port_misuse_policy(self):
- if self._values['port_misuse_policy'] is None:
- return None
- if self._values['port_misuse_policy'] == '':
- return ''
- return fq_name(self.partition, self._values['port_misuse_policy'])
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class UsableChanges(Changes):
- pass
-
-
-class ReportableChanges(Changes):
- pass
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(params=self.module.params)
- self.have = ApiParameters()
- self.changes = UsableChanges()
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = UsableChanges(params=changed)
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def exec_module(self):
- changed = False
- result = dict()
- state = self.want.state
-
- if state == "present":
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.client.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def present(self):
- if self.exists():
- return self.update()
- else:
- return self.create()
-
- def absent(self):
- if self.exists():
- return self.remove()
- return False
-
- def update(self):
- self.have = self.read_current_from_device()
- if not self.should_update():
- return False
- if self.want.port_misuse_policy:
- if not module_provisioned(self.client, 'afm'):
- raise F5ModuleError(
- "To configure a 'port_misuse_policy', you must have AFM provisioned."
- )
- if self.module.check_mode:
- return True
- self.update_on_device()
- return True
-
- def remove(self):
- if self.module.check_mode:
- return True
- self.remove_from_device()
- if self.exists():
- raise F5ModuleError("Failed to delete the resource.")
- return True
-
- def create(self):
- self._set_changed_options()
- if self.want.port_misuse_policy:
- if not module_provisioned(self.client, 'afm'):
- raise F5ModuleError(
- "To configure a 'port_misuse_policy', you must have AFM provisioned."
- )
- if self.module.check_mode:
- return True
- self.create_on_device()
- return True
-
- def exists(self):
- uri = "https://{0}:{1}/mgmt/tm/net/service-policy/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def create_on_device(self):
- params = self.changes.api_params()
- params['name'] = self.want.name
- params['partition'] = self.want.partition
- uri = "https://{0}:{1}/mgmt/tm/net/service-policy/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def update_on_device(self):
- params = self.changes.api_params()
- uri = "https://{0}:{1}/mgmt/tm/net/service-policy/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def remove_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/net/service-policy/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- response = self.client.api.delete(uri)
- if response.status == 200:
- return True
- raise F5ModuleError(response.content)
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/net/service-policy/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return ApiParameters(params=response)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- name=dict(),
- description=dict(),
- timer_policy=dict(),
- port_misuse_policy=dict(),
- state=dict(
- default='present',
- choices=['absent', 'present']
- ),
- partition=dict(
- default='Common',
- fallback=(env_fallback, ['F5_PARTITION'])
- )
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_smtp.py b/lib/ansible/modules/network/f5/bigip_smtp.py
deleted file mode 100644
index eb82572685..0000000000
--- a/lib/ansible/modules/network/f5/bigip_smtp.py
+++ /dev/null
@@ -1,568 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_smtp
-short_description: Manages SMTP settings on the BIG-IP
-description:
- - Allows configuring of the BIG-IP to send mail via an SMTP server by
- configuring the parameters of an SMTP server.
-version_added: 2.6
-options:
- name:
- description:
- - Specifies the name of the SMTP server configuration.
- type: str
- required: True
- partition:
- description:
- - Device partition to manage resources on.
- type: str
- default: Common
- smtp_server:
- description:
- - SMTP server host name in the format of a fully qualified domain name.
- - This value is required when create a new SMTP configuration.
- type: str
- smtp_server_port:
- description:
- - Specifies the SMTP port number.
- - When creating a new SMTP configuration, the default is C(25) when
- C(encryption) is C(none) or C(tls). The default is C(465) when C(ssl) is selected.
- type: int
- local_host_name:
- description:
- - Host name used in SMTP headers in the format of a fully qualified
- domain name. This setting does not refer to the BIG-IP system's hostname.
- type: str
- from_address:
- description:
- - Email address that the email is being sent from. This is the "Reply-to"
- address that the recipient sees.
- type: str
- encryption:
- description:
- - Specifies whether the SMTP server requires an encrypted connection in
- order to send mail.
- type: str
- choices:
- - none
- - ssl
- - tls
- authentication:
- description:
- - Credentials can be set on an SMTP server's configuration even if that
- authentication is not used (think staging configs or emergency changes).
- This parameter acts as a switch to make the specified C(smtp_server_username)
- and C(smtp_server_password) parameters active or not.
- - When C(yes), the authentication parameters will be active.
- - When C(no), the authentication parameters will be inactive.
- type: bool
- smtp_server_username:
- description:
- - User name that the SMTP server requires when validating a user.
- type: str
- smtp_server_password:
- description:
- - Password that the SMTP server requires when validating a user.
- type: str
- state:
- description:
- - When C(present), ensures that the SMTP configuration exists.
- - When C(absent), ensures that the SMTP configuration does not exist.
- type: str
- choices:
- - present
- - absent
- default: present
- update_password:
- description:
- - Passwords are stored encrypted, so the module cannot know if the supplied
- C(smtp_server_password) is the same or different than the existing password.
- This parameter controls the updating of the C(smtp_server_password)
- credential.
- - When C(always), will always update the password.
- - When C(on_create), will only set the password for newly created SMTP server
- configurations.
- type: str
- choices:
- - always
- - on_create
- default: always
-extends_documentation_fragment: f5
-author:
- - Tim Rupp (@caphrim007)
-'''
-
-EXAMPLES = r'''
-- name: Create a base SMTP server configuration
- bigip_smtp:
- name: my-smtp
- smtp_server: 1.1.1.1
- smtp_server_username: mail-admin
- smtp_server_password: mail-secret
- local_host_name: smtp.mydomain.com
- from_address: no-reply@mydomain.com
- state: present
- provider:
- user: admin
- password: secret
- server: lb.mydomain.com
- delegate_to: localhost
-'''
-
-RETURN = r'''
-smtp_server:
- description: The new C(smtp_server) value of the SMTP configuration.
- returned: changed
- type: str
- sample: mail.mydomain.com
-smtp_server_port:
- description: The new C(smtp_server_port) value of the SMTP configuration.
- returned: changed
- type: int
- sample: 25
-local_host_name:
- description: The new C(local_host_name) value of the SMTP configuration.
- returned: changed
- type: str
- sample: smtp.mydomain.com
-from_address:
- description: The new C(from_address) value of the SMTP configuration.
- returned: changed
- type: str
- sample: no-reply@mydomain.com
-encryption:
- description: The new C(encryption) value of the SMTP configuration.
- returned: changed
- type: str
- sample: tls
-authentication:
- description: Whether the authentication parameters are active or not.
- returned: changed
- type: bool
- sample: yes
-'''
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.basic import env_fallback
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.common import transform_name
- from library.module_utils.network.f5.common import is_valid_hostname
- from library.module_utils.network.f5.ipaddress import is_valid_ip
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.common import transform_name
- from ansible.module_utils.network.f5.common import is_valid_hostname
- from ansible.module_utils.network.f5.ipaddress import is_valid_ip
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'username': 'smtp_server_username',
- 'passwordEncrypted': 'smtp_server_password',
- 'localHostName': 'local_host_name',
- 'smtpServerHostName': 'smtp_server',
- 'smtpServerPort': 'smtp_server_port',
- 'encryptedConnection': 'encryption',
- 'authenticationEnabled': 'authentication_enabled',
- 'authenticationDisabled': 'authentication_disabled',
- 'fromAddress': 'from_address',
- }
-
- api_attributes = [
- 'username',
- 'passwordEncrypted',
- 'localHostName',
- 'smtpServerHostName',
- 'smtpServerPort',
- 'encryptedConnection',
- 'authenticationEnabled',
- 'authenticationDisabled',
- 'fromAddress',
- ]
-
- returnables = [
- 'smtp_server_username',
- 'smtp_server_password',
- 'local_host_name',
- 'smtp_server',
- 'smtp_server_port',
- 'encryption',
- 'authentication',
- 'from_address',
- ]
-
- updatables = [
- 'smtp_server_username',
- 'smtp_server_password',
- 'local_host_name',
- 'smtp_server',
- 'smtp_server_port',
- 'encryption',
- 'authentication',
- 'from_address',
- ]
-
-
-class ApiParameters(Parameters):
- pass
-
-
-class ModuleParameters(Parameters):
- @property
- def local_host_name(self):
- if self._values['local_host_name'] is None:
- return None
- if is_valid_ip(self._values['local_host_name']):
- return self._values['local_host_name']
- elif is_valid_hostname(self._values['local_host_name']):
- # else fallback to checking reasonably well formatted hostnames
- return str(self._values['local_host_name'])
- raise F5ModuleError(
- "The provided 'local_host_name' value {0} is not a valid IP or hostname".format(
- str(self._values['local_host_name'])
- )
- )
-
- @property
- def authentication_enabled(self):
- if self._values['authentication'] is None:
- return None
- if self._values['authentication']:
- return True
-
- @property
- def authentication_disabled(self):
- if self._values['authentication'] is None:
- return None
- if not self._values['authentication']:
- return True
-
- @property
- def smtp_server_port(self):
- if self._values['smtp_server_port'] is None:
- return None
- return int(self._values['smtp_server_port'])
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class UsableChanges(Changes):
- pass
-
-
-class ReportableChanges(Changes):
- @property
- def smtp_server_password(self):
- return None
-
- @property
- def smtp_server_username(self):
- return None
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
- @property
- def smtp_server_password(self):
- if self.want.update_password == 'on_create':
- return None
- return self.want.smtp_server_password
-
- @property
- def authentication(self):
- if self.want.authentication_enabled:
- if self.want.authentication_enabled != self.have.authentication_enabled:
- return dict(
- authentication_enabled=self.want.authentication_enabled
- )
- if self.want.authentication_disabled:
- if self.want.authentication_disabled != self.have.authentication_disabled:
- return dict(
- authentication_disable=self.want.authentication_disabled
- )
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(params=self.module.params)
- self.have = ApiParameters()
- self.changes = UsableChanges()
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = UsableChanges(params=changed)
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def exec_module(self):
- changed = False
- result = dict()
- state = self.want.state
-
- if state == "present":
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.client.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def present(self):
- if self.exists():
- return self.update()
- else:
- return self.create()
-
- def absent(self):
- if self.exists():
- return self.remove()
- return False
-
- def update(self):
- self.have = self.read_current_from_device()
- if not self.should_update():
- return False
- if self.module.check_mode:
- return True
- self.update_on_device()
- return True
-
- def remove(self):
- if self.module.check_mode:
- return True
- self.remove_from_device()
- if self.exists():
- raise F5ModuleError("Failed to delete the resource.")
- return True
-
- def create(self):
- self._set_changed_options()
- if self.module.check_mode:
- return True
- self.create_on_device()
- return True
-
- def exists(self):
- uri = "https://{0}:{1}/mgmt/tm/sys/smtp-server/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def create_on_device(self):
- params = self.want.api_params()
- params['name'] = self.want.name
- params['partition'] = self.want.partition
- uri = "https://{0}:{1}/mgmt/tm/sys/smtp-server/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def update_on_device(self):
- params = self.want.api_params()
- uri = "https://{0}:{1}/mgmt/tm/sys/smtp-server/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def remove_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/sys/smtp-server/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.delete(uri)
- if resp.status == 200:
- return True
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/sys/smtp-server/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return ApiParameters(params=response)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- name=dict(required=True),
- smtp_server=dict(),
- smtp_server_port=dict(type='int'),
- smtp_server_username=dict(no_log=True),
- smtp_server_password=dict(no_log=True),
- local_host_name=dict(),
- encryption=dict(choices=['none', 'ssl', 'tls']),
- update_password=dict(
- default='always',
- choices=['always', 'on_create']
- ),
- from_address=dict(),
- authentication=dict(type='bool'),
- partition=dict(
- default='Common',
- fallback=(env_fallback, ['F5_PARTITION'])
- ),
- state=dict(
- default='present',
- choices=['present', 'absent']
- )
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_snat_pool.py b/lib/ansible/modules/network/f5/bigip_snat_pool.py
deleted file mode 100644
index 690a7ef500..0000000000
--- a/lib/ansible/modules/network/f5/bigip_snat_pool.py
+++ /dev/null
@@ -1,530 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2016, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['stableinterface'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_snat_pool
-short_description: Manage SNAT pools on a BIG-IP
-description:
- - Manage SNAT pools on a BIG-IP.
-version_added: 2.3
-options:
- members:
- description:
- - List of members to put in the SNAT pool. When a C(state) of present is
- provided, this parameter is required. Otherwise, it is optional.
- - The members can be either IP addresses, or names of the SNAT translation objects.
- type: list
- aliases:
- - member
- description:
- description:
- - A general description of the SNAT pool, provided by the user for their
- benefit. It is optional.
- type: str
- version_added: 2.9
- name:
- description:
- - The name of the SNAT pool.
- type: str
- required: True
- state:
- description:
- - Whether the SNAT pool should exist or not.
- type: str
- choices:
- - present
- - absent
- default: present
- partition:
- description:
- - Device partition to manage resources on.
- type: str
- default: Common
- version_added: 2.5
-notes:
- - When C(bigip_snat_pool) object is removed it also removes any associated C(bigip_snat_translation) objects.
- - This is a BIG-IP behavior not module behavior and it only occurs when the C(bigip_snat_translation) objects
- are also not referenced by another C(bigip_snat_pool).
-extends_documentation_fragment: f5
-author:
- - Tim Rupp (@caphrim007)
- - Wojciech Wypior (@wojtek0806)
-'''
-
-EXAMPLES = r'''
-- name: Add the SNAT pool 'my-snat-pool'
- bigip_snat_pool:
- name: my-snat-pool
- state: present
- members:
- - 10.10.10.10
- - 20.20.20.20
- provider:
- server: lb.mydomain.com
- user: admin
- password: secret
- delegate_to: localhost
-
-- name: Change the SNAT pool's members to a single member
- bigip_snat_pool:
- name: my-snat-pool
- state: present
- member: 30.30.30.30
- provider:
- server: lb.mydomain.com
- user: admin
- password: secret
- delegate_to: localhost
-
-- name: Remove the SNAT pool 'my-snat-pool'
- bigip_snat_pool:
- name: johnd
- state: absent
- provider:
- server: lb.mydomain.com
- user: admin
- password: secret
- delegate_to: localhost
-
-- name: Add the SNAT pool 'my-snat-pool' with a description
- bigip_snat_pool:
- name: my-snat-pool
- state: present
- members:
- - 10.10.10.10
- - 20.20.20.20
- description: A SNAT pool description
- provider:
- server: lb.mydomain.com
- user: admin
- password: secret
- delegate_to: localhost
-'''
-
-RETURN = r'''
-members:
- description:
- - List of members that are part of the SNAT pool.
- returned: changed and success
- type: list
- sample: "['10.10.10.10']"
-'''
-
-import re
-import os
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.basic import env_fallback
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import fq_name
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.common import transform_name
- from library.module_utils.network.f5.ipaddress import is_valid_ip
- from library.module_utils.network.f5.ipaddress import compress_address
- from library.module_utils.network.f5.compare import cmp_str_with_none
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import fq_name
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.common import transform_name
- from ansible.module_utils.network.f5.ipaddress import is_valid_ip
- from ansible.module_utils.network.f5.ipaddress import compress_address
- from ansible.module_utils.network.f5.compare import cmp_str_with_none
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {}
-
- updatables = [
- 'members',
- 'description',
- ]
-
- returnables = [
- 'members',
- 'description',
- ]
-
- api_attributes = [
- 'members',
- 'description',
- ]
-
-
-class ApiParameters(Parameters):
- pass
-
-
-class ModuleParameters(Parameters):
- def _clear_member_prefix(self, member):
- result = os.path.basename(member)
- return result
-
- def _format_member_address(self, member):
- if len(member.split('%')) > 1:
- address, rd = member.split('%')
- if is_valid_ip(address):
- result = '/{0}/{1}%{2}'.format(self.partition, compress_address(address), rd)
- return result
- else:
- if is_valid_ip(member):
- address = '/{0}/{1}'.format(self.partition, member)
- return address
- else:
- # names must start with alphabetic character, and can contain hyphens and underscores and numbers
- # no special characters are allowed
- pattern = re.compile(r'(?!-)[A-Z-].*(?<!-)$', re.IGNORECASE)
- if pattern.match(member):
- address = '/{0}/{1}'.format(self.partition, member)
- return address
- raise F5ModuleError(
- 'The provided member address: {0} is not a valid IP address or snat translation name'.format(member)
- )
-
- @property
- def members(self):
- if self._values['members'] is None:
- return None
- result = set()
- for member in self._values['members']:
- member = self._clear_member_prefix(member)
- address = self._format_member_address(member)
- result.update([address])
- return list(result)
-
- @property
- def description(self):
- if self._values['description'] is None:
- return None
- elif self._values['description'] in ['none', '']:
- return ''
- return self._values['description']
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- for returnable in self.returnables:
- try:
- result[returnable] = getattr(self, returnable)
- except Exception:
- pass
- result = self._filter_params(result)
- return result
-
-
-class UsableChanges(Changes):
- pass
-
-
-class ReportableChanges(Changes):
- pass
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
- @property
- def members(self):
- if self.want.members is None:
- return None
- if set(self.want.members) == set(self.have.members):
- return None
- result = list(set(self.want.members))
- return result
-
- @property
- def description(self):
- result = cmp_str_with_none(self.want.description, self.have.description)
- return result
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(params=self.module.params)
- self.have = ApiParameters()
- self.changes = UsableChanges()
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = UsableChanges(params=changed)
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def exec_module(self):
- changed = False
- result = dict()
- state = self.want.state
-
- if state == "present":
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
-
- if self.module._diff and self.have:
- result['diff'] = self.make_diff()
-
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
-
- return result
-
- def _grab_attr(self, item):
- result = dict()
- updatables = Parameters.updatables
- for k in updatables:
- if getattr(item, k) is not None:
- result[k] = getattr(item, k)
- return result
-
- def make_diff(self):
- result = dict(before=self._grab_attr(self.have), after=self._grab_attr(self.want))
- return result
-
- def present(self):
- if self.exists():
- return self.update()
- else:
- return self.create()
-
- def absent(self):
- changed = False
- if self.exists():
- changed = self.remove()
- return changed
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def update(self):
- self.have = self.read_current_from_device()
- if not self.should_update():
- return False
- if self.module.check_mode:
- return True
- self.update_on_device()
- return True
-
- def create(self):
- self._set_changed_options()
- if self.module.check_mode:
- return True
- self.create_on_device()
- if not self.exists():
- raise F5ModuleError("Failed to create the SNAT pool")
- return True
-
- def remove(self):
- if self.module.check_mode:
- return True
- self.remove_from_device()
- if self.exists():
- raise F5ModuleError("Failed to delete the SNAT pool")
- return True
-
- def exists(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/snatpool/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def create_on_device(self):
- params = self.changes.api_params()
- params['name'] = self.want.name
- params['partition'] = self.want.partition
- uri = "https://{0}:{1}/mgmt/tm/ltm/snatpool/".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return response['selfLink']
-
- def update_on_device(self):
- params = self.changes.api_params()
- uri = "https://{0}:{1}/mgmt/tm/ltm/snatpool/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def remove_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/snatpool/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- response = self.client.api.delete(uri)
- if response.status == 200:
- return True
- raise F5ModuleError(response.content)
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/snatpool/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- query = '?expandSubcollections=true'
- resp = self.client.api.get(uri + query)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return ApiParameters(params=response)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- name=dict(required=True),
- members=dict(
- type='list',
- aliases=['member']
- ),
- description=dict(),
- state=dict(
- default='present',
- choices=['absent', 'present']
- ),
- partition=dict(
- default='Common',
- fallback=(env_fallback, ['F5_PARTITION'])
- )
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
- self.required_if = [
- ['state', 'present', ['members']]
- ]
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode,
- required_if=spec.required_if
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_snat_translation.py b/lib/ansible/modules/network/f5/bigip_snat_translation.py
deleted file mode 100644
index e88199f0ba..0000000000
--- a/lib/ansible/modules/network/f5/bigip_snat_translation.py
+++ /dev/null
@@ -1,779 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2019, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_snat_translation
-short_description: Manage SNAT Translations on a BIG-IP
-description:
- - Manage SNAT Translations on a BIG-IP.
-version_added: 2.9
-options:
- address:
- description:
- - Specifies the IP address of the SNAT translation. When a C(state) of present, enabled, or disabled is
- provided, this parameter is required.
- - This parameter cannot be updated after it is set.
- type: str
- aliases:
- - ip
- arp:
- description:
- - If C(yes), specifies that the NAT sends ARP requests.
- type: bool
- connection_limit:
- description:
- - Specifies a limit on the number of connections a translation address must reach before it no longer
- initiates a connection. The default value of 0 indicates that the setting is disabled.
- - The accepted value range is C(0 - 65535).
- type: int
- description:
- description:
- - Description of snat-translation. C(none or '') will set to default description of null.
- type: str
- ip_idle_timeout:
- description:
- - Specifies the amount of time that connections to an IP address initiated using a SNAT address are
- allowed to remain idle before being automatically disconnected. C(indefinite) prevents the connection
- from timing out.
- - The accepted value range is C(0 - 4294967295) seconds, specifying C(indefinite) will
- set it to the maximum value.
- type: str
- name:
- description:
- - The name of SNAT translation.
- type: str
- required: True
- partition:
- description:
- - Device partition to manage resources on.
- - Required with state C(absent) when partition other than Common used.
- type: str
- state:
- description:
- - The SNAT translation state. If C(absent), delete the SNAT translation
- if it exists. C(present) creates the SNAT translation and enable it.
- If C(enabled), enable the SNAT translation if it exists. If C(disabled),
- create the SNAT translation if needed, and set state to C(disabled).
- type: str
- choices:
- - present
- - absent
- - enabled
- - disabled
- default: present
- tcp_idle_timeout:
- description:
- - Specifies the amount of time that TCP connections initiated using a SNAT address are allowed
- to remain idle before being automatically disconnected. C(indefinite) Prevents the
- connection from timing out.
- - The accepted value range is C(0 - 4294967295) seconds, specifying C(indefinite) will
- set it to the maximum value.
- type: str
- traffic_group:
- description:
- - The traffic group for the snat-translation address. When creating a new address,
- if this value is not specified, the default of C(/Common/traffic-group-1)
- will be used.
- type: str
- udp_idle_timeout:
- description:
- - Specifies the amount of time that UDP connections initiated using a SNAT address are allowed
- to remain idle before being automatically disconnected. C(indefinite) Prevents the connection
- from timing out.
- - The accepted value range is C(0 - 4294967295) seconds, specifying C(indefinite) will
- set it to the maximum value.
- type: str
-extends_documentation_fragment: f5
-author:
- - Greg Crosby (@crosbygw)
- - Wojciech Wypior (@wojtek0806)
-'''
-
-EXAMPLES = r'''
-- name: Create a SNAT translation 'my-snat-translation'
- bigip_snat_translation:
- name: my-snat-pool
- state: present
- address: 10.10.10.10
- provider:
- server: lb.mydomain.com
- user: admin
- password: secret
- delegate_to: localhost
-
-- name: Modify a SNAT translation 'my-snat-translation'
- bigip_snat_translation:
- name: my-snat-pool
- state: present
- address: 10.10.10.10
- arp: no
- connection_limit: 300
- ip_idle_timeout: 1800
- tcp_idle_timeout: 1800
- udp_idle_timeout: 1800
- provider:
- server: lb.mydomain.com
- user: admin
- password: secret
- delegate_to: localhost
-
-- name: Disable a SNAT translation 'my-snat-translation'
- bigip_snat_translation:
- name: my-snat-pool
- state: disabled
- address: 10.10.10.10
- arp: no
- connection_limit: 300
- ip_idle_timeout: 1800
- tcp_idle_timeout: 1800
- udp_idle_timeout: 1800
- provider:
- server: lb.mydomain.com
- user: admin
- password: secret
- delegate_to: localhost
-
-- name: Enable a SNAT translation 'my-snat-translation'
- bigip_snat_translation:
- name: my-snat-pool
- state: enabled
- address: 10.10.10.10
- arp: no
- connection_limit: 300
- ip_idle_timeout: 1800
- tcp_idle_timeout: 1800
- udp_idle_timeout: 1800
- provider:
- server: lb.mydomain.com
- user: admin
- password: secret
- delegate_to: localhost
-
-- name: Create using partition other then /Common on a SNAT translation 'my-new-snat-translation'
- bigip_snat_translation:
- name: my-new-snat-pool
- state: enabled
- address: 10.10.10.10
- arp: no
- connection_limit: 300
- ip_idle_timeout: 1800
- partition: ansible
- tcp_idle_timeout: 1800
- udp_idle_timeout: 1800
- provider:
- server: lb.mydomain.com
- user: admin
- password: secret
- delegate_to: localhost
-
-- name: Modify using traffic group other then /Common/traffic-group-1 on a SNAT translation 'my-new-snat-translation'
- bigip_snat_translation:
- name: my-new-snat-pool
- state: enabled
- address: 10.10.10.10
- arp: no
- connection_limit: 300
- ip_idle_timeout: 1800
- partition: ansible
- tcp_idle_timeout: 1800
- traffic_group: /Common/ansible
- udp_idle_timeout: 1800
- provider:
- server: lb.mydomain.com
- user: admin
- password: secret
- delegate_to: localhost
-
-'''
-
-RETURN = r'''
-address:
- description:
- - ip address used for SNAT translation.
- returned: changed and success
- type: str
- sample: "10.10.10.10"
-arp:
- description: Whether snat-translation send arp requests.
- returned: changed
- type: bool
- sample: yes
-connection_limit:
- description: The new connection limit of the virtual address.
- returned: changed
- type: int
- sample: 1000
-description:
- description: Description of the snat-translaiton.
- returned: changed
- type: str
- sample: My snat-translation
-ip_idle_timeout:
- description: IP idle timeout value for snat-translation.
- returned: changed
- type: str
- sample: 300
-state:
- description: The new state of the snat-translation.
- returned: changed
- type: str
- sample: disabled
-tcp_idle_timeout:
- description: TCP idle timeout value for snat-translation.
- returned: changed
- type: str
- sample: 1800
-traffic_group:
- description: Assigned traffic group.
- returned: changed
- type: str
- sample: /Common/traffic-group-1
-udp_idle_timeout:
- description: UDP idle timeout value for snat-translation.
- returned: changed
- type: str
- sample: indifinite
-'''
-
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.basic import env_fallback
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import fq_name
- from library.module_utils.network.f5.common import flatten_boolean
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.common import transform_name
- from library.module_utils.network.f5.ipaddress import is_valid_ip
- from library.module_utils.network.f5.ipaddress import compress_address
- from ansible.module_utils.network.f5.compare import cmp_str_with_none
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import fq_name
- from ansible.module_utils.network.f5.common import flatten_boolean
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.common import transform_name
- from ansible.module_utils.network.f5.ipaddress import is_valid_ip
- from ansible.module_utils.network.f5.ipaddress import compress_address
- from ansible.module_utils.network.f5.compare import cmp_str_with_none
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'connectionLimit': 'connection_limit',
- 'ipIdleTimeout': 'ip_idle_timeout',
- 'tcpIdleTimeout': 'tcp_idle_timeout',
- 'trafficGroup': 'traffic_group',
- 'udpIdleTimeout': 'udp_idle_timeout',
- }
-
- api_attributes = [
- 'address',
- 'arp',
- 'connectionLimit',
- 'description',
- 'disabled',
- 'enabled',
- 'ipIdleTimeout',
- 'tcpIdleTimeout',
- 'trafficGroup',
- 'udpIdleTimeout',
- ]
-
- returnables = [
- 'address',
- 'arp',
- 'connection_limit',
- 'description',
- 'disabled',
- 'enabled',
- 'ip_idle_timeout',
- 'state',
- 'tcp_idle_timeout',
- 'traffic_group',
- 'udp_idle_timeout',
- ]
-
- updatables = [
- 'arp',
- 'connection_limit',
- 'description',
- 'disabled',
- 'enabled',
- 'ip_idle_timeout',
- 'traffic_group',
- 'tcp_idle_timeout',
- 'udp_idle_timeout',
- ]
-
-
-class ApiParameters(Parameters):
- @property
- def connection_limit(self):
- if self._values['connection_limit'] is None:
- return None
- return int(self._values['connection_limit'])
-
- @property
- def enabled(self):
- if 'enabled' in self._values:
- return True
- return False
-
- @property
- def disabled(self):
- if 'disabled' in self._values:
- return True
- return False
-
-
-class ModuleParameters(Parameters):
-
- def _validate_timeout_limit(self, limit):
- if limit is None:
- return None
- if limit in ['indefinite', '4294967295']:
- return 'indefinite'
- if 0 <= int(limit) <= 4294967295:
- return str(limit)
- raise F5ModuleError(
- "Valid 'maximum_age' must be in range 0 - 4294967295, or 'indefinite'."
- )
-
- def _validate_conn_limit(self, limit):
- if limit is None:
- return None
- if 0 <= int(limit) <= 65535:
- return int(limit)
- raise F5ModuleError(
- "Valid 'connection_limit' must be in range 0 - 65535."
- )
-
- @property
- def address(self):
- if self._values['address'] is None:
- return None
- if len(self._values['address'].split('%')) > 1:
- address, rd = self._values['address'].split('%')
- if is_valid_ip(address):
- result = '{0}%{1}'.format(compress_address(address), rd)
- return result
- else:
- if is_valid_ip(self._values['address']):
- return self._values['address']
- raise F5ModuleError(
- "The provided address: {0} is not a valid IP address".format(self._values['address'])
- )
-
- @property
- def arp(self):
- result = flatten_boolean(self._values['arp'])
- if result is None:
- return None
- if result == 'yes':
- return 'enabled'
- return 'disabled'
-
- @property
- def connection_limit(self):
- if self._values['connection_limit'] is None:
- return None
- return int(self._validate_conn_limit(self._values['connection_limit']))
-
- @property
- def description(self):
- if self._values['description'] is None:
- return None
- if self._values['description'] in ['', 'none']:
- return ''
- return self._values['description']
-
- @property
- def disabled(self):
- if self._values['state'] == 'disabled':
- return True
-
- @property
- def enabled(self):
- if self._values['state'] in ['enabled', 'present']:
- return True
-
- @property
- def ip_idle_timeout(self):
- return self._validate_timeout_limit(self._values['ip_idle_timeout'])
-
- @property
- def state(self):
- if self.enabled is True and self._values['state'] != 'present':
- return 'enabled'
- elif self.disabled is True:
- return 'disabled'
- else:
- return self._values['state']
-
- @property
- def tcp_idle_timeout(self):
- return self._validate_timeout_limit(self._values['tcp_idle_timeout'])
-
- @property
- def traffic_group(self):
- if self._values['traffic_group'] is None:
- return None
- return fq_name(self.partition, self._values['traffic_group'])
-
- @property
- def udp_idle_timeout(self):
- return self._validate_timeout_limit(self._values['udp_idle_timeout'])
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class UsableChanges(Changes):
- pass
-
-
-class ReportableChanges(Changes):
- def _change_limit_value(self, value):
- if value == 4294967295:
- return 'indefinite'
- else:
- return value
-
- @property
- def arp(self):
- return flatten_boolean(self._values['arp'])
-
- @property
- def ip_idle_timeout(self):
- if self._values['ip_idle_timeout'] is None:
- return None
- return self._change_limit_value(self._values['ip_idle_timeout'])
-
- @property
- def tcp_idle_timeout(self):
- if self._values['tcp_idle_timeout'] is None:
- return None
- return self._change_limit_value(self._values['tcp_idle_timeout'])
-
- @property
- def udp_idle_timeout(self):
- if self._values['udp_idle_timeout'] is None:
- return None
- return self._change_limit_value(self._values['udp_idle_timeout'])
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
- @property
- def description(self):
- return cmp_str_with_none(self.want.description, self.have.description)
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(params=self.module.params)
- self.have = ApiParameters()
- self.changes = UsableChanges()
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = UsableChanges(params=changed)
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def exec_module(self):
- changed = False
- result = dict()
- state = self.want.state
-
- if state in ['present', 'enabled', 'disabled']:
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
-
- if self.module._diff and self.have:
- result['diff'] = self.make_diff()
-
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
-
- return result
-
- def _grab_attr(self, item):
- result = dict()
- updatables = Parameters.updatables
- for k in updatables:
- if getattr(item, k) is not None:
- result[k] = getattr(item, k)
- return result
-
- def make_diff(self):
- result = dict(before=self._grab_attr(self.have), after=self._grab_attr(self.want))
- return result
-
- def present(self):
- if self.exists():
- return self.update()
- else:
- return self.create()
-
- def absent(self):
- changed = False
- if self.exists():
- changed = self.remove()
- return changed
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def update(self):
- self.have = self.read_current_from_device()
- if not self.should_update():
- return False
- if self.module.check_mode:
- return True
- self.update_on_device()
- return True
-
- def create(self):
- self._set_changed_options()
- if self.module.check_mode:
- return True
- self.create_on_device()
- if not self.exists():
- raise F5ModuleError("Failed to create the SNAT pool")
- return True
-
- def remove(self):
- if self.module.check_mode:
- return True
- self.remove_from_device()
- if self.exists():
- raise F5ModuleError("Failed to delete the SNAT pool")
- return True
-
- def exists(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/snat-translation/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def create_on_device(self):
- params = self.changes.api_params()
- params['name'] = self.want.name
- params['partition'] = self.want.partition
- uri = "https://{0}:{1}/mgmt/tm/ltm/snat-translation/".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 409]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return True
-
- def update_on_device(self):
- params = self.changes.api_params()
- uri = "https://{0}:{1}/mgmt/tm/ltm/snat-translation/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def remove_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/snat-translation/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- response = self.client.api.delete(uri)
- if response.status == 200:
- return True
- raise F5ModuleError(response.content)
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/snat-translation/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return ApiParameters(params=response)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- address=dict(
- aliases=['ip']
- ),
- arp=dict(
- type='bool'
- ),
- connection_limit=dict(
- type='int'
- ),
- description=dict(),
- ip_idle_timeout=dict(),
- name=dict(required=True),
- partition=dict(
- fallback=(env_fallback, ['F5_PARTITION'])
- ),
- state=dict(
- default='present',
- choices=['absent', 'present', 'enabled', 'disabled']
- ),
- tcp_idle_timeout=dict(),
- traffic_group=dict(),
- udp_idle_timeout=dict()
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
- self.required_if = [
- ['state', 'present', ['address', 'name']],
- ['state', 'enabled', ['address', 'name']],
- ['state', 'disabled', ['address', 'name']],
- ]
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode,
- required_if=spec.required_if
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_snmp.py b/lib/ansible/modules/network/f5/bigip_snmp.py
deleted file mode 100644
index 90da173269..0000000000
--- a/lib/ansible/modules/network/f5/bigip_snmp.py
+++ /dev/null
@@ -1,425 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['stableinterface'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_snmp
-short_description: Manipulate general SNMP settings on a BIG-IP
-description:
- - Manipulate general SNMP settings on a BIG-IP.
-version_added: 2.4
-options:
- allowed_addresses:
- description:
- - Configures the IP addresses of the SNMP clients from which the snmpd
- daemon accepts requests.
- - This value can be hostnames, IP addresses, or IP networks.
- - You may specify a single list item of C(default) to set the value back
- to the system's default of C(127.0.0.0/8).
- - You can remove all allowed addresses by either providing the word C(none), or
- by providing the empty string C("").
- type: raw
- version_added: 2.6
- contact:
- description:
- - Specifies the name of the person who administers the SNMP
- service for this system.
- type: str
- agent_status_traps:
- description:
- - When C(enabled), ensures that the system sends a trap whenever the
- SNMP agent starts running or stops running. This is usually enabled
- by default on a BIG-IP.
- type: str
- choices:
- - enabled
- - disabled
- agent_authentication_traps:
- description:
- - When C(enabled), ensures that the system sends authentication warning
- traps to the trap destinations. This is usually disabled by default on
- a BIG-IP.
- type: str
- choices:
- - enabled
- - disabled
- device_warning_traps:
- description:
- - When C(enabled), ensures that the system sends device warning traps
- to the trap destinations. This is usually enabled by default on a
- BIG-IP.
- type: str
- choices:
- - enabled
- - disabled
- location:
- description:
- - Specifies the description of this system's physical location.
- type: str
-extends_documentation_fragment: f5
-author:
- - Tim Rupp (@caphrim007)
- - Wojciech Wypior (@wojtek0806)
-'''
-
-EXAMPLES = r'''
-- name: Set snmp contact
- bigip_snmp:
- contact: Joe User
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-
-- name: Set snmp location
- bigip_snmp:
- location: US West 1
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-'''
-
-RETURN = r'''
-agent_status_traps:
- description: Value that the agent status traps was set to.
- returned: changed
- type: str
- sample: enabled
-agent_authentication_traps:
- description: Value that the authentication status traps was set to.
- returned: changed
- type: str
- sample: enabled
-device_warning_traps:
- description: Value that the warning status traps was set to.
- returned: changed
- type: str
- sample: enabled
-contact:
- description: The new value for the person who administers SNMP on the device.
- returned: changed
- type: str
- sample: Joe User
-location:
- description: The new value for the system's physical location.
- returned: changed
- type: str
- sample: US West 1a
-allowed_addresses:
- description: The new allowed addresses for SNMP client connections.
- returned: changed
- type: list
- sample: ['127.0.0.0/8', 'foo.bar.com', '10.10.10.10']
-'''
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.six import string_types
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.common import transform_name
- from library.module_utils.compat.ipaddress import ip_network
- from library.module_utils.network.f5.common import is_valid_hostname
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.common import transform_name
- from ansible.module_utils.compat.ipaddress import ip_network
- from ansible.module_utils.network.f5.common import is_valid_hostname
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'agentTrap': 'agent_status_traps',
- 'authTrap': 'agent_authentication_traps',
- 'bigipTraps': 'device_warning_traps',
- 'sysLocation': 'location',
- 'sysContact': 'contact',
- 'allowedAddresses': 'allowed_addresses',
- }
-
- updatables = [
- 'agent_status_traps',
- 'agent_authentication_traps',
- 'device_warning_traps',
- 'location',
- 'contact',
- 'allowed_addresses',
- ]
-
- returnables = [
- 'agent_status_traps',
- 'agent_authentication_traps',
- 'device_warning_traps',
- 'location', 'contact',
- 'allowed_addresses',
- ]
-
- api_attributes = [
- 'agentTrap',
- 'authTrap',
- 'bigipTraps',
- 'sysLocation',
- 'sysContact',
- 'allowedAddresses',
- ]
-
-
-class ApiParameters(Parameters):
- @property
- def allowed_addresses(self):
- if self._values['allowed_addresses'] is None:
- return None
- result = list(set(self._values['allowed_addresses']))
- result.sort()
- return result
-
-
-class ModuleParameters(Parameters):
- @property
- def allowed_addresses(self):
- if self._values['allowed_addresses'] is None:
- return None
- result = []
- addresses = self._values['allowed_addresses']
- if isinstance(addresses, string_types):
- if addresses in ['', 'none']:
- return []
- else:
- addresses = [addresses]
- if len(addresses) == 1 and addresses[0] in ['default', '']:
- result = ['127.0.0.0/8']
- return result
- for address in addresses:
- try:
- # Check for valid IPv4 or IPv6 entries
- ip_network(u'%s' % str(address))
- result.append(address)
- except ValueError:
- # else fallback to checking reasonably well formatted hostnames
- if is_valid_hostname(address):
- result.append(str(address))
- continue
- raise F5ModuleError(
- "The provided 'allowed_address' value {0} is not a valid IP or hostname".format(address)
- )
- result = list(set(result))
- result.sort()
- return result
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class UsableChanges(Changes):
- pass
-
-
-class ReportableChanges(Changes):
- pass
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
- @property
- def allowed_addresses(self):
- if self.want.allowed_addresses is None:
- return None
- if self.have.allowed_addresses is None:
- if self.want.allowed_addresses:
- return self.want.allowed_addresses
- return None
- want = set(self.want.allowed_addresses)
- have = set(self.have.allowed_addresses)
- if want != have:
- result = list(want)
- result.sort()
- return result
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.have = ApiParameters()
- self.want = ModuleParameters(params=self.module.params)
- self.changes = UsableChanges()
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def exec_module(self):
- result = dict()
-
- changed = self.update()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def update(self):
- self.have = self.read_current_from_device()
- if not self.should_update():
- return False
- if self.module.check_mode:
- return True
- self.update_on_device()
- return True
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/sys/snmp/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return ApiParameters(params=response)
-
- def update_on_device(self):
- params = self.changes.api_params()
- uri = "https://{0}:{1}/mgmt/tm/sys/snmp/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- self.choices = ['enabled', 'disabled']
- argument_spec = dict(
- contact=dict(),
- agent_status_traps=dict(
- choices=self.choices
- ),
- agent_authentication_traps=dict(
- choices=self.choices
- ),
- device_warning_traps=dict(
- choices=self.choices
- ),
- location=dict(),
- allowed_addresses=dict(type='raw')
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_snmp_community.py b/lib/ansible/modules/network/f5/bigip_snmp_community.py
deleted file mode 100644
index d01802b244..0000000000
--- a/lib/ansible/modules/network/f5/bigip_snmp_community.py
+++ /dev/null
@@ -1,919 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_snmp_community
-short_description: Manages SNMP communities on a BIG-IP.
-description:
- - Assists in managing SNMP communities on a BIG-IP. Different SNMP versions are supported
- by this module. Take note of the different parameters offered by this module, as different
- parameters work for different versions of SNMP. Typically this becomes an interest if you
- are mixing versions C(v2c) and C(3).
-version_added: 2.6
-options:
- state:
- description:
- - When C(present), ensures that the address list and entries exists.
- - When C(absent), ensures the address list is removed.
- type: str
- choices:
- - present
- - absent
- default: present
- version:
- description:
- - Specifies to which Simple Network Management Protocol (SNMP) version the trap destination applies.
- type: str
- choices:
- - v1
- - v2c
- - v3
- default: v2c
- name:
- description:
- - Name that identifies the SNMP community.
- - When C(version) is C(v1) or C(v2c), this parameter is required.
- - The name C(public) is a reserved name on the BIG-IP. This module handles that name differently
- than others. Functionally, you should not see a difference however.
- type: str
- community:
- description:
- - Specifies the community string (password) for access to the MIB.
- - This parameter is only relevant when C(version) is C(v1), or C(v2c). If C(version) is
- something else, this parameter is ignored.
- type: str
- source:
- description:
- - Specifies the source address for access to the MIB.
- - This parameter can accept a value of C(all).
- - If this parameter is not specified, the value C(all) is used.
- - This parameter is only relevant when C(version) is C(v1), or C(v2c). If C(version) is
- something else, this parameter is ignored.
- - If C(source) is set to C(all), then it is not possible to specify an C(oid). This will
- raise an error.
- - This parameter should be provided when C(state) is C(absent), so that the correct community
- is removed. To remove the C(public) SNMP community that comes with a BIG-IP, this parameter
- should be set to C(default).
- type: str
- port:
- description:
- - Specifies the port for the trap destination.
- - This parameter is only relevant when C(version) is C(v1), or C(v2c). If C(version) is
- something else, this parameter is ignored.
- type: int
- oid:
- description:
- - Specifies the object identifier (OID) for the record.
- - When C(version) is C(v3), this parameter is required.
- - When C(version) is either C(v1) or C(v2c), if this value is specified, then C(source)
- must not be set to C(all).
- type: str
- access:
- description:
- - Specifies the user's access level to the MIB.
- - When creating a new community, if this parameter is not specified, the default is C(ro).
- - When C(ro), specifies that the user can view the MIB, but cannot modify the MIB.
- - When C(rw), specifies that the user can view and modify the MIB.
- type: str
- choices:
- - ro
- - rw
- - read-only
- - read-write
- ip_version:
- description:
- - Specifies whether the record applies to IPv4 or IPv6 addresses.
- - When creating a new community, if this value is not specified, the default of C(4) will
- be used.
- - This parameter is only relevant when C(version) is C(v1), or C(v2c). If C(version) is
- something else, this parameter is ignored.
- type: str
- choices:
- - '4'
- - '6'
- snmp_username:
- description:
- - Specifies the name of the user for whom you want to grant access to the SNMP v3 MIB.
- - This parameter is only relevant when C(version) is C(v3). If C(version) is something
- else, this parameter is ignored.
- - When creating a new SNMP C(v3) community, this parameter is required.
- - This parameter cannot be changed once it has been set.
- type: str
- snmp_auth_protocol:
- description:
- - Specifies the authentication method for the user.
- - When C(md5), specifies that the system uses the MD5 algorithm to authenticate the user.
- - When C(sha), specifies that the secure hash algorithm (SHA) to authenticate the user.
- - When C(none), specifies that user does not require authentication.
- - When creating a new SNMP C(v3) community, if this parameter is not specified, the default
- of C(sha) will be used.
- type: str
- choices:
- - md5
- - sha
- - none
- snmp_auth_password:
- description:
- - Specifies the password for the user.
- - When creating a new SNMP C(v3) community, this parameter is required.
- - This value must be at least 8 characters long.
- type: str
- snmp_privacy_protocol:
- description:
- - Specifies the encryption protocol.
- - When C(aes), specifies that the system encrypts the user information using AES
- (Advanced Encryption Standard).
- - When C(des), specifies that the system encrypts the user information using DES
- (Data Encryption Standard).
- - When C(none), specifies that the system does not encrypt the user information.
- - When creating a new SNMP C(v3) community, if this parameter is not specified, the
- default of C(aes) will be used.
- type: str
- choices:
- - aes
- - des
- - none
- snmp_privacy_password:
- description:
- - Specifies the password for the user.
- - When creating a new SNMP C(v3) community, this parameter is required.
- - This value must be at least 8 characters long.
- type: str
- update_password:
- description:
- - C(always) will allow to update passwords if the user chooses to do so.
- C(on_create) will only set the password for newly created resources.
- type: str
- choices:
- - always
- - on_create
- default: always
- partition:
- description:
- - Device partition to manage resources on.
- type: str
- default: Common
-extends_documentation_fragment: f5
-author:
- - Tim Rupp (@caphrim007)
- - Wojciech Wypior (@wojtek0806)
-'''
-
-EXAMPLES = r'''
-- name: Create an SMNP v2c read-only community
- bigip_snmp_community:
- name: foo
- version: v2c
- source: all
- oid: .1
- access: ro
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-
-- name: Create an SMNP v3 read-write community
- bigip_snmp_community:
- name: foo
- version: v3
- snmp_username: foo
- snmp_auth_protocol: sha
- snmp_auth_password: secret
- snmp_privacy_protocol: aes
- snmp_privacy_password: secret
- oid: .1
- access: rw
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-
-- name: Remove the default 'public' SNMP community
- bigip_snmp_community:
- name: public
- source: default
- state: absent
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-'''
-
-RETURN = r'''
-community:
- description: The new community value.
- returned: changed
- type: str
- sample: community1
-oid:
- description: The new OID value.
- returned: changed
- type: str
- sample: .1
-ip_version:
- description: The new IP version value.
- returned: changed
- type: str
- sample: .1
-snmp_auth_protocol:
- description: The new SNMP auth protocol.
- returned: changed
- type: str
- sample: sha
-snmp_privacy_protocol:
- description: The new SNMP privacy protocol.
- returned: changed
- type: str
- sample: aes
-access:
- description: The new access level for the MIB.
- returned: changed
- type: str
- sample: ro
-source:
- description: The new source address to access the MIB.
- returned: changed
- type: str
- sample: 1.1.1.1
-snmp_username:
- description: The new SNMP username.
- returned: changed
- type: str
- sample: user1
-snmp_auth_password:
- description: The new password of the given snmp_username.
- returned: changed
- type: str
- sample: secret1
-snmp_privacy_password:
- description: The new password of the given snmp_username.
- returned: changed
- type: str
- sample: secret2
-'''
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.basic import env_fallback
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.common import transform_name
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.common import transform_name
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'communityName': 'community',
- 'oidSubset': 'oid',
- 'ipv6': 'ip_version',
- 'authProtocol': 'snmp_auth_protocol',
- 'privacyProtocol': 'snmp_privacy_protocol',
- 'username': 'snmp_username',
- 'securityLevel': 'security_level',
- 'authPassword': 'snmp_auth_password',
- 'privacyPassword': 'snmp_privacy_password',
- }
-
- api_attributes = [
- 'source',
- 'oidSubset',
- 'ipv6',
- 'communityName',
- 'access',
- 'authPassword',
- 'authProtocol',
- 'username',
- 'securityLevel',
- 'privacyProtocol',
- 'privacyPassword',
- ]
-
- returnables = [
- 'community',
- 'oid',
- 'ip_version',
- 'snmp_auth_protocol',
- 'snmp_privacy_protocol',
- 'access',
- 'source',
- 'snmp_username',
- 'snmp_auth_password',
- 'snmp_privacy_password',
- ]
-
- updatables = [
- 'community',
- 'oid',
- 'ip_version',
- 'snmp_auth_protocol',
- 'snmp_privacy_protocol',
- 'access',
- 'source',
- 'snmp_auth_password',
- 'snmp_privacy_password',
- 'security_level',
- 'snmp_username',
- ]
-
- @property
- def port(self):
- if self._values['port'] is None:
- return None
- return int(self._values['port'])
-
-
-class ApiParameters(Parameters):
- @property
- def ip_version(self):
- if self._values['ip_version'] is None:
- return None
- if self._values['ip_version'] == 'enabled':
- return 6
- return 4
-
- @property
- def source(self):
- if self._values['source'] is None:
- return 'all'
- return self._values['source']
-
-
-class ModuleParameters(Parameters):
- @property
- def ip_version(self):
- if self._values['ip_version'] is None:
- return None
- return int(self._values['ip_version'])
-
- @property
- def source(self):
- if self._values['source'] is None:
- return None
- if self._values['source'] == '':
- return 'all'
- return self._values['source']
-
- @property
- def access(self):
- if self._values['access'] is None:
- return None
- elif self._values['access'] in ['ro', 'read-only']:
- return 'ro'
- elif self._values['access'] in ['rw', 'read-write']:
- return 'rw'
- else:
- raise F5ModuleError(
- "Unknown access format specified: '{0}'.".format(self._values['access'])
- )
-
- @property
- def snmp_auth_password(self):
- if self._values['snmp_auth_password'] is None:
- return None
- if len(self._values['snmp_auth_password']) < 8:
- raise F5ModuleError(
- "snmp_auth_password must be at least 8 characters long."
- )
- return self._values['snmp_auth_password']
-
- @property
- def snmp_privacy_password(self):
- if self._values['snmp_privacy_password'] is None:
- return None
- if len(self._values['snmp_privacy_password']) < 8:
- raise F5ModuleError(
- "snmp_privacy_password must be at least 8 characters long."
- )
- return self._values['snmp_privacy_password']
-
- @property
- def name(self):
- if self._values['name'] == 'public':
- return 'comm-public'
- return self._values['name']
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class UsableChanges(Changes):
- @property
- def ip_version(self):
- if self._values['ip_version'] is None:
- return None
- elif self._values['ip_version'] == 4:
- return 'disabled'
- return 'enabled'
-
- @property
- def source(self):
- if self._values['source'] is None:
- return None
- if self._values['source'] == 'all':
- return ''
- return self._values['source']
-
-
-class ReportableChanges(Changes):
- pass
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
- def _check_source_and_oid(self):
- if self.have.oid is not None:
- if self.want.source == 'all' and self.want.oid != '':
- raise F5ModuleError(
- "When specifying an 'all' source for a resource with an existing OID, you must specify a new, empty, OID."
- )
- if self.want.source == 'all' and self.want.oid != '':
- raise F5ModuleError(
- "When specifying an 'all' source for a resource, you may not specify an OID."
- )
-
- @property
- def source(self):
- self._check_source_and_oid()
- if self.want.source != self.have.source:
- return self.want.source
-
- @property
- def oid(self):
- self._check_source_and_oid()
- if self.want.oid != self.have.oid:
- return self.want.oid
-
- @property
- def snmp_privacy_password(self):
- if self.want.update_password == 'always' and self.want.snmp_privacy_password is not None:
- return self.want.snmp_privacy_password
-
- @property
- def snmp_auth_password(self):
- if self.want.update_password == 'always' and self.want.snmp_auth_password is not None:
- return self.want.snmp_auth_password
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.kwargs = kwargs
- self.client = kwargs.get('client', None)
- self.module = kwargs.get('module', None)
-
- def exec_module(self):
- if self.version_is_less_than_3():
- manager = self.get_manager('v1')
- else:
- manager = self.get_manager('v2')
- return manager.exec_module()
-
- def get_manager(self, type):
- if type == 'v1':
- return V1Manager(**self.kwargs)
- elif type == 'v2':
- return V2Manager(**self.kwargs)
-
- def version_is_less_than_3(self):
- version = self.module.params.get('version')
- if version == 'v3':
- return False
- else:
- return True
-
-
-class BaseManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(params=self.module.params)
- self.have = ApiParameters()
- self.changes = UsableChanges()
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = UsableChanges(params=changed)
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def exec_module(self):
- changed = False
- result = dict()
- state = self.want.state
-
- if state == "present":
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.client.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def present(self):
- if self.exists():
- return self.update()
- else:
- return self.create()
-
- def update(self):
- self.have = self.read_current_from_device()
- if not self.should_update():
- return False
- if self.module.check_mode:
- return True
- self.update_on_device()
- return True
-
- def remove(self):
- if self.module.check_mode:
- return True
- self.remove_from_device()
- if self.exists():
- raise F5ModuleError("Failed to delete the resource.")
- return True
-
- def absent(self):
- if self.exists():
- return self.remove()
- return False
-
-
-class V1Manager(BaseManager):
- """Handles SNMP v1 and v2c
-
- """
- def create(self):
- if self.want.ip_version is None:
- self.want.update({'ip_version': 4})
- if self.want.access is None:
- self.want.update({'access': 'ro'})
- self._set_changed_options()
- if self.want.oid is not None and self.want.source == 'all':
- raise F5ModuleError(
- "When specify an oid, source may not be set to 'all'."
- )
- if self.module.check_mode:
- return True
- self.create_on_device()
- return True
-
- def exists(self):
- uri = "https://{0}:{1}/mgmt/tm/sys/snmp/communities/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def create_on_device(self):
- params = self.changes.api_params()
- params['name'] = self.want.name
- params['partition'] = self.want.partition
- uri = "https://{0}:{1}/mgmt/tm/sys/snmp/communities/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def update_on_device(self):
- params = self.changes.api_params()
- uri = "https://{0}:{1}/mgmt/tm/sys/snmp/communities/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def remove_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/sys/snmp/communities/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.delete(uri)
- if resp.status == 200:
- return True
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/sys/snmp/communities/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return ApiParameters(params=response)
-
-
-class V2Manager(BaseManager):
- """Handles SNMP v3
-
- SNMP v3 has (almost) a completely separate set of variables than v2c or v1.
- The functionality is placed in this separate class to handle these differences.
-
- """
- def create(self):
- if self.want.access is None:
- self.want.update({'access': 'ro'})
- if self.want.snmp_auth_protocol is None:
- self.want.update({'snmp_auth_protocol': 'sha'})
- if self.want.snmp_privacy_protocol is None:
- self.want.update({'snmp_privacy_protocol': 'aes'})
-
- self._set_changed_options()
- if self.want.snmp_username is None:
- raise F5ModuleError(
- "snmp_username must be specified when creating a new v3 community."
- )
- if self.want.snmp_auth_password is None:
- raise F5ModuleError(
- "snmp_auth_password must be specified when creating a new v3 community."
- )
- if self.want.snmp_privacy_password is None:
- raise F5ModuleError(
- "snmp_privacy_password must be specified when creating a new v3 community."
- )
- if self.want.oid is None:
- raise F5ModuleError(
- "oid must be specified when creating a new v3 community."
- )
- if self.module.check_mode:
- return True
- self.create_on_device()
- return True
-
- def exists(self):
- uri = "https://{0}:{1}/mgmt/tm/sys/snmp/users/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.snmp_username)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def create_on_device(self):
- params = self.changes.api_params()
- params['name'] = self.want.snmp_username
- params['partition'] = self.want.partition
- uri = "https://{0}:{1}/mgmt/tm/sys/snmp/users/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def update_on_device(self):
- params = self.changes.api_params()
- uri = "https://{0}:{1}/mgmt/tm/sys/snmp/users/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.snmp_username)
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def remove_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/sys/snmp/users/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.snmp_username)
- )
- resp = self.client.api.delete(uri)
- if resp.status == 200:
- return True
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/sys/snmp/users/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.snmp_username)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return ApiParameters(params=response)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- version=dict(
- default='v2c',
- choices=['v1', 'v2c', 'v3']
- ),
- name=dict(),
- community=dict(),
- source=dict(),
- port=dict(type='int'),
- oid=dict(),
- access=dict(
- choices=['ro', 'rw', 'read-only', 'read-write']
- ),
- ip_version=dict(
- choices=['4', '6']
- ),
- snmp_username=dict(),
- snmp_auth_protocol=dict(
- choices=['md5', 'sha', 'none']
- ),
- snmp_auth_password=dict(no_log=True),
- snmp_privacy_protocol=dict(
- choices=['aes', 'des', 'none']
- ),
- snmp_privacy_password=dict(no_log=True),
- update_password=dict(
- default='always',
- choices=['always', 'on_create']
- ),
- state=dict(default='present', choices=['absent', 'present']),
- partition=dict(
- default='Common',
- fallback=(env_fallback, ['F5_PARTITION'])
- ),
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
- self.required_if = [
- ['version', 'v1', ['name']],
- ['version', 'v2', ['name']],
- ['version', 'v3', ['snmp_username']]
- ]
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode,
- required_if=spec.required_if
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_snmp_trap.py b/lib/ansible/modules/network/f5/bigip_snmp_trap.py
deleted file mode 100644
index a215c52a81..0000000000
--- a/lib/ansible/modules/network/f5/bigip_snmp_trap.py
+++ /dev/null
@@ -1,681 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['stableinterface'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_snmp_trap
-short_description: Manipulate SNMP trap information on a BIG-IP
-description:
- - Manipulate SNMP trap information on a BIG-IP.
-version_added: 2.4
-options:
- name:
- description:
- - Name of the SNMP configuration endpoint.
- type: str
- required: True
- snmp_version:
- description:
- - Specifies to which Simple Network Management Protocol (SNMP) version
- the trap destination applies.
- type: str
- choices:
- - '1'
- - '2c'
- community:
- description:
- - Specifies the community name for the trap destination.
- type: str
- destination:
- description:
- - Specifies the address for the trap destination. This can be either an
- IP address or a hostname.
- type: str
- port:
- description:
- - Specifies the port for the trap destination.
- type: str
- network:
- description:
- - Specifies the name of the trap network. This option is not supported in
- versions of BIG-IP < 12.1.0. If used on versions < 12.1.0, it will simply
- be ignored.
- - The value C(default) was removed in BIG-IP version 13.1.0. Specifying this
- value when configuring a BIG-IP will cause the module to stop and report
- an error. The usual remedy is to choose one of the other options, such as
- C(management).
- type: str
- choices:
- - other
- - management
- - default
- state:
- description:
- - When C(present), ensures that the resource exists.
- - When C(absent), ensures that the resource does not exist.
- type: str
- choices:
- - present
- - absent
- default: present
- partition:
- description:
- - Device partition to manage resources on.
- type: str
- default: Common
- version_added: 2.5
-notes:
- - This module only supports version v1 and v2c of SNMP.
- - The C(network) option is not supported on versions of BIG-IP < 12.1.0 because
- the platform did not support that option until 12.1.0. If used on versions
- < 12.1.0, it will simply be ignored.
-extends_documentation_fragment: f5
-author:
- - Tim Rupp (@caphrim007)
- - Wojciech Wypior (@wojtek0806)
-'''
-
-EXAMPLES = r'''
-- name: Create snmp v1 trap
- bigip_snmp_trap:
- community: general
- destination: 1.2.3.4
- name: my-trap1
- network: management
- port: 9000
- snmp_version: 1
- provider:
- server: lb.mydomain.com
- user: admin
- password: secret
- delegate_to: localhost
-
-- name: Create snmp v2 trap
- bigip_snmp_trap:
- community: general
- destination: 5.6.7.8
- name: my-trap2
- network: default
- port: 7000
- snmp_version: 2c
- provider:
- server: lb.mydomain.com
- user: admin
- password: secret
- delegate_to: localhost
-'''
-
-RETURN = r'''
-snmp_version:
- description: The new C(snmp_version) configured on the remote device.
- returned: changed and success
- type: str
- sample: 2c
-community:
- description: The new C(community) name for the trap destination.
- returned: changed and success
- type: list
- sample: secret
-destination:
- description: The new address for the trap destination in either IP or hostname form.
- returned: changed and success
- type: str
- sample: 1.2.3.4
-port:
- description: The new C(port) of the trap destination.
- returned: changed and success
- type: str
- sample: 900
-network:
- description: The new name of the network the SNMP trap is on.
- returned: changed and success
- type: str
- sample: management
-'''
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.basic import env_fallback
-from distutils.version import LooseVersion
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.common import transform_name
- from library.module_utils.network.f5.icontrol import tmos_version
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.common import transform_name
- from ansible.module_utils.network.f5.icontrol import tmos_version
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'version': 'snmp_version',
- 'community': 'community',
- 'host': 'destination',
- }
-
- @property
- def snmp_version(self):
- if self._values['snmp_version'] is None:
- return None
- return str(self._values['snmp_version'])
-
- @property
- def port(self):
- if self._values['port'] is None:
- return None
- return int(self._values['port'])
-
- def to_return(self):
- result = {}
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- return result
-
-
-class V3Parameters(Parameters):
- updatables = [
- 'snmp_version',
- 'community',
- 'destination',
- 'port',
- 'network',
- ]
-
- returnables = [
- 'snmp_version',
- 'community',
- 'destination',
- 'port',
- 'network',
- ]
-
- api_attributes = [
- 'version',
- 'community',
- 'host',
- 'port',
- 'network',
- ]
-
- @property
- def network(self):
- if self._values['network'] is None:
- return None
- network = str(self._values['network'])
- if network == 'management':
- return 'mgmt'
- elif network == 'default':
- raise F5ModuleError(
- "'default' is not a valid option for this version of BIG-IP. "
- "Use either 'management', 'or 'other' instead."
- )
- else:
- return network
-
-
-class V2Parameters(Parameters):
- updatables = [
- 'snmp_version',
- 'community',
- 'destination',
- 'port',
- 'network',
- ]
-
- returnables = [
- 'snmp_version',
- 'community',
- 'destination',
- 'port',
- 'network',
- ]
-
- api_attributes = [
- 'version',
- 'community',
- 'host',
- 'port',
- 'network',
- ]
-
- @property
- def network(self):
- if self._values['network'] is None:
- return None
- network = str(self._values['network'])
- if network == 'management':
- return 'mgmt'
- elif network == 'default':
- return ''
- else:
- return network
-
-
-class V1Parameters(Parameters):
- updatables = [
- 'snmp_version',
- 'community',
- 'destination',
- 'port',
- ]
-
- returnables = [
- 'snmp_version',
- 'community',
- 'destination',
- 'port',
- ]
-
- api_attributes = [
- 'version',
- 'community',
- 'host',
- 'port',
- ]
-
- @property
- def network(self):
- return None
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.kwargs = kwargs
-
- def exec_module(self):
- if self.is_version_without_network():
- manager = V1Manager(**self.kwargs)
- elif self.is_version_with_default_network():
- manager = V2Manager(**self.kwargs)
- else:
- manager = V3Manager(**self.kwargs)
-
- return manager.exec_module()
-
- def is_version_without_network(self):
- """Is current BIG-IP version missing "network" value support
-
- Returns:
- bool: True when it is missing. False otherwise.
- """
- version = tmos_version(self.client)
- if LooseVersion(version) < LooseVersion('12.1.0'):
- return True
- else:
- return False
-
- def is_version_with_default_network(self):
- """Is current BIG-IP version missing "default" network value support
-
- Returns:
- bool: True when it is missing. False otherwise.
- """
- version = tmos_version(self.client)
- if LooseVersion(version) < LooseVersion('13.1.0'):
- return True
- else:
- return False
-
-
-class BaseManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.have = None
-
- def exec_module(self):
- changed = False
- result = dict()
- state = self.want.state
-
- if state == "present":
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
-
- changes = self.changes.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- return result
-
- def present(self):
- if self.exists():
- return self.update()
- else:
- return self.create()
-
- def absent(self):
- if self.exists():
- return self.remove()
- return False
-
- def remove(self):
- if self.module.check_mode:
- return True
- self.remove_from_device()
- if self.exists():
- raise F5ModuleError("Failed to delete the snmp trap")
- return True
-
- def create(self):
- self._set_changed_options()
- if self.module.check_mode:
- return True
- if all(getattr(self.want, v) is None for v in self.required_resources):
- raise F5ModuleError(
- "You must specify at least one of "
- ', '.join(self.required_resources)
- )
- self.create_on_device()
- return True
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def update(self):
- self.have = self.read_current_from_device()
- if not self.should_update():
- return False
- if self.module.check_mode:
- return True
- self.update_on_device()
- return True
-
- def exists(self):
- uri = "https://{0}:{1}/mgmt/tm/sys/snmp/traps/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def update_on_device(self):
- params = self.want.api_params()
- uri = "https://{0}:{1}/mgmt/tm/sys/snmp/traps/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def create_on_device(self):
- params = self.want.api_params()
- params['name'] = self.want.name
- params['partition'] = self.want.partition
- uri = "https://{0}:{1}/mgmt/tm/sys/snmp/traps/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def remove_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/sys/snmp/traps/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.delete(uri)
- if resp.status == 200:
- return True
-
-
-class V3Manager(BaseManager):
- def __init__(self, *args, **kwargs):
- super(V3Manager, self).__init__(**kwargs)
- self.required_resources = [
- 'version', 'community', 'destination', 'port', 'network'
- ]
- self.want = V3Parameters(params=self.module.params)
- self.changes = V3Parameters()
-
- def _set_changed_options(self):
- changed = {}
- for key in V3Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = V3Parameters(params=changed)
-
- def _update_changed_options(self):
- changed = {}
- for key in V3Parameters.updatables:
- if getattr(self.want, key) is not None:
- attr1 = getattr(self.want, key)
- attr2 = getattr(self.have, key)
- if attr1 != attr2:
- changed[key] = attr1
- if changed:
- self.changes = V3Parameters(params=changed)
- return True
- return False
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/sys/snmp/traps/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return V3Parameters(params=response)
-
-
-class V2Manager(BaseManager):
- def __init__(self, *args, **kwargs):
- super(V2Manager, self).__init__(**kwargs)
- self.required_resources = [
- 'version', 'community', 'destination', 'port', 'network'
- ]
- self.want = V2Parameters(params=self.module.params)
- self.changes = V2Parameters()
-
- def _set_changed_options(self):
- changed = {}
- for key in V2Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = V2Parameters(params=changed)
-
- def _update_changed_options(self):
- changed = {}
- for key in V2Parameters.updatables:
- if getattr(self.want, key) is not None:
- attr1 = getattr(self.want, key)
- attr2 = getattr(self.have, key)
- if attr1 != attr2:
- changed[key] = attr1
- if changed:
- self.changes = V2Parameters(params=changed)
- return True
- return False
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/sys/snmp/traps/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- self._ensure_network(response)
- return V2Parameters(params=response)
-
- def _ensure_network(self, result):
- # BIG-IP's value for "default" is that the key does not
- # exist. This conflicts with our purpose of having a key
- # not exist (which we equate to "i dont want to change that"
- # therefore, if we load the information from BIG-IP and
- # find that there is no 'network' key, that is BIG-IP's
- # way of saying that the network value is "default"
- if 'network' not in result:
- result['network'] = 'default'
-
-
-class V1Manager(BaseManager):
- def __init__(self, *args, **kwargs):
- super(V1Manager, self).__init__(**kwargs)
- self.required_resources = [
- 'version', 'community', 'destination', 'port'
- ]
- self.want = V1Parameters(params=self.module.params)
- self.changes = V1Parameters()
-
- def _set_changed_options(self):
- changed = {}
- for key in V1Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = V1Parameters(params=changed)
-
- def _update_changed_options(self):
- changed = {}
- for key in V1Parameters.updatables:
- if getattr(self.want, key) is not None:
- attr1 = getattr(self.want, key)
- attr2 = getattr(self.have, key)
- if attr1 != attr2:
- changed[key] = attr1
- if changed:
- self.changes = V1Parameters(params=changed)
- return True
- return False
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/sys/snmp/traps/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return V1Parameters(params=response)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- name=dict(
- required=True
- ),
- snmp_version=dict(
- choices=['1', '2c']
- ),
- community=dict(no_log=True),
- destination=dict(),
- port=dict(),
- network=dict(
- choices=['other', 'management', 'default']
- ),
- state=dict(
- default='present',
- choices=['absent', 'present']
- ),
- partition=dict(
- default='Common',
- fallback=(env_fallback, ['F5_PARTITION'])
- )
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_software_image.py b/lib/ansible/modules/network/f5/bigip_software_image.py
deleted file mode 100644
index 0574816684..0000000000
--- a/lib/ansible/modules/network/f5/bigip_software_image.py
+++ /dev/null
@@ -1,479 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2018, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_software_image
-short_description: Manage software images on a BIG-IP
-description:
- - Manages software images on a BIG-IP. These images may include both base images
- and hotfix images.
-version_added: 2.7
-options:
- force:
- description:
- - When C(yes), will upload the file every time and replace the file on the
- device.
- - When C(no), the file will only be uploaded if it does not already
- exist.
- - Generally should be C(yes) only in cases where you have reason
- to believe that the image was corrupted during upload.
- type: bool
- default: no
- state:
- description:
- - When C(present), ensures that the image is uploaded.
- - When C(absent), ensures that the image is removed.
- type: str
- choices:
- - absent
- - present
- default: present
- image:
- description:
- - The image to put on the remote device.
- - This may be an absolute or relative location on the Ansible controller.
- - Image names, whether they are base ISOs or hotfix ISOs, B(must) be unique.
- type: str
-extends_documentation_fragment: f5
-author:
- - Tim Rupp (@caphrim007)
-'''
-
-EXAMPLES = r'''
-- name: Upload relative image to the BIG-IP
- bigip_software_image:
- image: BIGIP-13.0.0.0.0.1645.iso
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-
-- name: Upload absolute image to the BIG-IP
- bigip_software_image:
- image: /path/to/images/BIGIP-13.0.0.0.0.1645.iso
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-
-- name: Upload image in a role to the BIG-IP
- bigip_software_image:
- image: "{{ role_path }}/files/BIGIP-13.0.0.0.0.1645.iso"
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-'''
-
-RETURN = r'''
-image_type:
- description: Whether the image is a release or hotfix image
- returned: changed
- type: str
- sample: release
-version:
- description: Version of the software contained in the image.
- returned: changed
- type: str
- sample: 13.1.0.8
-build:
- description: Build version of the software contained in the image.
- returned: changed
- type: str
- sample: 0.0.3
-checksum:
- description: MD5 checksum of the ISO.
- returned: changed
- type: str
- sample: 8cdbd094195fab4b2b47ff4285577b70
-file_size:
- description: Size of the uploaded image in MB.
- returned: changed
- type: int
- sample: 1948
-'''
-
-import os
-import time
-
-from ansible.module_utils.urls import urlparse
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.icontrol import upload_file
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.icontrol import upload_file
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'fileSize': 'file_size'
- }
-
- api_attributes = [
-
- ]
-
- returnables = [
- 'image_type',
- 'version',
- 'build',
- 'checksum',
- 'file_size',
- ]
-
- updatables = [
-
- ]
-
-
-class ApiParameters(Parameters):
- @property
- def file_size(self):
- if self._values['file_size'] is None:
- return None
- tmp = self._values['file_size'].split(' ')
- return int(tmp[0])
-
-
-class ModuleParameters(Parameters):
- @property
- def filename(self):
- return os.path.basename(self.image)
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class UsableChanges(Changes):
- pass
-
-
-class ReportableChanges(Changes):
- pass
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(params=self.module.params)
- self.have = ApiParameters()
- self.changes = UsableChanges()
- self.image_type = None
- self.image_url = None
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = UsableChanges(params=changed)
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def exec_module(self):
- changed = False
- result = dict()
- state = self.want.state
-
- if state == "present":
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.client.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def present(self):
- if self.exists():
- return self.update()
- else:
- return self.create()
-
- def exists(self):
- if self.image_exists() or self.hotfix_exists():
- return True
- return False
-
- def _set_image_url(self, item):
- path = urlparse(item['selfLink']).path
- self.image_url = "https://{0}:{1}{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- path
- )
-
- def image_exists(self):
- result = False
- uri = "https://{0}:{1}/mgmt/tm/sys/software/image/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.get(uri)
-
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'items' in response:
- for item in response['items']:
- if item['name'].startswith(self.want.filename):
- self._set_image_url(item)
- self.image_type = 'release'
- result = True
- break
- return result
-
- def hotfix_exists(self):
- result = False
- uri = "https://{0}:{1}/mgmt/tm/sys/software/hotfix/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.get(uri)
-
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'items' in response:
- for item in response['items']:
- if item['name'].startswith(self.want.filename):
- self._set_image_url(item)
- self.image_type = 'hotfix'
- result = True
- break
- return result
-
- def update(self):
- if self.module.check_mode:
- return True
- if self.want.force:
- # The process of updating is a forced re-creation.
- self.remove_from_device()
- self.create_on_device()
- return True
- return False
-
- def remove(self):
- if self.module.check_mode:
- return True
- self.remove_from_device()
-
- # Deleting images involves a short period of inconsistency in the REST
- # API due to needing to remove files from disk and update MCPD.
- #
- # This should not (realistically) take more than 30 seconds.
- for x in range(0, 30):
- if not self.exists():
- return True
- time.sleep(1)
- raise F5ModuleError("Failed to delete the resource.")
-
- def create(self):
- self._set_changed_options()
- if self.module.check_mode:
- return True
-
- self.create_on_device()
-
- # Creating images involves a short period of inconsistency in the REST
- # API likely due to having to move files into appropriate places on disk
- # and update MCPD with information.
- #
- # This should not (realistically) take more than 30 seconds.
- for x in range(0, 30):
- if self.exists():
- # We want to return some information about the image that was just uploaded
- #
- # This must appear after the creation process because the information
- # does not exist on the device (has been parsed by BIG-IP) until the
- # ISO is uploaded.
- self.want = self.read_current_from_device()
- self._set_changed_options()
- return True
- time.sleep(1)
- raise F5ModuleError("Failed to create the resource.")
-
- def create_on_device(self):
- url = 'https://{0}:{1}/mgmt/cm/autodeploy/software-image-uploads'.format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- try:
- upload_file(self.client, url, self.want.image)
- except F5ModuleError:
- raise F5ModuleError(
- "Failed to upload the file."
- )
-
- def read_current_from_device(self):
- resp = self.client.api.get(self.image_url)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 404]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- result = ApiParameters(params=response)
- result.update({'image_type': self.image_type})
- return result
-
- def absent(self):
- if self.exists():
- return self.remove()
- return False
-
- def remove_from_device(self):
- if self.image_exists():
- self.remove_iso_from_device('image')
- elif self.hotfix_exists():
- self.remove_iso_from_device('hotfix')
-
- def remove_iso_from_device(self, type):
- uri = "https://{0}:{1}/mgmt/tm/sys/software/{2}/{3}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- type,
- self.want.filename
- )
- response = self.client.api.delete(uri)
- if response.status == 200:
- return True
- if 'code' in response and response['code'] in [400, 404]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(response.content)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- force=dict(type='bool'),
- image=dict(required=True),
- state=dict(
- default='present',
- choices=['present', 'absent']
- ),
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_software_install.py b/lib/ansible/modules/network/f5/bigip_software_install.py
deleted file mode 100644
index 789c9d6198..0000000000
--- a/lib/ansible/modules/network/f5/bigip_software_install.py
+++ /dev/null
@@ -1,523 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2018, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_software_install
-short_description: Install software images on a BIG-IP
-description:
- - Install new images on a BIG-IP.
-version_added: 2.7
-options:
- image:
- description:
- - Image to install on the remote device.
- type: str
- volume:
- description:
- - The volume to install the software image to.
- type: str
- state:
- description:
- - When C(installed), ensures that the software is installed on the volume
- and the volume is set to be booted from. The device is B(not) rebooted
- into the new software.
- - When C(activated), performs the same operation as C(installed), but
- the system is rebooted to the new software.
- type: str
- choices:
- - activated
- - installed
- default: activated
-extends_documentation_fragment: f5
-author:
- - Tim Rupp (@caphrim007)
- - Wojciech Wypior (@wojtek0806)
-'''
-EXAMPLES = r'''
-- name: Ensure an existing image is installed in specified volume
- bigip_software_install:
- image: BIGIP-13.0.0.0.0.1645.iso
- volume: HD1.2
- state: installed
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-
-- name: Ensure an existing image is activated in specified volume
- bigip_software_install:
- image: BIGIP-13.0.0.0.0.1645.iso
- state: activated
- volume: HD1.2
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-'''
-
-RETURN = r'''
-# only common fields returned
-'''
-
-import time
-import ssl
-
-from ansible.module_utils.six.moves.urllib.error import URLError
-from ansible.module_utils.urls import urlparse
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import f5_argument_spec
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import f5_argument_spec
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
-
- }
-
- api_attributes = [
- 'options',
- 'volume',
- ]
-
- returnables = [
-
- ]
-
- updatables = [
-
- ]
-
-
-class ApiParameters(Parameters):
- @property
- def image_names(self):
- result = []
- result += self.read_image_from_device('image')
- result += self.read_image_from_device('hotfix')
- return result
-
- def read_image_from_device(self, t):
- uri = "https://{0}:{1}/mgmt/tm/sys/software/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- t,
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return []
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- return []
- else:
- return []
- if 'items' not in response:
- return []
- return [x['name'].split('/')[0] for x in response['items']]
-
-
-class ModuleParameters(Parameters):
- @property
- def version(self):
- if self._values['version']:
- return self._values['version']
-
- self._values['version'] = self.image_info['version']
- return self._values['version']
-
- @property
- def build(self):
- # Return cached copy if we have it
- if self._values['build']:
- return self._values['build']
-
- # Otherwise, get copy from image info cache
- self._values['build'] = self.image_info['build']
- return self._values['build']
-
- @property
- def image_info(self):
- if self._values['image_info']:
- image = self._values['image_info']
- else:
- # Otherwise, get a new copy and store in cache
- image = self.read_image()
- self._values['image_info'] = image
- return image
-
- @property
- def image_type(self):
- if self._values['image_type']:
- return self._values['image_type']
- if 'software:image' in self.image_info['kind']:
- self._values['image_type'] = 'image'
- else:
- self._values['image_type'] = 'hotfix'
- return self._values['image_type']
-
- def read_image(self):
- image = self.read_image_from_device(type='image')
- if image:
- return image
- image = self.read_image_from_device(type='hotfix')
- if image:
- return image
- return None
-
- def read_image_from_device(self, type):
- uri = "https://{0}:{1}/mgmt/tm/sys/software/{2}/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- type,
- )
- resp = self.client.api.get(uri)
-
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'items' in response:
- for item in response['items']:
- if item['name'].startswith(self.image):
- return item
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class UsableChanges(Changes):
- pass
-
-
-class ReportableChanges(Changes):
- pass
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(params=self.module.params, client=self.client)
- self.have = ApiParameters(client=self.client)
- self.changes = UsableChanges()
- self.volume_url = None
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = UsableChanges(params=changed)
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def exec_module(self):
- result = dict()
-
- changed = self.present()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.client.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def present(self):
- if self.exists():
- return False
- else:
- return self.update()
-
- def _set_volume_url(self, item):
- path = urlparse(item['selfLink']).path
- self.volume_url = "https://{0}:{1}{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- path
- )
-
- def exists(self):
- uri = "https://{0}:{1}/mgmt/tm/sys/software/volume/".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- resp = self.client.api.get(uri)
-
- try:
- collection = resp.json()
- except ValueError:
- return False
-
- for item in collection['items']:
- if item['name'].startswith(self.want.volume):
- self._set_volume_url(item)
- break
-
- if not self.volume_url:
- self.volume_url = uri + self.want.volume
-
- resp = self.client.api.get(self.volume_url)
-
- try:
- response = resp.json()
- except ValueError:
- return False
-
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
-
- # version key can be missing in the event that an existing volume has
- # no installed software in it.
- if self.want.version != response.get('version', None):
- return False
- if self.want.build != response.get('build', None):
- return False
-
- if self.want.state == 'installed':
- return True
- if self.want.state == 'activated':
- if 'defaultBootLocation' in response['media'][0]:
- return True
- return False
-
- def volume_exists(self):
- resp = self.client.api.get(self.volume_url)
-
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def update(self):
- if self.module.check_mode:
- return True
-
- if self.want.image and self.want.image not in self.have.image_names:
- raise F5ModuleError(
- "The specified image was not found on the device."
- )
-
- options = list()
- if not self.volume_exists():
- options.append({'create-volume': True})
- if self.want.state == 'activated':
- options.append({'reboot': True})
- self.want.update({'options': options})
-
- self.update_on_device()
- self.wait_for_software_install_on_device()
- if self.want.state == 'activated':
- self.wait_for_device_reboot()
- return True
-
- def update_on_device(self):
- params = {
- "command": "install",
- "name": self.want.image,
- }
- params.update(self.want.api_params())
-
- uri = "https://{0}:{1}/mgmt/tm/sys/software/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- self.want.image_type
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- if 'commandResult' in response and len(response['commandResult'].strip()) > 0:
- raise F5ModuleError(response['commandResult'])
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return True
-
- def wait_for_device_reboot(self):
- while True:
- time.sleep(5)
- try:
- self.client.reconnect()
- volume = self.read_volume_from_device()
- if volume is None:
- continue
- if 'active' in volume and volume['active'] is True:
- break
- except F5ModuleError:
- # Handle all exceptions because if the system is offline (for a
- # reboot) the REST client will raise exceptions about
- # connections
- pass
-
- def wait_for_software_install_on_device(self):
- # We need to delay this slightly in case the volume needs to be
- # created first
- for dummy in range(10):
- try:
- if self.volume_exists():
- break
- except F5ModuleError:
- pass
- time.sleep(5)
- while True:
- time.sleep(10)
- volume = self.read_volume_from_device()
- if volume is None or 'status' not in volume:
- self.client.reconnect()
- continue
- if volume['status'] == 'complete':
- break
- elif volume['status'] == 'failed':
- raise F5ModuleError
-
- def read_volume_from_device(self):
- try:
- resp = self.client.api.get(self.volume_url)
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- except ssl.SSLError:
- # Suggests BIG-IP is still in the middle of restarting itself or
- # restjavad is restarting.
- return None
- except URLError:
- # At times during reboot BIG-IP will reset or timeout connections so we catch and pass this here.
- return None
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return response
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- image=dict(),
- volume=dict(),
- state=dict(
- default='activated',
- choices=['activated', 'installed']
- ),
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode,
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_software_update.py b/lib/ansible/modules/network/f5/bigip_software_update.py
deleted file mode 100644
index 3e11154444..0000000000
--- a/lib/ansible/modules/network/f5/bigip_software_update.py
+++ /dev/null
@@ -1,335 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['stableinterface'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_software_update
-short_description: Manage the software update settings of a BIG-IP
-description:
- - Manage the software update settings of a BIG-IP.
-version_added: 2.5
-options:
- auto_check:
- description:
- - Specifies whether to automatically check for updates on the F5
- Networks downloads server.
- type: bool
- auto_phone_home:
- description:
- - Specifies whether to automatically send phone home data to the
- F5 Networks PhoneHome server.
- type: bool
- frequency:
- description:
- - Specifies the schedule for the automatic update check.
- type: str
- choices:
- - daily
- - monthly
- - weekly
-extends_documentation_fragment: f5
-author:
- - Tim Rupp (@caphrim007)
- - Wojciech Wypior (@wojtek0806)
-'''
-
-EXAMPLES = r'''
-- name: Enable automatic update checking
- bigip_software_update:
- auto_check: yes
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-
-- name: Disable automatic update checking and phoning home
- bigip_software_update:
- auto_check: no
- auto_phone_home: no
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-'''
-
-RETURN = r'''
-auto_check:
- description: Whether the system checks for updates automatically.
- returned: changed
- type: bool
- sample: True
-auto_phone_home:
- description: Whether the system automatically sends phone home data.
- returned: changed
- type: bool
- sample: True
-frequency:
- description: Frequency of auto update checks
- returned: changed
- type: str
- sample: weekly
-'''
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import f5_argument_spec
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import f5_argument_spec
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'autoCheck': 'auto_check',
- 'autoPhonehome': 'auto_phone_home'
- }
-
- api_attributes = [
- 'autoCheck', 'autoPhonehome', 'frequency',
- ]
-
- updatables = [
- 'auto_check', 'auto_phone_home', 'frequency',
- ]
-
- returnables = [
- 'auto_check', 'auto_phone_home', 'frequency',
- ]
-
-
-class ApiParameters(Parameters):
- @property
- def auto_check(self):
- if self._values['auto_check'] is None:
- return None
- return self._values['auto_check']
-
-
-class ModuleParameters(Parameters):
- @property
- def auto_check(self):
- if self._values['auto_check'] is None:
- return None
- elif self._values['auto_check'] is True:
- return 'enabled'
- else:
- return 'disabled'
-
- @property
- def auto_phone_home(self):
- if self._values['auto_phone_home'] is None:
- return None
- elif self._values['auto_phone_home'] is True:
- return 'enabled'
- else:
- return 'disabled'
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class UsableChanges(Changes):
- pass
-
-
-class ReportableChanges(Changes):
- @property
- def auto_check(self):
- if self._values['auto_check'] == 'enabled':
- return True
- elif self._values['auto_check'] == 'disabled':
- return False
-
- @property
- def auto_phone_home(self):
- if self._values['auto_phone_home'] == 'enabled':
- return True
- elif self._values['auto_phone_home'] == 'disabled':
- return False
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.have = None
- self.want = ModuleParameters(params=self.module.params)
- self.changes = UsableChanges()
-
- def exec_module(self):
- result = dict()
-
- changed = self.update()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def update(self):
- self.have = self.read_current_from_device()
- if not self.should_update():
- return False
- if self.module.check_mode:
- return True
- self.update_on_device()
- return True
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/sys/software/update/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return ApiParameters(params=response)
-
- def update_on_device(self):
- params = self.changes.api_params()
- uri = "https://{0}:{1}/mgmt/tm/sys/software/update/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- auto_check=dict(
- type='bool'
- ),
- auto_phone_home=dict(
- type='bool'
- ),
- frequency=dict(
- choices=['daily', 'monthly', 'weekly']
- )
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_ssl_certificate.py b/lib/ansible/modules/network/f5/bigip_ssl_certificate.py
deleted file mode 100644
index 58a69ab149..0000000000
--- a/lib/ansible/modules/network/f5/bigip_ssl_certificate.py
+++ /dev/null
@@ -1,579 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['stableinterface'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_ssl_certificate
-short_description: Import/Delete certificates from BIG-IP
-description:
- - This module will import/delete SSL certificates on BIG-IP LTM.
- Certificates can be imported from certificate and key files on the local
- disk, in PEM format.
-version_added: 2.2
-options:
- content:
- description:
- - Sets the contents of a certificate directly to the specified value.
- This is used with lookup plugins or for anything with formatting or
- - C(content) must be provided when C(state) is C(present).
- type: str
- aliases: ['cert_content']
- state:
- description:
- - Certificate state. This determines if the provided certificate
- and key is to be made C(present) on the device or C(absent).
- type: str
- choices:
- - present
- - absent
- default: present
- name:
- description:
- - SSL Certificate Name. This is the cert name used when importing a certificate
- into the F5. It also determines the filenames of the objects on the LTM.
- type: str
- required: True
- issuer_cert:
- description:
- - Issuer certificate used for OCSP monitoring.
- - This parameter is only valid on versions of BIG-IP 13.0.0 or above.
- type: str
- version_added: 2.5
- partition:
- description:
- - Device partition to manage resources on.
- type: str
- default: Common
- version_added: 2.5
-notes:
- - This module does not behave like other modules that you might include in
- roles where referencing files or templates first looks in the role's
- files or templates directory. To have it behave that way, use the Ansible
- file or template lookup (see Examples). The lookups behave as expected in
- a role context.
-extends_documentation_fragment: f5
-requirements:
- - BIG-IP >= v12
-author:
- - Tim Rupp (@caphrim007)
- - Wojciech Wypior (@wojtek0806)
-'''
-
-EXAMPLES = r'''
-- name: Use a file lookup to import PEM Certificate
- bigip_ssl_certificate:
- name: certificate-name
- state: present
- content: "{{ lookup('file', '/path/to/cert.crt') }}"
- provider:
- server: lb.mydomain.com
- user: admin
- password: secret
- delegate_to: localhost
-
-- name: Use a file lookup to import CA certificate chain
- bigip_ssl_certificate:
- name: ca-chain-name
- state: present
- content: "{{ lookup('file', '/path/to/ca-chain.crt') }}"
- provider:
- server: lb.mydomain.com
- user: admin
- password: secret
- delegate_to: localhost
-
-- name: Delete Certificate
- bigip_ssl_certificate:
- name: certificate-name
- state: absent
- provider:
- server: lb.mydomain.com
- user: admin
- password: secret
- delegate_to: localhost
-'''
-
-RETURN = r'''
-cert_name:
- description: The name of the certificate that the user provided
- returned: created
- type: str
- sample: cert1
-filename:
- description:
- - The name of the SSL certificate.
- returned: created
- type: str
- sample: cert1.crt
-checksum:
- description: SHA1 checksum of the cert that was provided.
- returned: changed and created
- type: str
- sample: f7ff9e8b7bb2e09b70935a5d785e0cc5d9d0abf0
-source_path:
- description: Path on BIG-IP where the source of the certificate is stored.
- returned: created
- type: str
- sample: /var/config/rest/downloads/cert1.crt
-'''
-
-import hashlib
-import os
-import re
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.basic import env_fallback
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.common import fq_name
- from library.module_utils.network.f5.common import transform_name
- from library.module_utils.network.f5.icontrol import upload_file
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.common import fq_name
- from ansible.module_utils.network.f5.common import transform_name
- from ansible.module_utils.network.f5.icontrol import upload_file
-
-try:
- from StringIO import StringIO
-except ImportError:
- from io import StringIO
-
-
-class Parameters(AnsibleF5Parameters):
- download_path = '/var/config/rest/downloads'
-
- api_map = {
- 'sourcePath': 'source_path',
- 'issuerCert': 'issuer_cert',
- }
-
- updatables = [
- 'content',
- 'issuer_cert',
- 'source_path',
- ]
-
- returnables = [
- 'filename',
- 'checksum',
- 'source_path',
- 'issuer_cert',
- ]
-
- api_attributes = [
- 'issuerCert',
- 'sourcePath',
- ]
-
-
-class ApiParameters(Parameters):
- @property
- def checksum(self):
- if self._values['checksum'] is None:
- return None
- pattern = r'SHA1:\d+:(?P<value>[\w+]{40})'
- matches = re.match(pattern, self._values['checksum'])
- if matches:
- return matches.group('value')
- else:
- return None
-
- @property
- def filename(self):
- return self._values['name']
-
-
-class ModuleParameters(Parameters):
- def _get_hash(self, content):
- k = hashlib.sha1()
- s = StringIO(content)
- while True:
- data = s.read(1024)
- if not data:
- break
- k.update(data.encode('utf-8'))
- return k.hexdigest()
-
- @property
- def issuer_cert(self):
- if self._values['issuer_cert'] is None:
- return None
- name = fq_name(self.partition, self._values['issuer_cert'])
- if name.endswith('.crt'):
- return name
- else:
- return name + '.crt'
-
- @property
- def checksum(self):
- if self.content is None:
- return None
- return self._get_hash(self.content)
-
- @property
- def filename(self):
- if self.name.endswith('.crt'):
- return self.name
- else:
- return self.name + '.crt'
-
- @property
- def source_path(self):
- result = 'file://' + os.path.join(
- self.download_path,
- self.filename
- )
- return result
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class ReportableChanges(Changes):
- pass
-
-
-class UsableChanges(Changes):
- pass
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- result = self.__default(param)
- return result
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
- @property
- def source_path(self):
- if self.want.source_path is None:
- return None
- if self.want.source_path == self.have.source_path:
- if self.content:
- return self.want.source_path
- if self.want.source_path != self.have.source_path:
- return self.want.source_path
-
- @property
- def content(self):
- if self.want.checksum != self.have.checksum:
- result = dict(
- checksum=self.want.checksum,
- content=self.want.content
- )
- return result
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(params=self.module.params)
- self.have = ApiParameters()
- self.changes = UsableChanges()
-
- def exec_module(self):
- changed = False
- result = dict()
- state = self.want.state
-
- if state == "present":
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def present(self):
- if self.exists():
- return self.update()
- else:
- return self.create()
-
- def create(self):
- self._set_changed_options()
- if self.module.check_mode:
- return True
- self.create_on_device()
- return True
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def update(self):
- self.have = self.read_current_from_device()
- if not self.should_update():
- return False
- if self.module.check_mode:
- return True
- self.update_on_device()
- return True
-
- def absent(self):
- if self.exists():
- return self.remove()
- return False
-
- def remove(self):
- if self.module.check_mode:
- return True
- self.remove_from_device()
- return True
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = UsableChanges(params=changed)
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def exists(self):
- uri = "https://{0}:{1}/mgmt/tm/sys/file/ssl-cert/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.filename)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def upload_file_to_device(self, content, name):
- url = 'https://{0}:{1}/mgmt/shared/file-transfer/uploads'.format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- try:
- upload_file(self.client, url, content, name)
- except F5ModuleError:
- raise F5ModuleError(
- "Failed to upload the file."
- )
-
- def update_on_device(self):
- content = StringIO(self.want.content)
- self.upload_file_to_device(content, self.want.filename)
- params = self.changes.api_params()
- uri = "https://{0}:{1}/mgmt/tm/sys/file/ssl-cert/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.filename)
- )
- resp = self.client.api.put(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def create_on_device(self):
- content = StringIO(self.want.content)
- self.upload_file_to_device(content, self.want.filename)
- uri = "https://{0}:{1}/mgmt/tm/sys/file/ssl-cert/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- params = dict(
- sourcePath=self.want.source_path,
- name=self.want.filename,
- partition=self.want.partition
- )
-
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- # This needs to be done because of the way that BIG-IP creates certificates.
- #
- # The extra params (such as OCSP and issuer stuff) are not available in the
- # payload. In a nutshell, the available resource attributes *change* after
- # a create so that *more* are available.
- params = self.want.api_params()
- if params:
- uri = "https://{0}:{1}/mgmt/tm/sys/file/ssl-cert/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.filename)
- )
- resp = self.client.api.put(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/sys/file/ssl-cert/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.filename)
- )
-
- query = '?expandSubcollections=true'
- resp = self.client.api.get(uri + query)
-
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return ApiParameters(params=response)
-
- def remove_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/sys/file/ssl-cert/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.filename)
- )
- response = self.client.api.delete(uri)
- if response.status == 200:
- return True
- raise F5ModuleError(response.content)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- name=dict(
- required=True
- ),
- content=dict(aliases=['cert_content']),
- state=dict(
- default='present',
- choices=['absent', 'present']
- ),
- issuer_cert=dict(),
- partition=dict(
- default='Common',
- fallback=(env_fallback, ['F5_PARTITION'])
- )
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_ssl_key.py b/lib/ansible/modules/network/f5/bigip_ssl_key.py
deleted file mode 100644
index 67fd8b460f..0000000000
--- a/lib/ansible/modules/network/f5/bigip_ssl_key.py
+++ /dev/null
@@ -1,520 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['stableinterface'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_ssl_key
-short_description: Import/Delete SSL keys from BIG-IP
-description:
- - This module will import/delete SSL keys on a BIG-IP. Keys can be imported
- from key files on the local disk, in PEM format.
-version_added: 2.5
-options:
- content:
- description:
- - Sets the contents of a key directly to the specified value. This is
- used with lookup plugins or for anything with formatting or templating.
- This must be provided when C(state) is C(present).
- type: str
- aliases:
- - key_content
- state:
- description:
- - When C(present), ensures that the key is uploaded to the device. When
- C(absent), ensures that the key is removed from the device. If the key
- is currently in use, the module will not be able to remove the key.
- type: str
- choices:
- - present
- - absent
- default: present
- name:
- description:
- - The name of the key.
- type: str
- required: True
- passphrase:
- description:
- - Passphrase on key.
- type: str
- partition:
- description:
- - Device partition to manage resources on.
- type: str
- default: Common
- version_added: 2.5
-notes:
- - This module does not behave like other modules that you might include in
- roles where referencing files or templates first looks in the role's
- files or templates directory. To have it behave that way, use the Ansible
- file or template lookup (see Examples). The lookups behave as expected in
- a role context.
-extends_documentation_fragment: f5
-requirements:
- - BIG-IP >= v12
-author:
- - Tim Rupp (@caphrim007)
- - Wojciech Wypior (@wojtek0806)
-'''
-
-EXAMPLES = r'''
-- name: Use a file lookup to import key
- bigip_ssl_key:
- name: key-name
- state: present
- content: "{{ lookup('file', '/path/to/key.key') }}"
- provider:
- server: lb.mydomain.com
- user: admin
- password: secret
- delegate_to: localhost
-
-- name: Delete key
- bigip_ssl_key:
- name: key-name
- state: absent
- provider:
- server: lb.mydomain.com
- user: admin
- password: secret
- delegate_to: localhost
-'''
-
-RETURN = r'''
-key_filename:
- description:
- - The name of the SSL certificate key. The C(key_filename) and
- C(cert_filename) will be similar to each other, however the
- C(key_filename) will have a C(.key) extension.
- returned: created
- type: str
- sample: cert1.key
-key_checksum:
- description: SHA1 checksum of the key that was provided.
- returned: changed and created
- type: str
- sample: cf23df2207d99a74fbe169e3eba035e633b65d94
-key_source_path:
- description: Path on BIG-IP where the source of the key is stored
- returned: created
- type: str
- sample: /var/config/rest/downloads/cert1.key
-'''
-
-import hashlib
-import os
-import re
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.basic import env_fallback
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.common import transform_name
- from library.module_utils.network.f5.icontrol import upload_file
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.common import transform_name
- from ansible.module_utils.network.f5.icontrol import upload_file
-
-try:
- from StringIO import StringIO
-except ImportError:
- from io import StringIO
-
-
-class Parameters(AnsibleF5Parameters):
- download_path = '/var/config/rest/downloads'
-
- api_map = {
- 'sourcePath': 'key_source_path'
- }
-
- updatables = [
- 'key_checksum',
- 'key_source_path',
- ]
-
- returnables = [
- 'key_filename',
- 'key_checksum',
- 'key_source_path',
- ]
-
- api_attributes = [
- 'passphrase',
- 'sourcePath',
- ]
-
-
-class ApiParameters(Parameters):
- @property
- def checksum(self):
- if self._values['checksum'] is None:
- return None
- pattern = r'SHA1:\d+:(?P<value>[\w+]{40})'
- matches = re.match(pattern, self._values['checksum'])
- if matches:
- return matches.group('value')
- else:
- return None
-
-
-class ModuleParameters(Parameters):
- def _get_hash(self, content):
- k = hashlib.sha1()
- s = StringIO(content)
- while True:
- data = s.read(1024)
- if not data:
- break
- k.update(data.encode('utf-8'))
- return k.hexdigest()
-
- @property
- def key_filename(self):
- if self.name.endswith('.key'):
- return self.name
- else:
- return self.name + '.key'
-
- @property
- def key_checksum(self):
- if self.content is None:
- return None
- return self._get_hash(self.content)
-
- @property
- def key_source_path(self):
- result = 'file://' + os.path.join(
- self.download_path,
- self.key_filename
- )
- return result
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class UsableChanges(Changes):
- pass
-
-
-class ReportableChanges(Changes):
- pass
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
- @property
- def key_checksum(self):
- if self.want.key_checksum is None:
- return None
- if self.want.key_checksum != self.have.checksum:
- return self.want.key_checksum
-
- @property
- def key_source_path(self):
- if self.want.key_source_path is None:
- return None
- if self.want.key_source_path == self.have.key_source_path:
- if self.key_checksum:
- return self.want.key_source_path
- if self.want.key_source_path != self.have.key_source_path:
- return self.want.key_source_path
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(params=self.module.params)
- self.have = ApiParameters()
- self.changes = UsableChanges()
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.client.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = UsableChanges(params=changed)
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def exec_module(self):
- changed = False
- result = dict()
- state = self.want.state
-
- if state == "present":
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def present(self):
- if self.exists():
- return self.update()
- else:
- return self.create()
-
- def absent(self):
- if self.exists():
- return self.remove()
- return False
-
- def update(self):
- self.have = self.read_current_from_device()
- if not self.should_update():
- return False
- if self.module.check_mode:
- return True
- self.update_on_device()
- return True
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def create(self):
- if self.want.content is None:
- return False
- self._set_changed_options()
- if self.module.check_mode:
- return True
- self.create_on_device()
- return True
-
- def remove(self):
- if self.module.check_mode:
- return True
- self.remove_from_device()
- if self.exists():
- raise F5ModuleError("Failed to delete the key")
- return True
-
- def exists(self):
- uri = "https://{0}:{1}/mgmt/tm/sys/file/ssl-key/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.key_filename)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def upload_file_to_device(self, content, name):
- url = 'https://{0}:{1}/mgmt/shared/file-transfer/uploads'.format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- try:
- upload_file(self.client, url, content, name)
- except F5ModuleError:
- raise F5ModuleError(
- "Failed to upload the file."
- )
-
- def update_on_device(self):
- content = StringIO(self.want.content)
- self.upload_file_to_device(content, self.want.key_filename)
- params = self.changes.api_params()
- uri = "https://{0}:{1}/mgmt/tm/sys/file/ssl-key/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.key_filename)
- )
- resp = self.client.api.put(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def create_on_device(self):
- params = self.changes.api_params()
- content = StringIO(self.want.content)
- self.upload_file_to_device(content, self.want.key_filename)
- params['name'] = self.want.key_filename
- params['partition'] = self.want.partition
- uri = "https://{0}:{1}/mgmt/tm/sys/file/ssl-key/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/sys/file/ssl-key/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.key_filename)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return ApiParameters(params=response)
-
- def remove_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/sys/file/ssl-key/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.key_filename)
- )
- response = self.client.api.delete(uri)
- if response.status == 200:
- return True
- raise F5ModuleError(response.content)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- name=dict(
- required=True
- ),
- content=dict(
- aliases=['key_content']
- ),
- passphrase=dict(
- no_log=True
- ),
- state=dict(
- required=False,
- default='present',
- choices=['absent', 'present']
- ),
- partition=dict(
- default='Common',
- fallback=(env_fallback, ['F5_PARTITION'])
- )
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_ssl_ocsp.py b/lib/ansible/modules/network/f5/bigip_ssl_ocsp.py
deleted file mode 100644
index 34c53c47bf..0000000000
--- a/lib/ansible/modules/network/f5/bigip_ssl_ocsp.py
+++ /dev/null
@@ -1,775 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2018, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_ssl_ocsp
-short_description: Manage OCSP configurations on BIG-IP
-description:
- - Manage OCSP configurations on BIG-IP.
-version_added: 2.8
-options:
- name:
- description:
- - Specifies the name of the OCSP certificate validator.
- type: str
- required: True
- cache_error_timeout:
- description:
- - Specifies the lifetime of an error response in the cache, in seconds.
- type: int
- proxy_server_pool:
- description:
- - Specifies the proxy server pool the BIG-IP system uses to fetch the OCSP
- response.
- - This involves creating a pool with proxy-servers.
- - Use this option when either the OCSP responder cannot be reached on any of
- BIG-IP system's interfaces or one or more servers can proxy an HTTP request
- to an external server and fetch the response.
- type: str
- cache_timeout:
- description:
- - Specifies the lifetime of the OCSP response in the cache, in seconds.
- type: str
- clock_skew:
- description:
- - Specifies the tolerable absolute difference in the clocks of the responder
- and the BIG-IP system, in seconds.
- type: int
- connections_limit:
- description:
- - Specifies the maximum number of connections per second allowed for the
- OCSP certificate validator.
- type: int
- dns_resolver:
- description:
- - Specifies the internal DNS resolver the BIG-IP system uses to fetch the
- OCSP response.
- - This involves specifying one or more DNS servers in the DNS resolver
- configuration.
- - Use this option when either there is a DNS server that can do the
- name-resolution of the OCSP responders or the OCSP responder can be
- reached on one of BIG-IP system's interfaces.
- type: str
- route_domain:
- description:
- - Specifies the route domain for fetching an OCSP response using HTTP
- forward proxy.
- type: str
- hash_algorithm:
- description:
- - Specifies a hash algorithm used to sign an OCSP request.
- type: str
- choices:
- - sha256
- - sha1
- certificate:
- description:
- - Specifies a certificate used to sign an OCSP request.
- type: str
- key:
- description:
- - Specifies a key used to sign an OCSP request.
- type: str
- passphrase:
- description:
- - Specifies a passphrase used to sign an OCSP request.
- type: str
- status_age:
- description:
- - Specifies the maximum allowed lag time that the BIG-IP system accepts for
- the 'thisUpdate' time in the OCSP response.
- type: int
- strict_responder_checking:
- description:
- - Specifies whether the responder's certificate is checked for an OCSP
- signing extension.
- type: bool
- connection_timeout:
- description:
- - Specifies the time interval that the BIG-IP system waits for before
- ending the connection to the OCSP responder, in seconds.
- type: int
- trusted_responders:
- description:
- - Specifies the certificates used for validating the OCSP response
- when the responder's certificate has been omitted from the response.
- type: str
- responder_url:
- description:
- - Specifies the absolute URL that overrides the OCSP responder URL
- obtained from the certificate's AIA extensions. This should be an
- HTTP-based URL.
- type: str
- update_password:
- description:
- - C(always) will allow to update passwords if the user chooses to do so.
- C(on_create) will only set the password for newly created OCSP validators.
- type: str
- choices:
- - always
- - on_create
- default: always
- partition:
- description:
- - Device partition to manage resources on.
- type: str
- default: Common
- version_added: 2.5
- state:
- description:
- - When C(present), ensures that the resource exists.
- - When C(absent), ensures that the resource does not exist.
- type: str
- choices:
- - present
- - absent
- default: present
-extends_documentation_fragment: f5
-notes:
- - Requires BIG-IP >= 13.x.
-author:
- - Tim Rupp (@caphrim007)
-'''
-
-EXAMPLES = r'''
-- name: Create a OCSP validator
- bigip_ssl_ocsp:
- name: foo
- proxy_server_pool: validators-pool
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-'''
-
-RETURN = r'''
-cache_error_timeout:
- description: The new Response Caching Error Timeout value.
- returned: changed
- type: int
- sample: 3600
-cache_timeout:
- description: The new Response Caching Timeout value.
- returned: changed
- type: str
- sample: indefinite
-clock_skew:
- description: The new Response Validation Clock Skew value.
- returned: changed
- type: int
- sample: 300
-connections_limit:
- description: The new Concurrent Connections Limit value.
- returned: changed
- type: int
- sample: 50
-dns_resolver:
- description: The new DNS Resolver value.
- returned: changed
- type: str
- sample: /Common/resolver1
-route_domain:
- description: The new Route Domain value.
- returned: changed
- type: str
- sample: /Common/0
-hash_algorithm:
- description: The new Request Signing Hash Algorithm value.
- returned: changed
- type: str
- sample: sha256
-certificate:
- description: The new Request Signing Certificate value.
- returned: changed
- type: str
- sample: /Common/cert1
-key:
- description: The new Request Signing Key value.
- returned: changed
- type: str
- sample: /Common/key1
-proxy_server_pool:
- description: The new Proxy Server Pool value.
- returned: changed
- type: str
- sample: /Common/pool1
-responder_url:
- description: The new Connection Responder URL value.
- returned: changed
- type: str
- sample: "http://responder.site.com"
-status_age:
- description: The new Response Validation Status Age value.
- returned: changed
- type: int
- sample: 0
-strict_responder_checking:
- description: The new Response Validation Strict Responder Certificate Checking value.
- returned: changed
- type: bool
- sample: yes
-connection_timeout:
- description: The new Connection Timeout value.
- returned: changed
- type: int
- sample: 8
-trusted_responders:
- description: The new Response Validation Trusted Responders value.
- returned: changed
- type: int
- sample: /Common/default
-'''
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.basic import env_fallback
-from distutils.version import LooseVersion
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import fq_name
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.common import transform_name
- from library.module_utils.network.f5.common import flatten_boolean
- from library.module_utils.network.f5.icontrol import tmos_version
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import fq_name
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.common import transform_name
- from ansible.module_utils.network.f5.common import flatten_boolean
- from ansible.module_utils.network.f5.icontrol import tmos_version
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'cacheErrorTimeout': 'cache_error_timeout',
- 'cacheTimeout': 'cache_timeout',
- 'clockSkew': 'clock_skew',
- 'concurrentConnectionsLimit': 'connections_limit',
- 'dnsResolver': 'dns_resolver',
- 'proxyServerPool': 'proxy_server_pool',
- 'responderUrl': 'responder_url',
- 'routeDomain': 'route_domain',
- 'signHash': 'hash_algorithm',
- 'signerCert': 'certificate',
- 'signerKey': 'key',
- 'signerKeyPassphrase': 'passphrase',
- 'statusAge': 'status_age',
- 'strictRespCertCheck': 'strict_responder_checking',
- 'timeout': 'connection_timeout',
- 'trustedResponders': 'trusted_responders',
- }
-
- api_attributes = [
- 'cacheErrorTimeout',
- 'cacheTimeout',
- 'clockSkew',
- 'concurrentConnectionsLimit',
- 'dnsResolver',
- 'routeDomain',
- 'proxyServerPool',
- 'responderUrl',
- 'signHash',
- 'signerCert',
- 'signerKey',
- 'signerKeyPassphrase',
- 'statusAge',
- 'strictRespCertCheck',
- 'timeout',
- 'trustedResponders',
- ]
-
- returnables = [
- 'cache_error_timeout',
- 'cache_timeout',
- 'clock_skew',
- 'connections_limit',
- 'dns_resolver',
- 'route_domain',
- 'hash_algorithm',
- 'certificate',
- 'key',
- 'passphrase',
- 'proxy_server_pool',
- 'responder_url',
- 'status_age',
- 'strict_responder_checking',
- 'connection_timeout',
- 'trusted_responders',
- ]
-
- updatables = [
- 'cache_error_timeout',
- 'cache_timeout',
- 'clock_skew',
- 'connections_limit',
- 'dns_resolver',
- 'route_domain',
- 'hash_algorithm',
- 'certificate',
- 'key',
- 'passphrase',
- 'proxy_server_pool',
- 'responder_url',
- 'status_age',
- 'strict_responder_checking',
- 'connection_timeout',
- 'trusted_responders',
- ]
-
- @property
- def strict_responder_checking(self):
- return flatten_boolean(self._values['strict_responder_checking'])
-
- @property
- def cache_timeout(self):
- if self._values['cache_timeout'] is None:
- return None
- try:
- return int(self._values['cache_timeout'])
- except ValueError:
- return self._values['cache_timeout']
-
-
-class ApiParameters(Parameters):
- pass
-
-
-class ModuleParameters(Parameters):
- @property
- def route_domain(self):
- if self._values['route_domain'] is None:
- return None
- result = fq_name(self.partition, self._values['route_domain'])
- return result
-
- @property
- def dns_resolver(self):
- if self._values['dns_resolver'] is None:
- return None
- result = fq_name(self.partition, self._values['dns_resolver'])
- return result
-
- @property
- def proxy_server_pool(self):
- if self._values['proxy_server_pool'] is None:
- return None
- result = fq_name(self.partition, self._values['proxy_server_pool'])
- return result
-
- @property
- def responder_url(self):
- if self._values['responder_url'] is None:
- return None
- if self._values['responder_url'] in ['', 'none']:
- return ''
- return self._values['responder_url']
-
- @property
- def certificate(self):
- if self._values['certificate'] is None:
- return None
- if self._values['certificate'] in ['', 'none']:
- return ''
- result = fq_name(self.partition, self._values['certificate'])
- return result
-
- @property
- def key(self):
- if self._values['key'] is None:
- return None
- if self._values['key'] in ['', 'none']:
- return ''
- result = fq_name(self.partition, self._values['key'])
- return result
-
- @property
- def trusted_responders(self):
- if self._values['trusted_responders'] is None:
- return None
- if self._values['trusted_responders'] in ['', 'none']:
- return ''
- result = fq_name(self.partition, self._values['trusted_responders'])
- return result
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class UsableChanges(Changes):
- @property
- def strict_responder_checking(self):
- if self._values['strict_responder_checking'] == 'yes':
- return 'enabled'
- elif self._values['strict_responder_checking'] == 'no':
- return 'disabled'
-
-
-class ReportableChanges(Changes):
- @property
- def strict_responder_checking(self):
- result = flatten_boolean(self._values['strict_responder_checking'])
- return result
-
- @property
- def passphrase(self):
- return None
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
- @property
- def responder_url(self):
- if self.want.responder_url is None:
- return None
- if self.want.responder_url == '' and self.have.responder_url is None:
- return None
- if self.want.responder_url != self.have.responder_url:
- return self.want.responder_url
-
- @property
- def certificate(self):
- if self.want.certificate is None:
- return None
- if self.want.certificate == '' and self.have.certificate is None:
- return None
- if self.want.certificate != self.have.certificate:
- return self.want.certificate
-
- @property
- def key(self):
- if self.want.key is None:
- return None
- if self.want.key == '' and self.have.key is None:
- return None
- if self.want.key != self.have.key:
- return self.want.key
-
- @property
- def trusted_responders(self):
- if self.want.trusted_responders is None:
- return None
- if self.want.trusted_responders == '' and self.have.trusted_responders is None:
- return None
- if self.want.trusted_responders != self.have.trusted_responders:
- return self.want.trusted_responders
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(params=self.module.params)
- self.have = ApiParameters()
- self.changes = UsableChanges()
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = UsableChanges(params=changed)
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def exec_module(self):
- tmos = tmos_version(self.client)
- if LooseVersion(tmos) < LooseVersion('13.0.0'):
- raise F5ModuleError(
- "BIG-IP v13 or greater is required to use this module."
- )
- changed = False
- result = dict()
- state = self.want.state
-
- if state == "present":
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.client.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def present(self):
- if self.exists():
- return self.update()
- else:
- return self.create()
-
- def exists(self):
- uri = "https://{0}:{1}/mgmt/tm/sys/crypto/cert-validator/ocsp/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def update(self):
- self.have = self.read_current_from_device()
-
- if self.want.update_password == 'always':
- self.want.update({'passphrase': self.want.passphrase})
- else:
- if self.want.passphrase:
- del self.want._values['passphrase']
-
- if not self.should_update():
- return False
-
- # these two params are mutually exclusive, and so one must be zeroed
- # out so that the other can be set. This zeros the non-specified values
- # out so that the PATCH can happen
- if self.want.dns_resolver:
- self.changes.update({'proxy_server_pool': ''})
- if self.want.proxy_server_pool:
- self.changes.update({'dns_resolver': ''})
-
- if self.module.check_mode:
- return True
- self.update_on_device()
- return True
-
- def remove(self):
- if self.module.check_mode:
- return True
- self.remove_from_device()
- if self.exists():
- raise F5ModuleError("Failed to delete the resource.")
- return True
-
- def create(self):
- self._set_changed_options()
- if self.module.check_mode:
- return True
- self.create_on_device()
- return True
-
- def create_on_device(self):
- params = self.changes.api_params()
- params['name'] = self.want.name
- params['partition'] = self.want.partition
- uri = "https://{0}:{1}/mgmt/tm/sys/crypto/cert-validator/ocsp/".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def update_on_device(self):
- params = self.changes.api_params()
- uri = "https://{0}:{1}/mgmt/tm/sys/crypto/cert-validator/ocsp/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def absent(self):
- if self.exists():
- return self.remove()
- return False
-
- def remove_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/sys/crypto/cert-validator/ocsp/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- response = self.client.api.delete(uri)
- if response.status == 200:
- return True
- raise F5ModuleError(response.content)
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/sys/crypto/cert-validator/ocsp/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return ApiParameters(params=response)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- name=dict(required=True),
- cache_error_timeout=dict(type='int'),
- proxy_server_pool=dict(),
- cache_timeout=dict(),
- clock_skew=dict(type='int'),
- connections_limit=dict(type='int'),
- dns_resolver=dict(),
- route_domain=dict(),
- hash_algorithm=dict(
- choices=['sha256', 'sha1']
- ),
- certificate=dict(),
- key=dict(),
- passphrase=dict(no_log=True),
- status_age=dict(type='int'),
- strict_responder_checking=dict(type='bool'),
- connection_timeout=dict(type='int'),
- trusted_responders=dict(),
- responder_url=dict(),
- update_password=dict(
- default='always',
- choices=['always', 'on_create']
- ),
- state=dict(
- default='present',
- choices=['present', 'absent']
- ),
- partition=dict(
- default='Common',
- fallback=(env_fallback, ['F5_PARTITION'])
- )
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
- self.mutually_exclusive = [
- ['dns_resolver', 'proxy_server_pool']
- ]
- self.required_together = [
- ['certificate', 'key']
- ]
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode,
- mutually_exclusive=spec.mutually_exclusive,
- required_together=spec.required_together,
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_static_route.py b/lib/ansible/modules/network/f5/bigip_static_route.py
deleted file mode 100644
index eaec82c715..0000000000
--- a/lib/ansible/modules/network/f5/bigip_static_route.py
+++ /dev/null
@@ -1,703 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['stableinterface'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_static_route
-short_description: Manipulate static routes on a BIG-IP
-description:
- - Manipulate static routes on a BIG-IP.
-version_added: 2.5
-options:
- name:
- description:
- - Name of the static route.
- type: str
- required: True
- description:
- description:
- - Descriptive text that identifies the route.
- type: str
- destination:
- description:
- - Specifies an IP address for the static entry in the routing table.
- When creating a new static route, this value is required.
- - This value cannot be changed once it is set.
- type: str
- netmask:
- description:
- - The netmask for the static route. When creating a new static route, this value
- is required.
- - This value can be in either IP or CIDR format.
- - This value cannot be changed once it is set.
- type: str
- gateway_address:
- description:
- - Specifies the router for the system to use when forwarding packets
- to the destination host or network. Also known as the next-hop router
- address. This can be either an IPv4 or IPv6 address. When it is an
- IPv6 address that starts with C(FE80:), the address will be treated
- as a link-local address. This requires that the C(vlan) parameter
- also be supplied.
- type: str
- vlan:
- description:
- - Specifies the VLAN or Tunnel through which the system forwards packets
- to the destination. When C(gateway_address) is a link-local IPv6
- address, this value is required.
- type: str
- pool:
- description:
- - Specifies the pool through which the system forwards packets to the
- destination.
- type: str
- reject:
- description:
- - Specifies that the system drops packets sent to the destination.
- type: bool
- mtu:
- description:
- - Specifies a specific maximum transmission unit (MTU).
- type: str
- route_domain:
- description:
- - The route domain id of the system. When creating a new static route, if
- this value is not specified, a default value of C(0) will be used.
- - This value cannot be changed once it is set.
- type: int
- partition:
- description:
- - Device partition to manage resources on.
- type: str
- default: Common
- version_added: 2.6
- state:
- description:
- - When C(present), ensures that the static route exists.
- - When C(absent), ensures that the static does not exist.
- type: str
- choices:
- - present
- - absent
- default: present
-extends_documentation_fragment: f5
-author:
- - Tim Rupp (@caphrim007)
-'''
-
-EXAMPLES = r'''
-- name: Create static route with gateway address
- bigip_static_route:
- destination: 10.10.10.10
- netmask: 255.255.255.255
- gateway_address: 10.2.2.3
- name: test-route
- provider:
- password: secret
- server: lb.mydomain.come
- user: admin
- validate_certs: no
- delegate_to: localhost
-'''
-
-RETURN = r'''
-vlan:
- description: Whether the banner is enabled or not.
- returned: changed
- type: str
- sample: true
-gateway_address:
- description: Whether the banner is enabled or not.
- returned: changed
- type: str
- sample: true
-destination:
- description: Whether the banner is enabled or not.
- returned: changed
- type: str
- sample: true
-route_domain:
- description: Route domain of the static route.
- returned: changed
- type: int
- sample: 1
-netmask:
- description: Netmask of the destination.
- returned: changed
- type: str
- sample: 255.255.255.255
-pool:
- description: Whether the banner is enabled or not.
- returned: changed
- type: str
- sample: true
-partition:
- description: The partition that the static route was created on.
- returned: changed
- type: str
- sample: Common
-description:
- description: Whether the banner is enabled or not.
- returned: changed
- type: str
- sample: true
-reject:
- description: Whether the banner is enabled or not.
- returned: changed
- type: str
- sample: true
-'''
-
-import re
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.basic import env_fallback
-from ansible.module_utils.parsing.convert_bool import BOOLEANS_TRUE
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import fq_name
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.common import transform_name
- from library.module_utils.network.f5.ipaddress import is_valid_ip
- from library.module_utils.network.f5.ipaddress import ipv6_netmask_to_cidr
- from library.module_utils.compat.ipaddress import ip_address
- from library.module_utils.compat.ipaddress import ip_network
- from library.module_utils.compat.ipaddress import ip_interface
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import fq_name
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.common import transform_name
- from ansible.module_utils.network.f5.ipaddress import is_valid_ip
- from ansible.module_utils.network.f5.ipaddress import ipv6_netmask_to_cidr
- from ansible.module_utils.compat.ipaddress import ip_address
- from ansible.module_utils.compat.ipaddress import ip_network
- from ansible.module_utils.compat.ipaddress import ip_interface
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'tmInterface': 'vlan',
- 'gw': 'gateway_address',
- 'network': 'destination',
- 'blackhole': 'reject'
- }
-
- updatables = [
- 'description',
- 'gateway_address',
- 'vlan',
- 'pool',
- 'mtu',
- 'reject',
- 'destination',
- 'route_domain',
- 'netmask',
- ]
-
- returnables = [
- 'vlan',
- 'gateway_address',
- 'destination',
- 'pool',
- 'description',
- 'reject',
- 'mtu',
- 'netmask',
- 'route_domain',
- ]
-
- api_attributes = [
- 'tmInterface',
- 'gw',
- 'network',
- 'blackhole',
- 'description',
- 'pool',
- 'mtu',
- ]
-
- def to_return(self):
- result = {}
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- return result
-
- @property
- def reject(self):
- if self._values['reject'] in BOOLEANS_TRUE:
- return True
-
-
-class ModuleParameters(Parameters):
- @property
- def vlan(self):
- if self._values['vlan'] is None:
- return None
- return fq_name(self.partition, self._values['vlan'])
-
- @property
- def gateway_address(self):
- if self._values['gateway_address'] is None:
- return None
- try:
- if '%' in self._values['gateway_address']:
- addr = self._values['gateway_address'].split('%')[0]
- else:
- addr = self._values['gateway_address']
- ip_interface(u'%s' % str(addr))
- return str(self._values['gateway_address'])
- except ValueError:
- raise F5ModuleError(
- "The provided gateway_address is not an IP address"
- )
-
- @property
- def route_domain(self):
- if self._values['route_domain'] is None:
- return None
- result = int(self._values['route_domain'])
- return result
-
- @property
- def destination(self):
- if self._values['destination'] is None:
- return None
- if self._values['destination'].startswith('default'):
- self._values['destination'] = '0.0.0.0/0'
- if self._values['destination'].startswith('default-inet6'):
- self._values['destination'] = '::/0'
- try:
- ip = ip_network(u'%s' % str(self.destination_ip))
- if self.route_domain:
- return '{0}%{1}/{2}'.format(str(ip.network_address), self.route_domain, ip.prefixlen)
- else:
- return '{0}/{1}'.format(str(ip.network_address), ip.prefixlen)
- except ValueError:
- raise F5ModuleError(
- "The provided destination is not an IP address"
- )
-
- @property
- def destination_ip(self):
- if self._values['destination']:
- ip = ip_network(u'{0}/{1}'.format(self._values['destination'], self.netmask))
- return '{0}/{1}'.format(str(ip.network_address), ip.prefixlen)
-
- @property
- def netmask(self):
- if self._values['netmask'] is None:
- return None
- try:
- result = int(self._values['netmask'])
-
- # CIDRs between 0 and 128 are allowed
- if 0 <= result <= 128:
- return result
- else:
- raise F5ModuleError(
- "The provided netmask must be between 0 and 32 for IPv4, or "
- "0 and 128 for IPv6."
- )
- except ValueError:
- # not a number, but that's ok. Further processing necessary
- pass
-
- if not is_valid_ip(self._values['netmask']):
- raise F5ModuleError(
- 'The provided netmask {0} is neither in IP or CIDR format'.format(result)
- )
-
- # Create a temporary address to check if the netmask IP is v4 or v6
- addr = ip_address(u'{0}'.format(str(self._values['netmask'])))
- if addr.version == 4:
- # Create a more real v4 address using a wildcard, so that we can determine
- # the CIDR value from it.
- ip = ip_network(u'0.0.0.0/%s' % str(self._values['netmask']))
- result = ip.prefixlen
- else:
- result = ipv6_netmask_to_cidr(self._values['netmask'])
-
- return result
-
-
-class ApiParameters(Parameters):
- @property
- def route_domain(self):
- if self._values['destination'] is None:
- return None
- pattern = r'([0-9a-zA-Z\:\-\.]+%(?P<rd>[0-9]+))'
- matches = re.search(pattern, self._values['destination'])
- if matches:
- return int(matches.group('rd'))
- return 0
-
- @property
- def destination_ip(self):
- if self._values['destination'] is None:
- return None
- destination = self.destination_to_network()
-
- try:
- pattern = r'(?P<rd>%[0-9]+)'
- addr = re.sub(pattern, '', destination)
- ip = ip_network(u'%s' % str(addr))
- return '{0}/{1}'.format(str(ip.network_address), ip.prefixlen)
- except ValueError:
- raise F5ModuleError(
- "The provided destination is not an IP address."
- )
-
- @property
- def netmask(self):
- destination = self.destination_to_network()
- ip = ip_network(u'%s' % str(destination))
- return int(ip.prefixlen)
-
- def destination_to_network(self):
- destination = self._values['destination']
- if destination.startswith('default%'):
- destination = '0.0.0.0%{0}/0'.format(destination.split('%')[1])
- elif destination.startswith('default-inet6%'):
- destination = '::%{0}/0'.format(destination.split('%')[1])
- elif destination.startswith('default-inet6'):
- destination = '::/0'
- elif destination.startswith('default'):
- destination = '0.0.0.0/0'
- return destination
-
-
-class Changes(Parameters):
- pass
-
-
-class UsableChanges(Parameters):
- pass
-
-
-class ReportableChanges(Parameters):
- pass
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
- @property
- def destination(self):
- if self.want.destination_ip is None:
- return None
- if self.want.destination_ip != self.have.destination_ip:
- raise F5ModuleError(
- "The destination cannot be changed. Delete and recreate "
- "the static route if you need to do this."
- )
-
- @property
- def route_domain(self):
- if self.want.route_domain is None:
- return None
- if self.want.route_domain is None and self.have.route_domain == 0:
- return None
- if self.want.route_domain != self.have.route_domain:
- raise F5ModuleError("You cannot change the route domain.")
-
- @property
- def netmask(self):
- if self.want.netmask is None:
- return None
- # It's easiest to just check the netmask by comparing dest IPs.
- if self.want.destination_ip != self.have.destination_ip:
- raise F5ModuleError(
- "The netmask cannot be changed. Delete and recreate "
- "the static route if you need to do this."
- )
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.have = None
- self.want = ModuleParameters(params=self.module.params)
- self.changes = UsableChanges()
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = UsableChanges(params=changed)
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if k in ['netmask', 'route_domain']:
- changed['address'] = change
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def exec_module(self):
- changed = False
- result = dict()
- state = self.want.state
-
- if state == "present":
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def exists(self):
- uri = "https://{0}:{1}/mgmt/tm/net/route/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def present(self):
- if self.exists():
- return self.update()
- else:
- return self.create()
-
- def create(self):
- required_resources = ['pool', 'vlan', 'reject', 'gateway_address']
- self._set_changed_options()
- if self.want.destination is None:
- raise F5ModuleError(
- 'destination must be specified when creating a static route'
- )
- if self.want.netmask is None:
- raise F5ModuleError(
- 'netmask must be specified when creating a static route'
- )
- if all(getattr(self.want, v) is None for v in required_resources):
- raise F5ModuleError(
- "You must specify at least one of " + ', '.join(required_resources)
- )
- if self.module.check_mode:
- return True
- self.create_on_device()
- return True
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def update(self):
- self.have = self.read_current_from_device()
- if not self.should_update():
- return False
- if self.module.check_mode:
- return True
- self.update_on_device()
- return True
-
- def update_on_device(self):
- params = self.want.api_params()
-
- # The 'network' attribute is not updatable
- params.pop('network', None)
-
- uri = "https://{0}:{1}/mgmt/tm/net/route/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/net/route/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return ApiParameters(params=response)
-
- def create_on_device(self):
- params = self.want.api_params()
- params['name'] = self.want.name
- params['partition'] = self.want.partition
- uri = "https://{0}:{1}/mgmt/tm/net/route/".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def absent(self):
- if self.exists():
- return self.remove()
- return False
-
- def remove(self):
- if self.module.check_mode:
- return True
- self.remove_from_device()
- if self.exists():
- raise F5ModuleError("Failed to delete the static route")
- return True
-
- def remove_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/net/route/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.delete(uri)
- if resp.status == 200:
- return True
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- name=dict(required=True),
- description=dict(),
- destination=dict(),
- netmask=dict(),
- gateway_address=dict(),
- vlan=dict(),
- pool=dict(),
- mtu=dict(),
- reject=dict(
- type='bool'
- ),
- state=dict(
- default='present',
- choices=['absent', 'present']
- ),
- partition=dict(
- default='Common',
- fallback=(env_fallback, ['F5_PARTITION'])
- ),
- route_domain=dict(type='int')
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
- self.mutually_exclusive = [
- ['gateway_address', 'pool', 'reject']
- ]
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode,
- mutually_exclusive=spec.mutually_exclusive,
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_sys_daemon_log_tmm.py b/lib/ansible/modules/network/f5/bigip_sys_daemon_log_tmm.py
deleted file mode 100644
index f5535625fd..0000000000
--- a/lib/ansible/modules/network/f5/bigip_sys_daemon_log_tmm.py
+++ /dev/null
@@ -1,493 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2018, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_sys_daemon_log_tmm
-short_description: Manage BIG-IP tmm daemon log settings
-description:
- - Manage BIG-IP tmm log settings.
-version_added: 2.8
-options:
- arp_log_level:
- description:
- - Specifies the lowest level of ARP messages from the tmm daemon
- to include in the system log.
- type: str
- choices:
- - debug
- - error
- - informational
- - notice
- - warning
- http_compression_log_level:
- description:
- - Specifies the lowest level of HTTP compression messages from the tmm daemon
- to include in the system log.
- type: str
- choices:
- - debug
- - error
- - informational
- - notice
- - warning
- http_log_level:
- description:
- - Specifies the lowest level of HTTP messages from the tmm daemon
- to include in the system log.
- type: str
- choices:
- - debug
- - error
- - informational
- - notice
- - warning
- ip_log_level:
- description:
- - Specifies the lowest level of IP address messages from the tmm daemon
- to include in the system log.
- type: str
- choices:
- - debug
- - informational
- - notice
- - warning
- irule_log_level:
- description:
- - Specifies the lowest level of iRule messages from the tmm daemon
- to include in the system log.
- type: str
- choices:
- - debug
- - error
- - informational
- - notice
- - warning
- layer4_log_level:
- description:
- - Specifies the lowest level of Layer 4 messages from the tmm daemon
- to include in the system log.
- type: str
- choices:
- - debug
- - informational
- - notice
- net_log_level:
- description:
- - Specifies the lowest level of network messages from the tmm daemon
- to include in the system log.
- type: str
- choices:
- - critical
- - debug
- - error
- - informational
- - notice
- - warning
- os_log_level:
- description:
- - Specifies the lowest level of operating system messages from the tmm daemon
- to include in the system log.
- type: str
- choices:
- - alert
- - critical
- - debug
- - emergency
- - error
- - informational
- - notice
- - warning
- pva_log_level:
- description:
- - Specifies the lowest level of PVA messages from the tmm daemon
- to include in the system log.
- type: str
- choices:
- - debug
- - informational
- - notice
- ssl_log_level:
- description:
- - Specifies the lowest level of SSL messages from the tmm daemon
- to include in the system log.
- type: str
- choices:
- - alert
- - critical
- - debug
- - emergency
- - error
- - informational
- - notice
- - warning
- state:
- description:
- - The state of the log level on the system. When C(present), guarantees
- that an existing log level is set to C(value).
- type: str
- choices:
- - present
- default: present
-extends_documentation_fragment: f5
-author:
- - Wojciech Wypior (@wojtek0806)
-'''
-
-EXAMPLES = r'''
-- name: Set SSL log level to debug
- bigip_sys_daemon_log_tmm:
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- ssl_log_level: debug
- delegate_to: localhost
-'''
-
-RETURN = r'''
-arp_log_level:
- description: Lowest level of ARP messages from the tmm daemon to log.
- returned: changed
- type: str
- sample: error
-http_compression_log_level:
- description: Lowest level of HTTP compression messages from the tmm daemon to log.
- returned: changed
- type: str
- sample: debug
-http_log_level:
- description: Lowest level of HTTP messages from the tmm daemon to log.
- returned: changed
- type: str
- sample: notice
-ip_log_level:
- description: Lowest level of IP address messages from the tmm daemon to log.
- returned: changed
- type: str
- sample: warning
-irule_log_level:
- description: Lowest level of iRule messages from the tmm daemon to log.
- returned: changed
- type: str
- sample: error
-layer4_log_level:
- description: Lowest level of Layer 4 messages from the tmm daemon to log.
- returned: changed
- type: str
- sample: notice
-net_log_level:
- description: Lowest level of network messages from the tmm daemon to log.
- returned: changed
- type: str
- sample: critical
-os_log_level:
- description: Lowest level of operating system messages from the tmm daemon to log.
- returned: changed
- type: str
- sample: critical
-pva_log_level:
- description: Lowest level of PVA messages from the tmm daemon to log.
- returned: changed
- type: str
- sample: debug
-ssl_log_level:
- description: Lowest level of SSL messages from the tmm daemon to log.
- returned: changed
- type: str
- sample: critical
-'''
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import f5_argument_spec
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import f5_argument_spec
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'arpLogLevel': 'arp_log_level',
- 'httpCompressionLogLevel': 'http_compression_log_level',
- 'httpLogLevel': 'http_log_level',
- 'ipLogLevel': 'ip_log_level',
- 'iruleLogLevel': 'irule_log_level',
- 'layer4LogLevel': 'layer4_log_level',
- 'netLogLevel': 'net_log_level',
- 'osLogLevel': 'os_log_level',
- 'pvaLogLevel': 'pva_log_level',
- 'sslLogLevel': 'ssl_log_level',
- }
-
- api_attributes = [
- 'arpLogLevel',
- 'httpCompressionLogLevel',
- 'httpLogLevel',
- 'ipLogLevel',
- 'iruleLogLevel',
- 'layer4LogLevel',
- 'netLogLevel',
- 'osLogLevel',
- 'pvaLogLevel',
- 'sslLogLevel',
- ]
-
- returnables = [
- 'arp_log_level',
- 'http_compression_log_level',
- 'http_log_level',
- 'ip_log_level',
- 'irule_log_level',
- 'layer4_log_level',
- 'net_log_level',
- 'os_log_level',
- 'pva_log_level',
- 'ssl_log_level',
- ]
-
- updatables = [
- 'arp_log_level',
- 'http_compression_log_level',
- 'http_log_level',
- 'ip_log_level',
- 'irule_log_level',
- 'layer4_log_level',
- 'net_log_level',
- 'os_log_level',
- 'pva_log_level',
- 'ssl_log_level',
- ]
-
-
-class ApiParameters(Parameters):
- pass
-
-
-class ModuleParameters(Parameters):
- pass
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class UsableChanges(Changes):
- pass
-
-
-class ReportableChanges(Changes):
- pass
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(params=self.module.params)
- self.have = ApiParameters()
- self.changes = UsableChanges()
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def exec_module(self):
- result = dict()
-
- changed = self.present()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.client.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def present(self):
- return self.update()
-
- def update(self):
- self.have = self.read_current_from_device()
- if not self.should_update():
- return False
- if self.module.check_mode:
- return True
- self.update_on_device()
- return True
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def update_on_device(self):
- params = self.changes.api_params()
- uri = "https://{0}:{1}/mgmt/tm/sys/daemon-log-settings/tmm".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/sys/daemon-log-settings/tmm".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return ApiParameters(params=response)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- self.choices_min = ['debug', 'informational', 'notice']
- self.choices_common = self.choices_min + ['warning', 'error']
- self.choices_all = self.choices_common + ['alert', 'critical', 'emergency']
- argument_spec = dict(
- arp_log_level=dict(
- choices=self.choices_common
- ),
- http_compression_log_level=dict(
- choices=self.choices_common
- ),
- http_log_level=dict(
- choices=self.choices_common
- ),
- ip_log_level=dict(
- choices=self.choices_min + ['warning']
- ),
- irule_log_level=dict(
- choices=self.choices_common
- ),
- layer4_log_level=dict(
- choices=self.choices_min
- ),
- net_log_level=dict(
- choices=self.choices_common + ['critical']
- ),
- os_log_level=dict(
- choices=self.choices_all
- ),
- pva_log_level=dict(
- choices=self.choices_min
- ),
- ssl_log_level=dict(
- choices=self.choices_all
- ),
- state=dict(default='present', choices=['present'])
- )
-
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode,
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_sys_db.py b/lib/ansible/modules/network/f5/bigip_sys_db.py
deleted file mode 100644
index ea0b875765..0000000000
--- a/lib/ansible/modules/network/f5/bigip_sys_db.py
+++ /dev/null
@@ -1,403 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2016, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_sys_db
-short_description: Manage BIG-IP system database variables
-description:
- - Manage BIG-IP system database variables
-version_added: 2.2
-options:
- key:
- description:
- - The database variable to manipulate.
- type: str
- required: True
- state:
- description:
- - The state of the variable on the system. When C(present), guarantees
- that an existing variable is set to C(value). When C(reset) sets the
- variable back to the default value. At least one of value and state
- C(reset) are required.
- type: str
- choices:
- - present
- - reset
- default: present
- value:
- description:
- - The value to set the key to. At least one of value and state C(reset)
- are required.
- type: str
-notes:
- - Requires BIG-IP version 12.0.0 or greater
-extends_documentation_fragment: f5
-author:
- - Tim Rupp (@caphrim007)
-'''
-
-EXAMPLES = r'''
-- name: Set the boot.quiet DB variable on the BIG-IP
- bigip_sys_db:
- key: boot.quiet
- value: disable
- provider:
- user: admin
- password: secret
- server: lb.mydomain.com
- delegate_to: localhost
-
-- name: Disable the initial setup screen
- bigip_sys_db:
- key: setup.run
- value: false
- provider:
- user: admin
- password: secret
- server: lb.mydomain.com
- delegate_to: localhost
-
-- name: Reset the initial setup screen
- bigip_sys_db:
- key: setup.run
- state: reset
- provider:
- user: admin
- password: secret
- server: lb.mydomain.com
- delegate_to: localhost
-'''
-
-RETURN = r'''
-name:
- description: The key in the system database that was specified
- returned: changed and success
- type: str
- sample: setup.run
-default_value:
- description: The default value of the key
- returned: changed and success
- type: str
- sample: true
-value:
- description: The value that you set the key to
- returned: changed and success
- type: str
- sample: false
-'''
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import f5_argument_spec
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import f5_argument_spec
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'defaultValue': 'default_value'
- }
- api_attributes = [
- 'value',
- ]
- updatables = [
- 'value',
- ]
- returnables = [
- 'name',
- 'value',
- 'default_value',
- ]
-
-
-class ApiParameters(Parameters):
- pass
-
-
-class ModuleParameters(Parameters):
- pass
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- change = getattr(self, returnable)
- if isinstance(change, dict):
- result.update(change)
- else:
- result[returnable] = change
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class UsableChanges(Changes):
- pass
-
-
-class ReportableChanges(Changes):
- pass
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
- @property
- def value(self):
- if self.want.state == 'reset':
- if str(self.have.value) != str(self.have.default_value):
- return self.have.default_value
- if self.want.value != self.have.value:
- return self.want.value
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.pop('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(params=self.module.params)
- self.have = ApiParameters()
- self.changes = UsableChanges()
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- changed['name'] = self.want.key
- changed['default_value'] = self.have.default_value
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def exec_module(self):
- changed = False
- result = dict()
- state = self.want.state
-
- if state == "present":
- changed = self.present()
- elif state == "reset":
- changed = self.reset()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def present(self):
- if self.exists():
- return False
- else:
- return self.update()
-
- def reset(self):
- self.have = self.read_current_from_device()
- if not self.should_update():
- return False
- if self.module.check_mode:
- return True
- self.reset_on_device()
- self.want.update({'key': self.want.key})
- self.want.update({'value': self.have.default_value})
- if self.exists():
- return True
- else:
- raise F5ModuleError(
- "Failed to reset the DB variable"
- )
-
- def update(self):
- if self.want.value is None:
- raise F5ModuleError(
- "When setting a key, a value must be supplied"
- )
- self.have = self.read_current_from_device()
- if not self.should_update():
- return False
- if self.module.check_mode:
- return True
- self.update_on_device()
- return True
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def exists(self):
- uri = "https://{0}:{1}/mgmt/tm/sys/db/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- self.want.key
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if str(response['value']) == str(self.want.value):
- return True
- return False
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/sys/db/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- self.want.key
- )
-
- resp = self.client.api.get(uri)
-
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- return ApiParameters(params=response)
-
- def update_on_device(self):
- params = self.changes.api_params()
- uri = "https://{0}:{1}/mgmt/tm/sys/db/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- self.want.key
- )
-
- resp = self.client.api.patch(uri, json=params)
-
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def reset_on_device(self):
- uri = "https://{0}:{1}/mgmt/tm/sys/db/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- self.want.key
- )
- params = dict(
- value=self.have.default_value
- )
-
- resp = self.client.api.patch(uri, json=params)
-
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- key=dict(required=True),
- state=dict(
- default='present',
- choices=['present', 'reset']
- ),
- value=dict()
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_sys_global.py b/lib/ansible/modules/network/f5/bigip_sys_global.py
deleted file mode 100644
index c69d4dd8f2..0000000000
--- a/lib/ansible/modules/network/f5/bigip_sys_global.py
+++ /dev/null
@@ -1,506 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2016, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_sys_global
-short_description: Manage BIG-IP global settings
-description:
- - Manage BIG-IP global settings.
-version_added: 2.3
-options:
- banner_text:
- description:
- - Specifies the text to present in the advisory banner.
- type: str
- console_timeout:
- description:
- - Specifies the number of seconds of inactivity before the system logs
- off a user that is logged on.
- type: int
- gui_setup:
- description:
- - C(yes) or C(no) the Setup utility in the browser-based
- Configuration utility.
- type: bool
- lcd_display:
- description:
- - Specifies, when C(yes), that the system menu displays on the
- LCD screen on the front of the unit. This setting has no effect
- when used on the VE platform.
- type: bool
- mgmt_dhcp:
- description:
- - Specifies whether or not to enable DHCP client on the management
- interface
- type: bool
- net_reboot:
- description:
- - Specifies, when C(yes), that the next time you reboot the system,
- the system boots to an ISO image on the network, rather than an
- internal media drive.
- type: bool
- quiet_boot:
- description:
- - Specifies, when C(yes), that the system suppresses informational
- text on the console during the boot cycle. When C(no), the
- system presents messages and informational text on the console during
- the boot cycle.
- type: bool
- security_banner:
- description:
- - Specifies whether the system displays an advisory message on the
- login screen.
- type: bool
- state:
- description:
- - The state of the variable on the system. When C(present), guarantees
- that an existing variable is set to C(value).
- type: str
- choices:
- - present
- default: present
-extends_documentation_fragment: f5
-author:
- - Tim Rupp (@caphrim007)
- - Wojciech Wypior (@wojtek0806)
-'''
-
-EXAMPLES = r'''
-- name: Disable the setup utility
- bigip_sys_global:
- gui_setup: no
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-'''
-
-RETURN = r'''
-banner_text:
- description: The new text to present in the advisory banner.
- returned: changed
- type: str
- sample: This is a corporate device. Do not touch.
-console_timeout:
- description:
- - The new number of seconds of inactivity before the system
- logs off a user that is logged on.
- returned: changed
- type: int
- sample: 600
-gui_setup:
- description: The new setting for the Setup utility.
- returned: changed
- type: bool
- sample: yes
-lcd_display:
- description: The new setting for displaying the system menu on the LCD.
- returned: changed
- type: bool
- sample: yes
-mgmt_dhcp:
- description: The new setting for whether the mgmt interface should DHCP or not.
- returned: changed
- type: bool
- sample: yes
-net_reboot:
- description: The new setting for whether the system should boot to an ISO on the network or not.
- returned: changed
- type: bool
- sample: yes
-quiet_boot:
- description:
- - The new setting for whether the system should suppress information to
- the console during boot or not.
- returned: changed
- type: bool
- sample: yes
-security_banner:
- description:
- - The new setting for whether the system should display an advisory message
- on the login screen or not.
- returned: changed
- type: bool
- sample: yes
-'''
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.common import flatten_boolean
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.common import flatten_boolean
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'guiSecurityBanner': 'security_banner',
- 'guiSecurityBannerText': 'banner_text',
- 'guiSetup': 'gui_setup',
- 'lcdDisplay': 'lcd_display',
- 'mgmtDhcp': 'mgmt_dhcp',
- 'netReboot': 'net_reboot',
- 'quietBoot': 'quiet_boot',
- 'consoleInactivityTimeout': 'console_timeout',
- }
-
- api_attributes = [
- 'guiSecurityBanner',
- 'guiSecurityBannerText',
- 'guiSetup',
- 'lcdDisplay',
- 'mgmtDhcp',
- 'netReboot',
- 'quietBoot',
- 'consoleInactivityTimeout',
- ]
-
- returnables = [
- 'security_banner',
- 'banner_text',
- 'gui_setup',
- 'lcd_display',
- 'mgmt_dhcp',
- 'net_reboot',
- 'quiet_boot',
- 'console_timeout',
- ]
-
- updatables = [
- 'security_banner',
- 'banner_text',
- 'gui_setup',
- 'lcd_display',
- 'mgmt_dhcp',
- 'net_reboot',
- 'quiet_boot',
- 'console_timeout',
- ]
-
- @property
- def security_banner(self):
- return flatten_boolean(self._values['security_banner'])
-
- @property
- def gui_setup(self):
- return flatten_boolean(self._values['gui_setup'])
-
- @property
- def lcd_display(self):
- return flatten_boolean(self._values['lcd_display'])
-
- @property
- def mgmt_dhcp(self):
- return flatten_boolean(self._values['mgmt_dhcp'])
-
- @property
- def net_reboot(self):
- return flatten_boolean(self._values['net_reboot'])
-
- @property
- def quiet_boot(self):
- return flatten_boolean(self._values['quiet_boot'])
-
-
-class ApiParameters(Parameters):
- pass
-
-
-class ModuleParameters(Parameters):
- pass
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class UsableChanges(Changes):
- @property
- def security_banner(self):
- if self._values['security_banner'] is None:
- return None
- if self._values['security_banner'] == 'yes':
- return 'enabled'
- return 'disabled'
-
- @property
- def gui_setup(self):
- if self._values['gui_setup'] is None:
- return None
- if self._values['gui_setup'] == 'yes':
- return 'enabled'
- return 'disabled'
-
- @property
- def lcd_display(self):
- if self._values['lcd_display'] is None:
- return None
- if self._values['lcd_display'] == 'yes':
- return 'enabled'
- return 'disabled'
-
- @property
- def mgmt_dhcp(self):
- if self._values['mgmt_dhcp'] is None:
- return None
- if self._values['mgmt_dhcp'] == 'yes':
- return 'enabled'
- return 'disabled'
-
- @property
- def net_reboot(self):
- if self._values['net_reboot'] is None:
- return None
- if self._values['net_reboot'] == 'yes':
- return 'enabled'
- return 'disabled'
-
- @property
- def quiet_boot(self):
- if self._values['quiet_boot'] is None:
- return None
- if self._values['quiet_boot'] == 'yes':
- return 'enabled'
- return 'disabled'
-
-
-class ReportableChanges(Changes):
- @property
- def security_banner(self):
- return flatten_boolean(self._values['security_banner'])
-
- @property
- def gui_setup(self):
- return flatten_boolean(self._values['gui_setup'])
-
- @property
- def lcd_display(self):
- return flatten_boolean(self._values['lcd_display'])
-
- @property
- def mgmt_dhcp(self):
- return flatten_boolean(self._values['mgmt_dhcp'])
-
- @property
- def net_reboot(self):
- return flatten_boolean(self._values['net_reboot'])
-
- @property
- def quiet_boot(self):
- return flatten_boolean(self._values['quiet_boot'])
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- def __default(self, param):
- want = getattr(self.want, param)
- try:
- have = getattr(self.have, param)
- if want != have:
- return want
- except AttributeError:
- return want
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(params=self.module.params)
- self.have = ApiParameters()
- self.changes = UsableChanges()
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = UsableChanges(params=changed)
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def exec_module(self):
- result = dict()
-
- changed = self.present()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def present(self):
- return self.update()
-
- def update(self):
- self.have = self.read_current_from_device()
- if not self.should_update():
- return False
- if self.module.check_mode:
- return True
- self.update_on_device()
- return True
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/sys/global-settings/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return ApiParameters(params=response)
-
- def update_on_device(self):
- params = self.changes.api_params()
- uri = "https://{0}:{1}/mgmt/tm/sys/global-settings/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- self.states = ['present']
- argument_spec = dict(
- security_banner=dict(
- type='bool'
- ),
- banner_text=dict(),
- gui_setup=dict(
- type='bool'
- ),
- lcd_display=dict(
- type='bool'
- ),
- mgmt_dhcp=dict(
- type='bool'
- ),
- net_reboot=dict(
- type='bool'
- ),
- quiet_boot=dict(
- type='bool'
- ),
- console_timeout=dict(
- type='int'
- ),
- state=dict(
- default='present', choices=['present']
- )
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_timer_policy.py b/lib/ansible/modules/network/f5/bigip_timer_policy.py
deleted file mode 100644
index 98d0f6f8c9..0000000000
--- a/lib/ansible/modules/network/f5/bigip_timer_policy.py
+++ /dev/null
@@ -1,636 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_timer_policy
-short_description: Manage timer policies on a BIG-IP
-description:
- - Manage timer policies on a BIG-IP.
-version_added: 2.6
-options:
- name:
- description:
- - Specifies the name of the timer policy.
- type: str
- required: True
- description:
- description:
- - Specifies descriptive text that identifies the timer policy.
- type: str
- rules:
- description:
- - Rules that you want assigned to the timer policy
- suboptions:
- name:
- description:
- - The name of the rule.
- type: str
- required: True
- protocol:
- description:
- - Specifies the IP protocol entry for which the timer policy rule is being
- configured. This could be a layer-4 protocol (such as C(tcp), C(udp) or
- C(sctp).
- - Only flows matching the configured protocol will make use of this rule.
- - When C(all-other) is specified, if there are no specific ip-protocol rules
- that match the flow, the flow matches all the other ip-protocol rules.
- - When specifying rules, if this parameter is not specified, the default of
- C(all-other) will be used.
- type: str
- choices:
- - all-other
- - ah
- - bna
- - esp
- - etherip
- - gre
- - icmp
- - ipencap
- - ipv6
- - ipv6-auth
- - ipv6-crypt
- - ipv6-icmp
- - isp-ip
- - mux
- - ospf
- - sctp
- - tcp
- - udp
- - udplite
- destination_ports:
- description:
- - The list of destination ports to match the rule on.
- - Specify a port range by specifying start and end ports separated by a
- dash (-).
- - This field is only available if you have selected the C(sctp), C(tcp), or
- C(udp) protocol.
- type: list
- idle_timeout:
- description:
- - Specifies an idle timeout, in seconds, for protocol and port pairs that
- match the timer policy rule.
- - When C(infinite), specifies that the protocol and port pairs that match
- the timer policy rule have no idle timeout.
- - When specifying rules, if this parameter is not specified, the default of
- C(unspecified) will be used.
- type: str
- type: list
- partition:
- description:
- - Device partition to manage resources on.
- type: str
- default: Common
- state:
- description:
- - When C(present), ensures that the resource exists.
- - When C(absent), ensures the resource is removed.
- type: str
- choices:
- - present
- - absent
- default: present
-extends_documentation_fragment: f5
-author:
- - Tim Rupp (@caphrim007)
-'''
-
-EXAMPLES = r'''
-- name: Create a timer policy
- bigip_timer_policy:
- name: timer1
- description: My timer policy
- rules:
- - name: rule1
- protocol: tcp
- idle_timeout: indefinite
- destination_ports:
- - 443
- - 80
- - name: rule2
- protocol: 200
- - name: rule3
- protocol: sctp
- idle_timeout: 200
- destination_ports:
- - 21
- state: present
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-
-- name: Remove a timer policy and all its associated rules
- bigip_timer_policy:
- name: timer1
- description: My timer policy
- state: absent
- provider:
- user: admin
- password: secret
- server: lb.mydomain.com
- delegate_to: localhost
-'''
-
-RETURN = r'''
-description:
- description: The new description of the timer policy.
- returned: changed
- type: str
- sample: true
-'''
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.basic import env_fallback
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.common import transform_name
- from library.module_utils.network.f5.compare import compare_complex_list
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import fq_name
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.common import transform_name
- from ansible.module_utils.network.f5.compare import compare_complex_list
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
-
- }
-
- api_attributes = [
- 'description',
- 'rules',
- ]
-
- returnables = [
- 'description',
- 'rules',
- ]
-
- updatables = [
- 'description',
- 'rules',
- ]
-
-
-class ApiParameters(Parameters):
- @property
- def rules(self):
- if self._values['rules'] is None:
- return None
- results = []
- for rule in self._values['rules']:
- result = dict()
- result['name'] = rule['name']
- if 'ipProtocol' in rule:
- result['protocol'] = str(rule['ipProtocol'])
- if 'timers' in rule:
- result['idle_timeout'] = str(rule['timers'][0]['value'])
- if 'destinationPorts' in rule:
- ports = list(set([str(x['name']) for x in rule['destinationPorts']]))
- ports.sort()
- result['destination_ports'] = ports
- results.append(result)
- results = sorted(results, key=lambda k: k['name'])
- return results
-
-
-class ModuleParameters(Parameters):
- @property
- def rules(self):
- if self._values['rules'] is None:
- return None
- if len(self._values['rules']) == 1 and self._values['rules'][0] == '':
- return ''
- results = []
- for rule in self._values['rules']:
- result = dict()
- result['name'] = rule['name']
- if 'protocol' in rule:
- result['protocol'] = str(rule['protocol'])
- else:
- result['protocol'] = 'all-other'
-
- if 'idle_timeout' in rule:
- result['idle_timeout'] = str(rule['idle_timeout'])
- else:
- result['idle_timeout'] = 'unspecified'
-
- if 'destination_ports' in rule:
- ports = list(set([str(x) for x in rule['destination_ports']]))
- ports.sort()
- ports = [str(self._validate_port_entries(x)) for x in ports]
- result['destination_ports'] = ports
- results.append(result)
- results = sorted(results, key=lambda k: k['name'])
- return results
-
- def _validate_port_entries(self, port):
- if port == 'all-other':
- return 0
- if '-' in port:
- parts = port.split('-')
- if len(parts) != 2:
- raise F5ModuleError(
- "The correct format for a port range is X-Y, where X is the start"
- "port and Y is the end port."
- )
- try:
- start = int(parts[0])
- end = int(parts[1])
- except ValueError:
- raise F5ModuleError(
- "The ports in a range must be numbers."
- "You provided '{0}' and '{1}'.".format(parts[0], parts[1])
- )
- if start == end:
- return start
- if start > end:
- return '{0}-{1}'.format(end, start)
- else:
- return port
- else:
- try:
- return int(port)
- except ValueError:
- raise F5ModuleError(
- "The specified destination port is not a number."
- )
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class UsableChanges(Changes):
- @property
- def rules(self):
- if self._values['rules'] is None:
- return None
- results = []
- for rule in self._values['rules']:
- result = dict()
- result['name'] = rule['name']
- if 'protocol' in rule:
- result['ipProtocol'] = rule['protocol']
-
- if 'destination_ports' in rule:
- if rule['protocol'] not in ['tcp', 'udp', 'sctp']:
- raise F5ModuleError(
- "Only the 'tcp', 'udp', and 'sctp' protocols support 'destination_ports'."
- )
- ports = [dict(name=str(x)) for x in rule['destination_ports']]
- result['destinationPorts'] = ports
- else:
- result['destinationPorts'] = []
-
- if 'idle_timeout' in rule:
- if rule['idle_timeout'] in ['indefinite', 'immediate', 'unspecified']:
- timeout = rule['idle_timeout']
- else:
- try:
- int(rule['idle_timeout'])
- timeout = rule['idle_timeout']
- except ValueError:
- raise F5ModuleError(
- "idle_timeout must be a number, or, one of 'indefinite', 'immediate', or 'unspecified'."
- )
- result['timers'] = [
- dict(name='flow-idle-timeout', value=timeout)
- ]
- results.append(result)
- results = sorted(results, key=lambda k: k['name'])
- return results
-
-
-class ReportableChanges(Changes):
- pass
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
- @property
- def rules(self):
- if self.want.rules is None:
- return None
- if self.have.rules is None and self.want.rules == '':
- return None
- if self.have.rules is not None and self.want.rules == '':
- return []
- if self.have.rules is None:
- return self.want.rules
-
- want = [tuple(x.pop('destination_ports')) for x in self.want.rules if 'destination_ports' in x]
- have = [tuple(x.pop('destination_ports')) for x in self.have.rules if 'destination_ports' in x]
- if set(want) != set(have):
- return self.want.rules
- if compare_complex_list(self.want.rules, self.have.rules):
- return self.want.rules
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(params=self.module.params)
- self.have = ApiParameters()
- self.changes = UsableChanges()
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = UsableChanges(params=changed)
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def exec_module(self):
- changed = False
- result = dict()
- state = self.want.state
-
- if state == "present":
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.client.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def present(self):
- if self.exists():
- return self.update()
- else:
- return self.create()
-
- def absent(self):
- if self.exists():
- return self.remove()
- return False
-
- def update(self):
- self.have = self.read_current_from_device()
- if not self.should_update():
- return False
- if self.module.check_mode:
- return True
- self.update_on_device()
- return True
-
- def remove(self):
- if self.module.check_mode:
- return True
- self.remove_from_device()
- if self.exists():
- raise F5ModuleError("Failed to delete the resource.")
- return True
-
- def create(self):
- self._set_changed_options()
- if self.module.check_mode:
- return True
- self.create_on_device()
- return True
-
- def exists(self):
- uri = "https://{0}:{1}/mgmt/tm/net/timer-policy/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name),
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def create_on_device(self):
- params = self.changes.api_params()
- params['name'] = self.want.name
- params['partition'] = self.want.partition
- uri = "https://{0}:{1}/mgmt/tm/net/timer-policy/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return response['selfLink']
-
- def update_on_device(self):
- params = self.changes.api_params()
- uri = "https://{0}:{1}/mgmt/tm/net/timer-policy/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name),
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def remove_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/net/timer-policy/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name),
- )
- response = self.client.api.delete(uri)
- if response.status == 200:
- return True
- raise F5ModuleError(response.content)
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/net/timer-policy/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name),
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return ApiParameters(params=response)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- name=dict(required=True),
- description=dict(),
- rules=dict(
- type='list',
- suboptions=dict(
- name=dict(required=True),
- protocol=dict(
- default='all-other',
- choices=[
- 'all-other',
- 'ah',
- 'bna',
- 'esp',
- 'etherip',
- 'gre',
- 'icmp',
- 'ipencap',
- 'ipv6',
- 'ipv6-auth',
- 'ipv6-crypt',
- 'ipv6-icmp',
- 'isp-ip',
- 'mux',
- 'ospf',
- 'sctp',
- 'tcp',
- 'udp',
- 'udplite',
- ]
- ),
- description=dict(),
- idle_timeout=dict(default='unspecified'),
- destination_ports=dict(
- type='list'
- )
- )
- ),
- state=dict(
- default='present',
- choices=['present', 'absent']
- ),
- partition=dict(
- default='Common',
- fallback=(env_fallback, ['F5_PARTITION'])
- )
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_traffic_selector.py b/lib/ansible/modules/network/f5/bigip_traffic_selector.py
deleted file mode 100644
index 6558fea2dc..0000000000
--- a/lib/ansible/modules/network/f5/bigip_traffic_selector.py
+++ /dev/null
@@ -1,509 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2018, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_traffic_selector
-short_description: Manage IPSec Traffic Selectors on BIG-IP
-description:
- - Manage IPSec Traffic Selectors on BIG-IP.
-version_added: 2.8
-options:
- name:
- description:
- - Specifies the name of the traffic selector.
- type: str
- required: True
- destination_address:
- description:
- - Specifies the host or network IP address to which the application traffic is destined.
- - When creating a new traffic selector, this parameter is required.
- type: str
- source_address:
- description:
- - Specifies the host or network IP address from which the application traffic originates.
- - When creating a new traffic selector, this parameter is required.
- type: str
- ipsec_policy:
- description:
- - Specifies the IPsec policy that tells the BIG-IP system how to handle the packets.
- - When creating a new traffic selector, if this parameter is not specified, the default
- is C(default-ipsec-policy).
- type: str
- order:
- description:
- - Specifies the order in which traffic is matched, if traffic can be matched to multiple
- traffic selectors.
- - Traffic is matched to the traffic selector with the highest priority (lowest order number).
- - When creating a new traffic selector, if this parameter is not specified, the default
- is C(last).
- type: int
- description:
- description:
- - Description of the traffic selector.
- type: str
- partition:
- description:
- - Device partition to manage resources on.
- type: str
- default: Common
- state:
- description:
- - When C(present), ensures that the resource exists.
- - When C(absent), ensures the resource is removed.
- type: str
- choices:
- - present
- - absent
- default: present
-extends_documentation_fragment: f5
-author:
- - Tim Rupp (@caphrim007)
- - Wojciech Wypior (@wojtek0806)
-'''
-
-EXAMPLES = r'''
-- name: Create a traffic selector
- bigip_traffic_selector:
- name: selector1
- destination_address: 1.1.1.1
- ipsec_policy: policy1
- order: 1
- source_address: 2.2.2.2
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-'''
-
-RETURN = r'''
-destination_address:
- description: The new Destination IP Address.
- returned: changed
- type: str
- sample: 1.2.3.4/32
-source_address:
- description: The new Source IP address.
- returned: changed
- type: str
- sample: 2.3.4.5/32
-ipsec_policy:
- description: The new IPSec policy.
- returned: changed
- type: str
- sample: /Common/policy1
-order:
- description: The new sort order.
- returned: changed
- type: int
- sample: 1
-'''
-
-import re
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.basic import env_fallback
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import fq_name
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.common import transform_name
- from library.module_utils.compat.ipaddress import ip_interface
- from library.module_utils.network.f5.compare import cmp_str_with_none
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import fq_name
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.common import transform_name
- from ansible.module_utils.compat.ipaddress import ip_interface
- from ansible.module_utils.network.f5.compare import cmp_str_with_none
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'destinationAddress': 'destination_address',
- 'sourceAddress': 'source_address',
- 'ipsecPolicy': 'ipsec_policy',
- }
-
- api_attributes = [
- 'destinationAddress',
- 'sourceAddress',
- 'ipsecPolicy',
- 'order',
- 'description',
- ]
-
- returnables = [
- 'destination_address',
- 'source_address',
- 'ipsec_policy',
- 'order',
- 'description',
- ]
-
- updatables = [
- 'destination_address',
- 'source_address',
- 'ipsec_policy',
- 'order',
- 'description',
- ]
-
-
-class ApiParameters(Parameters):
- @property
- def description(self):
- if self._values['description'] in [None, 'none']:
- return None
- return self._values['description']
-
-
-class ModuleParameters(Parameters):
- @property
- def ipsec_policy(self):
- if self._values['ipsec_policy'] is None:
- return None
- return fq_name(self.partition, self._values['ipsec_policy'])
-
- @property
- def destination_address(self):
- result = self._format_address('destination_address')
- if result == -1:
- raise F5ModuleError(
- "No IP address found in 'destination_address'."
- )
- return result
-
- @property
- def source_address(self):
- result = self._format_address('source_address')
- if result == -1:
- raise F5ModuleError(
- "No IP address found in 'source_address'."
- )
- return result
-
- @property
- def description(self):
- if self._values['description'] is None:
- return None
- elif self._values['description'] in ['none', '']:
- return ''
- return self._values['description']
-
- def _format_address(self, type):
- if self._values[type] is None:
- return None
- pattern = r'(?P<addr>[^%/]+)(%(?P<rd>\d+))?(/(?P<cidr>\d+))?'
- if '%' in self._values[type]:
- # Handle route domains
- matches = re.match(pattern, self._values[type])
- if not matches:
- return None
- addr = matches.group('addr')
- if addr is None:
- return -1
- cidr = matches.group('cidr')
- rd = matches.group('rd')
- if cidr is not None:
- ip = ip_interface(u'{0}/{1}'.format(addr, cidr))
- else:
- ip = ip_interface(u'{0}'.format(addr))
- if rd:
- result = '{0}%{1}/{2}'.format(str(ip.ip), rd, ip.network.prefixlen)
- else:
- result = '{0}/{1}'.format(str(ip.ip), ip.network.prefixlen)
- return result
- return str(ip_interface(u'{0}'.format(self._values[type])))
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class UsableChanges(Changes):
- pass
-
-
-class ReportableChanges(Changes):
- pass
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
- @property
- def description(self):
- return cmp_str_with_none(self.want.description, self.have.description)
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(params=self.module.params)
- self.have = ApiParameters()
- self.changes = UsableChanges()
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = UsableChanges(params=changed)
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def exec_module(self):
- changed = False
- result = dict()
- state = self.want.state
-
- if state == "present":
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.client.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def present(self):
- if self.exists():
- return self.update()
- else:
- return self.create()
-
- def exists(self):
- uri = "https://{0}:{1}/mgmt/tm/net/ipsec/traffic-selector/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def update(self):
- self.have = self.read_current_from_device()
- if not self.should_update():
- return False
- if self.module.check_mode:
- return True
- self.update_on_device()
- return True
-
- def remove(self):
- if self.module.check_mode:
- return True
- self.remove_from_device()
- if self.exists():
- raise F5ModuleError("Failed to delete the resource.")
- return True
-
- def create(self):
- self._set_changed_options()
- if self.module.check_mode:
- return True
- self.create_on_device()
- return True
-
- def create_on_device(self):
- params = self.changes.api_params()
- params['name'] = self.want.name
- params['partition'] = self.want.partition
- uri = "https://{0}:{1}/mgmt/tm/net/ipsec/traffic-selector/".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def update_on_device(self):
- params = self.changes.api_params()
- uri = "https://{0}:{1}/mgmt/tm/net/ipsec/traffic-selector/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def absent(self):
- if self.exists():
- return self.remove()
- return False
-
- def remove_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/net/ipsec/traffic-selector/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.delete(uri)
- if resp.status == 200:
- return True
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/net/ipsec/traffic-selector/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return ApiParameters(params=response)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- name=dict(required=True),
- destination_address=dict(),
- source_address=dict(),
- ipsec_policy=dict(),
- order=dict(type='int'),
- description=dict(),
- state=dict(
- default='present',
- choices=['present', 'absent']
- ),
- partition=dict(
- default='Common',
- fallback=(env_fallback, ['F5_PARTITION'])
- )
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode,
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_trunk.py b/lib/ansible/modules/network/f5/bigip_trunk.py
deleted file mode 100644
index 158c1fabdd..0000000000
--- a/lib/ansible/modules/network/f5/bigip_trunk.py
+++ /dev/null
@@ -1,605 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_trunk
-short_description: Manage trunks on a BIG-IP
-description:
- - Manages trunks on a BIG-IP.
-version_added: 2.6
-options:
- name:
- description:
- - Specifies the name of the trunk.
- type: str
- required: True
- interfaces:
- description:
- - The interfaces that are part of the trunk.
- - To clear the list of interfaces, specify an empty list.
- type: list
- description:
- description:
- - Description of the trunk.
- type: str
- version_added: 2.7
- link_selection_policy:
- description:
- - Specifies, once the trunk is configured, the policy that the trunk uses to determine
- which member link (interface) can handle new traffic.
- - When creating a new trunk, if this value is not specific, the default is C(auto).
- - When C(auto), specifies that the system automatically determines which interfaces
- can handle new traffic. For the C(auto) option, the member links must all be the
- same media type and speed.
- - When C(maximum-bandwidth), specifies that the system determines which interfaces
- can handle new traffic based on the members' maximum bandwidth.
- type: str
- choices:
- - auto
- - maximum-bandwidth
- frame_distribution_hash:
- description:
- - Specifies the basis for the hash that the system uses as the frame distribution
- algorithm. The system uses the resulting hash to determine which interface to
- use for forwarding traffic.
- - When creating a new trunk, if this parameter is not specified, the default is
- C(source-destination-ip).
- - When C(source-destination-mac), specifies that the system bases the hash on the
- combined MAC addresses of the source and the destination.
- - When C(destination-mac), specifies that the system bases the hash on the MAC
- address of the destination.
- - When C(source-destination-ip), specifies that the system bases the hash on the
- combined IP addresses of the source and the destination.
- type: str
- choices:
- - destination-mac
- - source-destination-ip
- - source-destination-mac
- lacp_enabled:
- description:
- - When C(yes), specifies that the system supports the link aggregation control
- protocol (LACP), which monitors the trunk by exchanging control packets over
- the member links to determine the health of the links.
- - If LACP detects a failure in a member link, it removes the link from the link
- aggregation.
- - When creating a new trunk, if this parameter is not specified, LACP is C(no).
- - LACP is disabled by default for backward compatibility. If this does not apply
- to your network, we recommend that you enable LACP.
- type: bool
- lacp_mode:
- description:
- - Specifies the operation mode for link aggregation control protocol (LACP),
- if LACP is enabled for the trunk.
- - When creating a new trunk, if this parameter is not specified, the default
- is C(active).
- - When C(active), specifies that the system periodically sends control packets
- regardless of whether the partner system has issued a request.
- - When C(passive), specifies that the system sends control packets only when
- the partner system has issued a request.
- type: str
- choices:
- - active
- - passive
- lacp_timeout:
- description:
- - Specifies the rate at which the system sends the LACP control packets.
- - When creating a new trunk, if this parameter is not specified, the default is
- C(long).
- - When C(long), specifies that the system sends an LACP control packet every 30 seconds.
- - When C(short), specifies that the system sends an LACP control packet every 1 seconds.
- type: str
- choices:
- - long
- - short
- qinq_ethertype:
- description:
- - Specifies the ether-type value used for the packets handled on this trunk when
- it is a member in a QinQ vlan.
- - The ether-type can be set to any string containing a valid hexadecimal 16 bits
- number, or any of the well known ether-types; C(0x8100), C(0x9100), C(0x88a8).
- - This parameter is not supported on Virtual Editions.
- - You should always wrap this value in quotes to prevent Ansible from interpreting
- the value as a literal hexadecimal number and converting it to an integer.
- type: raw
- version_added: 2.7
- state:
- description:
- - When C(present), ensures that the resource exists.
- - When C(absent), ensures the resource is removed.
- type: str
- choices:
- - present
- - absent
- default: present
-extends_documentation_fragment: f5
-author:
- - Tim Rupp (@caphrim007)
- - Wojciech Wypior (@wojtek0806)
-'''
-
-EXAMPLES = r'''
-- name: Create a trunk on hardware
- bigip_trunk:
- name: trunk1
- interfaces:
- - 1.1
- - 1.2
- link_selection_policy: maximum-bandwidth
- frame_distribution_hash: destination-mac
- lacp_enabled: yes
- lacp_mode: passive
- lacp_timeout: short
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-'''
-
-RETURN = r'''
-lacp_mode:
- description: Operation mode for LACP if the lacp option is enabled for the trunk.
- returned: changed
- type: str
- sample: active
-lacp_timeout:
- description: Rate at which the system sends the LACP control packets.
- returned: changed
- type: str
- sample: long
-link_selection_policy:
- description:
- - LACP policy that the trunk uses to determine which member link (interface)
- can handle new traffic.
- returned: changed
- type: str
- sample: auto
-frame_distribution_hash:
- description: Hash that the system uses as the frame distribution algorithm.
- returned: changed
- type: str
- sample: src-dst-ipport
-lacp_enabled:
- description: Whether the system supports the link aggregation control protocol (LACP) or not.
- returned: changed
- type: bool
- sample: yes
-interfaces:
- description: Interfaces that are part of the trunk.
- returned: changed
- type: list
- sample: ['int1', 'int2']
-description:
- description: Description of the trunk.
- returned: changed
- type: str
- sample: My trunk
-qinq_ethertype:
- description: Ether-type value used for the packets handled on this trunk when it is a member in a QinQ vlan.
- returned: changed
- type: str
- sample: 0x9100
-'''
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.compare import cmp_simple_list
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.compare import cmp_simple_list
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'lacpMode': 'lacp_mode',
- 'lacpTimeout': 'lacp_timeout',
- 'linkSelectPolicy': 'link_selection_policy',
- 'distributionHash': 'frame_distribution_hash',
- 'lacp': 'lacp_enabled',
- 'qinqEthertype': 'qinq_ethertype',
- }
-
- api_attributes = [
- 'lacp',
- 'lacpMode',
- 'lacpTimeout',
- 'linkSelectPolicy',
- 'distributionHash',
- 'interfaces',
- 'description',
- 'qinqEthertype',
- ]
-
- returnables = [
- 'lacp_mode',
- 'lacp_timeout',
- 'link_selection_policy',
- 'frame_distribution_hash',
- 'lacp_enabled',
- 'interfaces',
- 'description',
- 'qinq_ethertype',
- ]
-
- updatables = [
- 'lacp_mode',
- 'lacp_timeout',
- 'link_selection_policy',
- 'frame_distribution_hash',
- 'lacp_enabled',
- 'interfaces',
- 'description',
- 'qinq_ethertype',
- ]
-
-
-class ApiParameters(Parameters):
- @property
- def lacp_enabled(self):
- if self._values['lacp_enabled'] is None:
- return None
- if self._values['lacp_enabled'] == 'enabled':
- return True
- return False
-
- @property
- def interfaces(self):
- if self._values['interfaces'] is None:
- return None
- result = list(set(self._values['interfaces']))
- result.sort()
- return result
-
-
-class ModuleParameters(Parameters):
- @property
- def frame_distribution_hash(self):
- if self._values['frame_distribution_hash'] is None:
- return None
- elif self._values['frame_distribution_hash'] == 'source-destination-ip':
- return 'src-dst-ipport'
- elif self._values['frame_distribution_hash'] == 'source-destination-mac':
- return 'src-dst-mac'
- elif self._values['frame_distribution_hash'] == 'destination-mac':
- return 'dst-mac'
-
- @property
- def interfaces(self):
- if self._values['interfaces'] is None:
- return None
- if len(self._values['interfaces']) == 1 and self._values['interfaces'][0] == '':
- return ''
- result = [str(x) for x in self._values['interfaces']]
- result = list(set(result))
- result.sort()
- return result
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class UsableChanges(Changes):
- @property
- def lacp_enabled(self):
- if self._values['lacp_enabled'] is None:
- return None
- if self._values['lacp_enabled']:
- return 'enabled'
- return 'disabled'
-
-
-class ReportableChanges(Changes):
- @property
- def frame_distribution_hash(self):
- if self._values['frame_distribution_hash'] is None:
- return None
- elif self._values['frame_distribution_hash'] == 'src-dst-ipport':
- return 'source-destination-ip'
- elif self._values['frame_distribution_hash'] == 'src-dst-mac':
- return 'source-destination-mac'
- elif self._values['frame_distribution_hash'] == 'dst-mac':
- return 'destination-mac'
-
- @property
- def lacp_enabled(self):
- if self._values['lacp_enabled'] is None:
- return None
- if self._values['lacp_enabled'] == 'enabled':
- return True
- return False
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
- @property
- def interfaces(self):
- result = cmp_simple_list(self.want.interfaces, self.have.interfaces)
- return result
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(params=self.module.params)
- self.have = ApiParameters()
- self.changes = UsableChanges()
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = UsableChanges(params=changed)
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def exec_module(self):
- changed = False
- result = dict()
- state = self.want.state
-
- if state == "present":
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.client.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def present(self):
- if self.exists():
- return self.update()
- else:
- return self.create()
-
- def absent(self):
- if self.exists():
- return self.remove()
- return False
-
- def update(self):
- self.have = self.read_current_from_device()
- if not self.should_update():
- return False
- if self.module.check_mode:
- return True
- self.update_on_device()
- return True
-
- def remove(self):
- if self.module.check_mode:
- return True
- self.remove_from_device()
- if self.exists():
- raise F5ModuleError("Failed to delete the resource.")
- return True
-
- def create(self):
- if self.want.link_selection_policy is None:
- self.want.update({'link_selection_policy': 'auto'})
- if self.want.frame_distribution_hash is None:
- self.want.update({'frame_distribution_hash': 'source-destination-ip'})
- if self.want.lacp_enabled is None:
- self.want.update({'lacp_enabled': False})
- if self.want.lacp_mode is None:
- self.want.update({'lacp_mode': 'active'})
- if self.want.lacp_timeout is None:
- self.want.update({'lacp_timeout': 'long'})
- self._set_changed_options()
- if self.module.check_mode:
- return True
- self.create_on_device()
- return True
-
- def exists(self):
- uri = "https://{0}:{1}/mgmt/tm/net/trunk/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- self.want.name
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def create_on_device(self):
- params = self.changes.api_params()
- params['name'] = self.want.name
- uri = "https://{0}:{1}/mgmt/tm/net/trunk/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403, 409]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def update_on_device(self):
- params = self.changes.api_params()
- uri = "https://{0}:{1}/mgmt/tm/net/trunk/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- self.want.name
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def remove_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/net/trunk/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- self.want.name
- )
- resp = self.client.api.delete(uri)
- if resp.status == 200:
- return True
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/net/trunk/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- self.want.name
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return ApiParameters(params=response)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- name=dict(required=True),
- interfaces=dict(type='list'),
- link_selection_policy=dict(
- choices=['auto', 'maximum-bandwidth']
- ),
- frame_distribution_hash=dict(
- choices=['destination-mac', 'source-destination-ip', 'source-destination-mac']
- ),
- lacp_enabled=dict(type='bool'),
- lacp_mode=dict(choices=['active', 'passive']),
- lacp_timeout=dict(choices=['short', 'long']),
- description=dict(),
- state=dict(
- default='present',
- choices=['absent', 'present']
- ),
- qinq_ethertype=dict(type='raw'),
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_tunnel.py b/lib/ansible/modules/network/f5/bigip_tunnel.py
deleted file mode 100644
index bad35f1c26..0000000000
--- a/lib/ansible/modules/network/f5/bigip_tunnel.py
+++ /dev/null
@@ -1,619 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2018, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_tunnel
-short_description: Manage tunnels on a BIG-IP
-description:
- - Manages tunnels on a BIG-IP. Tunnels are usually based upon a tunnel profile which
- defines both default arguments and constraints for the tunnel.
- - Due to this, this module exposes a number of settings that may or may not be related
- to the type of tunnel you are working with. It is important that you take this into
- consideration when declaring your tunnel config.
- - If a specific tunnel does not support the parameter you are considering, the documentation
- of the parameter will usually make mention of this. Otherwise, when configuring that
- parameter on the device, the device will notify you.
-version_added: 2.7
-options:
- name:
- description:
- - Specifies the name of the tunnel.
- type: str
- required: True
- description:
- description:
- - Description of the tunnel.
- type: str
- profile:
- description:
- - Specifies the profile to associate with the tunnel for handling traffic.
- - Depending on your selection, other settings become available or disappear.
- - This parameter may not be changed after it is set.
- type: str
- key:
- description:
- - When applied to a GRE tunnel, this value specifies an optional field in the GRE header,
- used to authenticate the source of the packet.
- - When applied to a VXLAN or Geneve tunnel, this value specifies the Virtual Network
- Identifier (VNI).
- - When applied to an NVGRE tunnel, this value specifies the Virtual Subnet Identifier (VSID).
- - When creating a new tunnel, if this parameter is supported by the tunnel profile but not
- specified, the default value is C(0).
- type: int
- local_address:
- description:
- - Specifies the IP address of the local endpoint of the tunnel.
- type: str
- remote_address:
- description:
- - Specifies the IP address of the remote endpoint of the tunnel.
- - For C(dslite), C(fec) (when configuring the FEC tunnel for receiving traffic only),
- C(v6rd) (configured as a border relay), or C(map), the tunnel must have an unspecified
- remote address (any).
- type: str
- secondary_address:
- description:
- - Specifies a non-floating IP address for the tunnel, to be used with host-initiated traffic.
- type: str
- mtu:
- description:
- - Specifies the maximum transmission unit (MTU) of the tunnel.
- - When creating a new tunnel, if this parameter is supported by the tunnel profile but not
- specified, the default value is C(0).
- - The valid range is from C(0) to C(65515).
- type: int
- use_pmtu:
- description:
- - Enables or disables the tunnel to use the PMTU (Path MTU) information provided by ICMP
- NeedFrag error messages.
- - If C(yes) and the tunnel C(mtu) is set to C(0), the tunnel will use the PMTU information.
- - If C(yes) and the tunnel C(mtu) is fixed to a non-zero value, the tunnel will use the
- minimum of PMTU and MTU.
- - If C(no), the tunnel will use fixed MTU or calculate its MTU using tunnel encapsulation
- configurations.
- type: bool
- tos:
- description:
- - Specifies the Type of Service (TOS) value to insert in the encapsulating header of
- transmitted packets.
- - When creating a new tunnel, if this parameter is supported by the tunnel profile but not
- specified, the default value is C(preserve).
- - When C(preserve), the system copies the TOS value from the inner header to the outer header.
- - You may also specify a numeric value. The possible values are from C(0) to C(255).
- type: str
- auto_last_hop:
- description:
- - Allows you to configure auto last hop on a per-tunnel basis.
- - When creating a new tunnel, if this parameter is supported by the tunnel profile but not
- specified, the default is C(default).
- - When C(default), means that the system uses the global auto-lasthop setting to send back
- the request.
- - When C(enabled), allows the system to send return traffic to the MAC address that transmitted
- the request, even if the routing table points to a different network or interface. As a
- result, the system can send return traffic to clients even when there is no matching route.
- type: str
- choices:
- - default
- - enabled
- - disabled
- traffic_group:
- description:
- - Specifies the traffic group to associate with the tunnel.
- - This value cannot be changed after it is set. This is a limitation of BIG-IP.
- type: str
- mode:
- description:
- - Specifies how the tunnel carries traffic.
- - When creating a new tunnel, if this parameter is supported by the tunnel profile but not
- specified, the default is C(bidirectional).
- - When C(bidirectional), specifies that the tunnel carries both inbound and outbound traffic.
- - When C(inbound), specifies that the tunnel carries only incoming traffic.
- - When C(outbound), specifies that the tunnel carries only outgoing traffic.
- type: str
- choices:
- - bidirectional
- - inbound
- - outbound
- transparent:
- description:
- - Specifies that the tunnel operates in transparent mode.
- - When C(yes), you can inspect and manipulate the encapsulated traffic flowing through the BIG-IP
- system.
- - A transparent tunnel terminates a tunnel while presenting the illusion that the tunnel transits
- the device unmodified (that is, the BIG-IP system appears as if it were an intermediate router
- that simply routes IP traffic through the device).
- type: bool
- partition:
- description:
- - Device partition to manage resources on.
- type: str
- default: Common
- state:
- description:
- - When C(present), ensures that the tunnel exists.
- - When C(absent), ensures the tunnel is removed.
- type: str
- choices:
- - present
- - absent
- default: present
-extends_documentation_fragment: f5
-author:
- - Tim Rupp (@caphrim007)
-'''
-
-EXAMPLES = r'''
-- name: Create a VXLAN tunnel
- bigip_tunnel:
- name: openshift-tunnel
- local_address: 192.1681.240
- key: 0
- secondary_address: 192.168.1.100
- mtu: 0
- use_pmtu: yes
- tos: preserve
- auto_last_hop: default
- traffic_group: traffic-group-1
- state: present
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-'''
-
-RETURN = r'''
-param1:
- description: The new param1 value of the resource.
- returned: changed
- type: bool
- sample: true
-param2:
- description: The new param2 value of the resource.
- returned: changed
- type: str
- sample: Foo is bar
-'''
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.basic import env_fallback
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import fq_name
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.common import flatten_boolean
- from library.module_utils.network.f5.common import transform_name
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import fq_name
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.common import flatten_boolean
- from ansible.module_utils.network.f5.common import transform_name
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'autoLasthop': 'auto_last_hop',
- 'localAddress': 'local_address',
- 'remoteAddress': 'remote_address',
- 'secondaryAddress': 'secondary_address',
- 'usePmtu': 'use_pmtu',
- 'trafficGroup': 'traffic_group',
- }
-
- api_attributes = [
- 'autoLasthop',
- 'description',
- 'key',
- 'mtu',
- 'profile',
- 'transparent',
- 'usePmtu',
- 'tos',
- 'secondaryAddress',
- 'remoteAddress',
- 'mode',
- 'localAddress',
- 'trafficGroup',
- ]
-
- returnables = [
- 'auto_last_hop',
- 'local_address',
- 'mode',
- 'remote_address',
- 'secondary_address',
- 'description',
- 'key',
- 'mtu',
- 'profile',
- 'transparent',
- 'use_pmtu',
- 'tos',
- 'traffic_group',
- ]
-
- updatables = [
- 'auto_last_hop',
- 'local_address',
- 'mode',
- 'remote_address',
- 'profile',
- 'secondary_address',
- 'description',
- 'key',
- 'mtu',
- 'transparent',
- 'use_pmtu',
- 'tos',
- 'traffic_group',
- ]
-
-
-class ApiParameters(Parameters):
- pass
-
-
-class ModuleParameters(Parameters):
- @property
- def transparent(self):
- result = flatten_boolean(self._values['transparent'])
- if result == 'yes':
- return 'enabled'
- elif result == 'no':
- return 'disabled'
-
- @property
- def use_pmtu(self):
- result = flatten_boolean(self._values['use_pmtu'])
- if result == 'yes':
- return 'enabled'
- elif result == 'no':
- return 'disabled'
-
- @property
- def profile(self):
- if self._values['profile'] is None:
- return None
- return fq_name(self.partition, self._values['profile'])
-
- @property
- def traffic_group(self):
- if self._values['traffic_group'] is None:
- return None
- elif self._values['traffic_group'] in ['', 'none']:
- return ''
- return fq_name(self.partition, self._values['traffic_group'])
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class UsableChanges(Changes):
- pass
-
-
-class ReportableChanges(Changes):
- @property
- def transparent(self):
- result = flatten_boolean(self._values['transparent'])
- return result
-
- @property
- def use_pmtu(self):
- result = flatten_boolean(self._values['use_pmtu'])
- return result
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
- @property
- def profile(self):
- if self.want.profile is None:
- return None
- if self.want.profile != self.have.profile:
- raise F5ModuleError(
- "'profile' cannot be changed after it is set."
- )
-
- @property
- def traffic_group(self):
- if self.want.traffic_group is None:
- return None
- if self.want.traffic_group in ['', None] and self.have.traffic_group is None:
- return None
- if self.want.traffic_group != self.have.traffic_group:
- raise F5ModuleError(
- "'traffic_group' cannot be changed after it is set."
- )
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(params=self.module.params)
- self.have = ApiParameters()
- self.changes = UsableChanges()
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = UsableChanges(params=changed)
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def exec_module(self):
- changed = False
- result = dict()
- state = self.want.state
-
- if state == "present":
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.client.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def present(self):
- if self.exists():
- return self.update()
- else:
- return self.create()
-
- def exists(self):
- uri = "https://{0}:{1}/mgmt/tm/net/tunnels/tunnel/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def update(self):
- self.have = self.read_current_from_device()
- if not self.should_update():
- return False
- if self.module.check_mode:
- return True
- self.update_on_device()
- return True
-
- def remove(self):
- if self.module.check_mode:
- return True
- self.remove_from_device()
- if self.exists():
- raise F5ModuleError("Failed to delete the resource.")
- return True
-
- def create(self):
- self._set_changed_options()
- if self.module.check_mode:
- return True
- self.create_on_device()
- return True
-
- def create_on_device(self):
- params = self.changes.api_params()
- params['name'] = self.want.name
- params['partition'] = self.want.partition
- uri = "https://{0}:{1}/mgmt/tm/net/tunnels/tunnel/".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return response['selfLink']
-
- def update_on_device(self):
- params = self.changes.api_params()
- uri = "https://{0}:{1}/mgmt/tm/net/tunnels/tunnel/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def absent(self):
- if self.exists():
- return self.remove()
- return False
-
- def remove_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/net/tunnels/tunnel/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- response = self.client.api.delete(uri)
- if response.status == 200:
- return True
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(response.content)
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/net/tunnels/tunnel/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return ApiParameters(params=response)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- name=dict(required='true'),
- profile=dict(),
- description=dict(),
- key=dict(type='int'),
- local_address=dict(),
- remote_address=dict(),
- secondary_address=dict(),
- mtu=dict(type='int'),
- use_pmtu=dict(type='bool'),
- tos=dict(),
- auto_last_hop=dict(
- choices=['default', 'enabled', 'disabled']
- ),
- traffic_group=dict(),
- mode=dict(
- choices=['bidirectional', 'inbound', 'outbound']
- ),
- transparent=dict(type='bool'),
- state=dict(
- default='present',
- choices=['present', 'absent']
- ),
- partition=dict(
- default='Common',
- fallback=(env_fallback, ['F5_PARTITION'])
- )
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode,
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_ucs.py b/lib/ansible/modules/network/f5/bigip_ucs.py
deleted file mode 100644
index a3c7f592ba..0000000000
--- a/lib/ansible/modules/network/f5/bigip_ucs.py
+++ /dev/null
@@ -1,718 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_ucs
-short_description: Manage upload, installation and removal of UCS files
-description:
- - Manage upload, installation and removal of UCS files.
-version_added: 2.4
-options:
- include_chassis_level_config:
- description:
- - During restore of the UCS file, include chassis level configuration
- that is shared among boot volume sets. For example, cluster default
- configuration.
- type: bool
- ucs:
- description:
- - The path to the UCS file to install. The parameter must be
- provided if the C(state) is either C(installed) or C(activated).
- When C(state) is C(absent), the full path for this parameter will be
- ignored and only the filename will be used to select a UCS for removal.
- Therefore you could specify C(/mickey/mouse/test.ucs) and this module
- would only look for C(test.ucs).
- type: str
- force:
- description:
- - If C(yes) will upload the file every time and replace the file on the
- device. If C(no), the file will only be uploaded if it does not already
- exist. Generally should be C(yes) only in cases where you have reason
- to believe that the image was corrupted during upload.
- type: bool
- default: no
- no_license:
- description:
- - Performs a full restore of the UCS file and all the files it contains,
- with the exception of the license file. The option must be used to
- restore a UCS on RMA devices (Returned Materials Authorization).
- type: bool
- no_platform_check:
- description:
- - Bypasses the platform check and allows a UCS that was created using a
- different platform to be installed. By default (without this option),
- a UCS created from a different platform is not allowed to be installed.
- type: bool
- passphrase:
- description:
- - Specifies the passphrase that is necessary to load the specified UCS file.
- type: str
- reset_trust:
- description:
- - When specified, the device and trust domain certs and keys are not
- loaded from the UCS. Instead, a new set is regenerated.
- type: bool
- state:
- description:
- - When C(installed), ensures that the UCS is uploaded and installed,
- on the system. When C(present), ensures that the UCS is uploaded.
- When C(absent), the UCS will be removed from the system. When
- C(installed), the uploading of the UCS is idempotent, however the
- installation of that configuration is not idempotent.
- type: str
- choices:
- - absent
- - installed
- - present
- default: present
-notes:
- - Only the most basic checks are performed by this module. Other checks and
- considerations need to be taken into account. See the following URL.
- https://support.f5.com/kb/en-us/solutions/public/11000/300/sol11318.html
- - This module does not handle devices with the FIPS 140 HSM
- - This module does not handle BIG-IPs systems on the 6400, 6800, 8400, or
- 8800 hardware platform.
- - This module does not verify that the new or replaced SSH keys from the
- UCS file are synchronized between the BIG-IP system and the SCCP
- - This module does not support the 'rma' option
- - This module does not support restoring a UCS archive on a BIG-IP 1500,
- 3400, 4100, 6400, 6800, or 8400 hardware platform other than the system
- from which the backup was created
- - The UCS restore operation restores the full configuration only if the
- hostname of the target system matches the hostname on which the UCS
- archive was created. If the hostname does not match, only the shared
- configuration is restored. You can ensure hostnames match by using
- the C(bigip_hostname) Ansible module in a task before using this module.
- - This module does not support re-licensing a BIG-IP restored from a UCS
- - This module does not support restoring encrypted archives on replacement
- RMA units.
-extends_documentation_fragment: f5
-author:
- - Tim Rupp (@caphrim007)
- - Wojciech Wypior (@wojtek0806)
-'''
-
-EXAMPLES = r'''
-- name: Upload UCS
- bigip_ucs:
- ucs: /root/bigip.localhost.localdomain.ucs
- state: present
- provider:
- server: lb.mydomain.com
- user: admin
- password: secret
- delegate_to: localhost
-
-- name: Install (upload, install) UCS.
- bigip_ucs:
- ucs: /root/bigip.localhost.localdomain.ucs
- state: installed
- provider:
- server: lb.mydomain.com
- user: admin
- password: secret
- delegate_to: localhost
-
-- name: Install (upload, install) UCS without installing the license portion
- bigip_ucs:
- ucs: /root/bigip.localhost.localdomain.ucs
- state: installed
- no_license: yes
- provider:
- server: lb.mydomain.com
- user: admin
- password: secret
- delegate_to: localhost
-
-- name: Install (upload, install) UCS except the license, and bypassing the platform check
- bigip_ucs:
- ucs: /root/bigip.localhost.localdomain.ucs
- state: installed
- no_license: yes
- no_platform_check: yes
- provider:
- server: lb.mydomain.com
- user: admin
- password: secret
- delegate_to: localhost
-
-- name: Install (upload, install) UCS using a passphrase necessary to load the UCS
- bigip_ucs:
- ucs: /root/bigip.localhost.localdomain.ucs
- state: installed
- passphrase: MyPassphrase1234
- provider:
- server: lb.mydomain.com
- user: admin
- password: secret
- delegate_to: localhost
-
-- name: Remove uploaded UCS file
- bigip_ucs:
- ucs: bigip.localhost.localdomain.ucs
- state: absent
- provider:
- server: lb.mydomain.com
- user: admin
- password: secret
- delegate_to: localhost
-'''
-
-RETURN = r'''
-# only common fields returned
-'''
-
-import os
-import re
-import time
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.six import iteritems
-from distutils.version import LooseVersion
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.icontrol import tmos_version
- from library.module_utils.network.f5.icontrol import upload_file
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.icontrol import tmos_version
- from ansible.module_utils.network.f5.icontrol import upload_file
-
-try:
- from collections import OrderedDict
-except ImportError:
- try:
- from ordereddict import OrderedDict
- except ImportError:
- pass
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {}
- updatables = []
- returnables = []
- api_attributes = []
-
-
-class ApiParameters(Parameters):
- pass
-
-
-class ModuleParameters(Parameters):
- def _check_required_if(self, parameter):
- if self._values[parameter] is not True:
- return self._values[parameter]
- if self.state != 'installed':
- raise F5ModuleError(
- '"{0}" parameters requires "installed" state'.format(parameter)
- )
-
- @property
- def basename(self):
- return os.path.basename(self.ucs)
-
- @property
- def options(self):
- return {
- 'include-chassis-level-config': self.include_chassis_level_config,
- 'no-license': self.no_license,
- 'no-platform-check': self.no_platform_check,
- 'passphrase': self.passphrase,
- 'reset-trust': self.reset_trust
- }
-
- @property
- def reset_trust(self):
- self._check_required_if('reset_trust')
- return self._values['reset_trust']
-
- @property
- def passphrase(self):
- self._check_required_if('passphrase')
- return self._values['passphrase']
-
- @property
- def no_platform_check(self):
- self._check_required_if('no_platform_check')
- return self._values['no_platform_check']
-
- @property
- def no_license(self):
- self._check_required_if('no_license')
- return self._values['no_license']
-
- @property
- def include_chassis_level_config(self):
- self._check_required_if('include_chassis_level_config')
- return self._values['include_chassis_level_config']
-
- @property
- def install_command(self):
- cmd = 'tmsh load sys ucs /var/local/ucs/{0}'.format(self.basename)
- # Append any options that might be specified
- options = OrderedDict(sorted(self.options.items(), key=lambda t: t[0]))
- for k, v in iteritems(options):
- if v is False or v is None:
- continue
- elif k == 'passphrase':
- cmd += ' %s %s' % (k, v)
- else:
- cmd += ' %s' % (k)
- return cmd
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class ReportableChanges(Changes):
- pass
-
-
-class UsableChanges(Changes):
- pass
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.kwargs = kwargs
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
-
- def exec_module(self):
- if self.is_version_v1():
- manager = V1Manager(**self.kwargs)
- else:
- manager = V2Manager(**self.kwargs)
-
- return manager.exec_module()
-
- def is_version_v1(self):
- """Checks to see if the TMOS version is less than 12.1.0
-
- Versions prior to 12.1.0 have a bug which prevents the REST
- API from properly listing any UCS files when you query the
- /mgmt/tm/sys/ucs endpoint. Therefore you need to do everything
- through tmsh over REST.
-
- :return: Bool
- """
- version = tmos_version(self.client)
- if LooseVersion(version) < LooseVersion('12.1.0'):
- return True
- else:
- return False
-
-
-class Difference(object):
- pass
-
-
-class BaseManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(params=self.module.params)
- self.changes = UsableChanges()
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.client.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def exec_module(self):
- changed = False
- result = dict()
- state = self.want.state
-
- if state in ['present', 'installed']:
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def present(self):
- if self.exists():
- return self.update()
- else:
- return self.create()
-
- def update(self):
- if self.module.check_mode:
- if self.want.force:
- return True
- return False
- elif self.want.force:
- self.remove()
- return self.create()
- elif self.want.state == 'installed':
- return self.install_on_device()
- else:
- return False
-
- def create(self):
- if self.module.check_mode:
- return True
- self.create_on_device()
- if not self.exists():
- raise F5ModuleError("Failed to upload the UCS file")
- if self.want.state == 'installed':
- self.install_on_device()
- return True
-
- def absent(self):
- if self.exists():
- return self.remove()
- return False
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def remove(self):
- if self.module.check_mode:
- return True
- self.remove_from_device()
- if self.exists():
- raise F5ModuleError("Failed to delete the UCS file")
- return True
-
- def wait_for_rest_api_restart(self):
- time.sleep(5)
- for x in range(0, 60):
- try:
- self.client.reconnect()
- break
- except Exception:
- time.sleep(3)
-
- def wait_for_configuration_reload(self):
- noops = 0
- while noops < 4:
- time.sleep(3)
- try:
- params = dict(command="run",
- utilCmdArgs='-c "tmsh show sys mcp-state"'
- )
- uri = "https://{0}:{1}/mgmt/tm/util/bash".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- resp = self.client.api.post(uri, json=params)
- try:
- output = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if 'code' in output and output['code'] in [400, 403]:
- if 'message' in output:
- raise F5ModuleError(output['message'])
- else:
- raise F5ModuleError(resp.content)
- except Exception as ex:
- # This can be caused by restjavad restarting.
- continue
-
- if 'commandResult' not in output:
- continue
-
- # Need to re-connect here because the REST framework will be restarting
- # and thus be clearing its authorization cache
- result = output['commandResult']
- if self._is_config_reloading_failed_on_device(result):
- raise F5ModuleError(
- "Failed to reload the configuration. This may be due "
- "to a cross-version incompatibility. {0}".format(result)
- )
- if self._is_config_reloading_success_on_device(result):
- if self._is_config_reloading_running_on_device(result):
- noops += 1
- continue
- noops = 0
-
- def _is_config_reloading_success_on_device(self, output):
- succeed = r'Last Configuration Load Status\s+full-config-load-succeed'
- matches = re.search(succeed, output)
- if matches:
- return True
- return False
-
- def _is_config_reloading_running_on_device(self, output):
- running = r'Running Phase\s+running'
- matches = re.search(running, output)
- if matches:
- return True
- return False
-
- def _is_config_reloading_failed_on_device(self, output):
- failed = r'Last Configuration Load Status\s+base-config-load-failed'
- matches = re.search(failed, output)
- if matches:
- return True
- return False
-
-
-class V1Manager(BaseManager):
- """Manager class for V1 product
-
- V1 products include versions of BIG-IP < 12.1.0, but >= 12.0.0.
-
- These versions had a number of API deficiencies. These include, but
- are not limited to,
-
- * UCS collection endpoint listed no items
- * No API to upload UCS files
-
- """
- def upload_file_to_device(self, content, name):
- url = 'https://{0}:{1}/mgmt/shared/file-transfer/uploads'.format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- try:
- upload_file(self.client, url, content, name)
- except F5ModuleError:
- raise F5ModuleError(
- "Failed to upload the file."
- )
-
- def create_on_device(self):
- remote_path = "/var/local/ucs"
- tpath_name = '/var/config/rest/downloads'
-
- self.upload_file_to_device(self.want.ucs, self.want.basename)
-
- uri = "https://{0}:{1}/mgmt/tm/util/unix-mv/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- args = dict(
- command='run',
- utilCmdArgs='{0}/{2} {1}/{2}'.format(
- tpath_name, remote_path, self.want.basename
- )
- )
- resp = self.client.api.post(uri, json=args)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return True
-
- def read_current_from_device(self):
- result = []
- params = dict(command="run",
- utilCmdArgs='-c "tmsh list sys ucs"'
- )
- uri = "https://{0}:{1}/mgmt/tm/util/bash".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- resp = self.client.api.post(uri, json=params)
- try:
- output = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if 'code' in output and output['code'] in [400, 403]:
- if 'message' in output:
- raise F5ModuleError(output['message'])
- else:
- raise F5ModuleError(resp.content)
- if 'commandResult' in output:
- lines = output['commandResult'].split("\n")
- result = [x.strip() for x in lines]
- result = list(set(result))
- return result
-
- def exists(self):
- collection = self.read_current_from_device()
- if self.want.basename in collection:
- return True
- return False
-
- def remove_from_device(self):
- params = dict(command="run",
- utilCmdArgs='-c "tmsh delete sys ucs {0}"'.format(self.want.basename)
- )
- uri = "https://{0}:{1}/mgmt/tm/util/bash".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- resp = self.client.api.post(uri, json=params)
- try:
- output = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if 'code' in output and output['code'] in [400, 403]:
- if 'message' in output:
- raise F5ModuleError(output['message'])
- else:
- raise F5ModuleError(resp.content)
- if 'commandResult' in output:
- if '{0} is deleted'.format(self.want.basename) in output['commandResult']:
- return True
- return False
-
- def install_on_device(self):
- try:
- params = dict(command="run",
- utilCmdArgs='-c "{0}"'.format(self.want.install_command)
- )
- uri = "https://{0}:{1}/mgmt/tm/util/bash".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- resp = self.client.api.post(uri, json=params)
- try:
- output = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if 'code' in output and output['code'] in [400, 403]:
- if 'message' in output:
- raise F5ModuleError(output['message'])
- else:
- raise F5ModuleError(resp.content)
- except Exception as ex:
- # Reloading a UCS configuration will cause restjavad to restart,
- # aborting the connection.
- if 'Connection aborted' in str(ex):
- pass
- elif 'TimeoutException' in str(ex):
- # Timeouts appear to be able to happen in 12.1.2
- pass
- else:
- raise F5ModuleError(str(ex))
- self.wait_for_rest_api_restart()
- self.wait_for_configuration_reload()
- return True
-
-
-class V2Manager(V1Manager):
- """Manager class for V2 product
-
- V2 products include versions of BIG-IP >= 12.1.0 but < 13.0.0.
-
- These versions fixed the collection bug in V1, but had yet to add the
- ability to upload files using a dedicated UCS upload API.
-
- """
-
- def read_current_from_device(self):
- result = []
- uri = "https://{0}:{1}/mgmt/tm/sys/ucs/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- items = response.get('items', [])
- for item in items:
- result.append(os.path.basename(item['apiRawValues']['filename']))
- return result
-
- def exists(self):
- collection = self.read_current_from_device()
- if self.want.basename in collection:
- return True
- return False
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- force=dict(
- type='bool',
- default='no'
- ),
- include_chassis_level_config=dict(
- type='bool'
- ),
- no_license=dict(
- type='bool'
- ),
- no_platform_check=dict(
- type='bool'
- ),
- passphrase=dict(no_log=True),
- reset_trust=dict(type='bool'),
- state=dict(
- default='present',
- choices=['absent', 'installed', 'present']
- ),
- ucs=dict(required=True)
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_ucs_fetch.py b/lib/ansible/modules/network/f5/bigip_ucs_fetch.py
deleted file mode 100644
index 092771528c..0000000000
--- a/lib/ansible/modules/network/f5/bigip_ucs_fetch.py
+++ /dev/null
@@ -1,612 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_ucs_fetch
-short_description: Fetches a UCS file from remote nodes
-description:
- - This module is used for fetching UCS files from remote machines and
- storing them locally in a file tree, organized by hostname. Note that
- this module is written to transfer UCS files that might not be present,
- so a missing remote UCS won't be an error unless fail_on_missing is
- set to 'yes'.
-version_added: 2.5
-options:
- backup:
- description:
- - Create a backup file including the timestamp information so you can
- get the original file back if you somehow clobbered it incorrectly.
- type: bool
- default: no
- create_on_missing:
- description:
- - Creates the UCS based on the value of C(src) if the file does not already
- exist on the remote system.
- type: bool
- default: yes
- dest:
- description:
- - A directory to save the UCS file into.
- type: path
- required: True
- encryption_password:
- description:
- - Password to use to encrypt the UCS file if desired.
- type: str
- fail_on_missing:
- description:
- - Make the module fail if the UCS file on the remote system is missing.
- type: bool
- default: no
- force:
- description:
- - If C(no), the file will only be transferred if the destination does not
- exist.
- type: bool
- default: yes
- src:
- description:
- - The name of the UCS file to create on the remote server for downloading
- type: str
-notes:
- - BIG-IP provides no way to get a checksum of the UCS files on the system
- via any interface except, perhaps, logging in directly to the box (which
- would not support appliance mode). Therefore, the best this module can
- do is check for the existence of the file on disk; no check-summing.
- - If you are using this module with either Ansible Tower or Ansible AWX, you
- should be aware of how these Ansible products execute jobs in restricted
- environments. More information can be found here
- https://clouddocs.f5.com/products/orchestration/ansible/devel/usage/module-usage-with-tower.html
-extends_documentation_fragment: f5
-author:
- - Tim Rupp (@caphrim007)
- - Wojciech Wypior (@wojtek0806)
-'''
-
-EXAMPLES = r'''
-- name: Download a new UCS
- bigip_ucs_fetch:
- src: cs_backup.ucs
- dest: /tmp/cs_backup.ucs
- provider:
- server: lb.mydomain.com
- user: admin
- password: secret
- delegate_to: localhost
-'''
-
-RETURN = r'''
-checksum:
- description: The SHA1 checksum of the downloaded file
- returned: success or changed
- type: str
- sample: 7b46bbe4f8ebfee64761b5313855618f64c64109
-dest:
- description: Location on the ansible host that the UCS was saved to
- returned: success
- type: str
- sample: /path/to/file.txt
-src:
- description:
- - Name of the UCS file on the remote BIG-IP to download. If not
- specified, then this will be a randomly generated filename
- returned: changed
- type: str
- sample: cs_backup.ucs
-backup_file:
- description: Name of backup file created
- returned: changed and if backup=yes
- type: str
- sample: /path/to/file.txt.2015-02-12@22:09~
-gid:
- description: Group id of the UCS file, after execution
- returned: success
- type: int
- sample: 100
-group:
- description: Group of the UCS file, after execution
- returned: success
- type: str
- sample: httpd
-owner:
- description: Owner of the UCS file, after execution
- returned: success
- type: str
- sample: httpd
-uid:
- description: Owner id of the UCS file, after execution
- returned: success
- type: int
- sample: 100
-md5sum:
- description: The MD5 checksum of the downloaded file
- returned: changed or success
- type: str
- sample: 96cacab4c259c4598727d7cf2ceb3b45
-mode:
- description: Permissions of the target UCS, after execution
- returned: success
- type: str
- sample: 0644
-size:
- description: Size of the target UCS, after execution
- returned: success
- type: int
- sample: 1220
-'''
-
-import os
-import re
-import tempfile
-
-from ansible.module_utils.basic import AnsibleModule
-from distutils.version import LooseVersion
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.common import transform_name
- from library.module_utils.network.f5.icontrol import download_file
- from library.module_utils.network.f5.icontrol import tmos_version
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.common import transform_name
- from ansible.module_utils.network.f5.icontrol import download_file
- from ansible.module_utils.network.f5.icontrol import tmos_version
-
-
-class Parameters(AnsibleF5Parameters):
- updatables = []
- returnables = [
- 'dest',
- 'src',
- 'md5sum',
- 'checksum',
- 'backup_file']
- api_attributes = []
- api_map = {}
-
- @property
- def options(self):
- result = []
- if self.passphrase:
- result.append(dict(
- passphrase=self.want.passphrase
- ))
- return result
-
- @property
- def src(self):
- if self._values['src'] is not None:
- return self._values['src']
- result = next(tempfile._get_candidate_names()) + '.ucs'
- self._values['src'] = result
- return result
-
- @property
- def fulldest(self):
- result = None
- if os.path.isdir(self.dest):
- result = os.path.join(self.dest, self.src)
- else:
- if os.path.exists(os.path.dirname(self.dest)):
- result = self.dest
- else:
- try:
- # os.path.exists() can return false in some
- # circumstances where the directory does not have
- # the execute bit for the current user set, in
- # which case the stat() call will raise an OSError
- os.stat(os.path.dirname(result))
- except OSError as e:
- if "permission denied" in str(e).lower():
- raise F5ModuleError(
- "Destination directory {0} is not accessible".format(os.path.dirname(result))
- )
- raise F5ModuleError(
- "Destination directory {0} does not exist".format(os.path.dirname(result))
- )
-
- if not os.access(os.path.dirname(result), os.W_OK):
- raise F5ModuleError(
- "Destination {0} not writable".format(os.path.dirname(result))
- )
- return result
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class UsableChanges(Changes):
- pass
-
-
-class ReportableChanges(Changes):
- pass
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.kwargs = kwargs
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
-
- def exec_module(self):
- if self.is_version_v1():
- manager = self.get_manager('v1')
- else:
- manager = self.get_manager('v2')
- return manager.exec_module()
-
- def get_manager(self, type):
- if type == 'v1':
- return V1Manager(**self.kwargs)
- elif type == 'v2':
- return V2Manager(**self.kwargs)
-
- def is_version_v1(self):
- """Checks to see if the TMOS version is less than 12.1.0
-
- Versions prior to 12.1.0 have a bug which prevents the REST
- API from properly listing any UCS files when you query the
- /mgmt/tm/sys/ucs endpoint. Therefore you need to do everything
- through tmsh over REST.
-
- :return: bool
- """
- version = tmos_version(self.client)
- if LooseVersion(version) < LooseVersion('12.1.0'):
- return True
- else:
- return False
-
-
-class BaseManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = Parameters(params=self.module.params)
- self.changes = UsableChanges()
-
- def exec_module(self):
- result = dict()
-
- self.present()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=True))
- return result
-
- def present(self):
- if self.exists():
- self.update()
- else:
- self.create()
-
- def update(self):
- if os.path.exists(self.want.fulldest):
- if not self.want.force:
- raise F5ModuleError(
- "File '{0}' already exists".format(self.want.fulldest)
- )
- self.execute()
-
- def _get_backup_file(self):
- return self.module.backup_local(self.want.fulldest)
-
- def execute(self):
- try:
- if self.want.backup:
- if os.path.exists(self.want.fulldest):
- backup_file = self._get_backup_file()
- self.changes.update({'backup_file': backup_file})
- self.download()
- except IOError:
- raise F5ModuleError(
- "Failed to copy: {0} to {1}".format(self.want.src, self.want.fulldest)
- )
- self._set_checksum()
- self._set_md5sum()
- file_args = self.module.load_file_common_arguments(self.module.params)
- return self.module.set_fs_attributes_if_different(file_args, True)
-
- def _set_checksum(self):
- try:
- result = self.module.sha1(self.want.fulldest)
- self.want.update({'checksum': result})
- except ValueError:
- pass
-
- def _set_md5sum(self):
- try:
- result = self.module.md5(self.want.fulldest)
- self.want.update({'md5sum': result})
- except ValueError:
- pass
-
- def create(self):
- if self.want.fail_on_missing:
- raise F5ModuleError(
- "UCS '{0}' was not found".format(self.want.src)
- )
-
- if not self.want.create_on_missing:
- raise F5ModuleError(
- "UCS '{0}' was not found".format(self.want.src)
- )
-
- if self.module.check_mode:
- return True
- if self.want.create_on_missing:
- self.create_on_device()
- self.execute()
- return True
-
- def create_on_device(self):
- if self.want.passphrase:
- params = dict(
- command='save',
- name=self.want.src,
- options=[{'passphrase': self.want.encryption_password}]
- )
- else:
- params = dict(
- command='save',
- name=self.want.src,
- )
-
- uri = "https://{0}:{1}/mgmt/tm/sys/ucs".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def download(self):
- self.download_from_device(self.want.dest)
- if os.path.exists(self.want.dest):
- return True
- raise F5ModuleError(
- "Failed to download the remote file"
- )
-
-
-class V1Manager(BaseManager):
- def __init__(self, *args, **kwargs):
- super(V1Manager, self).__init__(**kwargs)
- self.remote_dir = '/var/config/rest/madm'
-
- def read_current(self):
- result = None
- output = self.read_current_from_device()
- if 'commandResult' in output:
- result = self._read_ucs_files_from_output(output['commandResult'])
- return result
-
- def read_current_from_device(self):
- params = dict(
- command='run',
- utilCmdArgs='-c "tmsh list sys ucs"'
- )
-
- uri = "https://{0}:{1}/mgmt/tm/util/bash".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
-
- resp = self.client.api.post(uri, json=params)
-
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return response
-
- def _read_ucs_files_from_output(self, output):
- search = re.compile(r'filename\s+(.*)').search
- lines = output.split("\n")
- result = [m.group(1) for m in map(search, lines) if m]
- return result
-
- def exists(self):
- collection = self.read_current()
- base = os.path.basename(self.want.src)
- if any(base == os.path.basename(x) for x in collection):
- return True
- return False
-
- def download_from_device(self, dest):
- url = 'https://{0}:{1}/mgmt/shared/file-transfer/madm/{2}'.format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- self.want.filename
- )
- try:
- download_file(self.client, url, dest)
- except F5ModuleError:
- raise F5ModuleError(
- "Failed to download the file."
- )
- if os.path.exists(self.want.dest):
- return True
- return False
-
- def _move_to_download(self):
- move_path = '/var/local/ucs/{0} {1}/{0}'.format(
- self.want.filename, self.remote_dir
- )
- params = dict(
- command='run',
- utilCmdArgs=move_path
- )
-
- uri = "https://{0}:{1}/mgmt/tm/util/unix-mv/".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
-
- resp = self.client.api.post(uri, json=params)
-
- try:
- response = resp.json()
- if 'commandResult' in response:
- if 'cannot stat' in response['commandResult']:
- raise F5ModuleError(response['commandResult'])
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- return True
-
-
-class V2Manager(BaseManager):
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/sys/ucs".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.get(uri)
-
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- return response
-
- def read_current(self):
- collection = self.read_current_from_device()
- if 'items' not in collection:
- return []
- resources = collection['items']
- result = [x['apiRawValues']['filename'] for x in resources]
- return result
-
- def exists(self):
- collection = self.read_current()
- base = os.path.basename(self.want.src)
- if any(base == os.path.basename(x) for x in collection):
- return True
- return False
-
- def download_from_device(self, dest):
- url = 'https://{0}:{1}/mgmt/shared/file-transfer/ucs-downloads/{2}'.format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- self.want.src
- )
- try:
- download_file(self.client, url, dest)
- except F5ModuleError:
- raise F5ModuleError(
- "Failed to download the file."
- )
- if os.path.exists(self.want.dest):
- return True
- return False
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- backup=dict(
- default='no',
- type='bool'
- ),
- create_on_missing=dict(
- default='yes',
- type='bool'
- ),
- encryption_password=dict(no_log=True),
- dest=dict(
- required=True,
- type='path'
- ),
- force=dict(
- default='yes',
- type='bool'
- ),
- fail_on_missing=dict(
- default='no',
- type='bool'
- ),
- src=dict()
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
- self.add_file_common_args = True
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode,
- add_file_common_args=spec.add_file_common_args
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_user.py b/lib/ansible/modules/network/f5/bigip_user.py
deleted file mode 100644
index 37f2e9098f..0000000000
--- a/lib/ansible/modules/network/f5/bigip_user.py
+++ /dev/null
@@ -1,1116 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_user
-short_description: Manage user accounts and user attributes on a BIG-IP
-description:
- - Manage user accounts and user attributes on a BIG-IP. Typically this
- module operates only on the REST API users and not the CLI users.
- When specifying C(root), you may only change the password.
- Your other parameters will be ignored in this case. Changing the C(root)
- password is not an idempotent operation. Therefore, it will change it
- every time this module attempts to change it.
-version_added: 2.4
-options:
- full_name:
- description:
- - Full name of the user.
- type: str
- username_credential:
- description:
- - Name of the user to create, remove or modify.
- - The C(root) user may not be removed.
- type: str
- required: True
- aliases:
- - name
- password_credential:
- description:
- - Set the users password to this unencrypted value.
- C(password_credential) is required when creating a new account.
- type: str
- shell:
- description:
- - Optionally set the users shell.
- type: str
- choices:
- - bash
- - none
- - tmsh
- partition_access:
- description:
- - Specifies the administrative partition to which the user has access.
- C(partition_access) is required when creating a new account.
- Should be in the form "partition:role".
- - Valid roles include C(acceleration-policy-editor), C(admin), C(application-editor),
- C(auditor), C(certificate-manager), C(guest), C(irule-manager), C(manager), C(no-access),
- C(operator), C(resource-admin), C(user-manager), C(web-application-security-administrator),
- and C(web-application-security-editor).
- - Partition portion of tuple should be an existing partition or the value 'all'.
- type: list
- state:
- description:
- - Whether the account should exist or not, taking action if the state is
- different from what is stated.
- type: str
- choices:
- - present
- - absent
- default: present
- update_password:
- description:
- - C(always) will allow to update passwords if the user chooses to do so.
- C(on_create) will only set the password for newly created users.
- - When C(username_credential) is C(root), this value will be forced to C(always).
- type: str
- choices:
- - always
- - on_create
- default: always
- partition:
- description:
- - Device partition to manage resources on.
- type: str
- default: Common
- version_added: 2.5
-notes:
- - Requires BIG-IP versions >= 12.0.0
-extends_documentation_fragment: f5
-author:
- - Tim Rupp (@caphrim007)
- - Wojciech Wypior (@wojtek0806)
-'''
-
-EXAMPLES = r'''
-- name: Add the user 'johnd' as an admin
- bigip_user:
- username_credential: johnd
- password_credential: password
- full_name: John Doe
- partition_access: all:admin
- update_password: on_create
- state: present
- provider:
- server: lb.mydomain.com
- user: admin
- password: secret
- delegate_to: localhost
-
-- name: Change the user "johnd's" role and shell
- bigip_user:
- username_credential: johnd
- partition_access: NewPartition:manager
- shell: tmsh
- state: present
- provider:
- server: lb.mydomain.com
- user: admin
- password: secret
- delegate_to: localhost
-
-- name: Make the user 'johnd' an admin and set to advanced shell
- bigip_user:
- name: johnd
- partition_access: all:admin
- shell: bash
- state: present
- provider:
- server: lb.mydomain.com
- user: admin
- password: secret
- delegate_to: localhost
-
-- name: Remove the user 'johnd'
- bigip_user:
- name: johnd
- state: absent
- provider:
- server: lb.mydomain.com
- user: admin
- password: secret
- delegate_to: localhost
-
-- name: Update password
- bigip_user:
- state: present
- username_credential: johnd
- password_credential: newsupersecretpassword
- provider:
- server: lb.mydomain.com
- user: admin
- password: secret
- delegate_to: localhost
-
-# Note that the second time this task runs, it would fail because
-# The password has been changed. Therefore, it is recommended that
-# you either,
-#
-# * Put this in its own playbook that you run when you need to
-# * Put this task in a `block`
-# * Include `ignore_errors` on this task
-- name: Change the Admin password
- bigip_user:
- state: present
- username_credential: admin
- password_credential: NewSecretPassword
- provider:
- server: lb.mydomain.com
- user: admin
- password: secret
- delegate_to: localhost
-
-- name: Change the root user's password
- bigip_user:
- username_credential: root
- password_credential: secret
- state: present
- provider:
- server: lb.mydomain.com
- user: admin
- password: secret
- delegate_to: localhost
-'''
-
-RETURN = r'''
-full_name:
- description: Full name of the user
- returned: changed and success
- type: str
- sample: John Doe
-partition_access:
- description:
- - List of strings containing the user's roles and which partitions they
- are applied to. They are specified in the form "partition:role".
- returned: changed and success
- type: list
- sample: ['all:admin']
-shell:
- description: The shell assigned to the user account
- returned: changed and success
- type: str
- sample: tmsh
-'''
-
-import os
-import tempfile
-
-from ansible.module_utils._text import to_bytes
-
-try:
- from BytesIO import BytesIO
-except ImportError:
- from io import BytesIO
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.basic import env_fallback
-from ansible.module_utils.six import string_types
-from distutils.version import LooseVersion
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.icontrol import tmos_version
- from library.module_utils.network.f5.icontrol import upload_file
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.icontrol import tmos_version
- from ansible.module_utils.network.f5.icontrol import upload_file
-
-
-try:
- # Crypto is used specifically for changing the root password via
- # tmsh over REST.
- #
- # We utilize the crypto library to encrypt the contents of a file
- # before we upload it, and then decrypt it on-box to change the
- # password.
- #
- # To accomplish such a process, we need to be able to encrypt the
- # temporary file with the public key found on the box.
- #
- # These libraries are used to do the encryption.
- #
- # Note that, if these are not available, the ability to change the
- # root password is disabled and the user will be notified as such
- # by a failure of the module.
- #
- # These libraries *should* be available on most Ansible controllers
- # by default though as crypto is a dependency of Ansible.
- #
- from cryptography.hazmat.backends import default_backend
- from cryptography.hazmat.primitives import serialization
- from cryptography.hazmat.primitives.asymmetric import padding
- from cryptography.hazmat.primitives import hashes
- HAS_CRYPTO = True
-except ImportError:
- HAS_CRYPTO = False
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'partitionAccess': 'partition_access',
- 'description': 'full_name',
- }
-
- updatables = [
- 'partition_access',
- 'full_name',
- 'shell',
- 'password_credential',
- ]
-
- returnables = [
- 'shell',
- 'partition_access',
- 'full_name',
- 'username_credential',
- 'password_credential',
- ]
-
- api_attributes = [
- 'shell',
- 'partitionAccess',
- 'description',
- 'name',
- 'password',
- ]
-
- @property
- def partition_access(self):
- """Partition access values will require some transformation.
-
- This operates on both user and device returned values.
- Check if the element is a string from user input in the format of
- name:role, if it is split it and create dictionary out of it.
-
- If the access value is a dictionary (returned from device,
- or already processed) and contains nameReference
- key, delete it and append the remaining dictionary element into
- a list.
-
- If the nameReference key is removed just append the dictionary
- into the list.
-
- Returns:
- List of dictionaries. Each item in the list is a dictionary
- which contains the ``name`` of the partition and the ``role`` to
- allow on that partition.
- """
- if self._values['partition_access'] is None:
- return
- result = []
- part_access = self._values['partition_access']
- for access in part_access:
- if isinstance(access, dict):
- if 'nameReference' in access:
- del access['nameReference']
-
- result.append(access)
- else:
- result.append(access)
- if isinstance(access, string_types):
- acl = access.split(':')
- if acl[0].lower() == 'all':
- acl[0] = 'all-partitions'
- value = dict(
- name=acl[0],
- role=acl[1]
- )
-
- result.append(value)
- return result
-
- @property
- def temp_upload_file(self):
- if self._values['temp_upload_file'] is None:
- f = tempfile.NamedTemporaryFile()
- name = os.path.basename(f.name)
- self._values['temp_upload_file'] = name
- return self._values['temp_upload_file']
-
-
-class ApiParameters(Parameters):
- @property
- def shell(self):
- if self._values['shell'] in [None, 'none']:
- return None
- return self._values['shell']
-
-
-class ModuleParameters(Parameters):
- @property
- def shell(self):
- if self._values['shell'] in [None, 'none']:
- return None
- return self._values['shell']
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- for returnable in self.returnables:
- try:
- result[returnable] = getattr(self, returnable)
- except Exception:
- pass
- result = self._filter_params(result)
- return result
-
-
-class UsableChanges(Changes):
- @property
- def password(self):
- if self._values['password_credential'] is None:
- return None
- return self._values['password_credential']
-
-
-class ReportableChanges(Changes):
- pass
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
- @property
- def password_credential(self):
- if self.want.password_credential is None:
- return None
- if self.want.update_password in ['always']:
- return self.want.password_credential
- return None
-
- @property
- def shell(self):
- if self.want.shell is None:
- if self.have.shell is not None:
- return 'none'
- else:
- return None
- if self.want.shell == 'bash':
- self._validate_shell_parameter()
- if self.want.shell == self.have.shell:
- return None
- else:
- return self.want.shell
- if self.want.shell != self.have.shell:
- return self.want.shell
-
- def _validate_shell_parameter(self):
- """Method to validate shell parameters.
-
- Raise when shell attribute is set to 'bash' with roles set to
- either 'admin' or 'resource-admin'.
-
- NOTE: Admin and Resource-Admin roles automatically enable access to
- all partitions, removing any other roles that the user might have
- had. There are few other roles which do that but those roles,
- do not allow bash.
- """
-
- err = "Shell access is only available to " \
- "'admin' or 'resource-admin' roles."
- permit = ['admin', 'resource-admin']
-
- have = self.have.partition_access
- if not any(r['role'] for r in have if r['role'] in permit):
- raise F5ModuleError(err)
-
- if self.want.partition_access is not None:
- want = self.want.partition_access
- if not any(r['role'] for r in want if r['role'] in permit):
- raise F5ModuleError(err)
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.kwargs = kwargs
-
- def exec_module(self):
- if self.is_root_username_credential():
- manager = self.get_manager('root')
- elif self.is_version_less_than_13():
- manager = self.get_manager('v1')
- else:
- manager = self.get_manager('v2')
- return manager.exec_module()
-
- def get_manager(self, type):
- if type == 'root':
- return RootUserManager(**self.kwargs)
- elif type == 'v1':
- return UnpartitionedManager(**self.kwargs)
- elif type == 'v2':
- return PartitionedManager(**self.kwargs)
-
- def is_version_less_than_13(self):
- """Checks to see if the TMOS version is less than 13
-
- Anything less than BIG-IP 13.x does not support users
- on different partitions.
-
- :return: Bool
- """
- version = tmos_version(self.client)
- if LooseVersion(version) < LooseVersion('13.0.0'):
- return True
- else:
- return False
-
- def is_root_username_credential(self):
- user = self.module.params.get('username_credential', None)
- if user == 'root':
- return True
- return False
-
-
-class BaseManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(params=self.module.params)
- self.have = ApiParameters()
- self.changes = UsableChanges()
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = UsableChanges(params=changed)
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def exec_module(self):
- changed = False
- result = dict()
- state = self.want.state
-
- if state == "present":
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def present(self):
- if self.exists():
- return self.update()
- else:
- return self.create()
-
- def absent(self):
- if self.exists():
- return self.remove()
- return False
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def update(self):
- self.have = self.read_current_from_device()
- if not self.should_update():
- return False
- if self.module.check_mode:
- return True
- self.update_on_device()
- return True
-
- def remove(self):
- if self.module.check_mode:
- return True
- self.remove_from_device()
- if self.exists():
- raise F5ModuleError("Failed to delete the user.")
- return True
-
- def create(self):
- self.validate_create_parameters()
- if self.want.shell == 'bash':
- self.validate_shell_parameter()
- self._set_changed_options()
- if self.module.check_mode:
- return True
- self.create_on_device()
- return True
-
- def validate_shell_parameter(self):
- """Method to validate shell parameters.
-
- Raise when shell attribute is set to 'bash' with roles set to
- either 'admin' or 'resource-admin'.
-
- NOTE: Admin and Resource-Admin roles automatically enable access to
- all partitions, removing any other roles that the user might have
- had. There are few other roles which do that but those roles,
- do not allow bash.
- """
-
- err = "Shell access is only available to " \
- "'admin' or 'resource-admin' roles."
- permit = ['admin', 'resource-admin']
-
- if self.want.partition_access is not None:
- want = self.want.partition_access
- if not any(r['role'] for r in want if r['role'] in permit):
- raise F5ModuleError(err)
-
- def validate_create_parameters(self):
- if self.want.partition_access is None:
- err = "The 'partition_access' option " \
- "is required when creating a resource."
- raise F5ModuleError(err)
-
-
-class UnpartitionedManager(BaseManager):
- def exists(self):
- uri = "https://{0}:{1}/mgmt/tm/auth/user/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- self.want.username_credential
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def create_on_device(self):
- params = self.changes.api_params()
- params['name'] = self.want.username_credential
- uri = "https://{0}:{1}/mgmt/tm/auth/user/".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return response['selfLink']
-
- def update_on_device(self):
- params = self.changes.api_params()
- uri = "https://{0}:{1}/mgmt/tm/auth/user/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- self.want.username_credential
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def remove_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/auth/user/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- self.want.username_credential
- )
- response = self.client.api.delete(uri)
- if response.status == 200:
- return True
- raise F5ModuleError(response.content)
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/auth/user/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- self.want.username_credential
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return ApiParameters(params=response)
-
-
-class PartitionedManager(BaseManager):
- def exists(self):
- response = self.list_users_on_device()
- if 'items' in response:
- collection = [x for x in response['items'] if x['name'] == self.want.username_credential]
- if len(collection) == 1:
- return True
- elif len(collection) == 0:
- return False
- else:
- raise F5ModuleError(
- "Multiple users with the provided name were found!"
- )
- return False
-
- def create_on_device(self):
- params = self.changes.api_params()
- params['name'] = self.want.username_credential
- params['partition'] = self.want.partition
- uri = "https://{0}:{1}/mgmt/tm/auth/user/".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if 'code' in response and response['code'] in [400, 404, 409, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return True
-
- def read_current_from_device(self):
- response = self.list_users_on_device()
- collection = [x for x in response['items'] if x['name'] == self.want.username_credential]
- if len(collection) == 1:
- user = collection.pop()
- return ApiParameters(params=user)
- elif len(collection) == 0:
- raise F5ModuleError(
- "No accounts with the provided name were found."
- )
- else:
- raise F5ModuleError(
- "Multiple users with the provided name were found!"
- )
-
- def update_on_device(self):
- params = self.changes.api_params()
- uri = "https://{0}:{1}/mgmt/tm/auth/user/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- self.want.username_credential
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 404, 409, 403]:
- if 'message' in response:
- if 'updated successfully' not in response['message']:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def remove_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/auth/user/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- self.want.username_credential
- )
- response = self.client.api.delete(uri)
- if response.status == 200:
- return True
- raise F5ModuleError(response.content)
-
- def list_users_on_device(self):
- uri = "https://{0}:{1}/mgmt/tm/auth/user/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- query = "?$filter=partition+eq+'{0}'".format(self.want.partition)
- resp = self.client.api.get(uri + query)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return response
-
-
-class RootUserManager(BaseManager):
- def exec_module(self):
- if not HAS_CRYPTO:
- raise F5ModuleError(
- "An installed and up-to-date python 'cryptography' package is "
- "required to change the 'root' password."
- )
-
- changed = False
- result = dict()
- state = self.want.state
-
- if state == "present":
- changed = self.present()
- elif state == "absent":
- raise F5ModuleError(
- "You may not remove the root user."
- )
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def exists(self):
- return True
-
- def update(self):
- public_key = self.get_public_key_from_device()
- public_key = self.extract_key(public_key)
- encrypted = self.encrypt_password_change_file(
- public_key, self.want.password_credential
- )
- self.upload_to_device(encrypted, self.want.temp_upload_file)
- result = self.update_on_device()
- self.remove_uploaded_file_from_device(self.want.temp_upload_file)
- return result
-
- def encrypt_password_change_file(self, public_key, password):
- # This function call requires that the public_key be expressed in bytes
- pub = serialization.load_pem_public_key(
- to_bytes(public_key),
- backend=default_backend()
- )
-
- message = to_bytes("{0}\n{0}\n".format(password))
- ciphertext = pub.encrypt(
- message,
-
- # OpenSSL craziness
- #
- # Using this padding because it is the only one that works with
- # the OpenSSL on BIG-IP at this time.
- padding.PKCS1v15(),
-
- #
- # OAEP is the recommended padding to use for encrypting, however, two
- # things are wrong with it on BIG-IP.
- #
- # The first is that one of the parameters required to decrypt the data
- # is not supported by the OpenSSL version on BIG-IP. A "parameter setting"
- # error is raised when you attempt to use the OAEP parameters to specify
- # hashing algorithms.
- #
- # This is validated by this thread here
- #
- # https://mta.openssl.org/pipermail/openssl-dev/2017-September/009745.html
- #
- # Were is supported, we could use OAEP, but the second problem is that OAEP
- # is not the default mode of the ``openssl`` command. Therefore, we need
- # to adjust the command we use to decrypt the encrypted file when it is
- # placed on BIG-IP.
- #
- # The correct (and recommended if BIG-IP ever upgrades OpenSSL) code is
- # shown below.
- #
- # padding.OAEP(
- # mgf=padding.MGF1(algorithm=hashes.SHA256()),
- # algorithm=hashes.SHA256(),
- # label=None
- # )
- #
- # Additionally, the code in ``update_on_device()`` would need to be changed
- # to pass the correct command line arguments to decrypt the file.
- )
- return BytesIO(ciphertext)
-
- def extract_key(self, content):
- """Extracts the public key from the openssl command output over REST
-
- The REST output includes some extra output that is not relevant to the
- public key. This function attempts to only return the valid public key
- data from the openssl output
-
- Args:
- content: The output from the REST API command to view the public key.
-
- Returns:
- string: The discovered public key
- """
-
- lines = content.split("\n")
- start = lines.index('-----BEGIN PUBLIC KEY-----')
- end = lines.index('-----END PUBLIC KEY-----')
- result = "\n".join(lines[start:end + 1])
- return result
-
- def update_on_device(self):
- errors = ['Bad password', 'password change canceled', 'based on a dictionary word']
-
- # Decrypting logic
- #
- # The following commented out command will **not** work on BIG-IP versions
- # utilizing OpenSSL 1.0.11-fips (15 Jan 2015).
- #
- # The reason is because that version of OpenSSL does not support the various
- # ``-pkeyopt`` parameters shown below.
- #
- # Nevertheless, I am including it here as a possible future enhancement in
- # case the method currently in use stops working.
- #
- # This command overrides defaults provided by OpenSSL because I am not
- # sure how long the defaults will remain the defaults. Probably as long
- # as it took OpenSSL to reach 1.0...
- #
- # openssl = [
- # 'openssl', 'pkeyutl', '-in', '/var/config/rest/downloads/{0}'.format(self.want.temp_upload_file),
- # '-decrypt', '-inkey', '/config/ssl/ssl.key/default.key',
- # '-pkeyopt', 'rsa_padding_mode:oaep', '-pkeyopt', 'rsa_oaep_md:sha256',
- # '-pkeyopt', 'rsa_mgf1_md:sha256'
- # ]
- #
- # The command we actually use is (while not recommended) also the only one
- # that works. It forgoes the usage of OAEP and uses the defaults that come
- # with OpenSSL (PKCS1v15)
- #
- # See this link for information on the parameters used
- #
- # https://www.openssl.org/docs/manmaster/man1/pkeyutl.html
- #
- # If you change the command below, you will need to additionally change
- # how the encryption is done in ``encrypt_password_change_file()``.
- #
- openssl = [
- 'openssl', 'pkeyutl', '-in', '/var/config/rest/downloads/{0}'.format(self.want.temp_upload_file),
- '-decrypt', '-inkey', '/config/ssl/ssl.key/default.key',
- ]
- cmd = '-c "{0} | tmsh modify auth password root"'.format(' '.join(openssl))
-
- params = dict(
- command='run',
- utilCmdArgs=cmd
- )
- uri = "https://{0}:{1}/mgmt/tm/util/bash".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- if 'commandResult' in response:
- if any(x for x in errors if x in response['commandResult']):
- raise F5ModuleError(response['commandResult'])
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return True
-
- def upload_to_device(self, content, name):
- """Uploads a file-like object via the REST API to a given filename
-
- Args:
- content: The file-like object whose content to upload
- name: The remote name of the file to store the content in. The
- final location of the file will be in /var/config/rest/downloads.
-
- Returns:
- void
- """
- url = 'https://{0}:{1}/mgmt/shared/file-transfer/uploads'.format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- try:
- upload_file(self.client, url, content, name)
- except F5ModuleError:
- raise F5ModuleError(
- "Failed to upload the file."
- )
-
- def remove_uploaded_file_from_device(self, name):
- filepath = '/var/config/rest/downloads/{0}'.format(name)
- params = {
- "command": "run",
- "utilCmdArgs": filepath
- }
- uri = "https://{0}:{1}/mgmt/tm/util/unix-rm".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def get_public_key_from_device(self):
- cmd = '-c "openssl rsa -in /config/ssl/ssl.key/default.key -pubout"'
-
- params = dict(
- command='run',
- utilCmdArgs=cmd
- )
- uri = "https://{0}:{1}/mgmt/tm/util/bash".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- if 'commandResult' in response:
- return response['commandResult']
- return None
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- username_credential=dict(
- required=True,
- aliases=['name']
- ),
- password_credential=dict(
- no_log=True,
- ),
- partition_access=dict(
- type='list'
- ),
- full_name=dict(),
- shell=dict(
- choices=['none', 'bash', 'tmsh']
- ),
- update_password=dict(
- default='always',
- choices=['always', 'on_create']
- ),
- state=dict(default='present', choices=['absent', 'present']),
- partition=dict(
- default='Common',
- fallback=(env_fallback, ['F5_PARTITION'])
- )
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_vcmp_guest.py b/lib/ansible/modules/network/f5/bigip_vcmp_guest.py
deleted file mode 100644
index 9aab8105df..0000000000
--- a/lib/ansible/modules/network/f5/bigip_vcmp_guest.py
+++ /dev/null
@@ -1,1017 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['stableinterface'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_vcmp_guest
-short_description: Manages vCMP guests on a BIG-IP
-description:
- - Manages vCMP guests on a BIG-IP. This functionality only exists on
- actual hardware and must be enabled by provisioning C(vcmp) with the
- C(bigip_provision) module.
-version_added: 2.5
-options:
- name:
- description:
- - The name of the vCMP guest to manage.
- type: str
- required: True
- vlans:
- description:
- - VLANs that the guest uses to communicate with other guests, the host, and with
- the external network. The available VLANs in the list are those that are
- currently configured on the vCMP host.
- - The order of these VLANs is not important; in fact, it's ignored. This module will
- order the VLANs for you automatically. Therefore, if you deliberately re-order them
- in subsequent tasks, you will find that this module will B(not) register a change.
- type: list
- initial_image:
- description:
- - Specifies the base software release ISO image file for installing the TMOS
- hypervisor instance and any licensed BIG-IP modules onto the guest's virtual
- disk. When creating a new guest, this parameter is required.
- type: str
- initial_hotfix:
- description:
- - Specifies the hotfix ISO image file which will be applied on top of the base
- image.
- type: str
- version_added: 2.9
- mgmt_network:
- description:
- - Specifies the method by which the management address is used in the vCMP guest.
- - When C(bridged), specifies that the guest can communicate with the vCMP host's
- management network.
- - When C(isolated), specifies that the guest is isolated from the vCMP host's
- management network. In this case, the only way that a guest can communicate
- with the vCMP host is through the console port or through a self IP address
- on the guest that allows traffic through port 22.
- - When C(host only), prevents the guest from installing images and hotfixes other
- than those provided by the hypervisor.
- - If the guest setting is C(isolated) or C(host only), the C(mgmt_address) does
- not apply.
- - Concerning mode changing, changing C(bridged) to C(isolated) causes the vCMP
- host to remove all of the guest's management interfaces from its bridged
- management network. This immediately disconnects the guest's VMs from the
- physical management network. Changing C(isolated) to C(bridged) causes the
- vCMP host to dynamically add the guest's management interfaces to the bridged
- management network. This immediately connects all of the guest's VMs to the
- physical management network. Changing this property while the guest is in the
- C(configured) or C(provisioned) state has no immediate effect.
- type: str
- choices:
- - bridged
- - isolated
- - host only
- delete_virtual_disk:
- description:
- - When C(state) is C(absent), will additionally delete the virtual disk associated
- with the vCMP guest. By default, this value is C(no).
- type: bool
- default: no
- mgmt_address:
- description:
- - Specifies the IP address, and subnet or subnet mask that you use to access
- the guest when you want to manage a module running within the guest. This
- parameter is required if the C(mgmt_network) parameter is C(bridged).
- - When creating a new guest, if you do not specify a network or network mask,
- a default of C(/24) (C(255.255.255.0)) will be assumed.
- type: str
- mgmt_route:
- description:
- - Specifies the gateway address for the C(mgmt_address).
- - If this value is not specified when creating a new guest, it is set to C(none).
- - The value C(none) can be used during an update to remove this value.
- type: str
- state:
- description:
- - The state of the vCMP guest on the system. Each state implies the actions of
- all states before it.
- - When C(configured), guarantees that the vCMP guest exists with the provided
- attributes. Additionally, ensures that the vCMP guest is turned off.
- - When C(disabled), behaves the same as C(configured) the name of this state
- is just a convenience for the user that is more understandable.
- - When C(provisioned), will ensure that the guest is created and installed.
- This state will not start the guest; use C(deployed) for that. This state
- is one step beyond C(present) as C(present) will not install the guest;
- only setup the configuration for it to be installed.
- - When C(present), ensures the guest is properly provisioned and starts
- the guest so that it is in a running state.
- - When C(absent), removes the vCMP from the system.
- type: str
- choices:
- - configured
- - disabled
- - provisioned
- - present
- - absent
- default: present
- cores_per_slot:
- description:
- - Specifies the number of cores that the system allocates to the guest.
- - Each core represents a portion of CPU and memory. Therefore, the amount of
- memory allocated per core is directly tied to the amount of CPU. This amount
- of memory varies per hardware platform type.
- - The number you can specify depends on the type of hardware you have.
- - In the event of a reboot, the system persists the guest to the same slot on
- which it ran prior to the reboot.
- type: int
- partition:
- description:
- - Device partition to manage resources on.
- type: str
- default: Common
- number_of_slots:
- description:
- - Specifies the number of slots for the system to use for creating the guest.
- - This value dictates how many cores a guest is allocated from each slot that
- it is assigned to.
- - Possible values are dependent on the type of blades being used in this cluster.
- - The default value depends on the type of blades being used in this cluster.
- type: int
- version_added: 2.7
- min_number_of_slots:
- description:
- - Specifies the minimum number of slots that the guest must be assigned to in
- order to deploy.
- - This field dictates the number of slots that the guest must be assigned to.
- - If at the end of any allocation attempt the guest is not assigned to at least
- this many slots, the attempt fails and the change that initiated it is reverted.
- - A guest's C(min_number_of_slots) value cannot be greater than its C(number_of_slots).
- type: int
- version_added: 2.7
- allowed_slots:
- description:
- - Contains those slots that the guest is allowed to be assigned to.
- - When the host determines which slots this guest should be assigned to, only slots
- in this list will be considered.
- - This is a good way to force guests to be assigned only to particular slots, or,
- by configuring disjoint C(allowed_slots) on two guests, that those guests are
- never assigned to the same slot.
- - By default this list includes every available slot in the cluster. This means,
- by default, the guest may be assigned to any slot.
- type: list
- version_added: 2.7
-notes:
- - This module can take a lot of time to deploy vCMP guests. This is an intrinsic
- limitation of the vCMP system because it is booting real VMs on the BIG-IP
- device. This boot time is very similar in length to the time it takes to
- boot VMs on any other virtualization platform; public or private.
- - When BIG-IP starts, the VMs are booted sequentially; not in parallel. This
- means that it is not unusual for a vCMP host with many guests to take a
- long time (60+ minutes) to reboot and bring all the guests online. The
- BIG-IP chassis will be available before all vCMP guests are online.
-extends_documentation_fragment: f5
-author:
- - Tim Rupp (@caphrim007)
- - Wojciech Wypior (@wojtek0806)
-'''
-
-EXAMPLES = r'''
-- name: Create a vCMP guest
- bigip_vcmp_guest:
- name: foo
- mgmt_network: bridge
- mgmt_address: 10.20.30.40/24
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-
-- name: Create a vCMP guest with specific VLANs
- bigip_vcmp_guest:
- name: foo
- mgmt_network: bridge
- mgmt_address: 10.20.30.40/24
- vlans:
- - vlan1
- - vlan2
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-
-- name: Remove vCMP guest and disk
- bigip_vcmp_guest:
- name: guest1
- state: absent
- delete_virtual_disk: yes
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- register: result
-'''
-
-RETURN = r'''
-vlans:
- description: The VLANs assigned to the vCMP guest, in their full path format.
- returned: changed
- type: list
- sample: ['/Common/vlan1', '/Common/vlan2']
-'''
-
-import time
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.basic import env_fallback
-from collections import namedtuple
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import fq_name
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.urls import parseStats
- from library.module_utils.network.f5.ipaddress import is_valid_ip
- from library.module_utils.compat.ipaddress import ip_interface
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import fq_name
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.urls import parseStats
- from ansible.module_utils.network.f5.ipaddress import is_valid_ip
- from ansible.module_utils.compat.ipaddress import ip_interface
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'managementGw': 'mgmt_route',
- 'managementNetwork': 'mgmt_network',
- 'managementIp': 'mgmt_address',
- 'initialImage': 'initial_image',
- 'initialHotfix': 'initial_hotfix',
- 'virtualDisk': 'virtual_disk',
- 'coresPerSlot': 'cores_per_slot',
- 'slots': 'number_of_slots',
- 'minSlots': 'min_number_of_slots',
- 'allowedSlots': 'allowed_slots',
- }
-
- api_attributes = [
- 'vlans',
- 'managementNetwork',
- 'managementIp',
- 'initialImage',
- 'initialHotfix',
- 'managementGw',
- 'state',
- 'coresPerSlot',
- 'slots',
- 'minSlots',
- 'allowedSlots',
- ]
-
- returnables = [
- 'vlans',
- 'mgmt_network',
- 'mgmt_address',
- 'initial_image',
- 'initial_hotfix',
- 'mgmt_route',
- 'name',
- 'cores_per_slot',
- 'number_of_slots',
- 'min_number_of_slots',
- 'allowed_slots',
- ]
-
- updatables = [
- 'vlans',
- 'mgmt_network',
- 'mgmt_address',
- 'initial_image',
- 'initial_hotfix',
- 'mgmt_route',
- 'state',
- 'cores_per_slot',
- 'number_of_slots',
- 'min_number_of_slots',
- 'allowed_slots',
- ]
-
-
-class ApiParameters(Parameters):
- pass
-
-
-class ModuleParameters(Parameters):
- @property
- def mgmt_route(self):
- if self._values['mgmt_route'] is None:
- return None
- elif self._values['mgmt_route'] == 'none':
- return 'none'
- if is_valid_ip(self._values['mgmt_route']):
- return self._values['mgmt_route']
- else:
- raise F5ModuleError(
- "The specified 'mgmt_route' is not a valid IP address."
- )
-
- @property
- def mgmt_address(self):
- if self._values['mgmt_address'] is None:
- return None
- try:
- addr = ip_interface(u'%s' % str(self._values['mgmt_address']))
- return str(addr.with_prefixlen)
- except ValueError:
- raise F5ModuleError(
- "The specified 'mgmt_address' is not a valid IP address."
- )
-
- @property
- def mgmt_tuple(self):
- Destination = namedtuple('Destination', ['ip', 'subnet'])
- try:
- parts = self._values['mgmt_address'].split('/')
- if len(parts) == 2:
- result = Destination(ip=parts[0], subnet=parts[1])
- elif len(parts) < 2:
- result = Destination(ip=parts[0], subnet=None)
- else:
- raise F5ModuleError(
- "The provided mgmt_address is malformed."
- )
- except ValueError:
- result = Destination(ip=None, subnet=None)
- return result
-
- @property
- def state(self):
- if self._values['state'] == 'present':
- return 'deployed'
- elif self._values['state'] in ['configured', 'disabled']:
- return 'configured'
- return self._values['state']
-
- @property
- def vlans(self):
- if self._values['vlans'] is None:
- return None
- result = [fq_name(self.partition, x) for x in self._values['vlans']]
- result.sort()
- return result
-
- @property
- def initial_image(self):
- if self._values['initial_image'] is None:
- return None
- if self.initial_image_exists(self._values['initial_image']):
- return self._values['initial_image']
- raise F5ModuleError(
- "The specified 'initial_image' does not exist on the remote device."
- )
-
- @property
- def initial_hotfix(self):
- if self._values['initial_hotfix'] is None:
- return None
- if self.initial_hotfix_exists(self._values['initial_hotfix']):
- return self._values['initial_hotfix']
- raise F5ModuleError(
- "The specified 'initial_hotfix' does not exist on the remote device."
- )
-
- def initial_image_exists(self, image):
- uri = "https://{0}:{1}/mgmt/tm/sys/software/image/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- for resource in response['items']:
- if resource['name'].startswith(image):
- return True
- return False
-
- def initial_hotfix_exists(self, hotfix):
- uri = "https://{0}:{1}/mgmt/tm/sys/software/hotfix/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- for resource in response['items']:
- if resource['name'].startswith(hotfix):
- return True
- return False
-
- @property
- def allowed_slots(self):
- if self._values['allowed_slots'] is None:
- return None
- result = self._values['allowed_slots']
- result.sort()
- return result
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- change = getattr(self, returnable)
- if isinstance(change, dict):
- result.update(change)
- else:
- result[returnable] = change
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class UsableChanges(Changes):
- pass
-
-
-class ReportableChanges(Changes):
- pass
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
- @property
- def mgmt_address(self):
- want = self.want.mgmt_tuple
- if want.subnet is None:
- raise F5ModuleError(
- "A subnet must be specified when changing the mgmt_address."
- )
- if self.want.mgmt_address != self.have.mgmt_address:
- return self.want.mgmt_address
-
- @property
- def allowed_slots(self):
- if self.want.allowed_slots is None:
- return None
- if self.have.allowed_slots is None:
- return self.want.allowed_slots
- if set(self.want.allowed_slots) != set(self.have.allowed_slots):
- return self.want.allowed_slots
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(client=self.client, params=self.module.params)
- self.have = None
- self.changes = ReportableChanges()
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = UsableChanges(params=changed)
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def exec_module(self):
- changed = False
- result = dict()
- state = self.want.state
-
- if state in ['configured', 'provisioned', 'deployed']:
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def present(self):
- if self.exists():
- return self.update()
- else:
- return self.create()
-
- def absent(self):
- if self.exists():
- return self.remove()
- return False
-
- def update(self):
- self.have = self.read_current_from_device()
- if not self.should_update():
- return False
- if self.module.check_mode:
- return True
- if self.changes.cores_per_slot:
- if not self.is_configured():
- self.configure()
- self.update_on_device()
- if self.want.state == 'provisioned':
- self.provision()
- elif self.want.state == 'deployed':
- self.deploy()
- elif self.want.state == 'configured':
- self.configure()
- return True
-
- def remove(self):
- if self.module.check_mode:
- return True
- if self.want.delete_virtual_disk:
- self.have = self.read_current_from_device()
- self.remove_from_device()
- if self.exists():
- raise F5ModuleError("Failed to delete the resource.")
- if self.want.delete_virtual_disk:
- self.remove_virtual_disk()
- return True
-
- def create(self):
- self._set_changed_options()
- if self.module.check_mode:
- return True
- if self.want.mgmt_tuple.subnet is None:
- self.want.update(dict(
- mgmt_address='{0}/255.255.255.0'.format(self.want.mgmt_tuple.ip)
- ))
- self.create_on_device()
- if self.want.state == 'provisioned':
- self.provision()
- elif self.want.state == 'deployed':
- self.deploy()
- elif self.want.state == 'configured':
- self.configure()
- return True
-
- def exists(self):
- uri = "https://{0}:{1}/mgmt/tm/vcmp/guest/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- self.want.name
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def create_on_device(self):
- params = self.changes.api_params()
- params['name'] = self.want.name
- uri = "https://{0}:{1}/mgmt/tm/vcmp/guest/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return response['selfLink']
-
- def update_on_device(self):
- params = self.changes.api_params()
- uri = "https://{0}:{1}/mgmt/tm/vcmp/guest/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- self.want.name
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def remove_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/vcmp/guest/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- self.want.name
- )
- response = self.client.api.delete(uri)
- if response.status == 200:
- return True
- raise F5ModuleError(response.content)
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/vcmp/guest/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- self.want.name
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return ApiParameters(params=response)
-
- def remove_virtual_disk(self):
- if self.virtual_disk_exists():
- return self.remove_virtual_disk_from_device()
- return False
-
- def get_virtual_disks_on_device(self):
- uri = "https://{0}:{1}/mgmt/tm/vcmp/virtual-disk/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- if 'items' in response:
- return response
-
- def virtual_disk_exists(self):
- """Checks if a virtual disk exists for a guest
-
- The virtual disk names can differ based on the device vCMP is installed on.
- For instance, on a shuttle-series device with no slots, you will see disks
- that resemble the following
-
- guest1.img
-
- On an 8-blade Viprion with slots though, you will see
-
- guest1.img/1
-
- The "/1" in this case is the slot that it is a part of. This method looks
- for the virtual-disk without the trailing slot.
-
- Returns:
- dict
- """
- response = self.get_virtual_disks_on_device()
- check = '{0}'.format(self.have.virtual_disk)
- for resource in response['items']:
- if resource['name'].startswith(check):
- return True
- else:
- return False
-
- def remove_virtual_disk_from_device(self):
- check = '{0}'.format(self.have.virtual_disk)
- response = self.get_virtual_disks_on_device()
- for resource in response['items']:
- if resource['name'].startswith(check):
- uri = "https://{0}:{1}/mgmt/tm/vcmp/virtual-disk/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- resource['name'].replace('/', '~')
- )
- response = self.client.api.delete(uri)
-
- if response.status == 200:
- continue
- else:
- raise F5ModuleError(response.content)
-
- return True
-
- def is_configured(self):
- """Checks to see if guest is disabled
-
- A disabled guest is fully disabled once their Stats go offline.
- Until that point they are still in the process of disabling.
-
- :return:
- """
- uri = "https://{0}:{1}/mgmt/tm/vcmp/guest/{2}/stats".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- self.want.name
- )
- resp = self.client.api.get(uri)
-
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return True
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- return False
-
- def is_provisioned(self):
- uri = "https://{0}:{1}/mgmt/tm/vcmp/guest/{2}/stats".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- self.want.name
- )
- resp = self.client.api.get(uri)
-
- try:
- response = resp.json()
- except ValueError:
- return False
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
-
- result = parseStats(response)
-
- if 'stats' in result:
- if result['stats']['requestedState'] == 'provisioned':
- if result['stats']['vmStatus'] == 'stopped':
- return True
- return False
-
- def is_deployed(self):
- uri = "https://{0}:{1}/mgmt/tm/vcmp/guest/{2}/stats".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- self.want.name
- )
- resp = self.client.api.get(uri)
-
- try:
- response = resp.json()
- except ValueError:
- return False
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
-
- result = parseStats(response)
-
- if 'stats' in result:
- if result['stats']['requestedState'] == 'deployed':
- if result['stats']['vmStatus'] == 'running':
- return True
- return False
-
- def configure(self):
- if self.is_configured():
- return False
- self.configure_on_device()
- self.wait_for_configured()
- return True
-
- def configure_on_device(self):
- params = dict(state='configured')
- uri = "https://{0}:{1}/mgmt/tm/vcmp/guest/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- self.want.name
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def wait_for_configured(self):
- nops = 0
- while nops < 3:
- if self.is_configured():
- nops += 1
- time.sleep(1)
-
- def provision(self):
- if self.is_provisioned():
- return False
- self.provision_on_device()
- self.wait_for_provisioned()
-
- def provision_on_device(self):
- params = dict(state='provisioned')
- uri = "https://{0}:{1}/mgmt/tm/vcmp/guest/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- self.want.name
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def wait_for_provisioned(self):
- nops = 0
- while nops < 3:
- if self.is_provisioned():
- nops += 1
- time.sleep(1)
-
- def deploy(self):
- if self.is_deployed():
- return False
- self.deploy_on_device()
- self.wait_for_deployed()
-
- def deploy_on_device(self):
- params = dict(state='deployed')
- uri = "https://{0}:{1}/mgmt/tm/vcmp/guest/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- self.want.name
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def wait_for_deployed(self):
- nops = 0
- while nops < 3:
- if self.is_deployed():
- nops += 1
- time.sleep(1)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- name=dict(required=True),
- vlans=dict(type='list'),
- mgmt_network=dict(choices=['bridged', 'isolated', 'host only']),
- mgmt_address=dict(),
- mgmt_route=dict(),
- initial_image=dict(),
- initial_hotfix=dict(),
- state=dict(
- default='present',
- choices=['configured', 'disabled', 'provisioned', 'absent', 'present']
- ),
- delete_virtual_disk=dict(
- type='bool',
- default='no'
- ),
- cores_per_slot=dict(type='int'),
- number_of_slots=dict(type='int'),
- min_number_of_slots=dict(type='int'),
- allowed_slots=dict(type='list'),
- partition=dict(
- default='Common',
- fallback=(env_fallback, ['F5_PARTITION'])
- )
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
- self.required_if = [
- ['mgmt_network', 'bridged', ['mgmt_address']]
- ]
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode,
- required_if=spec.required_if
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_virtual_address.py b/lib/ansible/modules/network/f5/bigip_virtual_address.py
deleted file mode 100644
index 08559b586c..0000000000
--- a/lib/ansible/modules/network/f5/bigip_virtual_address.py
+++ /dev/null
@@ -1,945 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_virtual_address
-short_description: Manage LTM virtual addresses on a BIG-IP
-description:
- - Manage LTM virtual addresses on a BIG-IP.
-version_added: 2.4
-options:
- name:
- description:
- - Name of the virtual address.
- - If this parameter is not provided, then the value of C(address) will
- be used.
- type: str
- version_added: 2.6
- address:
- description:
- - Virtual address. This value cannot be modified after it is set.
- - If you never created a virtual address, but did create virtual servers, then
- a virtual address for each virtual server was created automatically. The name
- of this virtual address is its IP address value.
- type: str
- netmask:
- description:
- - Netmask of the provided virtual address. This value cannot be
- modified after it is set.
- - When creating a new virtual address, if this parameter is not specified, the
- default value is C(255.255.255.255) for IPv4 addresses and
- C(ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff) for IPv6 addresses.
- type: str
- connection_limit:
- description:
- - Specifies the number of concurrent connections that the system
- allows on this virtual address.
- type: int
- arp_state:
- description:
- - Specifies whether the system accepts ARP requests. When (disabled),
- specifies that the system does not accept ARP requests. Note that
- both ARP and ICMP Echo must be disabled in order for forwarding
- virtual servers using that virtual address to forward ICMP packets.
- If (enabled), then the packets are dropped.
- - Deprecated. Use the C(arp) parameter instead.
- - When creating a new virtual address, if this parameter is not specified,
- the default value is C(enabled).
- type: str
- choices:
- - enabled
- - disabled
- arp:
- description:
- - Specifies whether the system accepts ARP requests.
- - When C(no), specifies that the system does not accept ARP requests.
- - When C(yes), then the packets are dropped.
- - Note that both ARP and ICMP Echo must be disabled in order for forwarding
- virtual servers using that virtual address to forward ICMP packets.
- - When creating a new virtual address, if this parameter is not specified,
- the default value is C(yes).
- type: bool
- version_added: 2.7
- auto_delete:
- description:
- - Specifies whether the system automatically deletes the virtual
- address with the deletion of the last associated virtual server.
- When C(disabled), specifies that the system leaves the virtual
- address even when all associated virtual servers have been deleted.
- When creating the virtual address, the default value is C(enabled).
- - C(enabled) and C(disabled) are deprecated and will be removed in
- Ansible 2.11. Instead, use known Ansible booleans such as C(yes) and
- C(no)
- type: str
- icmp_echo:
- description:
- - Specifies how the systems sends responses to (ICMP) echo requests
- on a per-virtual address basis for enabling route advertisement.
- When C(enabled), the BIG-IP system intercepts ICMP echo request
- packets and responds to them directly. When C(disabled), the BIG-IP
- system passes ICMP echo requests through to the backend servers.
- When (selective), causes the BIG-IP system to internally enable or
- disable responses based on virtual server state; C(when_any_available),
- C(when_all_available, or C(always), regardless of the state of any
- virtual servers.
- type: str
- choices:
- - enabled
- - disabled
- - selective
- state:
- description:
- - The virtual address state. If C(absent), an attempt to delete the
- virtual address will be made. This will only succeed if this
- virtual address is not in use by a virtual server. C(present) creates
- the virtual address and enables it. If C(enabled), enable the virtual
- address if it exists. If C(disabled), create the virtual address if
- needed, and set state to C(disabled).
- type: str
- choices:
- - present
- - absent
- - enabled
- - disabled
- default: present
- availability_calculation:
- description:
- - Specifies what routes of the virtual address the system advertises.
- When C(when_any_available), advertises the route when any virtual
- server is available. When C(when_all_available), advertises the
- route when all virtual servers are available. When (always), always
- advertises the route regardless of the virtual servers available.
- type: str
- choices:
- - always
- - when_all_available
- - when_any_available
- aliases: ['advertise_route']
- version_added: 2.6
- route_advertisement:
- description:
- - Specifies whether the system uses route advertisement for this
- virtual address.
- - When disabled, the system does not advertise routes for this virtual address.
- - The majority of these options are only supported on versions 13.0.0-HF1 or
- higher. On versions less than this, all choices expect C(disabled) will
- translate to C(enabled).
- - When C(always), the BIG-IP system will always advertise the route for the
- virtual address, regardless of availability status. This requires an C(enabled)
- virtual address.
- - When C(enabled), the BIG-IP system will advertise the route for the available
- virtual address, based on the calculation method in the availability calculation.
- - When C(disabled), the BIG-IP system will not advertise the route for the virtual
- address, regardless of the availability status.
- - When C(selective), you can also selectively enable ICMP echo responses, which
- causes the BIG-IP system to internally enable or disable responses based on
- virtual server state. Either C(any) virtual server, C(all) virtual servers, or
- C(always), regardless of the state of any virtual server.
- - When C(any), the BIG-IP system will advertise the route for the virtual address
- when any virtual server is available.
- - When C(all), the BIG-IP system will advertise the route for the virtual address
- when all virtual servers are available.
- type: str
- choices:
- - disabled
- - enabled
- - always
- - selective
- - any
- - all
- version_added: 2.6
- partition:
- description:
- - Device partition to manage resources on.
- type: str
- default: Common
- version_added: 2.5
- traffic_group:
- description:
- - The traffic group for the virtual address. When creating a new address,
- if this value is not specified, the default of C(/Common/traffic-group-1)
- will be used.
- type: str
- version_added: 2.5
- route_domain:
- description:
- - The route domain of the C(address) that you want to use.
- - This value cannot be modified after it is set.
- type: str
- version_added: 2.6
- spanning:
- description:
- - Enables all BIG-IP systems in a device group to listen for and process traffic
- on the same virtual address.
- - Spanning for a virtual address occurs when you enable the C(spanning) option on a
- device and then sync the virtual address to the other members of the device group.
- - Spanning also relies on the upstream router to distribute application flows to the
- BIG-IP systems using ECMP routes. ECMP defines a route to the virtual address using
- distinct Floating self-IP addresses configured on each BIG-IP system.
- - You must also configure MAC masquerade addresses and disable C(arp) on the virtual
- address when Spanning is enabled.
- - When creating a new virtual address, if this parameter is not specified, the default
- valus is C(no).
- version_added: 2.7
- type: bool
-extends_documentation_fragment: f5
-author:
- - Tim Rupp (@caphrim007)
- - Wojciech Wypior (@wojtek0806)
-'''
-
-EXAMPLES = r'''
-- name: Add virtual address
- bigip_virtual_address:
- state: present
- partition: Common
- address: 10.10.10.10
- provider:
- server: lb.mydomain.net
- user: admin
- password: secret
- delegate_to: localhost
-
-- name: Enable route advertisement on the virtual address
- bigip_virtual_address:
- state: present
- address: 10.10.10.10
- route_advertisement: any
- provider:
- server: lb.mydomain.net
- user: admin
- password: secret
- delegate_to: localhost
-'''
-
-RETURN = r'''
-availability_calculation:
- description: Specifies what routes of the virtual address the system advertises.
- returned: changed
- type: str
- sample: always
-auto_delete:
- description: New setting for auto deleting virtual address.
- returned: changed
- type: str
- sample: enabled
-icmp_echo:
- description: New ICMP echo setting applied to virtual address.
- returned: changed
- type: str
- sample: disabled
-connection_limit:
- description: The new connection limit of the virtual address.
- returned: changed
- type: int
- sample: 1000
-netmask:
- description: The netmask of the virtual address.
- returned: created
- type: int
- sample: 2345
-arp:
- description: The new way the virtual address handles ARP requests.
- returned: changed
- type: bool
- sample: yes
-address:
- description: The address of the virtual address.
- returned: created
- type: int
- sample: 2345
-state:
- description: The new state of the virtual address.
- returned: changed
- type: str
- sample: disabled
-spanning:
- description: Whether spanning is enabled or not
- returned: changed
- type: str
- sample: disabled
-'''
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.basic import env_fallback
-from ansible.module_utils.parsing.convert_bool import BOOLEANS_TRUE
-from ansible.module_utils.parsing.convert_bool import BOOLEANS_FALSE
-from distutils.version import LooseVersion
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import transform_name
- from library.module_utils.network.f5.common import fq_name
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.ipaddress import is_valid_ip
- from library.module_utils.network.f5.ipaddress import compress_address
- from library.module_utils.network.f5.icontrol import tmos_version
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import transform_name
- from ansible.module_utils.network.f5.common import fq_name
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.ipaddress import is_valid_ip
- from ansible.module_utils.network.f5.ipaddress import compress_address
- from ansible.module_utils.network.f5.icontrol import tmos_version
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'routeAdvertisement': 'route_advertisement_type',
- 'autoDelete': 'auto_delete',
- 'icmpEcho': 'icmp_echo',
- 'connectionLimit': 'connection_limit',
- 'serverScope': 'availability_calculation',
- 'mask': 'netmask',
- 'trafficGroup': 'traffic_group',
- }
-
- updatables = [
- 'route_advertisement_type',
- 'auto_delete',
- 'icmp_echo',
- 'connection_limit',
- 'arp',
- 'enabled',
- 'availability_calculation',
- 'traffic_group',
- 'spanning',
- ]
-
- returnables = [
- 'route_advertisement_type',
- 'auto_delete',
- 'icmp_echo',
- 'connection_limit',
- 'netmask',
- 'arp',
- 'address',
- 'state',
- 'traffic_group',
- 'route_domain',
- 'spanning',
- 'availability_calculation',
- ]
-
- api_attributes = [
- 'routeAdvertisement',
- 'autoDelete',
- 'icmpEcho',
- 'connectionLimit',
- 'advertiseRoute',
- 'arp',
- 'mask',
- 'enabled',
- 'serverScope',
- 'trafficGroup',
- 'spanning',
- 'serverScope',
- ]
-
- @property
- def availability_calculation(self):
- if self._values['availability_calculation'] is None:
- return None
- elif self._values['availability_calculation'] in ['any', 'when_any_available']:
- return 'any'
- elif self._values['availability_calculation'] in ['all', 'when_all_available']:
- return 'all'
- elif self._values['availability_calculation'] in ['none', 'always']:
- return 'none'
-
- @property
- def connection_limit(self):
- if self._values['connection_limit'] is None:
- return None
- return int(self._values['connection_limit'])
-
- @property
- def enabled(self):
- if self._values['state'] in ['enabled', 'present']:
- return 'yes'
- elif self._values['enabled'] in BOOLEANS_TRUE:
- return 'yes'
- elif self._values['state'] == 'disabled':
- return 'no'
- elif self._values['enabled'] in BOOLEANS_FALSE:
- return 'no'
- else:
- return None
-
- @property
- def netmask(self):
- if self._values['netmask'] is None:
- return None
- if is_valid_ip(self._values['netmask']):
- return self._values['netmask']
- else:
- raise F5ModuleError(
- "The provided 'netmask' is not a valid IP address"
- )
-
- @property
- def auto_delete(self):
- if self._values['auto_delete'] is None:
- return None
- elif self._values['auto_delete'] in BOOLEANS_TRUE:
- return True
- elif self._values['auto_delete'] == 'enabled':
- return True
- else:
- return False
-
- @property
- def state(self):
- if self.enabled == 'yes' and self._values['state'] != 'present':
- return 'enabled'
- elif self.enabled == 'no':
- return 'disabled'
- else:
- return self._values['state']
-
- @property
- def traffic_group(self):
- if self._values['traffic_group'] is None:
- return None
- else:
- result = fq_name(self.partition, self._values['traffic_group'])
- if result.startswith('/Common/'):
- return result
- else:
- raise F5ModuleError(
- "Traffic groups can only exist in /Common"
- )
-
- @property
- def route_advertisement_type(self):
- if self.route_advertisement:
- return self.route_advertisement
- else:
- return self._values['route_advertisement_type']
-
- @property
- def route_advertisement(self):
- if self._values['route_advertisement'] is None:
- return None
- version = tmos_version(self.client)
- if LooseVersion(version) <= LooseVersion('13.0.0'):
- if self._values['route_advertisement'] == 'disabled':
- return 'disabled'
- else:
- return 'enabled'
- else:
- return self._values['route_advertisement']
-
-
-class ApiParameters(Parameters):
- @property
- def arp(self):
- if self._values['arp'] is None:
- return None
- elif self._values['arp'] == 'enabled':
- return True
- return False
-
- @property
- def spanning(self):
- if self._values['spanning'] is None:
- return None
- if self._values['spanning'] == 'enabled':
- return True
- return False
-
-
-class ModuleParameters(Parameters):
- @property
- def arp(self):
- if self._values['arp'] is None:
- if self.arp_state and self.arp_state == 'enabled':
- return True
- elif self.arp_state and self.arp_state == 'disabled':
- return False
- else:
- return self._values['arp']
-
- @property
- def address(self):
- if self._values['address'] is None:
- return None
- if is_valid_ip(self._values['address']):
- return compress_address(self._values['address'])
- else:
- raise F5ModuleError(
- "The provided 'address' is not a valid IP address"
- )
-
- @property
- def full_address(self):
- if self.route_domain is not None:
- return '{0}%{1}'.format(self.address, self.route_domain)
- return self.address
-
- @property
- def name(self):
- if self._values['name'] is None:
- result = str(self.address)
- if self.route_domain:
- result = "{0}%{1}".format(result, self.route_domain)
- else:
- result = self._values['name']
- return result
-
- @property
- def route_domain(self):
- if self._values['route_domain'] is None:
- return None
- try:
- return int(self._values['route_domain'])
- except ValueError:
- uri = "https://{0}:{1}/mgmt/tm/net/route-domain/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self._values['partition'], self._values['route_domain'])
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- raise F5ModuleError(
- "The specified 'route_domain' was not found."
- )
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- raise F5ModuleError(
- "The specified 'route_domain' was not found."
- )
-
- return int(response['id'])
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class UsableChanges(Changes):
- @property
- def address(self):
- if self._values['address'] is None:
- return None
- if self._values['route_domain'] is None:
- return self._values['address']
- result = "{0}%{1}".format(self._values['address'], self.route_domain)
- return result
-
- @property
- def arp(self):
- if self._values['arp'] is None:
- return None
- elif self._values['arp'] is True:
- return 'enabled'
- elif self._values['arp'] is False:
- return 'disabled'
-
- @property
- def spanning(self):
- if self._values['spanning'] is None:
- return None
- if self._values['spanning']:
- return 'enabled'
- return 'disabled'
-
-
-class ReportableChanges(Changes):
- @property
- def arp(self):
- if self._values['arp'] == 'disabled':
- return 'no'
- elif self._values['arp'] == 'enabled':
- return 'yes'
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
- @property
- def traffic_group(self):
- if self.want.traffic_group != self.have.traffic_group:
- return self.want.traffic_group
-
- @property
- def spanning(self):
- if self.want.spanning is None:
- return None
- if self.want.spanning != self.have.spanning:
- return self.want.spanning
-
- @property
- def arp_state(self):
- if self.want.arp_state is None:
- return None
- if self.want.arp_state != self.have.arp_state:
- return self.want.arp_state
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.have = ApiParameters()
- self.want = ModuleParameters(client=self.client, params=self.module.params)
- self.changes = UsableChanges()
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = UsableChanges(params=changed)
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.client.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def exec_module(self):
- changed = False
- result = dict()
- state = self.want.state
-
- if state in ['present', 'enabled', 'disabled']:
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
-
- if self.module._diff and self.have:
- result['diff'] = self.make_diff()
-
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
-
- return result
-
- def _grab_attr(self, item):
- result = dict()
- updatables = Parameters.updatables
- for k in updatables:
- if getattr(item, k) is not None:
- result[k] = getattr(item, k)
- return result
-
- def make_diff(self):
- result = dict(before=self._grab_attr(self.have), after=self._grab_attr(self.want))
- return result
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def present(self):
- if self.exists():
- return self.update()
- else:
- return self.create()
-
- def absent(self):
- changed = False
- if self.exists():
- changed = self.remove()
- return changed
-
- def remove(self):
- if self.module.check_mode:
- return True
- self.remove_from_device()
- if self.exists():
- raise F5ModuleError("Failed to delete the virtual address")
- return True
-
- def create(self):
- self._set_changed_options()
-
- if self.want.traffic_group is None:
- self.want.update({'traffic_group': '/Common/traffic-group-1'})
- if self.want.arp is None:
- self.want.update({'arp': True})
- if self.want.spanning is None:
- self.want.update({'spanning': False})
-
- if self.want.netmask is None:
- if is_valid_ip(self.want.address, type='ipv4'):
- self.want.update({'netmask': '255.255.255.255'})
- else:
- self.want.update({'netmask': 'ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff'})
-
- if self.want.arp and self.want.spanning:
- raise F5ModuleError(
- "'arp' and 'spanning' cannot both be enabled on virtual address."
- )
- if self.module.check_mode:
- return True
- self.create_on_device()
- if self.exists():
- return True
- else:
- raise F5ModuleError("Failed to create the virtual address")
-
- def update(self):
- self.have = self.read_current_from_device()
- if self.want.netmask is not None:
- if self.have.netmask != self.want.netmask:
- raise F5ModuleError(
- "The netmask cannot be changed. Delete and recreate "
- "the virtual address if you need to do this."
- )
- if self.want.address is not None:
- if self.have.address != self.want.full_address:
- raise F5ModuleError(
- "The address cannot be changed. Delete and recreate "
- "the virtual address if you need to do this."
- )
- if self.changes.arp and self.changes.spanning:
- raise F5ModuleError(
- "'arp' and 'spanning' cannot both be enabled on virtual address."
- )
-
- if not self.should_update():
- return False
- if self.module.check_mode:
- return True
- self.update_on_device()
- return True
-
- def exists(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/virtual-address/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/virtual-address/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return ApiParameters(params=response)
-
- def update_on_device(self):
- params = self.changes.api_params()
- uri = "https://{0}:{1}/mgmt/tm/ltm/virtual-address/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def create_on_device(self):
- params = self.changes.api_params()
- params['name'] = self.want.name
- params['partition'] = self.want.partition
- params['address'] = self.changes.address
- uri = "https://{0}:{1}/mgmt/tm/ltm/virtual-address/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403, 409]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- return response['selfLink']
-
- def remove_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/virtual-address/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.delete(uri)
- if resp.status == 200:
- return True
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- state=dict(
- default='present',
- choices=['present', 'absent', 'disabled', 'enabled']
- ),
- name=dict(),
- address=dict(),
- netmask=dict(),
- connection_limit=dict(
- type='int'
- ),
-
- auto_delete=dict(),
- icmp_echo=dict(
- choices=['enabled', 'disabled', 'selective'],
- ),
- availability_calculation=dict(
- choices=['always', 'when_all_available', 'when_any_available'],
- aliases=['advertise_route']
- ),
- traffic_group=dict(),
- partition=dict(
- default='Common',
- fallback=(env_fallback, ['F5_PARTITION'])
- ),
- route_domain=dict(),
- spanning=dict(type='bool'),
- route_advertisement=dict(
- choices=[
- 'disabled',
- 'enabled',
- 'always',
- 'selective',
- 'any',
- 'all',
- ]
- ),
-
- # Deprecated pair - ARP
- arp_state=dict(
- choices=['enabled', 'disabled'],
- removed_in_version=2.11,
- ),
- arp=dict(type='bool'),
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
- self.required_one_of = [
- ['name', 'address']
- ]
- self.mutually_exclusive = [
- ['arp_state', 'arp']
- ]
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode,
- mutually_exclusive=spec.mutually_exclusive,
- required_one_of=spec.required_one_of
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_virtual_server.py b/lib/ansible/modules/network/f5/bigip_virtual_server.py
deleted file mode 100644
index 2876bf4c79..0000000000
--- a/lib/ansible/modules/network/f5/bigip_virtual_server.py
+++ /dev/null
@@ -1,3665 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_virtual_server
-short_description: Manage LTM virtual servers on a BIG-IP
-description:
- - Manage LTM virtual servers on a BIG-IP.
-version_added: 2.1
-options:
- state:
- description:
- - The virtual server state. If C(absent), delete the virtual server
- if it exists. C(present) creates the virtual server and enable it.
- If C(enabled), enable the virtual server if it exists. If C(disabled),
- create the virtual server if needed, and set state to C(disabled).
- type: str
- choices:
- - present
- - absent
- - enabled
- - disabled
- default: present
- type:
- description:
- - Specifies the network service provided by this virtual server.
- - When creating a new virtual server, if this parameter is not provided, the
- default will be C(standard).
- - This value cannot be changed after it is set.
- - When C(standard), specifies a virtual server that directs client traffic to
- a load balancing pool and is the most basic type of virtual server. When you
- first create the virtual server, you assign an existing default pool to it.
- From then on, the virtual server automatically directs traffic to that default pool.
- - When C(forwarding-l2), specifies a virtual server that shares the same IP address as a
- node in an associated VLAN.
- - When C(forwarding-ip), specifies a virtual server like other virtual servers, except
- that the virtual server has no pool members to load balance. The virtual server simply
- forwards the packet directly to the destination IP address specified in the client request.
- - When C(performance-http), specifies a virtual server with which you associate a Fast HTTP
- profile. Together, the virtual server and profile increase the speed at which the virtual
- server processes HTTP requests.
- - When C(performance-l4), specifies a virtual server with which you associate a Fast L4 profile.
- Together, the virtual server and profile increase the speed at which the virtual server
- processes layer 4 requests.
- - When C(stateless), specifies a virtual server that accepts traffic matching the virtual
- server address and load balances the packet to the pool members without attempting to
- match the packet to a pre-existing connection in the connection table. New connections
- are immediately removed from the connection table. This addresses the requirement for
- one-way UDP traffic that needs to be processed at very high throughput levels, for example,
- load balancing syslog traffic to a pool of syslog servers. Stateless virtual servers are
- not suitable for processing traffic that requires stateful tracking, such as TCP traffic.
- Stateless virtual servers do not support iRules, persistence, connection mirroring,
- rateshaping, or SNAT automap.
- - When C(reject), specifies that the BIG-IP system rejects any traffic destined for the
- virtual server IP address.
- - When C(dhcp), specifies a virtual server that relays Dynamic Host Control Protocol (DHCP)
- client requests for an IP address to one or more DHCP servers, and provides DHCP server
- responses with an available IP address for the client.
- - When C(internal), specifies a virtual server that supports modification of HTTP requests
- and responses. Internal virtual servers enable usage of ICAP (Internet Content Adaptation
- Protocol) servers to modify HTTP requests and responses by creating and applying an ICAP
- profile and adding Request Adapt or Response Adapt profiles to the virtual server.
- - When C(message-routing), specifies a virtual server that uses a SIP application protocol
- and functions in accordance with a SIP session profile and SIP router profile.
- type: str
- choices:
- - standard
- - forwarding-l2
- - forwarding-ip
- - performance-http
- - performance-l4
- - stateless
- - reject
- - dhcp
- - internal
- - message-routing
- default: standard
- version_added: 2.6
- name:
- description:
- - Virtual server name.
- type: str
- required: True
- aliases:
- - vs
- destination:
- description:
- - Destination IP of the virtual server.
- - Required when C(state) is C(present) and virtual server does not exist.
- - When C(type) is C(internal), this parameter is ignored. For all other types,
- it is required.
- - Destination can also be specified as a name for an existing Virtual Address.
- type: str
- aliases:
- - address
- - ip
- source:
- description:
- - Specifies an IP address or network from which the virtual server accepts traffic.
- - The virtual server accepts clients only from one of these IP addresses.
- - For this setting to function effectively, specify a value other than 0.0.0.0/0 or ::/0
- (that is, any/0, any6/0).
- - In order to maximize utility of this setting, specify the most specific address
- prefixes covering all customer addresses and no others.
- - Specify the IP address in Classless Inter-Domain Routing (CIDR) format; address/prefix,
- where the prefix length is in bits. For example, for IPv4, 10.0.0.1/32 or 10.0.0.0/24,
- and for IPv6, ffe1::0020/64 or 2001:ed8:77b5:2:10:10:100:42/64.
- type: str
- version_added: 2.5
- port:
- description:
- - Port of the virtual server. Required when C(state) is C(present)
- and virtual server does not exist.
- - If you do not want to specify a particular port, use the value C(0).
- The result is that the virtual server will listen on any port.
- - When C(type) is C(dhcp), this module will force the C(port) parameter to be C(67).
- - When C(type) is C(internal), this module will force the C(port) parameter to be C(0).
- - In addition to specifying a port number, a select number of service names may also
- be provided.
- - The string C(ftp) may be substituted for for port C(21).
- - The string C(http) may be substituted for for port C(80).
- - The string C(https) may be substituted for for port C(443).
- - The string C(telnet) may be substituted for for port C(23).
- - The string C(smtp) may be substituted for for port C(25).
- - The string C(snmp) may be substituted for for port C(161).
- - The string C(snmp-trap) may be substituted for for port C(162).
- - The string C(ssh) may be substituted for for port C(22).
- - The string C(tftp) may be substituted for for port C(69).
- - The string C(isakmp) may be substituted for for port C(500).
- - The string C(mqtt) may be substituted for for port C(1883).
- - The string C(mqtt-tls) may be substituted for for port C(8883).
- type: str
- profiles:
- description:
- - List of profiles (HTTP, ClientSSL, ServerSSL, etc) to apply to both sides
- of the connection (client-side and server-side).
- - If you only want to apply a particular profile to the client-side of
- the connection, specify C(client-side) for the profile's C(context).
- - If you only want to apply a particular profile to the server-side of
- the connection, specify C(server-side) for the profile's C(context).
- - If C(context) is not provided, it will default to C(all).
- - If you want to remove a profile from the list of profiles currently active
- on the virtual, then simply remove it from the C(profiles) list. See
- examples for an illustration of this.
- - If you want to add a profile to the list of profiles currently active
- on the virtual, then simply add it to the C(profiles) list. See
- examples for an illustration of this.
- - B(Profiles matter). This module will fail to configure a BIG-IP if you mix up
- your profiles, or, if you attempt to set an IP protocol which your current,
- or new, profiles do not support. Both this module, and BIG-IP, will tell you
- when you are wrong, with an error resembling C(lists profiles incompatible
- with its protocol).
- - If you are unsure what correct profile combinations are, then have a BIG-IP
- available to you in which you can make changes and copy what the correct
- combinations are.
- suboptions:
- name:
- description:
- - Name of the profile.
- - If this is not specified, then it is assumed that the profile item is
- only a name of a profile.
- - This must be specified if a context is specified.
- type: str
- context:
- description:
- - The side of the connection on which the profile should be applied.
- type: str
- choices:
- - all
- - server-side
- - client-side
- default: all
- type: list
- aliases:
- - all_profiles
- irules:
- version_added: 2.2
- description:
- - List of rules to be applied in priority order.
- - If you want to remove existing iRules, specify a single empty value; C("").
- See the documentation for an example.
- - When C(type) is C(dhcp), this parameter will be ignored.
- - When C(type) is C(stateless), this parameter will be ignored.
- - When C(type) is C(reject), this parameter will be ignored.
- - When C(type) is C(internal), this parameter will be ignored.
- type: list
- aliases:
- - all_rules
- enabled_vlans:
- description:
- - List of VLANs to be enabled. When a VLAN named C(all) is used, all
- VLANs will be allowed. VLANs can be specified with or without the
- leading partition. If the partition is not specified in the VLAN,
- then the C(partition) option of this module will be used.
- - This parameter is mutually exclusive with the C(disabled_vlans) parameter.
- type: list
- version_added: 2.2
- disabled_vlans:
- description:
- - List of VLANs to be disabled. If the partition is not specified in the VLAN,
- then the C(partition) option of this module will be used.
- - This parameter is mutually exclusive with the C(enabled_vlans) parameters.
- type: list
- version_added: 2.5
- pool:
- description:
- - Default pool for the virtual server.
- - If you want to remove the existing pool, specify an empty value; C("").
- See the documentation for an example.
- - When creating a new virtual server, and C(type) is C(stateless), this parameter
- is required.
- - If C(type) is C(stateless), the C(pool) that is used must not have any members
- which define a C(rate_limit).
- type: str
- policies:
- description:
- - Specifies the policies for the virtual server.
- - When C(type) is C(dhcp), this parameter will be ignored.
- - When C(type) is C(reject), this parameter will be ignored.
- - When C(type) is C(internal), this parameter will be ignored.
- type: list
- aliases:
- - all_policies
- snat:
- description:
- - Source network address policy.
- - When C(type) is C(dhcp), this parameter is ignored.
- - When C(type) is C(reject), this parameter will be ignored.
- - When C(type) is C(internal), this parameter will be ignored.
- - The name of a SNAT pool (eg "/Common/snat_pool_name") can be specified to enable SNAT
- with the specific pool.
- - To remove SNAT, specify the word C(none).
- - To specify automap, use the word C(automap).
- type: str
- default_persistence_profile:
- description:
- - Default Profile which manages the session persistence.
- - If you want to remove the existing default persistence profile, specify an
- empty value; C(""). See the documentation for an example.
- - When C(type) is C(dhcp), this parameter will be ignored.
- type: str
- description:
- description:
- - Virtual server description.
- type: str
- fallback_persistence_profile:
- description:
- - Specifies the persistence profile you want the system to use if it
- cannot use the specified default persistence profile.
- - If you want to remove the existing fallback persistence profile, specify an
- empty value; C(""). See the documentation for an example.
- - When C(type) is C(dhcp), this parameter will be ignored.
- type: str
- version_added: 2.3
- partition:
- description:
- - Device partition to manage resources on.
- type: str
- default: Common
- version_added: 2.5
- metadata:
- description:
- - Arbitrary key/value pairs that you can attach to a virtual server. This is useful in
- situations where you might want to annotate a virtual to be managed by Ansible.
- - Key names will be stored as strings; this includes names that are numbers.
- - Values for all of the keys will be stored as strings; this includes values
- that are numbers.
- - Data will be persisted, not ephemeral.
- type: raw
- version_added: 2.5
- insert_metadata:
- description:
- - When set to C(no) it will not set metadata on the device.
- - Currently there is a limitation that non-admin users cannot set metadata on the object, despite being
- able to create and modify virtual server objects, setting this option to C(no) will allow
- such users to utilize this module to manage Virtual Server objects on the device.
- type: bool
- default: yes
- version_added: 2.8
- address_translation:
- description:
- - Specifies, when C(enabled), that the system translates the address of the
- virtual server.
- - When C(disabled), specifies that the system uses the address without translation.
- - This option is useful when the system is load balancing devices that have the
- same IP address.
- - When creating a new virtual server, the default is C(enabled).
- type: bool
- version_added: 2.6
- port_translation:
- description:
- - Specifies, when C(enabled), that the system translates the port of the virtual
- server.
- - When C(disabled), specifies that the system uses the port without translation.
- Turning off port translation for a virtual server is useful if you want to use
- the virtual server to load balance connections to any service.
- - When creating a new virtual server, the default is C(enabled).
- type: bool
- version_added: 2.6
- source_port:
- description:
- - Specifies whether the system preserves the source port of the connection.
- - When creating a new virtual server, if this parameter is not specified, the default is C(preserve).
- type: str
- choices:
- - preserve
- - preserve-strict
- - change
- version_added: 2.8
- mirror:
- description:
- - Specifies that the system mirrors connections on each member of a redundant pair.
- - When creating a new virtual server, if this parameter is not specified, the default is C(disabled).
- type: bool
- version_added: 2.8
- mask:
- description:
- - Specifies the destination address network mask. This parameter will work with IPv4 and IPv6 type of addresses.
- - This is an optional parameter which can be specified when creating or updating virtual server.
- - If C(destination) is set in CIDR notation format and C(mask) is provided the C(mask) parameter takes precedence.
- - If catchall destination is specified, i.e. C(0.0.0.0) for IPv4 C(::) for IPv6,
- mask parameter is set to C(any) or C(any6) respectively.
- - When the C(destination) is provided not in CIDR notation and C(mask) is not specified, C(255.255.255.255) or
- C(ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff) is set for IPv4 and IPv6 addresses respectively.
- - When C(destination) is provided in CIDR notation format and C(mask) is not specified the mask parameter is
- inferred from C(destination).
- - When C(destination) is provided as Virtual Address name, and C(mask) is not specified,
- the mask will be C(None) allowing device set it with its internal defaults.
- type: str
- version_added: 2.8
- ip_protocol:
- description:
- - Specifies a network protocol name you want the system to use to direct traffic
- on this virtual server.
- - When creating a new virtual server, if this parameter is not specified, the default is C(tcp).
- - The Protocol setting is not available when you select Performance (HTTP) as the Type.
- - The value of this argument can be specified in either it's numeric value, or,
- for convenience, in a select number of named values. Refer to C(choices) for examples.
- - For a list of valid IP protocol numbers, refer to this page
- https://en.wikipedia.org/wiki/List_of_IP_protocol_numbers
- - When C(type) is C(dhcp), this module will force the C(ip_protocol) parameter to be C(17) (UDP).
- type: str
- choices:
- - ah
- - any
- - bna
- - esp
- - etherip
- - gre
- - icmp
- - ipencap
- - ipv6
- - ipv6-auth
- - ipv6-crypt
- - ipv6-icmp
- - isp-ip
- - mux
- - ospf
- - sctp
- - tcp
- - udp
- - udplite
- version_added: 2.6
- firewall_enforced_policy:
- description:
- - Applies the specify AFM policy to the virtual in an enforcing way.
- - When creating a new virtual, if this parameter is not specified, the enforced
- policy is disabled.
- type: str
- version_added: 2.6
- firewall_staged_policy:
- description:
- - Applies the specify AFM policy to the virtual in an enforcing way.
- - A staged policy shows the results of the policy rules in the log, while not
- actually applying the rules to traffic.
- - When creating a new virtual, if this parameter is not specified, the staged
- policy is disabled.
- type: str
- version_added: 2.6
- security_log_profiles:
- description:
- - Specifies the log profile applied to the virtual server.
- - To make use of this feature, the AFM module must be licensed and provisioned.
- - The C(Log all requests) and C(Log illegal requests) are mutually exclusive and
- therefore, this module will raise an error if the two are specified together.
- type: list
- version_added: 2.6
- security_nat_policy:
- description:
- - Specify the Firewall NAT policies for the virtual server.
- - You can specify one or more NAT policies to use.
- - The most specific policy is used. For example, if you specify that the
- virtual server use the device policy and the route domain policy, the route
- domain policy overrides the device policy.
- version_added: 2.7
- suboptions:
- policy:
- description:
- - Policy to apply a NAT policy directly to the virtual server.
- - The virtual server NAT policy is the most specific, and overrides a
- route domain and device policy, if specified.
- - To remove the policy, specify an empty string value.
- type: str
- use_device_policy:
- description:
- - Specify that the virtual server uses the device NAT policy, as specified
- in the Firewall Options.
- - The device policy is used if no route domain or virtual server NAT
- setting is specified.
- type: bool
- use_route_domain_policy:
- description:
- - Specify that the virtual server uses the route domain policy, as
- specified in the Route Domain Security settings.
- - When specified, the route domain policy overrides the device policy, and
- is overridden by a virtual server policy.
- type: bool
- type: dict
- ip_intelligence_policy:
- description:
- - Specifies the IP intelligence policy applied to the virtual server.
- - This parameter requires that a valid BIG-IP security module such as ASM or AFM
- be provisioned.
- type: str
- version_added: 2.8
- rate_limit:
- description:
- - Virtual server rate limit (connections-per-second). Setting this to 0
- disables the limit.
- - The valid value range is C(0) - C(4294967295).
- type: int
- version_added: 2.8
- rate_limit_dst_mask:
- description:
- - Specifies a mask, in bits, to be applied to the destination address as part of the rate limiting.
- - The default value is C(0), which is equivalent to using the entire address - C(32) in IPv4, or C(128) in IPv6.
- - The valid value range is C(0) - C(4294967295).
- type: int
- version_added: 2.8
- rate_limit_src_mask:
- description:
- - Specifies a mask, in bits, to be applied to the source address as part of the rate limiting.
- - The default value is C(0), which is equivalent to using the entire address - C(32) in IPv4, or C(128) in IPv6.
- - The valid value range is C(0) - C(4294967295).
- type: int
- version_added: 2.8
- rate_limit_mode:
- description:
- - Indicates whether the rate limit is applied per virtual object, per source address, per destination address,
- or some combination thereof.
- - The default value is 'object', which does not use the source or destination address as part of the key.
- type: str
- choices:
- - object
- - object-source
- - object-destination
- - object-source-destination
- - destination
- - source
- - source-destination
- default: object
- version_added: 2.8
- clone_pools:
- description:
- - Specifies a pool or list of pools that the virtual server uses to replicate either client-side
- or server-side traffic.
- - Typically this option is used for intrusion detection.
- suboptions:
- pool_name:
- description:
- - The pool name to which the server replicates the traffic.
- - Only pools created on Common partition or on the same partition as the virtual server can be used.
- - Referencing pool on common partition needs to be done in the full path format,
- for example, C(/Common/pool_name).
- type: str
- required: True
- context:
- description:
- - The context option for a clone pool to replicate either client-side or server-side traffic.
- type: str
- choices:
- - clientside
- - serverside
- type: list
- version_added: 2.8
-extends_documentation_fragment: f5
-author:
- - Tim Rupp (@caphrim007)
- - Wojciech Wypior (@wojtek0806)
-'''
-
-EXAMPLES = r'''
-- name: Modify Port of the Virtual Server
- bigip_virtual_server:
- state: present
- partition: Common
- name: my-virtual-server
- port: 8080
- provider:
- server: lb.mydomain.net
- user: admin
- password: secret
- delegate_to: localhost
-
-- name: Delete virtual server
- bigip_virtual_server:
- state: absent
- partition: Common
- name: my-virtual-server
- provider:
- server: lb.mydomain.net
- user: admin
- password: secret
- delegate_to: localhost
-
-- name: Add virtual server
- bigip_virtual_server:
- state: present
- partition: Common
- name: my-virtual-server
- destination: 10.10.10.10
- port: 443
- pool: my-pool
- snat: Automap
- description: Test Virtual Server
- profiles:
- - http
- - fix
- - name: clientssl
- context: server-side
- - name: ilx
- context: client-side
- policies:
- - my-ltm-policy-for-asm
- - ltm-uri-policy
- - ltm-policy-2
- - ltm-policy-3
- enabled_vlans:
- - /Common/vlan2
- provider:
- server: lb.mydomain.net
- user: admin
- password: secret
- delegate_to: localhost
-
-- name: Add FastL4 virtual server
- bigip_virtual_server:
- destination: 1.1.1.1
- name: fastl4_vs
- port: 80
- profiles:
- - fastL4
- state: present
- provider:
- server: lb.mydomain.net
- user: admin
- password: secret
- delegate_to: localhost
-
-- name: Add iRules to the Virtual Server
- bigip_virtual_server:
- name: my-virtual-server
- irules:
- - irule1
- - irule2
- provider:
- server: lb.mydomain.net
- user: admin
- password: secret
- delegate_to: localhost
-
-- name: Remove one iRule from the Virtual Server
- bigip_virtual_server:
- name: my-virtual-server
- irules:
- - irule2
- provider:
- server: lb.mydomain.net
- user: admin
- password: secret
- delegate_to: localhost
-
-- name: Remove all iRules from the Virtual Server
- bigip_virtual_server:
- name: my-virtual-server
- irules: ""
- provider:
- server: lb.mydomain.net
- user: admin
- password: secret
- delegate_to: localhost
-
-- name: Remove pool from the Virtual Server
- bigip_virtual_server:
- name: my-virtual-server
- pool: ""
- provider:
- server: lb.mydomain.net
- user: admin
- password: secret
- delegate_to: localhost
-
-- name: Add metadata to virtual
- bigip_pool:
- state: absent
- name: my-pool
- partition: Common
- metadata:
- ansible: 2.4
- updated_at: 2017-12-20T17:50:46Z
- provider:
- server: lb.mydomain.com
- user: admin
- password: secret
- delegate_to: localhost
-
-- name: Add virtual with two profiles
- bigip_pool:
- state: absent
- name: my-pool
- partition: Common
- profiles:
- - http
- - tcp
- provider:
- server: lb.mydomain.com
- user: admin
- password: secret
- delegate_to: localhost
-
-- name: Remove HTTP profile from previous virtual
- bigip_pool:
- state: absent
- name: my-pool
- partition: Common
- profiles:
- - tcp
- provider:
- server: lb.mydomain.com
- user: admin
- password: secret
- delegate_to: localhost
-
-- name: Add the HTTP profile back to the previous virtual
- bigip_pool:
- state: absent
- name: my-pool
- partition: Common
- profiles:
- - http
- - tcp
- provider:
- server: lb.mydomain.com
- user: admin
- password: secret
- delegate_to: localhost
-
-- name: Add virtual server with rate limit
- bigip_virtual_server:
- state: present
- partition: Common
- name: my-virtual-server
- destination: 10.10.10.10
- port: 443
- pool: my-pool
- snat: Automap
- description: Test Virtual Server
- profiles:
- - http
- - fix
- - name: clientssl
- context: server-side
- - name: ilx
- context: client-side
- policies:
- - my-ltm-policy-for-asm
- - ltm-uri-policy
- - ltm-policy-2
- - ltm-policy-3
- enabled_vlans:
- - /Common/vlan2
- rate_limit: 400
- rate_limit_mode: destination
- rate_limit_dst_mask: 32
- provider:
- server: lb.mydomain.net
- user: admin
- password: secret
- delegate_to: localhost
-
-- name: Add FastL4 virtual server with clone_pools
- bigip_virtual_server:
- destination: 1.1.1.1
- name: fastl4_vs
- port: 80
- profiles:
- - fastL4
- state: present
- clone_pools:
- - pool_name: FooPool
- context: clientside
- provider:
- server: lb.mydomain.net
- user: admin
- password: secret
- delegate_to: localhost
-'''
-
-RETURN = r'''
-description:
- description: New description of the virtual server.
- returned: changed
- type: str
- sample: This is my description
-default_persistence_profile:
- description: Default persistence profile set on the virtual server.
- returned: changed
- type: str
- sample: /Common/dest_addr
-destination:
- description: Destination of the virtual server.
- returned: changed
- type: str
- sample: 1.1.1.1
-disabled:
- description: Whether the virtual server is disabled, or not.
- returned: changed
- type: bool
- sample: True
-disabled_vlans:
- description: List of VLANs that the virtual is disabled for.
- returned: changed
- type: list
- sample: ['/Common/vlan1', '/Common/vlan2']
-enabled:
- description: Whether the virtual server is enabled, or not.
- returned: changed
- type: bool
- sample: False
-enabled_vlans:
- description: List of VLANs that the virtual is enabled for.
- returned: changed
- type: list
- sample: ['/Common/vlan5', '/Common/vlan6']
-fallback_persistence_profile:
- description: Fallback persistence profile set on the virtual server.
- returned: changed
- type: str
- sample: /Common/source_addr
-irules:
- description: iRules set on the virtual server.
- returned: changed
- type: list
- sample: ['/Common/irule1', '/Common/irule2']
-pool:
- description: Pool that the virtual server is attached to.
- returned: changed
- type: str
- sample: /Common/my-pool
-policies:
- description: List of policies attached to the virtual.
- returned: changed
- type: list
- sample: ['/Common/policy1', '/Common/policy2']
-port:
- description: Port that the virtual server is configured to listen on.
- returned: changed
- type: int
- sample: 80
-profiles:
- description: List of profiles set on the virtual server.
- returned: changed
- type: list
- sample: [{'name': 'tcp', 'context': 'server-side'}, {'name': 'tcp-legacy', 'context': 'client-side'}]
-snat:
- description: SNAT setting of the virtual server.
- returned: changed
- type: str
- sample: Automap
-source:
- description: Source address, in CIDR form, set on the virtual server.
- returned: changed
- type: str
- sample: 1.2.3.4/32
-metadata:
- description: The new value of the virtual.
- returned: changed
- type: dict
- sample: {'key1': 'foo', 'key2': 'bar'}
-address_translation:
- description: The new value specifying whether address translation is on or off.
- returned: changed
- type: bool
- sample: True
-port_translation:
- description: The new value specifying whether port translation is on or off.
- returned: changed
- type: bool
- sample: True
-source_port:
- description: Specifies whether the system preserves the source port of the connection.
- returned: changed
- type: str
- sample: change
-mirror:
- description: Specifies that the system mirrors connections on each member of a redundant pair.
- returned: changed
- type: bool
- sample: True
-ip_protocol:
- description: The new value of the IP protocol.
- returned: changed
- type: int
- sample: 6
-firewall_enforced_policy:
- description: The new enforcing firewall policy.
- returned: changed
- type: str
- sample: /Common/my-enforced-fw
-firewall_staged_policy:
- description: The new staging firewall policy.
- returned: changed
- type: str
- sample: /Common/my-staged-fw
-security_log_profiles:
- description: The new list of security log profiles.
- returned: changed
- type: list
- sample: ['/Common/profile1', '/Common/profile2']
-ip_intelligence_policy:
- description: The new IP Intelligence Policy assigned to the virtual.
- returned: changed
- type: str
- sample: /Common/ip-intelligence
-rate_limit:
- description: The maximum number of connections per second allowed for a virtual server.
- returned: changed
- type: int
- sample: 5000
-rate_limit_src_mask:
- description: Specifies a mask, in bits, to be applied to the source address as part of the rate limiting.
- returned: changed
- type: int
- sample: 32
-rate_limit_dst_mask:
- description: Specifies a mask, in bits, to be applied to the destination address as part of the rate limiting.
- returned: changed
- type: int
- sample: 32
-rate_limit_mode:
- description: Sets the type of rate limiting to be used on the virtual server.
- returned: changed
- type: str
- sample: object-source
-clone_pools:
- description: Pools to which virtual server copies traffic.
- returned: changed
- type: list
- sample: [{'pool_name':'/Common/Pool1', 'context': 'clientside'}]
-'''
-import os
-import re
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.basic import env_fallback
-from ansible.module_utils.six import iteritems
-from collections import namedtuple
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import MANAGED_BY_ANNOTATION_VERSION
- from library.module_utils.network.f5.common import MANAGED_BY_ANNOTATION_MODIFIED
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import fq_name
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.common import transform_name
- from library.module_utils.network.f5.common import mark_managed_by
- from library.module_utils.network.f5.common import only_has_managed_metadata
- from library.module_utils.network.f5.common import flatten_boolean
- from library.module_utils.network.f5.compare import cmp_simple_list
- from library.module_utils.network.f5.ipaddress import is_valid_ip
- from library.module_utils.network.f5.ipaddress import is_valid_ip_interface
- from library.module_utils.network.f5.ipaddress import ip_interface
- from library.module_utils.network.f5.ipaddress import validate_ip_v6_address
- from library.module_utils.network.f5.ipaddress import get_netmask
- from library.module_utils.network.f5.ipaddress import compress_address
- from library.module_utils.network.f5.icontrol import modules_provisioned
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import MANAGED_BY_ANNOTATION_VERSION
- from ansible.module_utils.network.f5.common import MANAGED_BY_ANNOTATION_MODIFIED
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import fq_name
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.common import transform_name
- from ansible.module_utils.network.f5.common import mark_managed_by
- from ansible.module_utils.network.f5.common import only_has_managed_metadata
- from ansible.module_utils.network.f5.common import flatten_boolean
- from ansible.module_utils.network.f5.compare import cmp_simple_list
- from ansible.module_utils.network.f5.ipaddress import is_valid_ip
- from ansible.module_utils.network.f5.ipaddress import is_valid_ip_interface
- from ansible.module_utils.network.f5.ipaddress import ip_interface
- from ansible.module_utils.network.f5.ipaddress import validate_ip_v6_address
- from ansible.module_utils.network.f5.ipaddress import get_netmask
- from ansible.module_utils.network.f5.ipaddress import compress_address
- from ansible.module_utils.network.f5.icontrol import modules_provisioned
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'sourceAddressTranslation': 'snat',
- 'fallbackPersistence': 'fallback_persistence_profile',
- 'persist': 'default_persistence_profile',
- 'vlansEnabled': 'vlans_enabled',
- 'vlansDisabled': 'vlans_disabled',
- 'profilesReference': 'profiles',
- 'policiesReference': 'policies',
- 'rules': 'irules',
- 'translateAddress': 'address_translation',
- 'translatePort': 'port_translation',
- 'ipProtocol': 'ip_protocol',
- 'fwEnforcedPolicy': 'firewall_enforced_policy',
- 'fwStagedPolicy': 'firewall_staged_policy',
- 'securityLogProfiles': 'security_log_profiles',
- 'securityNatPolicy': 'security_nat_policy',
- 'sourcePort': 'source_port',
- 'ipIntelligencePolicy': 'ip_intelligence_policy',
- 'rateLimit': 'rate_limit',
- 'rateLimitMode': 'rate_limit_mode',
- 'rateLimitDstMask': 'rate_limit_dst_mask',
- 'rateLimitSrcMask': 'rate_limit_src_mask',
- 'clonePools': 'clone_pools',
- }
-
- api_attributes = [
- 'description',
- 'destination',
- 'disabled',
- 'enabled',
- 'fallbackPersistence',
- 'ipProtocol',
- 'metadata',
- 'persist',
- 'policies',
- 'pool',
- 'profiles',
- 'rules',
- 'source',
- 'sourceAddressTranslation',
- 'vlans',
- 'vlansEnabled',
- 'vlansDisabled',
- 'translateAddress',
- 'translatePort',
- 'l2Forward',
- 'ipForward',
- 'stateless',
- 'reject',
- 'dhcpRelay',
- 'internal',
- 'fwEnforcedPolicy',
- 'fwStagedPolicy',
- 'securityLogProfiles',
- 'securityNatPolicy',
- 'sourcePort',
- 'mirror',
- 'mask',
- 'ipIntelligencePolicy',
- 'rateLimit',
- 'rateLimitMode',
- 'rateLimitDstMask',
- 'rateLimitSrcMask',
- 'clonePools',
- ]
-
- updatables = [
- 'address_translation',
- 'description',
- 'default_persistence_profile',
- 'destination',
- 'disabled_vlans',
- 'enabled',
- 'enabled_vlans',
- 'fallback_persistence_profile',
- 'ip_protocol',
- 'irules',
- 'metadata',
- 'pool',
- 'policies',
- 'port',
- 'port_translation',
- 'profiles',
- 'snat',
- 'source',
- 'type',
- 'firewall_enforced_policy',
- 'firewall_staged_policy',
- 'security_log_profiles',
- 'security_nat_policy',
- 'source_port',
- 'mirror',
- 'mask',
- 'ip_intelligence_policy',
- 'rate_limit',
- 'rate_limit_mode',
- 'rate_limit_src_mask',
- 'rate_limit_dst_mask',
- 'clone_pools',
- ]
-
- returnables = [
- 'address_translation',
- 'description',
- 'default_persistence_profile',
- 'destination',
- 'disabled',
- 'disabled_vlans',
- 'enabled',
- 'enabled_vlans',
- 'fallback_persistence_profile',
- 'ip_protocol',
- 'irules',
- 'metadata',
- 'pool',
- 'policies',
- 'port',
- 'port_translation',
- 'profiles',
- 'snat',
- 'source',
- 'vlans',
- 'vlans_enabled',
- 'vlans_disabled',
- 'type',
- 'firewall_enforced_policy',
- 'firewall_staged_policy',
- 'security_log_profiles',
- 'security_nat_policy',
- 'source_port',
- 'mirror',
- 'mask',
- 'ip_intelligence_policy',
- 'rate_limit',
- 'rate_limit_mode',
- 'rate_limit_src_mask',
- 'rate_limit_dst_mask',
- 'clone_pools',
- ]
-
- profiles_mutex = [
- 'sip',
- 'sipsession',
- 'iiop',
- 'rtsp',
- 'http',
- 'diameter',
- 'diametersession',
- 'radius',
- 'ftp',
- 'tftp',
- 'dns',
- 'pptp',
- 'fix',
- ]
-
- ip_protocols_map = [
- ('ah', 51),
- ('bna', 49),
- ('esp', 50),
- ('etherip', 97),
- ('gre', 47),
- ('icmp', 1),
- ('ipencap', 4),
- ('ipv6', 41),
- ('ipv6-auth', 51), # not in the official list
- ('ipv6-crypt', 50), # not in the official list
- ('ipv6-icmp', 58),
- ('iso-ip', 80),
- ('mux', 18),
- ('ospf', 89),
- ('sctp', 132),
- ('tcp', 6),
- ('udp', 17),
- ('udplite', 136),
- ]
-
- def to_return(self):
- result = {}
- for returnable in self.returnables:
- try:
- result[returnable] = getattr(self, returnable)
- except Exception:
- pass
- result = self._filter_params(result)
- return result
-
- def _format_port_for_destination(self, ip, port):
- if validate_ip_v6_address(ip):
- result = '.{0}'.format(port)
- else:
- result = ':{0}'.format(port)
- return result
-
- def _format_destination(self, address, port, route_domain):
- if port is None:
- if route_domain is None:
- result = '{0}'.format(
- fq_name(self.partition, address)
- )
- else:
- result = '{0}%{1}'.format(
- fq_name(self.partition, address),
- route_domain
- )
- else:
- port = self._format_port_for_destination(address, port)
- if route_domain is None:
- result = '{0}{1}'.format(
- fq_name(self.partition, address),
- port
- )
- else:
- result = '{0}%{1}{2}'.format(
- fq_name(self.partition, address),
- route_domain,
- port
- )
- return result
-
- @property
- def ip_protocol(self):
- if self._values['ip_protocol'] is None:
- return None
- if self._values['ip_protocol'] == 'any':
- return 'any'
- for x in self.ip_protocols_map:
- if x[0] == self._values['ip_protocol']:
- return int(x[1])
- try:
- return int(self._values['ip_protocol'])
- except ValueError:
- raise F5ModuleError(
- "Specified ip_protocol was neither a number nor in the list of common protocols."
- )
-
- @property
- def has_message_routing_profiles(self):
- if self.profiles is None:
- return None
- current = self._read_current_message_routing_profiles_from_device()
- result = [x['name'] for x in self.profiles if x['name'] in current]
- if len(result) > 0:
- return True
- return False
-
- @property
- def has_fastl4_profiles(self):
- if self.profiles is None:
- return None
- current = self._read_current_fastl4_profiles_from_device()
- result = [x['name'] for x in self.profiles if x['name'] in current]
- if len(result) > 0:
- return True
- return False
-
- @property
- def has_fasthttp_profiles(self):
- """Check if ``fasthttp`` profile is in API profiles
-
- This method is used to determine the server type when doing comparisons
- in the Difference class.
-
- Returns:
- bool: True if server has ``fasthttp`` profiles. False otherwise.
- """
- if self.profiles is None:
- return None
- current = self._read_current_fasthttp_profiles_from_device()
- result = [x['name'] for x in self.profiles if x['name'] in current]
- if len(result) > 0:
- return True
- return False
-
- def _read_current_message_routing_profiles_from_device(self):
- result = []
- result += self._read_diameter_profiles_from_device()
- result += self._read_sip_profiles_from_device()
- return result
-
- def _read_diameter_profiles_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/profile/diameter/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- result = [x['name'] for x in response['items']]
- return result
-
- def _read_sip_profiles_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/profile/sip/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- result = [x['name'] for x in response['items']]
- return result
-
- def _read_current_fastl4_profiles_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/profile/fastl4/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- result = [x['name'] for x in response['items']]
- return result
-
- def _read_current_fasthttp_profiles_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/profile/fasthttp/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- result = [x['name'] for x in response['items']]
- return result
-
- def _read_current_clientssl_profiles_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/profile/client-ssl/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- result = [x['name'] for x in response['items']]
- return result
-
- def _read_current_serverssl_profiles_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/profile/server-ssl/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- result = [x['name'] for x in response['items']]
- return result
-
- def _is_client_ssl_profile(self, profile):
- if profile['name'] in self._read_current_clientssl_profiles_from_device():
- return True
- return False
-
- def _is_server_ssl_profile(self, profile):
- if profile['name'] in self._read_current_serverssl_profiles_from_device():
- return True
- return False
-
- def _check_pool(self, item):
- pool = transform_name(name=fq_name(self.partition, item))
- uri = "https://{0}:{1}/mgmt/tm/ltm/pool/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- pool
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- raise F5ModuleError(
- 'The specified pool {0} does not exist.'.format(pool)
- )
- return item
-
-
-class ApiParameters(Parameters):
- @property
- def type(self):
- """Attempt to determine the current server type
-
- This check is very unscientific. It turns out that this information is not
- exactly available anywhere on a BIG-IP. Instead, we rely on a semi-reliable
- means for determining what the type of the virtual server is. Hopefully it
- always works.
-
- There are a handful of attributes that can be used to determine a specific
- type. There are some types though that can only be determined by looking at
- the profiles that are assigned to them. We follow that method for those
- complicated types; message-routing, fasthttp, and fastl4.
-
- Because type determination is an expensive operation, we cache the result
- from the operation.
-
- Returns:
- string: The server type.
- """
- if self._values['type']:
- return self._values['type']
- if self.l2Forward is True:
- result = 'forwarding-l2'
- elif self.ipForward is True:
- result = 'forwarding-ip'
- elif self.stateless is True:
- result = 'stateless'
- elif self.reject is True:
- result = 'reject'
- elif self.dhcpRelay is True:
- result = 'dhcp'
- elif self.internal is True:
- result = 'internal'
- elif self.has_fasthttp_profiles:
- result = 'performance-http'
- elif self.has_fastl4_profiles:
- result = 'performance-l4'
- elif self.has_message_routing_profiles:
- result = 'message-routing'
- else:
- result = 'standard'
- self._values['type'] = result
- return result
-
- @property
- def destination(self):
- if self._values['destination'] is None:
- return None
- destination = self.destination_tuple
- result = self._format_destination(destination.ip, destination.port, destination.route_domain)
- return result
-
- @property
- def destination_tuple(self):
- Destination = namedtuple('Destination', ['ip', 'port', 'route_domain', 'mask'])
-
- # Remove the partition
- if self._values['destination'] is None:
- result = Destination(ip=None, port=None, route_domain=None, mask=None)
- return result
- destination = re.sub(r'^/[a-zA-Z0-9_.-]+/', '', self._values['destination'])
- # Covers the following examples
- #
- # /Common/2700:bc00:1f10:101::6%2.80
- # 2700:bc00:1f10:101::6%2.80
- # 1.1.1.1%2:80
- # /Common/1.1.1.1%2:80
- # /Common/2700:bc00:1f10:101::6%2.any
- #
- pattern = r'(?P<ip>[^%]+)%(?P<route_domain>[0-9]+)[:.](?P<port>[0-9]+|any)'
- matches = re.search(pattern, destination)
- if matches:
- try:
- port = int(matches.group('port'))
- except ValueError:
- # Can be a port of "any". This only happens with IPv6
- port = matches.group('port')
- if port == 'any':
- port = 0
- result = Destination(
- ip=matches.group('ip'),
- port=port,
- route_domain=int(matches.group('route_domain')),
- mask=self.mask
- )
- return result
-
- pattern = r'(?P<ip>[^%]+)%(?P<route_domain>[0-9]+)'
- matches = re.search(pattern, destination)
- if matches:
- result = Destination(
- ip=matches.group('ip'),
- port=None,
- route_domain=int(matches.group('route_domain')),
- mask=self.mask
- )
- return result
-
- # this will match any IPV4 Address and port, no RD
- pattern = r'^(?P<ip>(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4]' \
- r'[0-9]|25[0-5])):(?P<port>[0-9]+)'
-
- matches = re.search(pattern, destination)
- if matches:
- result = Destination(
- ip=matches.group('ip'),
- port=int(matches.group('port')),
- route_domain=None,
- mask=self.mask
- )
- return result
-
- # match standalone IPV6 address, no port
- pattern = r'^([0-9a-f]{0,4}:){2,7}(:|[0-9a-f]{1,4})$'
- matches = re.search(pattern, destination)
- if matches:
- result = Destination(
- ip=destination,
- port=None,
- route_domain=None,
- mask=self.mask
- )
- return result
-
- # match IPV6 address with port
- pattern = r'(?P<ip>([0-9a-f]{0,4}:){2,7}(:|[0-9a-f]{1,4}).(?P<port>[0-9]+|any))'
- matches = re.search(pattern, destination)
- if matches:
- ip = matches.group('ip').split('.')[0]
- try:
- port = int(matches.group('port'))
- except ValueError:
- # Can be a port of "any". This only happens with IPv6
- port = matches.group('port')
- if port == 'any':
- port = 0
- result = Destination(
- ip=ip,
- port=port,
- route_domain=None,
- mask=self.mask
- )
- return result
-
- # this will match any alphanumeric Virtual Address and port
- pattern = r'(?P<name>^[a-zA-Z0-9_.-]+):(?P<port>[0-9]+)'
- matches = re.search(pattern, destination)
- if matches:
- result = Destination(
- ip=matches.group('name'),
- port=int(matches.group('port')),
- route_domain=None,
- mask=self.mask
- )
- return result
-
- # this will match any alphanumeric Virtual Address
- pattern = r'(?P<name>^[a-zA-Z0-9_.-]+)'
- matches = re.search(pattern, destination)
- if matches:
- result = Destination(
- ip=matches.group('name'),
- port=None,
- route_domain=None,
- mask=self.mask
- )
- return result
-
- # match IPv6 wildcard with port without RD
- pattern = r'(?P<ip>[^.]+).(?P<port>[0-9]+|any)'
- matches = re.search(pattern, destination)
- if matches:
- result = Destination(
- ip=matches.group('ip'),
- port=matches.group('port'),
- route_domain=None,
- mask=self.mask
- )
- return result
-
- result = Destination(ip=None, port=None, route_domain=None, mask=None)
- return result
-
- @property
- def port(self):
- destination = self.destination_tuple
- self._values['port'] = destination.port
- return destination.port
-
- @property
- def route_domain(self):
- """Return a route domain number from the destination
-
- Returns:
- int: The route domain number
- """
- destination = self.destination_tuple
- self._values['route_domain'] = destination.route_domain
- return int(destination.route_domain)
-
- @property
- def profiles(self):
- """Returns a list of profiles from the API
-
- The profiles are formatted so that they are usable in this module and
- are able to be compared by the Difference engine.
-
- Returns:
- list (:obj:`list` of :obj:`dict`): List of profiles.
-
- Each dictionary in the list contains the following three (3) keys.
-
- * name
- * context
- * fullPath
-
- Raises:
- F5ModuleError: If the specified context is a value other that
- ``all``, ``serverside``, or ``clientside``.
- """
- if 'items' not in self._values['profiles']:
- return None
- result = []
- for item in self._values['profiles']['items']:
- context = item['context']
- name = item['name']
- if context in ['all', 'serverside', 'clientside']:
- result.append(dict(name=name, context=context, fullPath=item['fullPath']))
- else:
- raise F5ModuleError(
- "Unknown profile context found: '{0}'".format(context)
- )
- return result
-
- @property
- def profile_types(self):
- return [x['name'] for x in iteritems(self.profiles)]
-
- @property
- def policies(self):
- if 'items' not in self._values['policies']:
- return None
- result = []
- for item in self._values['policies']['items']:
- name = item['name']
- partition = item['partition']
- result.append(dict(name=name, partition=partition))
- return result
-
- @property
- def default_persistence_profile(self):
- """Get the name of the current default persistence profile
-
- These persistence profiles are always lists when we get them
- from the REST API even though there can only be one. We'll
- make it a list again when we get to the Difference engine.
-
- Returns:
- string: The name of the default persistence profile
- """
- if self._values['default_persistence_profile'] is None:
- return None
- return self._values['default_persistence_profile'][0]
-
- @property
- def enabled(self):
- if 'enabled' in self._values:
- return True
- return False
-
- @property
- def disabled(self):
- if 'disabled' in self._values:
- return True
- return False
-
- @property
- def metadata(self):
- if self._values['metadata'] is None:
- return None
- if only_has_managed_metadata(self._values['metadata']):
- return None
- result = []
- for md in self._values['metadata']:
- if md['name'] in [MANAGED_BY_ANNOTATION_VERSION, MANAGED_BY_ANNOTATION_MODIFIED]:
- continue
-
- tmp = dict(name=str(md['name']))
- if 'value' in md:
- tmp['value'] = str(md['value'])
- else:
- tmp['value'] = ''
- result.append(tmp)
- return result
-
- @property
- def security_log_profiles(self):
- if self._values['security_log_profiles'] is None:
- return None
- # At the moment, BIG-IP wraps the names of log profiles in double-quotes if
- # the profile name contains spaces. This is likely due to the REST code being
- # too close to actual tmsh code and, at the tmsh level, a space in the profile
- # name would cause tmsh to see the 2nd word (and beyond) as "the next parameter".
- #
- # This seems like a bug to me.
- result = list(set([x.strip('"') for x in self._values['security_log_profiles']]))
- result.sort()
- return result
-
- @property
- def sec_nat_use_device_policy(self):
- if self._values['security_nat_policy'] is None:
- return None
- if 'useDevicePolicy' not in self._values['security_nat_policy']:
- return None
- if self._values['security_nat_policy']['useDevicePolicy'] == "no":
- return False
- return True
-
- @property
- def sec_nat_use_rd_policy(self):
- if self._values['security_nat_policy'] is None:
- return None
- if 'useRouteDomainPolicy' not in self._values['security_nat_policy']:
- return None
- if self._values['security_nat_policy']['useRouteDomainPolicy'] == "no":
- return False
- return True
-
- @property
- def sec_nat_policy(self):
- if self._values['security_nat_policy'] is None:
- return None
- if 'policy' not in self._values['security_nat_policy']:
- return None
- return self._values['security_nat_policy']['policy']
-
- @property
- def irules(self):
- if self._values['irules'] is None:
- return []
- return self._values['irules']
-
- @property
- def rate_limit(self):
- if self._values['rate_limit'] is None:
- return None
- if self._values['rate_limit'] == 'disabled':
- return 0
- return int(self._values['rate_limit'])
-
- @property
- def clone_pools(self):
- if self._values['clone_pools'] is None:
- return None
- result = []
- for item in self._values['clone_pools']:
- pool_name = fq_name(item['partition'], item['name'])
- context = item['context']
- tmp = {
- 'name': pool_name,
- 'context': context
- }
- result.append(tmp)
- return result
-
-
-class ModuleParameters(Parameters):
- services_map = {
- 'ftp': 21,
- 'http': 80,
- 'https': 443,
- 'telnet': 23,
- 'pptp': 1723,
- 'smtp': 25,
- 'snmp': 161,
- 'snmp-trap': 162,
- 'ssh': 22,
- 'tftp': 69,
- 'isakmp': 500,
- 'mqtt': 1883,
- 'mqtt-tls': 8883,
- 'rtsp': 554
- }
-
- def _handle_profile_context(self, tmp):
- if 'context' not in tmp:
- tmp['context'] = 'all'
- else:
- if 'name' not in tmp:
- raise F5ModuleError(
- "A profile name must be specified when a context is specified."
- )
- tmp['context'] = tmp['context'].replace('server-side', 'serverside')
- tmp['context'] = tmp['context'].replace('client-side', 'clientside')
-
- def _handle_ssl_profile_nuances(self, profile):
- if profile['name'] == 'serverssl' or self._is_server_ssl_profile(profile):
- if profile['context'] != 'serverside':
- profile['context'] = 'serverside'
- if profile['name'] == 'clientssl' or self._is_client_ssl_profile(profile):
- if profile['context'] != 'clientside':
- profile['context'] = 'clientside'
- return
-
- def _check_port(self):
- try:
- port = int(self._values['port'])
- except ValueError:
- raise F5ModuleError(
- "The specified port was not a valid integer"
- )
- if 0 <= port <= 65535:
- return port
- raise F5ModuleError(
- "Valid ports must be in range 0 - 65535"
- )
-
- def _check_clone_pool_contexts(self):
- client = 0
- server = 0
- for item in self._values['clone_pools']:
- if item['context'] == 'clientside':
- client += 1
- if item['context'] == 'serverside':
- server += 1
- if client > 1 or server > 1:
- raise F5ModuleError(
- 'You must specify only one clone pool for each context.'
- )
-
- @property
- def source(self):
- if self._values['source'] is None:
- return None
- source = self.source_tuple
- if is_valid_ip_interface(u'{0}/{1}'.format(source.ip, source.cidr)):
- if source.route_domain:
- result = '{0}%{1}/{2}'.format(source.ip, source.route_domain, source.cidr)
- else:
- result = '{0}/{1}'.format(source.ip, source.cidr)
- return result
- raise F5ModuleError(
- "The source IP address must be a valid CIDR format: address/prefix."
- )
-
- @property
- def source_tuple(self):
- Source = namedtuple('Source', ['ip', 'route_domain', 'cidr'])
- if self._values['source'] is None:
- result = Source(ip=None, route_domain=None, cidr=None)
- return result
- # match source with RD
- pattern = r'(?P<ip>[^%]+)%(?P<route_domain>[0-9]+)/(?P<cidr>[0-9]+)'
- matches = re.search(pattern, self._values['source'])
- if matches:
- result = Source(
- ip=matches.group('ip'),
- route_domain=matches.group('route_domain'),
- cidr=matches.group('cidr')
- )
- return result
- # match source without RD
- pattern = r'(?P<ip>[^%]+)/(?P<cidr>[0-9]+)'
- matches = re.search(pattern, self._values['source'])
- if matches:
- result = Source(
- ip=matches.group('ip'),
- route_domain=None,
- cidr=matches.group('cidr')
- )
- return result
-
- result = Source(ip=None, route_domain=None, cidr=None)
- return result
-
- @property
- def destination(self):
- pattern = r'^[a-zA-Z0-9_.-]+'
- if len(self._values['destination'].split('/')) > 1:
- addr, dud = self._values['destination'].split('/')
- if '%' in addr:
- addr = addr.split('%')[0]
- else:
- addr = self._values['destination'].split('%')[0]
- if not is_valid_ip(addr):
- matches = re.search(pattern, addr)
- if not matches:
- raise F5ModuleError(
- "The provided destination is not a valid IP address or a Virtual Address name."
- )
- result = self._format_destination(addr, self.port, self.route_domain)
- return result
-
- @property
- def route_domain(self):
- if self._values['destination'] is None:
- return None
- result = None
- if len(self._values['destination'].split('/')) > 1:
- addr, dud = self._values['destination'].split('/')
- if '%' in addr:
- result = addr.split('%')
- else:
- result = self._values['destination'].split('%')
- if result and len(result) > 1:
- pattern = r'^[a-zA-Z0-9_.-]+'
- matches = re.search(pattern, result[0])
- if matches and not is_valid_ip(result[0]):
- # we need to strip RD because when using Virtual Address names the RD is not needed.
- return None
- return int(result[1])
- return None
-
- @property
- def destination_tuple(self):
- Destination = namedtuple('Destination', ['ip', 'port', 'route_domain', 'mask'])
- if self._values['destination'] is None:
- result = Destination(ip=None, port=None, route_domain=None, mask=None)
- return result
- addr = self._values['destination'].split("%")[0].split('/')[0]
- if is_valid_ip(addr):
- addr = compress_address(u'{0}'.format(addr))
- result = Destination(ip=addr, port=self.port, route_domain=self.route_domain, mask=self.mask)
- return result
-
- @property
- def mask(self):
- if self._values['destination'] is None:
- return None
- if len(self._values['destination'].split('/')) > 1:
- addr, cidr = self._values['destination'].split('/')
- if '%' in addr:
- addr = addr.split('%')[0] + '/' + cidr
- else:
- addr = self._values['destination']
- else:
- addr = self._values['destination'].split('%')[0]
- if addr in ['0.0.0.0', '0.0.0.0/any', '0.0.0.0/0']:
- return 'any'
- if addr in ['::', '::/0', '::/any6']:
- return 'any6'
- if self._values['mask'] is None:
- if is_valid_ip_interface(addr):
- return get_netmask(addr)
- else:
- return None
- return compress_address(self._values['mask'])
-
- @property
- def port(self):
- if self._values['port'] is None:
- return None
- if self._values['port'] in ['*', 'any', '0']:
- return 0
- if self._values['port'] in self.services_map:
- port = self._values['port']
- self._values['port'] = self.services_map[port]
- self._check_port()
- return int(self._values['port'])
-
- @property
- def irules(self):
- results = []
- if self._values['irules'] is None:
- return None
- if len(self._values['irules']) == 1 and self._values['irules'][0] == '':
- return ''
- for irule in self._values['irules']:
- result = fq_name(self.partition, irule)
- results.append(result)
- return results
-
- @property
- def profiles(self):
- if self._values['profiles'] is None:
- return None
- if len(self._values['profiles']) == 1 and self._values['profiles'][0] == '':
- return ''
- result = []
- for profile in self._values['profiles']:
- tmp = dict()
- if isinstance(profile, dict):
- tmp.update(profile)
- self._handle_profile_context(tmp)
- if 'name' not in profile:
- tmp['name'] = profile
- tmp['fullPath'] = fq_name(self.partition, tmp['name'])
- self._handle_ssl_profile_nuances(tmp)
- else:
- full_path = fq_name(self.partition, profile)
- tmp['name'] = os.path.basename(profile)
- tmp['context'] = 'all'
- tmp['fullPath'] = full_path
- self._handle_ssl_profile_nuances(tmp)
- result.append(tmp)
- mutually_exclusive = [x['name'] for x in result if x in self.profiles_mutex]
- if len(mutually_exclusive) > 1:
- raise F5ModuleError(
- "Profiles {0} are mutually exclusive".format(
- ', '.join(self.profiles_mutex).strip()
- )
- )
- return result
-
- @property
- def policies(self):
- if self._values['policies'] is None:
- return None
- if len(self._values['policies']) == 1 and self._values['policies'][0] == '':
- return ''
- result = []
- policies = [fq_name(self.partition, p) for p in self._values['policies']]
- policies = set(policies)
- for policy in policies:
- parts = policy.split('/')
- if len(parts) != 3:
- raise F5ModuleError(
- "The specified policy '{0}' is malformed".format(policy)
- )
- tmp = dict(
- name=parts[2],
- partition=parts[1]
- )
- result.append(tmp)
- return result
-
- @property
- def pool(self):
- if self._values['pool'] is None:
- return None
- if self._values['pool'] == '':
- return ''
- return fq_name(self.partition, self._values['pool'])
-
- @property
- def vlans_enabled(self):
- if self._values['enabled_vlans'] is None:
- return None
- elif self._values['vlans_enabled'] is False:
- # This is a special case for "all" enabled VLANs
- return False
- if self._values['disabled_vlans'] is None:
- return True
- return False
-
- @property
- def vlans_disabled(self):
- if self._values['disabled_vlans'] is None:
- return None
- elif self._values['vlans_disabled'] is True:
- # This is a special case for "all" enabled VLANs
- return True
- elif self._values['enabled_vlans'] is None:
- return True
- return False
-
- @property
- def enabled_vlans(self):
- if self._values['enabled_vlans'] is None:
- return None
- elif any(x.lower() for x in self._values['enabled_vlans'] if x.lower() in ['all', '*']):
- result = [fq_name(self.partition, 'all')]
- return result
- results = list(set([fq_name(self.partition, x) for x in self._values['enabled_vlans']]))
- results.sort()
- return results
-
- @property
- def disabled_vlans(self):
- if self._values['disabled_vlans'] is None:
- return None
- elif any(x.lower() for x in self._values['disabled_vlans'] if x.lower() in ['all', '*']):
- raise F5ModuleError(
- "You cannot disable all VLANs. You must name them individually."
- )
- results = list(set([fq_name(self.partition, x) for x in self._values['disabled_vlans']]))
- results.sort()
- return results
-
- @property
- def vlans(self):
- disabled = self.disabled_vlans
- if disabled:
- return self.disabled_vlans
- return self.enabled_vlans
-
- @property
- def state(self):
- if self._values['state'] == 'present':
- return 'enabled'
- return self._values['state']
-
- @property
- def snat(self):
- if self._values['snat'] is None:
- return None
- lowercase = self._values['snat'].lower()
- if lowercase in ['automap', 'none']:
- return dict(type=lowercase)
- snat_pool = fq_name(self.partition, self._values['snat'])
- return dict(pool=snat_pool, type='snat')
-
- @property
- def default_persistence_profile(self):
- if self._values['default_persistence_profile'] is None:
- return None
- if self._values['default_persistence_profile'] == '':
- return ''
- profile = fq_name(self.partition, self._values['default_persistence_profile'])
- parts = profile.split('/')
- if len(parts) != 3:
- raise F5ModuleError(
- "The specified 'default_persistence_profile' is malformed"
- )
- result = dict(
- name=parts[2],
- partition=parts[1]
- )
- return result
-
- @property
- def fallback_persistence_profile(self):
- if self._values['fallback_persistence_profile'] is None:
- return None
- if self._values['fallback_persistence_profile'] == '':
- return ''
- result = fq_name(self.partition, self._values['fallback_persistence_profile'])
- return result
-
- @property
- def enabled(self):
- if self._values['state'] == 'enabled':
- return True
- elif self._values['state'] == 'disabled':
- return False
- else:
- return None
-
- @property
- def disabled(self):
- if self._values['state'] == 'enabled':
- return False
- elif self._values['state'] == 'disabled':
- return True
- else:
- return None
-
- @property
- def metadata(self):
- if self._values['metadata'] is None:
- return None
- if self._values['metadata'] == '':
- return []
- result = []
- try:
- for k, v in iteritems(self._values['metadata']):
- tmp = dict(name=str(k))
- if v:
- tmp['value'] = str(v)
- else:
- tmp['value'] = ''
- result.append(tmp)
- except AttributeError:
- raise F5ModuleError(
- "The 'metadata' parameter must be a dictionary of key/value pairs."
- )
- return result
-
- @property
- def address_translation(self):
- if self._values['address_translation'] is None:
- return None
- if self._values['address_translation']:
- return 'enabled'
- return 'disabled'
-
- @property
- def port_translation(self):
- if self._values['port_translation'] is None:
- return None
- if self._values['port_translation']:
- return 'enabled'
- return 'disabled'
-
- @property
- def firewall_enforced_policy(self):
- if self._values['firewall_enforced_policy'] is None:
- return None
- return fq_name(self.partition, self._values['firewall_enforced_policy'])
-
- @property
- def firewall_staged_policy(self):
- if self._values['firewall_staged_policy'] is None:
- return None
- return fq_name(self.partition, self._values['firewall_staged_policy'])
-
- @property
- def ip_intelligence_policy(self):
- if self._values['ip_intelligence_policy'] is None:
- return None
- if self._values['ip_intelligence_policy'] in ['', 'none']:
- return ''
- return fq_name(self.partition, self._values['ip_intelligence_policy'])
-
- @property
- def security_log_profiles(self):
- if self._values['security_log_profiles'] is None:
- return None
- if len(self._values['security_log_profiles']) == 1 and self._values['security_log_profiles'][0] == '':
- return ''
- result = list(set([fq_name(self.partition, x) for x in self._values['security_log_profiles']]))
- result.sort()
- return result
-
- @property
- def sec_nat_use_device_policy(self):
- if self._values['security_nat_policy'] is None:
- return None
- if 'use_device_policy' not in self._values['security_nat_policy']:
- return None
- return self._values['security_nat_policy']['use_device_policy']
-
- @property
- def sec_nat_use_rd_policy(self):
- if self._values['security_nat_policy'] is None:
- return None
- if 'use_route_domain_policy' not in self._values['security_nat_policy']:
- return None
- return self._values['security_nat_policy']['use_route_domain_policy']
-
- @property
- def sec_nat_policy(self):
- if self._values['security_nat_policy'] is None:
- return None
- if 'policy' not in self._values['security_nat_policy']:
- return None
- if self._values['security_nat_policy']['policy'] == '':
- return ''
- return fq_name(self.partition, self._values['security_nat_policy']['policy'])
-
- @property
- def security_nat_policy(self):
- result = dict()
- if self.sec_nat_policy:
- result['policy'] = self.sec_nat_policy
- if self.sec_nat_use_device_policy is not None:
- result['use_device_policy'] = self.sec_nat_use_device_policy
- if self.sec_nat_use_rd_policy is not None:
- result['use_route_domain_policy'] = self.sec_nat_use_rd_policy
- if result:
- return result
- return None
-
- @property
- def mirror(self):
- result = flatten_boolean(self._values['mirror'])
- if result is None:
- return None
- if result == 'yes':
- return 'enabled'
- return 'disabled'
-
- @property
- def rate_limit(self):
- if self._values['rate_limit'] is None:
- return None
- if 0 <= int(self._values['rate_limit']) <= 4294967295:
- return int(self._values['rate_limit'])
- raise F5ModuleError(
- "Valid 'rate_limit' must be in range 0 - 4294967295."
- )
-
- @property
- def rate_limit_src_mask(self):
- if self._values['rate_limit_src_mask'] is None:
- return None
- if 0 <= int(self._values['rate_limit_src_mask']) <= 4294967295:
- return int(self._values['rate_limit_src_mask'])
- raise F5ModuleError(
- "Valid 'rate_limit_src_mask' must be in range 0 - 4294967295."
- )
-
- @property
- def rate_limit_dst_mask(self):
- if self._values['rate_limit_dst_mask'] is None:
- return None
- if 0 <= int(self._values['rate_limit_dst_mask']) <= 4294967295:
- return int(self._values['rate_limit_dst_mask'])
- raise F5ModuleError(
- "Valid 'rate_limit_dst_mask' must be in range 0 - 4294967295."
- )
-
- @property
- def clone_pools(self):
- if self._values['clone_pools'] is None:
- return None
- if len(self._values['clone_pools']) == 1 and self._values['clone_pools'][0] in ['', []]:
- return []
- self._check_clone_pool_contexts()
- result = []
- for item in self._values['clone_pools']:
- pool_name = fq_name(self.partition, self._check_pool(item['pool_name']))
- context = item['context']
- tmp = {
- 'name': pool_name,
- 'context': context
- }
- result.append(tmp)
- return result
-
-
-class Changes(Parameters):
- pass
-
-
-class UsableChanges(Changes):
- @property
- def destination(self):
- if self._values['type'] == 'internal':
- return None
- return self._values['destination']
-
- @property
- def vlans(self):
- if self._values['vlans'] is None:
- return None
- elif len(self._values['vlans']) == 0:
- return []
- elif any(x for x in self._values['vlans'] if x.lower() in ['/common/all', 'all']):
- return []
- return self._values['vlans']
-
- @property
- def irules(self):
- if self._values['irules'] is None:
- return None
- if self._values['type'] in ['dhcp', 'stateless', 'reject', 'internal']:
- return None
- if self._values['irules'] == '':
- return []
- return self._values['irules']
-
- @property
- def policies(self):
- if self._values['policies'] is None:
- return None
- if self._values['type'] in ['dhcp', 'reject', 'internal']:
- return None
- if self._values['policies'] == '':
- return []
- return self._values['policies']
-
- @property
- def default_persistence_profile(self):
- if self._values['default_persistence_profile'] is None:
- return None
- if self._values['type'] == 'dhcp':
- return None
- if not self._values['default_persistence_profile']:
- return []
- return [self._values['default_persistence_profile']]
-
- @property
- def fallback_persistence_profile(self):
- if self._values['fallback_persistence_profile'] is None:
- return None
- if self._values['type'] == 'dhcp':
- return None
- return self._values['fallback_persistence_profile']
-
- @property
- def snat(self):
- if self._values['snat'] is None:
- return None
- if self._values['type'] in ['dhcp', 'reject', 'internal']:
- return None
- return self._values['snat']
-
- @property
- def dhcpRelay(self):
- if self._values['type'] == 'dhcp':
- return True
-
- @property
- def reject(self):
- if self._values['type'] == 'reject':
- return True
-
- @property
- def stateless(self):
- if self._values['type'] == 'stateless':
- return True
-
- @property
- def internal(self):
- if self._values['type'] == 'internal':
- return True
-
- @property
- def ipForward(self):
- if self._values['type'] == 'forwarding-ip':
- return True
-
- @property
- def l2Forward(self):
- if self._values['type'] == 'forwarding-l2':
- return True
-
- @property
- def security_log_profiles(self):
- if self._values['security_log_profiles'] is None:
- return None
- mutex = ('Log all requests', 'Log illegal requests')
- if len([x for x in self._values['security_log_profiles'] if x.endswith(mutex)]) >= 2:
- raise F5ModuleError(
- "The 'Log all requests' and 'Log illegal requests' are mutually exclusive."
- )
- return self._values['security_log_profiles']
-
- @property
- def security_nat_policy(self):
- if self._values['security_nat_policy'] is None:
- return None
- result = dict()
- sec = self._values['security_nat_policy']
- if 'policy' in sec:
- result['policy'] = sec['policy']
- if 'use_device_policy' in sec:
- result['useDevicePolicy'] = 'yes' if sec['use_device_policy'] else 'no'
- if 'use_route_domain_policy' in sec:
- result['useRouteDomainPolicy'] = 'yes' if sec['use_route_domain_policy'] else 'no'
- if result:
- return result
- return None
-
-
-class ReportableChanges(Changes):
- @property
- def mirror(self):
- if self._values['mirror'] is None:
- return None
- elif self._values['mirror'] == 'enabled':
- return 'yes'
- return 'no'
-
- @property
- def snat(self):
- if self._values['snat'] is None:
- return None
- result = self._values['snat'].get('type', None)
- if result == 'automap':
- return 'Automap'
- elif result == 'none':
- return 'none'
- result = self._values['snat'].get('pool', None)
- return result
-
- @property
- def destination(self):
- params = ApiParameters(params=dict(destination=self._values['destination']))
- result = params.destination_tuple.ip
- return result
-
- @property
- def port(self):
- params = ApiParameters(params=dict(destination=self._values['destination']))
- result = params.destination_tuple.port
- return result
-
- @property
- def default_persistence_profile(self):
- if len(self._values['default_persistence_profile']) == 0:
- return []
- profile = self._values['default_persistence_profile'][0]
- result = '/{0}/{1}'.format(profile['partition'], profile['name'])
- return result
-
- @property
- def policies(self):
- if len(self._values['policies']) == 0:
- return []
- if len(self._values['policies']) == 1 and self._values['policies'][0] == '':
- return ''
- result = ['/{0}/{1}'.format(x['partition'], x['name']) for x in self._values['policies']]
- return result
-
- @property
- def irules(self):
- if len(self._values['irules']) == 0:
- return []
- if len(self._values['irules']) == 1 and self._values['irules'][0] == '':
- return ''
- return self._values['irules']
-
- @property
- def enabled_vlans(self):
- if len(self._values['vlans']) == 0 and self._values['vlans_disabled'] is True:
- return 'all'
- elif len(self._values['vlans']) > 0 and self._values['vlans_enabled'] is True:
- return self._values['vlans']
-
- @property
- def disabled_vlans(self):
- if len(self._values['vlans']) > 0 and self._values['vlans_disabled'] is True:
- return self._values['vlans']
-
- @property
- def address_translation(self):
- if self._values['address_translation'] == 'enabled':
- return True
- return False
-
- @property
- def port_translation(self):
- if self._values['port_translation'] == 'enabled':
- return True
- return False
-
- @property
- def ip_protocol(self):
- if self._values['ip_protocol'] is None:
- return None
- try:
- int(self._values['ip_protocol'])
- except ValueError:
- return self._values['ip_protocol']
-
- protocol = next((x[0] for x in self.ip_protocols_map if x[1] == self._values['ip_protocol']), None)
- if protocol:
- return protocol
- return self._values['ip_protocol']
-
-
-class VirtualServerValidator(object):
- def __init__(self, module=None, client=None, want=None, have=None):
- self.have = have if have else ApiParameters()
- self.want = want if want else ModuleParameters()
- self.client = client
- self.module = module
-
- def check_update(self):
- # Regular checks
- self._override_port_by_type()
- self._override_protocol_by_type()
- self._verify_type_has_correct_profiles()
- self._verify_default_persistence_profile_for_type()
- self._verify_fallback_persistence_profile_for_type()
- self._update_persistence_profile()
- self._ensure_server_type_supports_vlans()
- self._verify_type_has_correct_ip_protocol()
-
- # For different server types
- self._verify_dhcp_profile()
- self._verify_fastl4_profile()
- self._verify_stateless_profile()
-
- def check_create(self):
- # Regular checks
- self._set_default_ip_protocol()
- self._set_default_profiles()
- self._override_port_by_type()
- self._override_protocol_by_type()
- self._verify_type_has_correct_profiles()
- self._verify_default_persistence_profile_for_type()
- self._verify_fallback_persistence_profile_for_type()
- self._update_persistence_profile()
- self._verify_virtual_has_required_parameters()
- self._ensure_server_type_supports_vlans()
- self._override_vlans_if_all_specified()
- self._check_source_and_destination_match()
- self._verify_type_has_correct_ip_protocol()
- self._verify_minimum_profile()
-
- # For different server types
- self._verify_dhcp_profile()
- self._verify_fastl4_profile()
- self._verify_stateless_profile_on_create()
-
- def _ensure_server_type_supports_vlans(self):
- """Verifies the specified server type supports VLANs
-
- A select number of server types do not support VLANs. This method
- checks to see if the specified types were provided along with VLANs.
- If they were, the module will raise an error informing the user that
- they need to either remove the VLANs, or, change the ``type``.
-
- Returns:
- None: Returned if no VLANs are specified.
- Raises:
- F5ModuleError: Raised if the server type conflicts with VLANs.
- """
- if self.want.enabled_vlans is None:
- return
- if self.want.type == 'internal':
- raise F5ModuleError(
- "The 'internal' server type does not support VLANs."
- )
-
- def _override_vlans_if_all_specified(self):
- """Overrides any specified VLANs if "all" VLANs are specified
-
- The special setting "all VLANs" in a BIG-IP requires that no other VLANs
- be specified. If you specify any number of VLANs, AND include the "all"
- VLAN, this method will erase all of the other VLANs and only return the
- "all" VLAN.
- """
- all_vlans = ['/common/all', 'all']
- if self.want.enabled_vlans is not None:
- if any(x for x in self.want.enabled_vlans if x.lower() in all_vlans):
- self.want.update(
- dict(
- enabled_vlans=[],
- vlans_disabled=True,
- vlans_enabled=False
- )
- )
-
- def _override_port_by_type(self):
- if self.want.type == 'dhcp':
- self.want.update({'port': 67})
- elif self.want.type == 'internal':
- self.want.update({'port': 0})
-
- def _override_protocol_by_type(self):
- if self.want.type in ['stateless']:
- self.want.update({'ip_protocol': 17})
-
- def _check_source_and_destination_match(self):
- """Verify that destination and source are of the same IP version
-
- BIG-IP does not allow for mixing of the IP versions for destination and
- source addresses. For example, a destination IPv6 address cannot be
- associated with a source IPv4 address.
-
- This method checks that you specified the same IP version for these
- parameters
-
- Raises:
- F5ModuleError: Raised when the IP versions of source and destination differ.
- """
- if self.want.source and self.want.destination:
- want = ip_interface(u'{0}/{1}'.format(self.want.source_tuple.ip, self.want.source_tuple.cidr))
- have = ip_interface(u'{0}'.format(self.want.destination_tuple.ip))
- if want.version != have.version:
- raise F5ModuleError(
- "The source and destination addresses for the virtual server must be be the same type (IPv4 or IPv6)."
- )
-
- def _verify_type_has_correct_ip_protocol(self):
- if self.want.ip_protocol is None:
- return
- if self.want.type == 'standard':
- # Standard supports
- # - tcp
- # - udp
- # - sctp
- # - ipsec-ah
- # - ipsec esp
- # - all protocols
- if self.want.ip_protocol not in [6, 17, 132, 51, 50, 'any']:
- raise F5ModuleError(
- "The 'standard' server type does not support the specified 'ip_protocol'."
- )
- elif self.want.type == 'performance-http':
- # Perf HTTP supports
- #
- # - tcp
- if self.want.ip_protocol not in [6]:
- raise F5ModuleError(
- "The 'performance-http' server type does not support the specified 'ip_protocol'."
- )
- elif self.want.type == 'stateless':
- # Stateless supports
- #
- # - udp
- if self.want.ip_protocol not in [17]:
- raise F5ModuleError(
- "The 'stateless' server type does not support the specified 'ip_protocol'."
- )
- elif self.want.type == 'dhcp':
- # DHCP supports no IP protocols
- if self.want.ip_protocol is not None:
- raise F5ModuleError(
- "The 'dhcp' server type does not support an 'ip_protocol'."
- )
- elif self.want.type == 'internal':
- # Internal supports
- #
- # - tcp
- # - udp
- if self.want.ip_protocol not in [6, 17]:
- raise F5ModuleError(
- "The 'internal' server type does not support the specified 'ip_protocol'."
- )
- elif self.want.type == 'message-routing':
- # Message Routing supports
- #
- # - tcp
- # - udp
- # - sctp
- # - all protocols
- if self.want.ip_protocol not in [6, 17, 132, 'all', 'any']:
- raise F5ModuleError(
- "The 'message-routing' server type does not support the specified 'ip_protocol'."
- )
-
- def _verify_virtual_has_required_parameters(self):
- """Verify that the virtual has required parameters
-
- Virtual servers require several parameters that are not necessarily required
- when updating the virtual. This method will check for the required params
- upon creation.
-
- Ansible supports ``default`` variables in an Argument Spec, but those defaults
- apply to all operations; including create, update, and delete. Since users are not
- required to always specify these parameters, we cannot use Ansible's facility.
- If we did, and then users would be required to provide them when, for example,
- they attempted to delete a virtual (even though they are not required to delete
- a virtual.
-
- Raises:
- F5ModuleError: Raised when the user did not specify required parameters.
- """
- required_resources = ['destination', 'port']
- if self.want.type == 'internal':
- return
- if all(getattr(self.want, v) is None for v in required_resources):
- raise F5ModuleError(
- "You must specify both of " + ', '.join(required_resources)
- )
-
- def _verify_default_persistence_profile_for_type(self):
- """Verify that the server type supports default persistence profiles
-
- Verifies that the specified server type supports default persistence profiles.
- Some virtual servers do not support these types of profiles. This method will
- check that the type actually supports what you are sending it.
-
- Types that do not, at this time, support default persistence profiles include,
-
- * dhcp
- * message-routing
- * reject
- * stateless
- * forwarding-ip
- * forwarding-l2
-
- Raises:
- F5ModuleError: Raised if server type does not support default persistence profiles.
- """
- default_profile_not_allowed = [
- 'dhcp', 'message-routing', 'reject', 'stateless', 'forwarding-ip', 'forwarding-l2'
- ]
- if self.want.ip_protocol in default_profile_not_allowed:
- raise F5ModuleError(
- "The '{0}' server type does not support a 'default_persistence_profile'".format(self.want.type)
- )
-
- def _verify_fallback_persistence_profile_for_type(self):
- """Verify that the server type supports fallback persistence profiles
-
- Verifies that the specified server type supports fallback persistence profiles.
- Some virtual servers do not support these types of profiles. This method will
- check that the type actually supports what you are sending it.
-
- Types that do not, at this time, support fallback persistence profiles include,
-
- * dhcp
- * message-routing
- * reject
- * stateless
- * forwarding-ip
- * forwarding-l2
- * performance-http
-
- Raises:
- F5ModuleError: Raised if server type does not support fallback persistence profiles.
- """
- default_profile_not_allowed = [
- 'dhcp', 'message-routing', 'reject', 'stateless', 'forwarding-ip', 'forwarding-l2',
- 'performance-http'
- ]
- if self.want.ip_protocol in default_profile_not_allowed:
- raise F5ModuleError(
- "The '{0}' server type does not support a 'fallback_persistence_profile'".format(self.want.type)
- )
-
- def _update_persistence_profile(self):
- # This must be changed back to a list to make a valid REST API
- # value. The module manipulates this as a normal dictionary
- if self.want.default_persistence_profile is not None:
- self.want.update({'default_persistence_profile': self.want.default_persistence_profile})
-
- def _verify_type_has_correct_profiles(self):
- """Verify that specified server type does not include forbidden profiles
-
- The type of the server determines the ``type``s of profiles that it accepts. This
- method checks that the server ``type`` that you specified is indeed one that can
- accept the profiles that you specified.
-
- The common situations are
-
- * ``standard`` types that include ``fasthttp``, ``fastl4``, or ``message routing`` profiles
- * ``fasthttp`` types that are missing a ``fasthttp`` profile
- * ``fastl4`` types that are missing a ``fastl4`` profile
- * ``message-routing`` types that are missing ``diameter`` or ``sip`` profiles
-
- Raises:
- F5ModuleError: Raised when a validation check fails.
- """
- if self.want.type == 'standard':
- if self.want.has_fasthttp_profiles:
- raise F5ModuleError("A 'standard' type may not have 'fasthttp' profiles.")
- if self.want.has_fastl4_profiles:
- raise F5ModuleError("A 'standard' type may not have 'fastl4' profiles.")
- if self.want.has_message_routing_profiles:
- raise F5ModuleError("A 'standard' type may not have 'message-routing' profiles.")
- elif self.want.type == 'performance-http':
- if not self.want.has_fasthttp_profiles:
- raise F5ModuleError("A 'fasthttp' type must have at least one 'fasthttp' profile.")
- elif self.want.type == 'performance-l4':
- if not self.want.has_fastl4_profiles:
- raise F5ModuleError("A 'fastl4' type must have at least one 'fastl4' profile.")
- elif self.want.type == 'message-routing':
- if not self.want.has_message_routing_profiles:
- raise F5ModuleError("A 'message-routing' type must have either a 'sip' or 'diameter' profile.")
-
- def _set_default_ip_protocol(self):
- if self.want.type == 'dhcp':
- return
- if self.want.ip_protocol is None:
- self.want.update({'ip_protocol': 6})
-
- def _set_default_profiles(self):
- if self.want.type == 'standard':
- if not self.want.profiles:
- # Sets a default profiles when creating a new standard virtual.
- #
- # It appears that if no profiles are deliberately specified, then under
- # certain circumstances, the server type will default to ``performance-l4``.
- #
- # It's unclear what these circumstances are, but they are met in issue 00093.
- # If this block of profile setting code is removed, the virtual server's
- # type will change to performance-l4 for some reason.
- #
- if self.want.ip_protocol == 6:
- self.want.update({'profiles': ['tcp']})
- if self.want.ip_protocol == 17:
- self.want.update({'profiles': ['udp']})
- if self.want.ip_protocol == 132:
- self.want.update({'profiles': ['sctp']})
-
- def _verify_minimum_profile(self):
- if self.want.profiles:
- return None
- if self.want.type == 'internal' and self.want.profiles == '':
- raise F5ModuleError(
- "An 'internal' server must have at least one profile relevant to its 'ip_protocol'. "
- "For example, 'tcp', 'udp', or variations of those."
- )
-
- def _verify_dhcp_profile(self):
- if self.want.type != 'dhcp':
- return
- if self.want.profiles is None:
- return
- have = set(self.read_dhcp_profiles_from_device())
- want = set([x['fullPath'] for x in self.want.profiles])
- if have.intersection(want):
- return True
- raise F5ModuleError(
- "A dhcp profile, such as 'dhcpv4', or 'dhcpv6' must be specified when 'type' is 'dhcp'."
- )
-
- def _verify_fastl4_profile(self):
- if self.want.type != 'performance-l4':
- return
- if self.want.profiles is None:
- return
- have = set(self.read_fastl4_profiles_from_device())
- want = set([x['fullPath'] for x in self.want.profiles])
- if have.intersection(want):
- return True
- raise F5ModuleError(
- "A performance-l4 profile, such as 'fastL4', must be specified when 'type' is 'performance-l4'."
- )
-
- def _verify_fasthttp_profile(self):
- if self.want.type != 'performance-http':
- return
- if self.want.profiles is None:
- return
- have = set(self.read_fasthttp_profiles_from_device())
- want = set([x['fullPath'] for x in self.want.profiles])
- if have.intersection(want):
- return True
- raise F5ModuleError(
- "A performance-http profile, such as 'fasthttp', must be specified when 'type' is 'performance-http'."
- )
-
- def _verify_stateless_profile_on_create(self):
- if self.want.type != 'stateless':
- return
- result = self._verify_stateless_profile()
- if result is None:
- raise F5ModuleError(
- "A udp profile, must be specified when 'type' is 'stateless'."
- )
-
- def _verify_stateless_profile(self):
- if self.want.type != 'stateless':
- return
- if self.want.profiles is None:
- return
- have = set(self.read_udp_profiles_from_device())
- want = set([x['fullPath'] for x in self.want.profiles])
- if have.intersection(want):
- return True
- raise F5ModuleError(
- "A udp profile, must be specified when 'type' is 'stateless'."
- )
-
- def read_dhcp_profiles_from_device(self):
- result = []
- result += self.read_dhcpv4_profiles_from_device()
- result += self.read_dhcpv6_profiles_from_device()
- return result
-
- def read_dhcpv4_profiles_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/profile/dhcpv4/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- result = [fq_name(self.want.partition, x['name']) for x in response['items']]
- return result
-
- def read_dhcpv6_profiles_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/profile/dhcpv6/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- result = [fq_name(self.want.partition, x['name']) for x in response['items']]
- return result
-
- def read_fastl4_profiles_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/profile/fastl4/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- result = [fq_name(self.want.partition, x['name']) for x in response['items']]
- return result
-
- def read_fasthttp_profiles_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/profile/fasthttp/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- result = [fq_name(self.want.partition, x['name']) for x in response['items']]
- return result
-
- def read_udp_profiles_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/profile/udp/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- result = [fq_name(self.want.partition, x['name']) for x in response['items']]
- return result
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.have = have
- self.want = want
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- result = self.__default(param)
- return result
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
- def to_tuple(self, items):
- result = []
- for x in items:
- tmp = [(str(k), str(v)) for k, v in iteritems(x)]
- result += tmp
- return result
-
- def _diff_complex_items(self, want, have):
- if want == [] and have is None:
- return None
- if want is None:
- return None
- w = self.to_tuple(want)
- h = self.to_tuple(have)
- if set(w).issubset(set(h)):
- return None
- else:
- return want
-
- def _update_vlan_status(self, result):
- if self.want.vlans_disabled is not None:
- if self.want.vlans_disabled != self.have.vlans_disabled:
- result['vlans_disabled'] = self.want.vlans_disabled
- result['vlans_enabled'] = not self.want.vlans_disabled
- elif self.want.vlans_enabled is not None:
- if any(x.lower().endswith('/all') for x in self.want.vlans):
- if self.have.vlans_enabled is True:
- result['vlans_disabled'] = True
- result['vlans_enabled'] = False
- elif self.want.vlans_enabled != self.have.vlans_enabled:
- result['vlans_disabled'] = not self.want.vlans_enabled
- result['vlans_enabled'] = self.want.vlans_enabled
-
- @property
- def destination(self):
- # The internal type does not support the 'destination' parameter, so it is ignored.
- if self.want.type == 'internal':
- return
-
- addr_tuple = [self.want.destination, self.want.port, self.want.route_domain]
- if all(x is None for x in addr_tuple):
- return None
-
- have = self.have.destination_tuple
- if self.want.port is None:
- self.want.update({'port': have.port})
- if self.want.route_domain is None:
- self.want.update({'route_domain': have.route_domain})
- if self.want.destination_tuple.ip is None:
- address = have.ip
- else:
- address = self.want.destination_tuple.ip
- want = self.want._format_destination(address, self.want.port, self.want.route_domain)
- if want != self.have.destination:
- return fq_name(self.want.partition, want)
-
- @property
- def source(self):
- if self.want.source is None:
- return None
- if self.want.source != self.have.source:
- return self.want.source
-
- @property
- def vlans(self):
- if self.want.vlans is None:
- return None
- elif self.want.vlans == [] and self.have.vlans is None:
- return None
- elif self.want.vlans == self.have.vlans:
- return None
-
- # Specifically looking for /all because the vlans return value will be
- # an FQDN list. This means that "all" will be returned as "/partition/all",
- # ex, /Common/all.
- #
- # We do not want to accidentally match values that would end with the word
- # "all", like "vlansall". Therefore we look for the forward slash because this
- # is a path delimiter.
- elif any(x.lower().endswith('/all') for x in self.want.vlans):
- if self.have.vlans is None:
- return None
- else:
- return []
- else:
- return self.want.vlans
-
- @property
- def enabled_vlans(self):
- return self.vlan_status
-
- @property
- def disabled_vlans(self):
- return self.vlan_status
-
- @property
- def vlan_status(self):
- result = dict()
- vlans = self.vlans
- if vlans is not None:
- result['vlans'] = vlans
- self._update_vlan_status(result)
- return result
-
- @property
- def port(self):
- result = self.destination
- if result is not None:
- return dict(
- destination=result
- )
-
- @property
- def profiles(self):
- if self.want.profiles is None:
- return None
- if self.want.profiles == '' and len(self.have.profiles) > 0:
- have = set([(p['name'], p['context'], p['fullPath']) for p in self.have.profiles])
- if len(self.have.profiles) == 1:
- if not any(x[0] in ['tcp', 'udp', 'sctp'] for x in have):
- return []
- else:
- return None
- else:
- return []
- if self.want.profiles == '' and len(self.have.profiles) == 0:
- return None
- want = set([(p['name'], p['context'], p['fullPath']) for p in self.want.profiles])
- have = set([(p['name'], p['context'], p['fullPath']) for p in self.have.profiles])
- if len(have) == 0:
- return self.want.profiles
- elif len(have) == 1:
- if want != have:
- return self.want.profiles
- else:
- if not any(x[0] == 'tcp' for x in want):
- if self.want.type != 'stateless':
- have = set([x for x in have if x[0] != 'tcp'])
- if not any(x[0] == 'udp' for x in want):
- have = set([x for x in have if x[0] != 'udp'])
- if not any(x[0] == 'sctp' for x in want):
- if self.want.type != 'stateless':
- have = set([x for x in have if x[0] != 'sctp'])
- want = set([(p[2], p[1]) for p in want])
- have = set([(p[2], p[1]) for p in have])
- if want != have:
- return self.want.profiles
-
- @property
- def ip_protocol(self):
- if self.want.ip_protocol != self.have.ip_protocol:
- return self.want.ip_protocol
-
- @property
- def fallback_persistence_profile(self):
- if self.want.fallback_persistence_profile is None:
- return None
- if self.want.fallback_persistence_profile == '' and self.have.fallback_persistence_profile is not None:
- return ""
- if self.want.fallback_persistence_profile == '' and self.have.fallback_persistence_profile is None:
- return None
- if self.want.fallback_persistence_profile != self.have.fallback_persistence_profile:
- return self.want.fallback_persistence_profile
-
- @property
- def default_persistence_profile(self):
- if self.want.default_persistence_profile is None:
- return None
- if self.want.default_persistence_profile == '' and self.have.default_persistence_profile is not None:
- return []
- if self.want.default_persistence_profile == '' and self.have.default_persistence_profile is None:
- return None
- if self.have.default_persistence_profile is None:
- return dict(
- default_persistence_profile=self.want.default_persistence_profile
- )
- w_name = self.want.default_persistence_profile.get('name', None)
- w_partition = self.want.default_persistence_profile.get('partition', None)
- h_name = self.have.default_persistence_profile.get('name', None)
- h_partition = self.have.default_persistence_profile.get('partition', None)
- if w_name != h_name or w_partition != h_partition:
- return dict(
- default_persistence_profile=self.want.default_persistence_profile
- )
-
- @property
- def ip_intelligence_policy(self):
- if self.want.ip_intelligence_policy is None:
- return None
- if self.want.ip_intelligence_policy == '' and self.have.ip_intelligence_policy is not None:
- return ""
- if self.want.ip_intelligence_policy == '' and self.have.ip_intelligence_policy is None:
- return None
- if self.want.ip_intelligence_policy != self.have.ip_intelligence_policy:
- return self.want.ip_intelligence_policy
-
- @property
- def policies(self):
- if self.want.policies is None:
- return None
- if self.want.policies in [[], ''] and self.have.policies is None:
- return None
- if self.want.policies == '' and len(self.have.policies) > 0:
- return []
- if not self.have.policies:
- return self.want.policies
- want = set([(p['name'], p['partition']) for p in self.want.policies])
- have = set([(p['name'], p['partition']) for p in self.have.policies])
- if not want == have:
- return self.want.policies
-
- @property
- def snat(self):
- if self.want.snat is None:
- return None
- if self.want.snat['type'] != self.have.snat['type']:
- result = dict(snat=self.want.snat)
- return result
-
- if self.want.snat.get('pool', None) is None:
- return None
-
- if self.want.snat['pool'] != self.have.snat['pool']:
- result = dict(snat=self.want.snat)
- return result
-
- @property
- def enabled(self):
- if self.want.state == 'enabled' and self.have.disabled:
- result = dict(
- enabled=True,
- disabled=False
- )
- return result
- elif self.want.state == 'disabled' and self.have.enabled:
- result = dict(
- enabled=False,
- disabled=True
- )
- return result
-
- @property
- def irules(self):
- if self.want.irules is None:
- return None
- if self.want.irules == '' and len(self.have.irules) > 0:
- return []
- if self.want.irules in [[], ''] and len(self.have.irules) == 0:
- return None
- if sorted(set(self.want.irules)) != sorted(set(self.have.irules)):
- return self.want.irules
-
- @property
- def pool(self):
- if self.want.pool is None:
- return None
- if self.want.pool == '' and self.have.pool is not None:
- return ""
- if self.want.pool == '' and self.have.pool is None:
- return None
- if self.want.pool != self.have.pool:
- return self.want.pool
-
- @property
- def metadata(self):
- if self.want.metadata is None:
- return None
- elif len(self.want.metadata) == 0 and self.have.metadata is None:
- return None
- elif len(self.want.metadata) == 0 and not self.want.insert_metadata:
- return None
- elif len(self.want.metadata) == 0 and self.want.insert_metadata:
- return []
- elif self.have.metadata is None:
- return self.want.metadata
- result = self._diff_complex_items(self.want.metadata, self.have.metadata)
- return result
-
- @property
- def type(self):
- if self.want.type != self.have.type:
- raise F5ModuleError(
- "Changing the 'type' parameter is not supported."
- )
-
- @property
- def security_log_profiles(self):
- result = cmp_simple_list(self.want.security_log_profiles, self.have.security_log_profiles)
- return result
-
- @property
- def security_nat_policy(self):
- result = dict()
- if self.want.sec_nat_use_device_policy is not None:
- if self.want.sec_nat_use_device_policy != self.have.sec_nat_use_device_policy:
- result['use_device_policy'] = self.want.sec_nat_use_device_policy
- if self.want.sec_nat_use_rd_policy is not None:
- if self.want.sec_nat_use_rd_policy != self.have.sec_nat_use_rd_policy:
- result['use_route_domain_policy'] = self.want.sec_nat_use_rd_policy
- if self.want.sec_nat_policy is not None:
- if self.want.sec_nat_policy == '' and self.have.sec_nat_policy is None:
- pass
- elif self.want.sec_nat_policy != self.have.sec_nat_policy:
- result['policy'] = self.want.sec_nat_policy
- if result:
- return dict(security_nat_policy=result)
-
- @property
- def clone_pools(self):
- if self.want.clone_pools == [] and self.have.clone_pools:
- return self.want.clone_pools
- result = self._diff_complex_items(self.want.clone_pools, self.have.clone_pools)
- return result
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.have = ApiParameters(client=self.client)
- self.want = ModuleParameters(client=self.client, params=self.module.params)
- self.changes = UsableChanges()
- self.provisioned_modules = []
-
- def exec_module(self):
- changed = False
- result = dict()
- state = self.want.state
-
- self.provisioned_modules = modules_provisioned(self.client)
-
- if state in ['present', 'enabled', 'disabled']:
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- return result
-
- def present(self):
- if self.exists():
- return self.update()
- else:
- return self.create()
-
- def absent(self):
- if self.exists():
- return self.remove()
- return False
-
- def update(self):
- self.have = self.read_current_from_device()
- validator = VirtualServerValidator(
- module=self.module, client=self.client, have=self.have, want=self.want
- )
- validator.check_update()
-
- if self.want.ip_intelligence_policy is not None:
- if not any(x for x in self.provisioned_modules if x in ['afm', 'asm']):
- raise F5ModuleError(
- "AFM must be provisioned to configure an IP Intelligence policy."
- )
-
- if not self.should_update():
- return False
- if self.module.check_mode:
- return True
- self.update_on_device()
- return True
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def remove(self):
- if self.module.check_mode:
- return True
- self.remove_from_device()
- if self.exists():
- raise F5ModuleError("Failed to delete the resource")
- return True
-
- def get_reportable_changes(self):
- result = ReportableChanges(params=self.changes.to_return())
- return result
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = UsableChanges(params=changed)
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def exists(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/virtual/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def create(self):
- validator = VirtualServerValidator(
- module=self.module, client=self.client, have=self.have, want=self.want
- )
- validator.check_create()
-
- if self.want.ip_intelligence_policy is not None:
- if not any(x for x in self.provisioned_modules if x in ['afm', 'asm']):
- raise F5ModuleError(
- "AFM must be provisioned to configure an IP Intelligence policy."
- )
-
- self._set_changed_options()
- if self.module.check_mode:
- return True
- self.create_on_device()
- return True
-
- def update_on_device(self):
- params = self.changes.api_params()
-
- if self.want.insert_metadata:
- # Mark the resource as managed by Ansible, this is default behavior
- params = mark_managed_by(self.module.ansible_version, params)
-
- uri = "https://{0}:{1}/mgmt/tm/ltm/virtual/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 404]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/virtual/{2}?expandSubcollections=true".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- return ApiParameters(params=response, client=self.client)
-
- def create_on_device(self):
- params = self.changes.api_params()
- params['name'] = self.want.name
- params['partition'] = self.want.partition
- if self.want.insert_metadata:
- # Mark the resource as managed by Ansible, this is default behavior
- params = mark_managed_by(self.module.ansible_version, params)
-
- uri = "https://{0}:{1}/mgmt/tm/ltm/virtual/".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- # Code 404 can occur when you specify a fallback profile that does
- # not exist
- if 'code' in response and response['code'] in [400, 403, 404]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def remove_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/ltm/virtual/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- response = self.client.api.delete(uri)
- if response.status == 200:
- return True
- raise F5ModuleError(response.content)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- state=dict(
- default='present',
- choices=['present', 'absent', 'disabled', 'enabled']
- ),
- name=dict(
- required=True,
- aliases=['vs']
- ),
- destination=dict(
- aliases=['address', 'ip']
- ),
- port=dict(),
- profiles=dict(
- type='list',
- aliases=['all_profiles'],
- options=dict(
- name=dict(),
- context=dict(default='all', choices=['all', 'server-side', 'client-side'])
- )
- ),
- policies=dict(
- type='list',
- aliases=['all_policies']
- ),
- irules=dict(
- type='list',
- aliases=['all_rules']
- ),
- enabled_vlans=dict(
- type='list'
- ),
- disabled_vlans=dict(
- type='list'
- ),
- pool=dict(),
- description=dict(),
- snat=dict(),
- default_persistence_profile=dict(),
- fallback_persistence_profile=dict(),
- source=dict(),
- metadata=dict(type='raw'),
- partition=dict(
- default='Common',
- fallback=(env_fallback, ['F5_PARTITION'])
- ),
- address_translation=dict(type='bool'),
- port_translation=dict(type='bool'),
- source_port=dict(
- choices=[
- 'preserve', 'preserve-strict', 'change'
- ]
- ),
- ip_protocol=dict(
- choices=[
- 'ah', 'any', 'bna', 'esp', 'etherip', 'gre', 'icmp', 'ipencap', 'ipv6',
- 'ipv6-auth', 'ipv6-crypt', 'ipv6-icmp', 'isp-ip', 'mux', 'ospf',
- 'sctp', 'tcp', 'udp', 'udplite'
- ]
- ),
- type=dict(
- default='standard',
- choices=[
- 'standard', 'forwarding-ip', 'forwarding-l2', 'internal', 'message-routing',
- 'performance-http', 'performance-l4', 'reject', 'stateless', 'dhcp'
- ]
- ),
- mirror=dict(type='bool'),
- mask=dict(),
- firewall_staged_policy=dict(),
- firewall_enforced_policy=dict(),
- ip_intelligence_policy=dict(),
- security_log_profiles=dict(type='list'),
- security_nat_policy=dict(
- type='dict',
- options=dict(
- policy=dict(),
- use_device_policy=dict(type='bool'),
- use_route_domain_policy=dict(type='bool')
- )
- ),
- insert_metadata=dict(
- type='bool',
- default='yes'
- ),
- rate_limit=dict(type='int'),
- rate_limit_dst_mask=dict(type='int'),
- rate_limit_src_mask=dict(type='int'),
- rate_limit_mode=dict(
- default='object',
- choices=[
- 'destination', 'object-destination', 'object-source-destination',
- 'source-destination', 'object', 'object-source', 'source'
- ]
- ),
- clone_pools=dict(
- type='list',
- options=dict(
- pool_name=dict(required=True),
- context=dict(
- required=True,
- choices=[
- 'clientside', 'serverside'
- ]
- )
- )
- )
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
- self.mutually_exclusive = [
- ['enabled_vlans', 'disabled_vlans']
- ]
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode,
- mutually_exclusive=spec.mutually_exclusive
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_vlan.py b/lib/ansible/modules/network/f5/bigip_vlan.py
deleted file mode 100644
index f48cb0a8ff..0000000000
--- a/lib/ansible/modules/network/f5/bigip_vlan.py
+++ /dev/null
@@ -1,967 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['stableinterface'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_vlan
-short_description: Manage VLANs on a BIG-IP system
-description:
- - Manage VLANs on a BIG-IP system
-version_added: 2.2
-options:
- description:
- description:
- - The description to give to the VLAN.
- type: str
- tagged_interfaces:
- description:
- - Specifies a list of tagged interfaces and trunks that you want to
- configure for the VLAN. Use tagged interfaces or trunks when
- you want to assign a single interface or trunk to multiple VLANs.
- - This parameter is mutually exclusive with the C(untagged_interfaces)
- and C(interfaces) parameters.
- type: list
- aliases:
- - tagged_interface
- untagged_interfaces:
- description:
- - Specifies a list of untagged interfaces and trunks that you want to
- configure for the VLAN.
- - This parameter is mutually exclusive with the C(tagged_interfaces)
- and C(interfaces) parameters.
- type: list
- aliases:
- - untagged_interface
- name:
- description:
- - The VLAN to manage. If the special VLAN C(ALL) is specified with
- the C(state) value of C(absent) then all VLANs will be removed.
- type: str
- required: True
- state:
- description:
- - The state of the VLAN on the system. When C(present), guarantees
- that the VLAN exists with the provided attributes. When C(absent),
- removes the VLAN from the system.
- type: str
- choices:
- - absent
- - present
- default: present
- tag:
- description:
- - Tag number for the VLAN. The tag number can be any integer between 1
- and 4094. The system automatically assigns a tag number if you do not
- specify a value.
- type: int
- mtu:
- description:
- - Specifies the maximum transmission unit (MTU) for traffic on this VLAN.
- When creating a new VLAN, if this parameter is not specified, the default
- value used will be C(1500).
- - This number must be between 576 to 9198.
- type: int
- version_added: 2.5
- cmp_hash:
- description:
- - Specifies how the traffic on the VLAN will be disaggregated. The value
- selected determines the traffic disaggregation method. You can choose to
- disaggregate traffic based on C(source-address) (the source IP address),
- C(destination-address) (destination IP address), or C(default), which
- specifies that the default CMP hash uses L4 ports.
- - When creating a new VLAN, if this parameter is not specified, the default
- of C(default) is used.
- type: str
- choices:
- - default
- - destination-address
- - source-address
- - dst-ip
- - src-ip
- - dest
- - destination
- - source
- - dst
- - src
- version_added: 2.5
- dag_tunnel:
- description:
- - Specifies how the disaggregator (DAG) distributes received tunnel-encapsulated
- packets to TMM instances. Select C(inner) to distribute packets based on information
- in inner headers. Select C(outer) to distribute packets based on information in
- outer headers without inspecting inner headers.
- - When creating a new VLAN, if this parameter is not specified, the default
- of C(outer) is used.
- - This parameter is not supported on Virtual Editions of BIG-IP.
- type: str
- choices:
- - inner
- - outer
- version_added: 2.5
- dag_round_robin:
- description:
- - Specifies whether some of the stateless traffic on the VLAN should be
- disaggregated in a round-robin order instead of using a static hash. The
- stateless traffic includes non-IP L2 traffic, ICMP, some UDP protocols,
- and so on.
- - When creating a new VLAN, if this parameter is not specified, the default
- of (no) is used.
- type: bool
- version_added: 2.5
- partition:
- description:
- - Device partition to manage resources on.
- type: str
- default: Common
- version_added: 2.5
- source_check:
- description:
- - When C(yes), specifies that the system verifies that the return route to an initial
- packet is the same VLAN from which the packet originated.
- - The system performs this verification only if the C(auto_last_hop) option is C(no).
- type: bool
- version_added: 2.8
- fail_safe:
- description:
- - When C(yes), specifies that the VLAN takes the specified C(fail_safe_action) if the
- system detects a loss of traffic on this VLAN's interfaces.
- type: bool
- version_added: 2.8
- fail_safe_timeout:
- description:
- - Specifies the number of seconds that a system can run without detecting network
- traffic on this VLAN before it takes the C(fail_safe_action).
- type: int
- version_added: 2.8
- fail_safe_action:
- description:
- - Specifies the action that the system takes when it does not detect any traffic on
- this VLAN, and the C(fail_safe_timeout) has expired.
- type: str
- choices:
- - reboot
- - restart-all
- - failover
- version_added: 2.8
- sflow_poll_interval:
- description:
- - Specifies the maximum interval in seconds between two pollings.
- type: int
- version_added: 2.8
- sflow_sampling_rate:
- description:
- - Specifies the ratio of packets observed to the samples generated.
- type: int
- version_added: 2.8
- interfaces:
- description:
- - Interfaces that you want added to the VLAN. This can include both tagged
- and untagged interfaces as the C(tagging) parameter specifies.
- - This parameter is mutually exclusive with the C(untagged_interfaces) and
- C(tagged_interfaces) parameters.
- suboptions:
- interface:
- description:
- - The name of the interface
- type: str
- tagging:
- description:
- - Whether the interface is C(tagged) or C(untagged).
- type: str
- choices:
- - tagged
- - untagged
- type: list
- version_added: 2.8
-notes:
- - Requires BIG-IP versions >= 12.0.0
-extends_documentation_fragment: f5
-author:
- - Tim Rupp (@caphrim007)
- - Wojciech Wypior (@wojtek0806)
-'''
-
-EXAMPLES = r'''
-- name: Create VLAN
- bigip_vlan:
- name: net1
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-
-- name: Set VLAN tag
- bigip_vlan:
- name: net1
- tag: 2345
- provider:
- user: admin
- password: secret
- server: lb.mydomain.com
- delegate_to: localhost
-
-- name: Add VLAN 2345 as tagged to interface 1.1
- bigip_vlan:
- tagged_interface: 1.1
- name: net1
- tag: 2345
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-
-- name: Add VLAN 1234 as tagged to interfaces 1.1 and 1.2
- bigip_vlan:
- tagged_interfaces:
- - 1.1
- - 1.2
- name: net1
- tag: 1234
- provider:
- user: admin
- password: secret
- server: lb.mydomain.com
- delegate_to: localhost
-'''
-
-RETURN = r'''
-description:
- description: The description set on the VLAN.
- returned: changed
- type: str
- sample: foo VLAN
-interfaces:
- description: Interfaces that the VLAN is assigned to.
- returned: changed
- type: list
- sample: ['1.1','1.2']
-partition:
- description: The partition that the VLAN was created on.
- returned: changed
- type: str
- sample: Common
-tag:
- description: The ID of the VLAN.
- returned: changed
- type: int
- sample: 2345
-cmp_hash:
- description: New traffic disaggregation method.
- returned: changed
- type: str
- sample: source-address
-dag_tunnel:
- description: The new DAG tunnel setting.
- returned: changed
- type: str
- sample: outer
-source_check:
- description: The new Source Check setting.
- returned: changed
- type: bool
- sample: yes
-fail_safe:
- description: The new Fail Safe setting.
- returned: changed
- type: bool
- sample: no
-fail_safe_timeout:
- description: The new Fail Safe Timeout setting.
- returned: changed
- type: int
- sample: 90
-fail_safe_action:
- description: The new Fail Safe Action setting.
- returned: changed
- type: str
- sample: reboot
-sflow_poll_interval:
- description: The new sFlow Polling Interval setting.
- returned: changed
- type: int
- sample: 10
-sflow_sampling_rate:
- description: The new sFlow Sampling Rate setting.
- returned: changed
- type: int
- sample: 20
-'''
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.basic import env_fallback
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import fq_name
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.common import transform_name
- from library.module_utils.network.f5.common import flatten_boolean
- from library.module_utils.network.f5.compare import compare_complex_list
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import fq_name
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.common import transform_name
- from ansible.module_utils.network.f5.common import flatten_boolean
- from ansible.module_utils.network.f5.compare import compare_complex_list
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'cmpHash': 'cmp_hash',
- 'dagTunnel': 'dag_tunnel',
- 'dagRoundRobin': 'dag_round_robin',
- 'interfacesReference': 'interfaces',
- 'sourceChecking': 'source_check',
- 'failsafe': 'fail_safe',
- 'failsafeAction': 'fail_safe_action',
- 'failsafeTimeout': 'fail_safe_timeout',
- }
-
- api_attributes = [
- 'description',
- 'interfaces',
- 'tag',
- 'mtu',
- 'cmpHash',
- 'dagTunnel',
- 'dagRoundRobin',
- 'sourceChecking',
- 'failsafe',
- 'failsafeAction',
- 'failsafeTimeout',
- 'sflow',
- ]
-
- updatables = [
- 'interfaces',
- 'tagged_interfaces',
- 'untagged_interfaces',
- 'tag',
- 'description',
- 'mtu',
- 'cmp_hash',
- 'dag_tunnel',
- 'dag_round_robin',
- 'source_check',
- 'fail_safe',
- 'fail_safe_action',
- 'fail_safe_timeout',
- 'sflow_poll_interval',
- 'sflow_sampling_rate',
- 'sflow',
- ]
-
- returnables = [
- 'description',
- 'partition',
- 'tag',
- 'interfaces',
- 'tagged_interfaces',
- 'untagged_interfaces',
- 'mtu',
- 'cmp_hash',
- 'dag_tunnel',
- 'dag_round_robin',
- 'source_check',
- 'fail_safe',
- 'fail_safe_action',
- 'fail_safe_timeout',
- 'sflow_poll_interval',
- 'sflow_sampling_rate',
- 'sflow',
- ]
-
- @property
- def source_check(self):
- return flatten_boolean(self._values['source_check'])
-
- @property
- def fail_safe(self):
- return flatten_boolean(self._values['fail_safe'])
-
-
-class ApiParameters(Parameters):
- @property
- def interfaces(self):
- if self._values['interfaces'] is None:
- return None
- if 'items' not in self._values['interfaces']:
- return None
- result = []
- for item in self._values['interfaces']['items']:
- name = item['name']
- if 'tagged' in item:
- tagged = item['tagged']
- result.append(dict(name=name, tagged=tagged))
- if 'untagged' in item:
- untagged = item['untagged']
- result.append(dict(name=name, untagged=untagged))
- return result
-
- @property
- def tagged_interfaces(self):
- if self.interfaces is None:
- return None
- result = [str(x['name']) for x in self.interfaces if 'tagged' in x and x['tagged'] is True]
- result = sorted(result)
- return result
-
- @property
- def untagged_interfaces(self):
- if self.interfaces is None:
- return None
- result = [str(x['name']) for x in self.interfaces if 'untagged' in x and x['untagged'] is True]
- result = sorted(result)
- return result
-
- @property
- def sflow_poll_interval(self):
- try:
- return self._values['sflow']['pollInterval']
- except (KeyError, TypeError):
- return None
-
- @property
- def sflow_sampling_rate(self):
- try:
- return self._values['sflow']['samplingRate']
- except (KeyError, TypeError):
- return None
-
-
-class ModuleParameters(Parameters):
- @property
- def interfaces(self):
- if self._values['interfaces'] is None:
- return None
- elif len(self._values['interfaces']) == 1 and self._values['interfaces'][0] in ['', 'none']:
- return ''
- result = []
- for item in self._values['interfaces']:
- if 'interface' not in item:
- raise F5ModuleError(
- "An 'interface' key must be provided when specifying a list of interfaces."
- )
- if 'tagging' not in item:
- raise F5ModuleError(
- "A 'tagging' key must be provided when specifying a list of interfaces."
- )
- name = str(item['interface'])
- tagging = item['tagging']
-
- if tagging == 'tagged':
- result.append(dict(name=name, tagged=True))
- else:
- result.append(dict(name=name, untagged=True))
- return result
-
- @property
- def untagged_interfaces(self):
- if self._values['untagged_interfaces'] is None:
- return None
- if self._values['untagged_interfaces'] is None:
- return None
- if len(self._values['untagged_interfaces']) == 1 and self._values['untagged_interfaces'][0] == '':
- return ''
- result = sorted([str(x) for x in self._values['untagged_interfaces']])
- return result
-
- @property
- def tagged_interfaces(self):
- if self._values['tagged_interfaces'] is None:
- return None
- if self._values['tagged_interfaces'] is None:
- return None
- if len(self._values['tagged_interfaces']) == 1 and self._values['tagged_interfaces'][0] == '':
- return ''
- result = sorted([str(x) for x in self._values['tagged_interfaces']])
- return result
-
- @property
- def mtu(self):
- if self._values['mtu'] is None:
- return None
- if int(self._values['mtu']) < 576 or int(self._values['mtu']) > 9198:
- raise F5ModuleError(
- "The mtu value must be between 576 - 9198"
- )
- return int(self._values['mtu'])
-
- @property
- def cmp_hash(self):
- if self._values['cmp_hash'] is None:
- return None
- if self._values['cmp_hash'] in ['source-address', 'src', 'src-ip', 'source']:
- return 'src-ip'
- if self._values['cmp_hash'] in ['destination-address', 'dest', 'dst-ip', 'destination', 'dst']:
- return 'dst-ip'
- else:
- return 'default'
-
- @property
- def dag_round_robin(self):
- if self._values['dag_round_robin'] is None:
- return None
- if self._values['dag_round_robin'] is True:
- return 'enabled'
- else:
- return 'disabled'
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class UsableChanges(Changes):
- @property
- def source_check(self):
- if self._values['source_check'] is None:
- return None
- if self._values['source_check'] == 'yes':
- return 'enabled'
- return 'disabled'
-
- @property
- def fail_safe(self):
- if self._values['fail_safe'] is None:
- return None
- if self._values['fail_safe'] == 'yes':
- return 'enabled'
- return 'disabled'
-
-
-class ReportableChanges(Changes):
- @property
- def tagged_interfaces(self):
- if self.interfaces is None:
- return None
- result = [str(x['name']) for x in self.interfaces if 'tagged' in x and x['tagged'] is True]
- result = sorted(result)
- return result
-
- @property
- def untagged_interfaces(self):
- if self.interfaces is None:
- return None
- result = [str(x['name']) for x in self.interfaces if 'untagged' in x and x['untagged'] is True]
- result = sorted(result)
- return result
-
- @property
- def source_check(self):
- return flatten_boolean(self._values['source_check'])
-
- @property
- def fail_safe(self):
- return flatten_boolean(self._values['fail_safe'])
-
- @property
- def sflow(self):
- return None
-
- @property
- def sflow_poll_interval(self):
- try:
- return self._values['sflow']['pollInterval']
- except (KeyError, TypeError):
- return None
-
- @property
- def sflow_sampling_rate(self):
- try:
- return self._values['sflow']['samplingRate']
- except (KeyError, TypeError):
- return None
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
- @property
- def interfaces(self):
- if self.want.interfaces is None:
- return None
- if self.have.interfaces is None and self.want.interfaces in ['', 'none']:
- return None
- if self.have.interfaces is not None and self.want.interfaces in ['', 'none']:
- return []
- if self.have.interfaces is None:
- return dict(
- interfaces=self.want.interfaces
- )
- return compare_complex_list(self.want.interfaces, self.have.interfaces)
-
- @property
- def untagged_interfaces(self):
- result = self.cmp_interfaces(self.want.untagged_interfaces, self.have.untagged_interfaces, False)
- return result
-
- @property
- def tagged_interfaces(self):
- result = self.cmp_interfaces(self.want.tagged_interfaces, self.have.tagged_interfaces, True)
- return result
-
- def cmp_interfaces(self, want, have, tagged):
- result = []
- if tagged:
- tag_key = 'tagged'
- else:
- tag_key = 'untagged'
- if want is None:
- return None
- elif want == '' and have is None:
- return None
- elif want == '' and len(have) > 0:
- pass
- elif not have:
- result = dict(
- interfaces=[{'name': x, tag_key: True} for x in want]
- )
- elif set(want) != set(have):
- result = dict(
- interfaces=[{'name': x, tag_key: True} for x in want]
- )
- else:
- return None
- return result
-
- @property
- def sflow(self):
- result = {}
- s = self.sflow_poll_interval
- if s:
- result.update(s)
- s = self.sflow_sampling_rate
- if s:
- result.update(s)
- if result:
- return dict(
- sflow=result
- )
-
- @property
- def sflow_poll_interval(self):
- if self.want.sflow_poll_interval is None:
- return None
- if self.want.sflow_poll_interval != self.have.sflow_poll_interval:
- return dict(
- pollInterval=self.want.sflow_poll_interval
- )
-
- @property
- def sflow_sampling_rate(self):
- if self.want.sflow_sampling_rate is None:
- return None
- if self.want.sflow_sampling_rate != self.have.sflow_sampling_rate:
- return dict(
- samplingRate=self.want.sflow_sampling_rate
- )
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(params=self.module.params)
- self.have = ApiParameters()
- self.changes = UsableChanges()
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def exec_module(self):
- changed = False
- result = dict()
- state = self.want.state
-
- if state == "present":
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def present(self):
- if self.exists():
- return self.update()
- else:
- return self.create()
-
- def absent(self):
- if self.exists():
- return self.remove()
- return False
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def update(self):
- self.have = self.read_current_from_device()
- if not self.should_update():
- return False
- if self.module.check_mode:
- return True
- self.update_on_device()
- return True
-
- def remove(self):
- if self.module.check_mode:
- return True
- self.remove_from_device()
- if self.exists():
- raise F5ModuleError("Failed to delete the VLAN")
- return True
-
- def create(self):
- self.have = ApiParameters()
- if self.want.mtu is None:
- self.want.update({'mtu': 1500})
- self._update_changed_options()
- if self.module.check_mode:
- return True
- self.create_on_device()
- return True
-
- def create_on_device(self):
- params = self.changes.api_params()
- params['name'] = self.want.name
- params['partition'] = self.want.partition
- uri = "https://{0}:{1}/mgmt/tm/net/vlan".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return response['selfLink']
-
- def update_on_device(self):
- params = self.changes.api_params()
- uri = "https://{0}:{1}/mgmt/tm/net/vlan/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def exists(self):
- uri = "https://{0}:{1}/mgmt/tm/net/vlan/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def remove_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/net/vlan/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- resp = self.client.api.delete(uri)
- if resp.status == 200:
- return True
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/net/vlan/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(self.want.partition, self.want.name)
- )
- query = '?expandSubcollections=true'
- resp = self.client.api.get(uri + query)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return ApiParameters(params=response)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- name=dict(
- required=True,
- ),
- tagged_interfaces=dict(
- type='list',
- aliases=['tagged_interface']
- ),
- untagged_interfaces=dict(
- type='list',
- aliases=['untagged_interface']
- ),
- interfaces=dict(
- type='list',
- options=dict(
- interface=dict(),
- tagging=dict(
- choices=['tagged', 'untagged']
- )
- )
- ),
- description=dict(),
- tag=dict(
- type='int'
- ),
- mtu=dict(type='int'),
- cmp_hash=dict(
- choices=[
- 'default',
- 'destination-address', 'dest', 'dst-ip', 'destination', 'dst',
- 'source-address', 'src', 'src-ip', 'source'
- ]
- ),
- dag_tunnel=dict(
- choices=['inner', 'outer']
- ),
- dag_round_robin=dict(type='bool'),
- source_check=dict(type='bool'),
- fail_safe=dict(type='bool'),
- fail_safe_timeout=dict(type='int'),
- fail_safe_action=dict(
- choices=['reboot', 'restart-all', 'failover']
- ),
- sflow_poll_interval=dict(type='int'),
- sflow_sampling_rate=dict(type='int'),
- state=dict(
- default='present',
- choices=['present', 'absent']
- ),
- partition=dict(
- default='Common',
- fallback=(env_fallback, ['F5_PARTITION'])
- ),
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
- self.mutually_exclusive = [
- ['tagged_interfaces', 'untagged_interfaces', 'interfaces'],
- ]
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode,
- mutually_exclusive=spec.mutually_exclusive
- )
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigip_wait.py b/lib/ansible/modules/network/f5/bigip_wait.py
deleted file mode 100644
index f84e800d22..0000000000
--- a/lib/ansible/modules/network/f5/bigip_wait.py
+++ /dev/null
@@ -1,346 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['stableinterface'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigip_wait
-short_description: Wait for a BIG-IP condition before continuing
-description:
- - You can wait for BIG-IP to be "ready". By "ready", we mean that BIG-IP is ready
- to accept configuration.
- - This module can take into account situations where the device is in the middle
- of rebooting due to a configuration change.
-version_added: 2.5
-options:
- timeout:
- description:
- - Maximum number of seconds to wait for.
- - When used without other conditions it is equivalent of just sleeping.
- - The default timeout is deliberately set to 2 hours because no individual
- REST API.
- type: int
- default: 7200
- delay:
- description:
- - Number of seconds to wait before starting to poll.
- type: int
- default: 0
- sleep:
- description:
- - Number of seconds to sleep between checks, before 2.3 this was hardcoded to 1 second.
- type: int
- default: 1
- msg:
- description:
- - This overrides the normal error message from a failure to meet the required conditions.
- type: str
-extends_documentation_fragment: f5
-author:
- - Tim Rupp (@caphrim007)
-'''
-
-EXAMPLES = r'''
-- name: Wait for BIG-IP to be ready to take configuration
- bigip_wait:
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-
-- name: Wait a maximum of 300 seconds for BIG-IP to be ready to take configuration
- bigip_wait:
- timeout: 300
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-
-- name: Wait for BIG-IP to be ready, don't start checking for 10 seconds
- bigip_wait:
- delay: 10
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-'''
-
-RETURN = r'''
-# only common fields returned
-'''
-
-import datetime
-import signal
-import time
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.module_utils.network.f5.bigip import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import f5_argument_spec
-except ImportError:
- from ansible.module_utils.network.f5.bigip import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import f5_argument_spec
-
-
-def hard_timeout(module, want, start):
- elapsed = datetime.datetime.utcnow() - start
- module.fail_json(
- msg=want.msg or "Timeout when waiting for BIG-IP", elapsed=elapsed.seconds
- )
-
-
-class Parameters(AnsibleF5Parameters):
- returnables = [
- 'elapsed'
- ]
-
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
- @property
- def delay(self):
- if self._values['delay'] is None:
- return None
- return int(self._values['delay'])
-
- @property
- def timeout(self):
- if self._values['timeout'] is None:
- return None
- return int(self._values['timeout'])
-
- @property
- def sleep(self):
- if self._values['sleep'] is None:
- return None
- return int(self._values['sleep'])
-
-
-class Changes(Parameters):
- pass
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.have = None
- self.want = Parameters(params=self.module.params)
- self.changes = Parameters()
-
- def exec_module(self):
- result = dict()
-
- changed = self.execute()
-
- changes = self.changes.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def _get_client_connection(self):
- return F5RestClient(**self.module.params)
-
- def execute(self):
- signal.signal(
- signal.SIGALRM,
- lambda sig, frame: hard_timeout(self.module, self.want, start)
- )
-
- # setup handler before scheduling signal, to eliminate a race
- signal.alarm(int(self.want.timeout))
-
- start = datetime.datetime.utcnow()
- if self.want.delay:
- time.sleep(float(self.want.delay))
- end = start + datetime.timedelta(seconds=int(self.want.timeout))
- while datetime.datetime.utcnow() < end:
- time.sleep(int(self.want.sleep))
- try:
- # The first test verifies that the REST API is available; this is done
- # by repeatedly trying to login to it.
- self.client = self._get_client_connection()
- if not self.client:
- continue
-
- if self._device_is_rebooting():
- # Wait for the reboot to happen and then start from the beginning
- # of the waiting.
- continue
-
- if self._is_mprov_running_on_device():
- self._wait_for_module_provisioning()
- break
- except Exception as ex:
- if 'Failed to validate the SSL' in str(ex):
- raise F5ModuleError(str(ex))
-
- # The types of exception's we're handling here are "REST API is not
- # ready" exceptions.
- #
- # For example,
- #
- # Typically caused by device starting up:
- #
- # icontrol.exceptions.iControlUnexpectedHTTPError: 404 Unexpected Error:
- # Not Found for uri: https://localhost:10443/mgmt/tm/sys/
- # icontrol.exceptions.iControlUnexpectedHTTPError: 503 Unexpected Error:
- # Service Temporarily Unavailable for uri: https://localhost:10443/mgmt/tm/sys/
- #
- #
- # Typically caused by a device being down
- #
- # requests.exceptions.SSLError: HTTPSConnectionPool(host='localhost', port=10443):
- # Max retries exceeded with url: /mgmt/tm/sys/ (Caused by SSLError(
- # SSLError("bad handshake: SysCallError(-1, 'Unexpected EOF')",),))
- #
- #
- # Typically caused by device still booting
- #
- # raise SSLError(e, request=request)\nrequests.exceptions.SSLError:
- # HTTPSConnectionPool(host='localhost', port=10443): Max retries
- # exceeded with url: /mgmt/shared/authn/login (Caused by
- # SSLError(SSLError(\"bad handshake: SysCallError(-1, 'Unexpected EOF')\",),)),
- continue
- else:
- elapsed = datetime.datetime.utcnow() - start
- self.module.fail_json(
- msg=self.want.msg or "Timeout when waiting for BIG-IP", elapsed=elapsed.seconds
- )
- elapsed = datetime.datetime.utcnow() - start
- self.changes.update({'elapsed': elapsed.seconds})
- return False
-
- def _device_is_rebooting(self):
- params = {
- "command": "run",
- "utilCmdArgs": '-c "runlevel"'
- }
- uri = "https://{0}:{1}/mgmt/tm/util/bash".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- if 'commandResult' in response and '6' in response['commandResult']:
- return True
- return False
-
- def _wait_for_module_provisioning(self):
- # To prevent things from running forever, the hack is to check
- # for mprov's status twice. If mprov is finished, then in most
- # cases (not ASM) the provisioning is probably ready.
- nops = 0
- # Sleep a little to let provisioning settle and begin properly
- time.sleep(5)
- while nops < 4:
- try:
- if not self._is_mprov_running_on_device():
- nops += 1
- else:
- nops = 0
- except Exception as ex:
- # This can be caused by restjavad restarting.
- pass
- time.sleep(10)
-
- def _is_mprov_running_on_device(self):
- params = {
- "command": "run",
- "utilCmdArgs": '-c "ps aux | grep \'[m]prov\'"'
- }
- uri = "https://{0}:{1}/mgmt/tm/util/bash".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- if 'commandResult' in response:
- return True
- return False
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- timeout=dict(default=7200, type='int'),
- delay=dict(default=0, type='int'),
- sleep=dict(default=1, type='int'),
- msg=dict()
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigiq_application_fasthttp.py b/lib/ansible/modules/network/f5/bigiq_application_fasthttp.py
deleted file mode 100644
index 3211b1abfc..0000000000
--- a/lib/ansible/modules/network/f5/bigiq_application_fasthttp.py
+++ /dev/null
@@ -1,756 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2018, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigiq_application_fasthttp
-short_description: Manages BIG-IQ FastHTTP applications
-description:
- - Manages BIG-IQ applications used for load balancing an HTTP-based application, speeding
- up connections and reducing the number of connections to the back-end server.
-version_added: 2.6
-options:
- name:
- description:
- - Name of the new application.
- type: str
- required: True
- description:
- description:
- - Description of the application.
- type: str
- servers:
- description:
- - A list of servers that the application is hosted on.
- - If you are familiar with other BIG-IP setting, you might also refer to this
- list as the list of pool members.
- - When creating a new application, at least one server is required.
- suboptions:
- address:
- description:
- - The IP address of the server.
- type: str
- required: True
- port:
- description:
- - The port of the server.
- - When creating a new application and specifying a server, if this parameter
- is not provided, the default of C(80) will be used.
- type: str
- default: 80
- type: list
- inbound_virtual:
- description:
- - Settings to configure the virtual which will receive the inbound connection.
- - This virtual will be used to host the HTTP endpoint of the application.
- suboptions:
- address:
- description:
- - Specifies destination IP address information to which the virtual server
- sends traffic.
- - This parameter is required when creating a new application.
- type: str
- required: True
- netmask:
- description:
- - Specifies the netmask to associate with the given C(destination).
- - This parameter is required when creating a new application.
- type: str
- required: True
- port:
- description:
- - The port that the virtual listens for connections on.
- - When creating a new application, if this parameter is not specified, the
- default value of C(80) will be used.
- type: str
- default: 80
- type: dict
- service_environment:
- description:
- - Specifies the name of service environment that the application will be
- deployed to.
- - When creating a new application, this parameter is required.
- - The service environment type will be discovered by this module automatically.
- Therefore, it is crucial that you maintain unique names for items in the
- different service environment types (at this time, SSGs and BIGIPs).
- type: str
- add_analytics:
- description:
- - Collects statistics of the BIG-IP that the application is deployed to.
- - This parameter is only relevant when specifying a C(service_environment) which
- is a BIG-IP; not an SSG.
- type: bool
- default: no
- state:
- description:
- - The state of the resource on the system.
- - When C(present), guarantees that the resource exists with the provided attributes.
- - When C(absent), removes the resource from the system.
- type: str
- choices:
- - absent
- - present
- default: present
- wait:
- description:
- - If the module should wait for the application to be created, deleted or updated.
- type: bool
- default: yes
-extends_documentation_fragment: f5
-notes:
- - This module does not support updating of your application (whether deployed or not).
- If you need to update the application, the recommended practice is to remove and
- re-create.
- - This module will not work on BIGIQ version 6.1.x or greater.
-author:
- - Tim Rupp (@caphrim007)
-'''
-
-EXAMPLES = r'''
-- name: Load balance an HTTP application on port 80 on BIG-IP
- bigiq_application_fasthttp:
- name: my-app
- description: Fast HTTP
- service_environment: my-ssg
- servers:
- - address: 1.2.3.4
- port: 8080
- - address: 5.6.7.8
- port: 8080
- inbound_virtual:
- name: foo
- address: 2.2.2.2
- netmask: 255.255.255.255
- port: 80
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- state: present
- delegate_to: localhost
-'''
-
-RETURN = r'''
-description:
- description: The new description of the application of the resource.
- returned: changed
- type: str
- sample: My application
-service_environment:
- description: The environment which the service was deployed to.
- returned: changed
- type: str
- sample: my-ssg1
-inbound_virtual_destination:
- description: The destination of the virtual that was created.
- returned: changed
- type: str
- sample: 6.7.8.9
-inbound_virtual_netmask:
- description: The network mask of the provided inbound destination.
- returned: changed
- type: str
- sample: 255.255.255.0
-inbound_virtual_port:
- description: The port the inbound virtual address listens on.
- returned: changed
- type: int
- sample: 80
-servers:
- description: List of servers, and their ports, that make up the application.
- type: complex
- returned: changed
- contains:
- address:
- description: The IP address of the server.
- returned: changed
- type: str
- sample: 2.3.4.5
- port:
- description: The port that the server listens on.
- returned: changed
- type: int
- sample: 8080
- sample: hash/dictionary of values
-'''
-
-import time
-
-from distutils.version import LooseVersion
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.module_utils.network.f5.bigiq import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.ipaddress import is_valid_ip
- from library.module_utils.network.f5.icontrol import bigiq_version
-except ImportError:
- from ansible.module_utils.network.f5.bigiq import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.ipaddress import is_valid_ip
- from ansible.module_utils.network.f5.icontrol import bigiq_version
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'templateReference': 'template_reference',
- 'subPath': 'sub_path',
- 'ssgReference': 'ssg_reference',
- 'configSetName': 'config_set_name',
- 'defaultDeviceReference': 'default_device_reference',
- 'addAnalytics': 'add_analytics'
- }
-
- api_attributes = [
- 'resources', 'description', 'configSetName', 'subPath', 'templateReference',
- 'ssgReference', 'defaultDeviceReference', 'addAnalytics'
- ]
-
- returnables = [
- 'resources', 'description', 'config_set_name', 'sub_path', 'template_reference',
- 'ssg_reference', 'default_device_reference', 'servers', 'inbound_virtual',
- 'add_analytics'
- ]
-
- updatables = [
- 'resources', 'description', 'config_set_name', 'sub_path', 'template_reference',
- 'ssg_reference', 'default_device_reference', 'servers', 'add_analytics'
- ]
-
-
-class ApiParameters(Parameters):
- pass
-
-
-class ModuleParameters(Parameters):
- @property
- def http_profile(self):
- return "profile_http"
-
- @property
- def config_set_name(self):
- return self.name
-
- @property
- def sub_path(self):
- return self.name
-
- @property
- def template_reference(self):
- filter = "name+eq+'Default-f5-fastHTTP-lb-template'"
- uri = "https://{0}:{1}/mgmt/cm/global/templates/?$filter={2}&$top=1&$select=selfLink".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- filter
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if resp.status == 200 and response['totalItems'] == 0:
- raise F5ModuleError(
- "No default HTTP LB template was found."
- )
- elif 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp._content)
-
- result = dict(
- link=response['items'][0]['selfLink']
- )
- return result
-
- @property
- def default_device_reference(self):
- if is_valid_ip(self.service_environment):
- # An IP address was specified
- filter = "address+eq+'{0}'".format(self.service_environment)
- else:
- # Assume a hostname was specified
- filter = "hostname+eq+'{0}'".format(self.service_environment)
-
- uri = "https://{0}:{1}/mgmt/shared/resolver/device-groups/cm-adccore-allbigipDevices/devices/?$filter={2}&$top=1&$select=selfLink".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- filter
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if resp.status == 200 and response['totalItems'] == 0:
- return None
- elif 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp._content)
- result = dict(
- link=response['items'][0]['selfLink']
- )
- return result
-
- @property
- def ssg_reference(self):
- filter = "name+eq+'{0}'".format(self.service_environment)
- uri = "https://{0}:{1}/mgmt/cm/cloud/service-scaling-groups/?$filter={2}&$top=1&$select=selfLink".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- filter
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if resp.status == 200 and response['totalItems'] == 0:
- return None
- elif 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp._content)
- result = dict(
- link=response['items'][0]['selfLink']
- )
- return result
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class UsableChanges(Changes):
- @property
- def resources(self):
- result = dict()
- result.update(self.http_profile)
- result.update(self.http_monitor)
- result.update(self.virtual)
- result.update(self.pool)
- result.update(self.nodes)
- return result
-
- @property
- def virtual(self):
- result = dict()
- result['ltm:virtual:0257bb9bb997'] = [
- dict(
- parameters=dict(
- name='virtual',
- destinationAddress=self.inbound_virtual['address'],
- mask=self.inbound_virtual['netmask'],
- destinationPort=self.inbound_virtual['port']
- ),
- subcollectionResources=self.profiles
- )
- ]
- return result
-
- @property
- def profiles(self):
- result = {
- 'profiles:53f9b3028d90': [
- dict(
- parameters=dict()
- )
- ],
- 'profiles:b2f39bda63fd': [
- dict(
- parameters=dict()
- )
- ]
- }
- return result
-
- @property
- def pool(self):
- result = dict()
- result['ltm:pool:f76ae78f1de6'] = [
- dict(
- parameters=dict(
- name='pool_0'
- ),
- subcollectionResources=self.pool_members
- )
- ]
- return result
-
- @property
- def pool_members(self):
- result = dict()
- result['members:15ad51f7229e'] = []
- for x in self.servers:
- member = dict(
- parameters=dict(
- port=x['port'],
- nodeReference=dict(
- link='#/resources/ltm:node:0783ce16685f/{0}'.format(x['address']),
- fullPath='# {0}'.format(x['address'])
- )
- )
- )
- result['members:15ad51f7229e'].append(member)
- return result
-
- @property
- def http_profile(self):
- result = dict()
- result['ltm:profile:http:b2f39bda63fd'] = [
- dict(
- parameters=dict(
- name='profile_http'
- )
- )
- ]
- return result
-
- @property
- def http_monitor(self):
- result = dict()
- result['ltm:monitor:http:cf6f6e7ae758'] = [
- dict(
- parameters=dict(
- name='monitor-http'
- )
- )
- ]
- return result
-
- @property
- def nodes(self):
- result = dict()
- result['ltm:node:0783ce16685f'] = []
- for x in self.servers:
- tmp = dict(
- parameters=dict(
- name=x['address'],
- address=x['address']
- )
- )
- result['ltm:node:0783ce16685f'].append(tmp)
- return result
-
- @property
- def node_addresses(self):
- result = [x['address'] for x in self.servers]
- return result
-
-
-class ReportableChanges(Changes):
- pass
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(params=self.module.params)
- self.want.client = self.client
- self.have = ApiParameters()
- self.changes = UsableChanges()
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = UsableChanges(params=changed)
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def check_bigiq_version(self):
- version = bigiq_version(self.client)
- if LooseVersion(version) >= LooseVersion('6.1.0'):
- raise F5ModuleError(
- 'Module supports only BIGIQ version 6.0.x or lower.'
- )
-
- def exec_module(self):
- self.check_bigiq_version()
- changed = False
- result = dict()
- state = self.want.state
-
- if state == "present":
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.client.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def present(self):
- if self.exists():
- return False
- else:
- return self.create()
-
- def exists(self):
- uri = "https://{0}:{1}/mgmt/ap/query/v1/tenants/default/reports/AllApplicationsList?$filter=name+eq+'{2}'".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- self.want.name
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if resp.status == 200 and 'result' in response and 'totalItems' in response['result'] and response['result']['totalItems'] == 0:
- return False
- return True
-
- def remove(self):
- if self.module.check_mode:
- return True
- self_link = self.remove_from_device()
- if self.want.wait:
- self.wait_for_apply_template_task(self_link)
- if self.exists():
- raise F5ModuleError("Failed to delete the resource.")
- return True
-
- def has_no_service_environment(self):
- if self.want.default_device_reference is None and self.want.ssg_reference is None:
- return True
- return False
-
- def create(self):
- if self.want.service_environment is None:
- raise F5ModuleError(
- "A 'service_environment' must be specified when creating a new application."
- )
- if self.want.servers is None:
- raise F5ModuleError(
- "At least one 'servers' item is needed when creating a new application."
- )
- if self.want.inbound_virtual is None:
- raise F5ModuleError(
- "An 'inbound_virtual' must be specified when creating a new application."
- )
- self._set_changed_options()
-
- if self.has_no_service_environment():
- raise F5ModuleError(
- "The specified 'service_environment' ({0}) was not found.".format(self.want.service_environment)
- )
-
- if self.module.check_mode:
- return True
- self_link = self.create_on_device()
- if self.want.wait:
- self.wait_for_apply_template_task(self_link)
- if not self.exists():
- raise F5ModuleError(
- "Failed to deploy application."
- )
- return True
-
- def create_on_device(self):
- params = self.changes.api_params()
- params['mode'] = 'CREATE'
-
- uri = 'https://{0}:{1}/mgmt/cm/global/tasks/apply-template'.format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
-
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp._content)
- return response['selfLink']
-
- def absent(self):
- if self.exists():
- return self.remove()
- return False
-
- def remove_from_device(self):
- params = dict(
- configSetName=self.want.name,
- mode='DELETE'
- )
- uri = 'https://{0}:{1}/mgmt/cm/global/tasks/apply-template'.format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
-
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp._content)
- return response['selfLink']
-
- def wait_for_apply_template_task(self, self_link):
- host = 'https://{0}:{1}'.format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- uri = self_link.replace('https://localhost', host)
-
- while True:
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if response['status'] == 'FINISHED' and response.get('currentStep', None) == 'DONE':
- return True
- elif 'errorMessage' in response:
- raise F5ModuleError(response['errorMessage'])
- time.sleep(5)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- name=dict(required=True),
- description=dict(),
- servers=dict(
- type='list',
- options=dict(
- address=dict(required=True),
- port=dict(default=80)
- )
- ),
- inbound_virtual=dict(
- type='dict',
- options=dict(
- address=dict(required=True),
- netmask=dict(required=True),
- port=dict(default=80)
- )
- ),
- service_environment=dict(),
- add_analytics=dict(type='bool', default='no'),
- state=dict(
- default='present',
- choices=['present', 'absent']
- ),
- wait=dict(type='bool', default='yes')
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigiq_application_fastl4_tcp.py b/lib/ansible/modules/network/f5/bigiq_application_fastl4_tcp.py
deleted file mode 100644
index d6207886cd..0000000000
--- a/lib/ansible/modules/network/f5/bigiq_application_fastl4_tcp.py
+++ /dev/null
@@ -1,702 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2018, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigiq_application_fastl4_tcp
-short_description: Manages BIG-IQ FastL4 TCP applications
-description:
- - Manages BIG-IQ applications used for load balancing a TCP-based application
- with a FastL4 profile.
-version_added: 2.6
-options:
- name:
- description:
- - Name of the new application.
- type: str
- required: True
- description:
- description:
- - Description of the application.
- type: str
- servers:
- description:
- - A list of servers that the application is hosted on.
- - If you are familiar with other BIG-IP setting, you might also refer to this
- list as the list of pool members.
- - When creating a new application, at least one server is required.
- suboptions:
- address:
- description:
- - The IP address of the server.
- type: str
- required: True
- port:
- description:
- - The port of the server.
- - When creating a new application and specifying a server, if this parameter
- is not provided, the default of C(8000) will be used.
- type: str
- default: 8000
- type: list
- inbound_virtual:
- description:
- - Settings to configure the virtual which will receive the inbound connection.
- type: dict
- suboptions:
- address:
- description:
- - Specifies destination IP address information to which the virtual server
- sends traffic.
- - This parameter is required when creating a new application.
- type: str
- required: True
- netmask:
- description:
- - Specifies the netmask to associate with the given C(destination).
- - This parameter is required when creating a new application.
- type: str
- required: True
- port:
- description:
- - The port that the virtual listens for connections on.
- - When creating a new application, if this parameter is not specified, the
- default value of C(8080) will be used.
- type: str
- default: 8080
- service_environment:
- description:
- - Specifies the name of service environment that the application will be
- deployed to.
- - When creating a new application, this parameter is required.
- - The service environment type will be discovered by this module automatically.
- Therefore, it is crucial that you maintain unique names for items in the
- different service environment types.
- - SSGs are not supported for this type of application.
- type: str
- add_analytics:
- description:
- - Collects statistics of the BIG-IP that the application is deployed to.
- - This parameter is only relevant when specifying a C(service_environment) which
- is a BIG-IP; not an SSG.
- type: bool
- default: no
- state:
- description:
- - The state of the resource on the system.
- - When C(present), guarantees that the resource exists with the provided attributes.
- - When C(absent), removes the resource from the system.
- type: str
- choices:
- - absent
- - present
- default: present
- wait:
- description:
- - If the module should wait for the application to be created, deleted or updated.
- type: bool
- default: yes
-extends_documentation_fragment: f5
-notes:
- - This module does not support updating of your application (whether deployed or not).
- If you need to update the application, the recommended practice is to remove and
- re-create.
- - This module will not work on BIGIQ version 6.1.x or greater.
-author:
- - Tim Rupp (@caphrim007)
-'''
-
-EXAMPLES = r'''
-- name: Load balance a TCP-based application with a FastL4 profile
- bigiq_application_fastl4_tcp:
- name: my-app
- description: My description
- service_environment: my-bigip-device
- servers:
- - address: 1.2.3.4
- port: 8080
- - address: 5.6.7.8
- port: 8080
- inbound_virtual:
- name: foo
- address: 2.2.2.2
- netmask: 255.255.255.255
- port: 443
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- state: present
- delegate_to: localhost
-'''
-
-RETURN = r'''
-description:
- description: The new description of the application of the resource.
- returned: changed
- type: str
- sample: My application
-service_environment:
- description: The environment which the service was deployed to.
- returned: changed
- type: str
- sample: my-ssg1
-inbound_virtual_destination:
- description: The destination of the virtual that was created.
- returned: changed
- type: str
- sample: 6.7.8.9
-inbound_virtual_netmask:
- description: The network mask of the provided inbound destination.
- returned: changed
- type: str
- sample: 255.255.255.0
-inbound_virtual_port:
- description: The port the inbound virtual address listens on.
- returned: changed
- type: int
- sample: 80
-servers:
- description: List of servers, and their ports, that make up the application.
- type: complex
- returned: changed
- contains:
- address:
- description: The IP address of the server.
- returned: changed
- type: str
- sample: 2.3.4.5
- port:
- description: The port that the server listens on.
- returned: changed
- type: int
- sample: 8080
- sample: hash/dictionary of values
-'''
-
-import time
-
-from distutils.version import LooseVersion
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.module_utils.network.f5.bigiq import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.ipaddress import is_valid_ip
- from library.module_utils.network.f5.icontrol import bigiq_version
-except ImportError:
- from ansible.module_utils.network.f5.bigiq import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.ipaddress import is_valid_ip
- from ansible.module_utils.network.f5.icontrol import bigiq_version
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'templateReference': 'template_reference',
- 'subPath': 'sub_path',
- 'configSetName': 'config_set_name',
- 'defaultDeviceReference': 'default_device_reference',
- 'addAnalytics': 'add_analytics'
- }
-
- api_attributes = [
- 'resources', 'description', 'configSetName', 'subPath', 'templateReference',
- 'defaultDeviceReference', 'addAnalytics'
- ]
-
- returnables = [
- 'resources', 'description', 'config_set_name', 'sub_path', 'template_reference',
- 'default_device_reference', 'servers', 'inbound_virtual', 'add_analytics'
- ]
-
- updatables = [
- 'resources', 'description', 'config_set_name', 'sub_path', 'template_reference',
- 'default_device_reference', 'servers', 'add_analytics'
- ]
-
-
-class ApiParameters(Parameters):
- pass
-
-
-class ModuleParameters(Parameters):
- @property
- def http_profile(self):
- return "profile_http"
-
- @property
- def config_set_name(self):
- return self.name
-
- @property
- def sub_path(self):
- return self.name
-
- @property
- def template_reference(self):
- filter = "name+eq+'Default-f5-FastL4-TCP-lb-template'"
- uri = "https://{0}:{1}/mgmt/cm/global/templates/?$filter={2}&$top=1&$select=selfLink".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- filter
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if resp.status == 200 and response['totalItems'] == 0:
- raise F5ModuleError(
- "No default HTTP LB template was found."
- )
- elif 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp._content)
-
- result = dict(
- link=response['items'][0]['selfLink']
- )
- return result
-
- @property
- def default_device_reference(self):
- if is_valid_ip(self.service_environment):
- # An IP address was specified
- filter = "address+eq+'{0}'".format(self.service_environment)
- else:
- # Assume a hostname was specified
- filter = "hostname+eq+'{0}'".format(self.service_environment)
-
- uri = "https://{0}:{1}/mgmt/shared/resolver/device-groups/cm-adccore-allbigipDevices/devices/?$filter={2}&$top=1&$select=selfLink".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- filter
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if resp.status == 200 and response['totalItems'] == 0:
- raise F5ModuleError(
- "The specified service_environment '{0}' was found.".format(self.service_environment)
- )
- elif 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp._content)
- result = dict(
- link=response['items'][0]['selfLink']
- )
- return result
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class UsableChanges(Changes):
- @property
- def resources(self):
- result = dict()
- result.update(self.tcp_monitor)
- result.update(self.virtual)
- result.update(self.pool)
- result.update(self.nodes)
- return result
-
- @property
- def virtual(self):
- result = dict()
- result['ltm:virtual:20e0ce0ae107'] = [
- dict(
- parameters=dict(
- name='virtual',
- destinationAddress=self.inbound_virtual['address'],
- mask=self.inbound_virtual['netmask'],
- destinationPort=self.inbound_virtual.get('port', 8080)
- ),
- subcollectionResources=self.profiles
- )
- ]
- return result
-
- @property
- def profiles(self):
- result = {
- 'profiles:53f9b3028d90': [
- dict(
- parameters=dict()
- )
- ]
- }
- return result
-
- @property
- def pool(self):
- result = dict()
- result['ltm:pool:9fa59a7bfc5c'] = [
- dict(
- parameters=dict(
- name='pool_0'
- ),
- subcollectionResources=self.pool_members
- )
- ]
- return result
-
- @property
- def pool_members(self):
- result = dict()
- result['members:3e91bd30bbfb'] = []
- for x in self.servers:
- member = dict(
- parameters=dict(
- port=x.get('port', 8000),
- nodeReference=dict(
- link='#/resources/ltm:node:3e91bd30bbfb/{0}'.format(x['address']),
- fullPath='# {0}'.format(x['address'])
- )
- )
- )
- result['members:3e91bd30bbfb'].append(member)
- return result
-
- @property
- def tcp_monitor(self):
- result = dict()
- result['ltm:monitor:tcp:f864a2efffea'] = [
- dict(
- parameters=dict(
- name='monitor-tcp'
- )
- )
- ]
- return result
-
- @property
- def nodes(self):
- result = dict()
- result['ltm:node:3e91bd30bbfb'] = []
- for x in self.servers:
- tmp = dict(
- parameters=dict(
- name=x['address'],
- address=x['address']
- )
- )
- result['ltm:node:3e91bd30bbfb'].append(tmp)
- return result
-
- @property
- def node_addresses(self):
- result = [x['address'] for x in self.servers]
- return result
-
-
-class ReportableChanges(Changes):
- pass
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(params=self.module.params)
- self.want.client = self.client
- self.have = ApiParameters()
- self.changes = UsableChanges()
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = UsableChanges(params=changed)
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def check_bigiq_version(self):
- version = bigiq_version(self.client)
- if LooseVersion(version) >= LooseVersion('6.1.0'):
- raise F5ModuleError(
- 'Module supports only BIGIQ version 6.0.x or lower.'
- )
-
- def exec_module(self):
- self.check_bigiq_version()
- changed = False
- result = dict()
- state = self.want.state
-
- if state == "present":
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.client.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def present(self):
- if self.exists():
- return False
- else:
- return self.create()
-
- def exists(self):
- uri = "https://{0}:{1}/mgmt/ap/query/v1/tenants/default/reports/AllApplicationsList?$filter=name+eq+'{2}'".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- self.want.name
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if resp.status == 200 and 'result' in response and 'totalItems' in response['result'] and response['result']['totalItems'] == 0:
- return False
- return True
-
- def remove(self):
- if self.module.check_mode:
- return True
- self_link = self.remove_from_device()
- if self.want.wait:
- self.wait_for_apply_template_task(self_link)
- if self.exists():
- raise F5ModuleError("Failed to delete the resource.")
- return True
-
- def create(self):
- if self.want.service_environment is None:
- raise F5ModuleError(
- "A 'service_environment' must be specified when creating a new application."
- )
- if self.want.servers is None:
- raise F5ModuleError(
- "At least one 'servers' item is needed when creating a new application."
- )
- if self.want.inbound_virtual is None:
- raise F5ModuleError(
- "An 'inbound_virtual' must be specified when creating a new application."
- )
- self._set_changed_options()
- if self.module.check_mode:
- return True
- self_link = self.create_on_device()
- if self.want.wait:
- self.wait_for_apply_template_task(self_link)
- if not self.exists():
- raise F5ModuleError(
- "Failed to deploy application."
- )
- return True
-
- def create_on_device(self):
- params = self.changes.api_params()
- params['mode'] = 'CREATE'
-
- uri = 'https://{0}:{1}/mgmt/cm/global/tasks/apply-template'.format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
-
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp._content)
- return response['selfLink']
-
- def absent(self):
- if self.exists():
- return self.remove()
- return False
-
- def remove_from_device(self):
- params = dict(
- configSetName=self.want.name,
- mode='DELETE'
- )
- uri = 'https://{0}:{1}/mgmt/cm/global/tasks/apply-template'.format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
-
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp._content)
- return response['selfLink']
-
- def wait_for_apply_template_task(self, self_link):
- host = 'https://{0}:{1}'.format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- uri = self_link.replace('https://localhost', host)
-
- while True:
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if response['status'] == 'FINISHED' and response.get('currentStep', None) == 'DONE':
- return True
- elif 'errorMessage' in response:
- raise F5ModuleError(response['errorMessage'])
- time.sleep(5)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- name=dict(required=True),
- description=dict(),
- servers=dict(
- type='list',
- options=dict(
- address=dict(required=True),
- port=dict(default=8000)
- )
- ),
- inbound_virtual=dict(
- type='dict',
- options=dict(
- address=dict(required=True),
- netmask=dict(required=True),
- port=dict(default=8080)
- )
- ),
- service_environment=dict(),
- add_analytics=dict(type='bool', default='no'),
- state=dict(
- default='present',
- choices=['present', 'absent']
- ),
- wait=dict(type='bool', default='yes')
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigiq_application_fastl4_udp.py b/lib/ansible/modules/network/f5/bigiq_application_fastl4_udp.py
deleted file mode 100644
index 7f0cc5fdd6..0000000000
--- a/lib/ansible/modules/network/f5/bigiq_application_fastl4_udp.py
+++ /dev/null
@@ -1,702 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2018, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigiq_application_fastl4_udp
-short_description: Manages BIG-IQ FastL4 UDP applications
-description:
- - Manages BIG-IQ applications used for load balancing a UDP-based application
- with a FastL4 profile.
-version_added: 2.6
-options:
- name:
- description:
- - Name of the new application.
- type: str
- required: True
- description:
- description:
- - Description of the application.
- type: str
- servers:
- description:
- - A list of servers that the application is hosted on.
- - If you are familiar with other BIG-IP setting, you might also refer to this
- list as the list of pool members.
- - When creating a new application, at least one server is required.
- suboptions:
- address:
- description:
- - The IP address of the server.
- type: str
- required: True
- port:
- description:
- - The port of the server.
- - When creating a new application and specifying a server, if this parameter
- is not provided, the default of C(8000) will be used.
- type: str
- default: 8000
- type: list
- inbound_virtual:
- description:
- - Settings to configure the virtual which will receive the inbound connection.
- type: dict
- suboptions:
- address:
- description:
- - Specifies destination IP address information to which the virtual server
- sends traffic.
- - This parameter is required when creating a new application.
- type: str
- required: True
- netmask:
- description:
- - Specifies the netmask to associate with the given C(destination).
- - This parameter is required when creating a new application.
- type: str
- required: True
- port:
- description:
- - The port that the virtual listens for connections on.
- - When creating a new application, if this parameter is not specified, the
- default value of C(53) will be used.
- type: str
- default: 53
- service_environment:
- description:
- - Specifies the name of service environment that the application will be
- deployed to.
- - When creating a new application, this parameter is required.
- - The service environment type will be discovered by this module automatically.
- Therefore, it is crucial that you maintain unique names for items in the
- different service environment types.
- - SSGs are not supported for this type of application.
- type: str
- add_analytics:
- description:
- - Collects statistics of the BIG-IP that the application is deployed to.
- - This parameter is only relevant when specifying a C(service_environment) which
- is a BIG-IP; not an SSG.
- type: bool
- default: no
- state:
- description:
- - The state of the resource on the system.
- - When C(present), guarantees that the resource exists with the provided attributes.
- - When C(absent), removes the resource from the system.
- type: str
- choices:
- - absent
- - present
- default: present
- wait:
- description:
- - If the module should wait for the application to be created, deleted or updated.
- type: bool
- default: yes
-extends_documentation_fragment: f5
-notes:
- - This module does not support updating of your application (whether deployed or not).
- If you need to update the application, the recommended practice is to remove and
- re-create.
- - This module will not work on BIGIQ version 6.1.x or greater.
-author:
- - Tim Rupp (@caphrim007)
-'''
-
-EXAMPLES = r'''
-- name: Load balance a UDP-based application with a FastL4 profile
- bigiq_application_fastl4_udp:
- name: my-app
- description: My description
- service_environment: my-bigip-device
- servers:
- - address: 1.2.3.4
- port: 8080
- - address: 5.6.7.8
- port: 8080
- inbound_virtual:
- name: foo
- address: 2.2.2.2
- netmask: 255.255.255.255
- port: 53
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- state: present
- delegate_to: localhost
-'''
-
-RETURN = r'''
-description:
- description: The new description of the application of the resource.
- returned: changed
- type: str
- sample: My application
-service_environment:
- description: The environment which the service was deployed to.
- returned: changed
- type: str
- sample: my-ssg1
-inbound_virtual_destination:
- description: The destination of the virtual that was created.
- returned: changed
- type: str
- sample: 6.7.8.9
-inbound_virtual_netmask:
- description: The network mask of the provided inbound destination.
- returned: changed
- type: str
- sample: 255.255.255.0
-inbound_virtual_port:
- description: The port the inbound virtual address listens on.
- returned: changed
- type: int
- sample: 80
-servers:
- description: List of servers, and their ports, that make up the application.
- type: complex
- returned: changed
- contains:
- address:
- description: The IP address of the server.
- returned: changed
- type: str
- sample: 2.3.4.5
- port:
- description: The port that the server listens on.
- returned: changed
- type: int
- sample: 8080
- sample: hash/dictionary of values
-'''
-
-import time
-
-from distutils.version import LooseVersion
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.module_utils.network.f5.bigiq import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.ipaddress import is_valid_ip
- from library.module_utils.network.f5.icontrol import bigiq_version
-except ImportError:
- from ansible.module_utils.network.f5.bigiq import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.ipaddress import is_valid_ip
- from ansible.module_utils.network.f5.icontrol import bigiq_version
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'templateReference': 'template_reference',
- 'subPath': 'sub_path',
- 'configSetName': 'config_set_name',
- 'defaultDeviceReference': 'default_device_reference',
- 'addAnalytics': 'add_analytics'
- }
-
- api_attributes = [
- 'resources', 'description', 'configSetName', 'subPath', 'templateReference',
- 'defaultDeviceReference', 'addAnalytics'
- ]
-
- returnables = [
- 'resources', 'description', 'config_set_name', 'sub_path', 'template_reference',
- 'default_device_reference', 'servers', 'inbound_virtual', 'add_analytics'
- ]
-
- updatables = [
- 'resources', 'description', 'config_set_name', 'sub_path', 'template_reference',
- 'default_device_reference', 'servers', 'add_analytics'
- ]
-
-
-class ApiParameters(Parameters):
- pass
-
-
-class ModuleParameters(Parameters):
- @property
- def http_profile(self):
- return "profile_http"
-
- @property
- def config_set_name(self):
- return self.name
-
- @property
- def sub_path(self):
- return self.name
-
- @property
- def template_reference(self):
- filter = "name+eq+'Default-f5-FastL4-UDP-lb-template'"
- uri = "https://{0}:{1}/mgmt/cm/global/templates/?$filter={2}&$top=1&$select=selfLink".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- filter
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if resp.status == 200 and response['totalItems'] == 0:
- raise F5ModuleError(
- "No default HTTP LB template was found."
- )
- elif 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp._content)
-
- result = dict(
- link=response['items'][0]['selfLink']
- )
- return result
-
- @property
- def default_device_reference(self):
- if is_valid_ip(self.service_environment):
- # An IP address was specified
- filter = "address+eq+'{0}'".format(self.service_environment)
- else:
- # Assume a hostname was specified
- filter = "hostname+eq+'{0}'".format(self.service_environment)
-
- uri = "https://{0}:{1}/mgmt/shared/resolver/device-groups/cm-adccore-allbigipDevices/devices/?$filter={2}&$top=1&$select=selfLink".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- filter
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if resp.status == 200 and response['totalItems'] == 0:
- raise F5ModuleError(
- "The specified service_environment '{0}' was found.".format(self.service_environment)
- )
- elif 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp._content)
- result = dict(
- link=response['items'][0]['selfLink']
- )
- return result
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class UsableChanges(Changes):
- @property
- def resources(self):
- result = dict()
- result.update(self.udp_monitor)
- result.update(self.virtual)
- result.update(self.pool)
- result.update(self.nodes)
- return result
-
- @property
- def virtual(self):
- result = dict()
- result['ltm:virtual:c2e739ba116f'] = [
- dict(
- parameters=dict(
- name='virtual',
- destinationAddress=self.inbound_virtual['address'],
- mask=self.inbound_virtual['netmask'],
- destinationPort=self.inbound_virtual.get('port', 53)
- ),
- subcollectionResources=self.profiles
- )
- ]
- return result
-
- @property
- def profiles(self):
- result = {
- 'profiles:53f9b3028d90': [
- dict(
- parameters=dict()
- )
- ]
- }
- return result
-
- @property
- def pool(self):
- result = dict()
- result['ltm:pool:e6879775458c'] = [
- dict(
- parameters=dict(
- name='pool_0'
- ),
- subcollectionResources=self.pool_members
- )
- ]
- return result
-
- @property
- def pool_members(self):
- result = dict()
- result['members:b19842fe713a'] = []
- for x in self.servers:
- member = dict(
- parameters=dict(
- port=x.get('port', 8000),
- nodeReference=dict(
- link='#/resources/ltm:node:b19842fe713a/{0}'.format(x['address']),
- fullPath='# {0}'.format(x['address'])
- )
- )
- )
- result['members:b19842fe713a'].append(member)
- return result
-
- @property
- def udp_monitor(self):
- result = dict()
- result['ltm:monitor:udp:22cdcfda0a40'] = [
- dict(
- parameters=dict(
- name='monitor-udp'
- )
- )
- ]
- return result
-
- @property
- def nodes(self):
- result = dict()
- result['ltm:node:b19842fe713a'] = []
- for x in self.servers:
- tmp = dict(
- parameters=dict(
- name=x['address'],
- address=x['address']
- )
- )
- result['ltm:node:b19842fe713a'].append(tmp)
- return result
-
- @property
- def node_addresses(self):
- result = [x['address'] for x in self.servers]
- return result
-
-
-class ReportableChanges(Changes):
- pass
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(params=self.module.params)
- self.want.client = self.client
- self.have = ApiParameters()
- self.changes = UsableChanges()
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = UsableChanges(params=changed)
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def check_bigiq_version(self):
- version = bigiq_version(self.client)
- if LooseVersion(version) >= LooseVersion('6.1.0'):
- raise F5ModuleError(
- 'Module supports only BIGIQ version 6.0.x or lower.'
- )
-
- def exec_module(self):
- self.check_bigiq_version()
- changed = False
- result = dict()
- state = self.want.state
-
- if state == "present":
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.client.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def present(self):
- if self.exists():
- return False
- else:
- return self.create()
-
- def exists(self):
- uri = "https://{0}:{1}/mgmt/ap/query/v1/tenants/default/reports/AllApplicationsList?$filter=name+eq+'{2}'".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- self.want.name
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if resp.status == 200 and 'result' in response and 'totalItems' in response['result'] and response['result']['totalItems'] == 0:
- return False
- return True
-
- def remove(self):
- if self.module.check_mode:
- return True
- self_link = self.remove_from_device()
- if self.want.wait:
- self.wait_for_apply_template_task(self_link)
- if self.exists():
- raise F5ModuleError("Failed to delete the resource.")
- return True
-
- def create(self):
- if self.want.service_environment is None:
- raise F5ModuleError(
- "A 'service_environment' must be specified when creating a new application."
- )
- if self.want.servers is None:
- raise F5ModuleError(
- "At least one 'servers' item is needed when creating a new application."
- )
- if self.want.inbound_virtual is None:
- raise F5ModuleError(
- "An 'inbound_virtual' must be specified when creating a new application."
- )
- self._set_changed_options()
- if self.module.check_mode:
- return True
- self_link = self.create_on_device()
- if self.want.wait:
- self.wait_for_apply_template_task(self_link)
- if not self.exists():
- raise F5ModuleError(
- "Failed to deploy application."
- )
- return True
-
- def create_on_device(self):
- params = self.changes.api_params()
- params['mode'] = 'CREATE'
-
- uri = 'https://{0}:{1}/mgmt/cm/global/tasks/apply-template'.format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
-
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp._content)
- return response['selfLink']
-
- def absent(self):
- if self.exists():
- return self.remove()
- return False
-
- def remove_from_device(self):
- params = dict(
- configSetName=self.want.name,
- mode='DELETE'
- )
- uri = 'https://{0}:{1}/mgmt/cm/global/tasks/apply-template'.format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
-
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp._content)
- return response['selfLink']
-
- def wait_for_apply_template_task(self, self_link):
- host = 'https://{0}:{1}'.format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- uri = self_link.replace('https://localhost', host)
-
- while True:
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if response['status'] == 'FINISHED' and response.get('currentStep', None) == 'DONE':
- return True
- elif 'errorMessage' in response:
- raise F5ModuleError(response['errorMessage'])
- time.sleep(5)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- name=dict(required=True),
- description=dict(),
- servers=dict(
- type='list',
- options=dict(
- address=dict(required=True),
- port=dict(default=8000)
- )
- ),
- inbound_virtual=dict(
- type='dict',
- options=dict(
- address=dict(required=True),
- netmask=dict(required=True),
- port=dict(default=53)
- )
- ),
- service_environment=dict(),
- add_analytics=dict(type='bool', default='no'),
- state=dict(
- default='present',
- choices=['present', 'absent']
- ),
- wait=dict(type='bool', default='yes')
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigiq_application_http.py b/lib/ansible/modules/network/f5/bigiq_application_http.py
deleted file mode 100644
index edb56145e7..0000000000
--- a/lib/ansible/modules/network/f5/bigiq_application_http.py
+++ /dev/null
@@ -1,755 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2018, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigiq_application_http
-short_description: Manages BIG-IQ HTTP applications
-description:
- - Manages BIG-IQ applications used for load balancing an HTTP application on
- port 80 on BIG-IP.
-version_added: 2.6
-options:
- name:
- description:
- - Name of the new application.
- type: str
- required: True
- description:
- description:
- - Description of the application.
- type: str
- servers:
- description:
- - A list of servers that the application is hosted on.
- - If you are familiar with other BIG-IP setting, you might also refer to this
- list as the list of pool members.
- - When creating a new application, at least one server is required.
- suboptions:
- address:
- description:
- - The IP address of the server.
- type: str
- required: True
- port:
- description:
- - The port of the server.
- - When creating a new application and specifying a server, if this parameter
- is not provided, the default of C(80) will be used.
- type: str
- default: 80
- type: list
- inbound_virtual:
- description:
- - Settings to configure the virtual which will receive the inbound connection.
- - This virtual will be used to host the HTTP endpoint of the application.
- suboptions:
- address:
- description:
- - Specifies destination IP address information to which the virtual server
- sends traffic.
- - This parameter is required when creating a new application.
- type: str
- required: True
- netmask:
- description:
- - Specifies the netmask to associate with the given C(destination).
- - This parameter is required when creating a new application.
- type: str
- required: True
- port:
- description:
- - The port that the virtual listens for connections on.
- - When creating a new application, if this parameter is not specified, the
- default value of C(80) will be used.
- type: str
- default: 80
- type: dict
- service_environment:
- description:
- - Specifies the name of service environment that the application will be
- deployed to.
- - When creating a new application, this parameter is required.
- - The service environment type will be discovered by this module automatically.
- Therefore, it is crucial that you maintain unique names for items in the
- different service environment types (at this time, SSGs and BIGIPs).
- type: str
- add_analytics:
- description:
- - Collects statistics of the BIG-IP that the application is deployed to.
- - This parameter is only relevant when specifying a C(service_environment) which
- is a BIG-IP; not an SSG.
- type: bool
- default: no
- state:
- description:
- - The state of the resource on the system.
- - When C(present), guarantees that the resource exists with the provided attributes.
- - When C(absent), removes the resource from the system.
- type: str
- choices:
- - absent
- - present
- default: present
- wait:
- description:
- - If the module should wait for the application to be created, deleted or updated.
- type: bool
- default: yes
-extends_documentation_fragment: f5
-notes:
- - This module does not support updating of your application (whether deployed or not).
- If you need to update the application, the recommended practice is to remove and
- re-create.
- - This module will not work on BIGIQ version 6.1.x or greater.
-author:
- - Tim Rupp (@caphrim007)
-'''
-
-EXAMPLES = r'''
-- name: Load balance an HTTP application on port 80 on BIG-IP
- bigiq_application_http:
- name: my-app
- description: Redirect HTTP to HTTPS
- service_environment: my-ssg
- servers:
- - address: 1.2.3.4
- port: 8080
- - address: 5.6.7.8
- port: 8080
- inbound_virtual:
- name: foo
- address: 2.2.2.2
- netmask: 255.255.255.255
- port: 443
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- state: present
- delegate_to: localhost
-'''
-
-RETURN = r'''
-description:
- description: The new description of the application of the resource.
- returned: changed
- type: str
- sample: My application
-service_environment:
- description: The environment which the service was deployed to.
- returned: changed
- type: str
- sample: my-ssg1
-inbound_virtual_destination:
- description: The destination of the virtual that was created.
- returned: changed
- type: str
- sample: 6.7.8.9
-inbound_virtual_netmask:
- description: The network mask of the provided inbound destination.
- returned: changed
- type: str
- sample: 255.255.255.0
-inbound_virtual_port:
- description: The port the inbound virtual address listens on.
- returned: changed
- type: int
- sample: 80
-servers:
- description: List of servers, and their ports, that make up the application.
- type: complex
- returned: changed
- contains:
- address:
- description: The IP address of the server.
- returned: changed
- type: str
- sample: 2.3.4.5
- port:
- description: The port that the server listens on.
- returned: changed
- type: int
- sample: 8080
- sample: hash/dictionary of values
-'''
-
-import time
-
-from distutils.version import LooseVersion
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.module_utils.network.f5.bigiq import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.ipaddress import is_valid_ip
- from library.module_utils.network.f5.icontrol import bigiq_version
-except ImportError:
- from ansible.module_utils.network.f5.bigiq import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.ipaddress import is_valid_ip
- from ansible.module_utils.network.f5.icontrol import bigiq_version
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'templateReference': 'template_reference',
- 'subPath': 'sub_path',
- 'ssgReference': 'ssg_reference',
- 'configSetName': 'config_set_name',
- 'defaultDeviceReference': 'default_device_reference',
- 'addAnalytics': 'add_analytics'
- }
-
- api_attributes = [
- 'resources', 'description', 'configSetName', 'subPath', 'templateReference',
- 'ssgReference', 'defaultDeviceReference', 'addAnalytics'
- ]
-
- returnables = [
- 'resources', 'description', 'config_set_name', 'sub_path', 'template_reference',
- 'ssg_reference', 'default_device_reference', 'servers', 'inbound_virtual',
- 'add_analytics'
- ]
-
- updatables = [
- 'resources', 'description', 'config_set_name', 'sub_path', 'template_reference',
- 'ssg_reference', 'default_device_reference', 'servers', 'add_analytics'
- ]
-
-
-class ApiParameters(Parameters):
- pass
-
-
-class ModuleParameters(Parameters):
- @property
- def http_profile(self):
- return "profile_http"
-
- @property
- def config_set_name(self):
- return self.name
-
- @property
- def sub_path(self):
- return self.name
-
- @property
- def template_reference(self):
- filter = "name+eq+'Default-f5-HTTP-lb-template'"
- uri = "https://{0}:{1}/mgmt/cm/global/templates/?$filter={2}&$top=1&$select=selfLink".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- filter
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if resp.status == 200 and response['totalItems'] == 0:
- raise F5ModuleError(
- "No default HTTP LB template was found."
- )
- elif 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp._content)
-
- result = dict(
- link=response['items'][0]['selfLink']
- )
- return result
-
- @property
- def default_device_reference(self):
- if is_valid_ip(self.service_environment):
- filter = "address+eq+'{0}'".format(self.service_environment)
- else:
- # Assume a hostname was specified
- filter = "hostname+eq+'{0}'".format(self.service_environment)
-
- uri = "https://{0}:{1}/mgmt/shared/resolver/device-groups/cm-adccore-allbigipDevices/devices/?$filter={2}&$top=1&$select=selfLink".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- filter
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if resp.status == 200 and response['totalItems'] == 0:
- return None
- elif 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp._content)
- result = dict(
- link=response['items'][0]['selfLink']
- )
- return result
-
- @property
- def ssg_reference(self):
- filter = "name+eq+'{0}'".format(self.service_environment)
- uri = "https://{0}:{1}/mgmt/cm/cloud/service-scaling-groups/?$filter={2}&$top=1&$select=selfLink".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- filter
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if resp.status == 200 and response['totalItems'] == 0:
- return None
- elif 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp._content)
- result = dict(
- link=response['items'][0]['selfLink']
- )
- return result
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class UsableChanges(Changes):
- @property
- def resources(self):
- result = dict()
- result.update(self.http_profile)
- result.update(self.http_monitor)
- result.update(self.virtual)
- result.update(self.pool)
- result.update(self.nodes)
- return result
-
- @property
- def virtual(self):
- result = dict()
- result['ltm:virtual::b487671f29ba'] = [
- dict(
- parameters=dict(
- name='virtual',
- destinationAddress=self.inbound_virtual['address'],
- mask=self.inbound_virtual['netmask'],
- destinationPort=self.inbound_virtual.get('port', 80)
- ),
- subcollectionResources=self.profiles
- )
- ]
- return result
-
- @property
- def profiles(self):
- result = {
- 'profiles:9448fe71611e': [
- dict(
- parameters=dict()
- )
- ],
- 'profiles:03a4950ab656': [
- dict(
- parameters=dict()
- )
- ]
- }
- return result
-
- @property
- def pool(self):
- result = dict()
- result['ltm:pool:9a593d17495b'] = [
- dict(
- parameters=dict(
- name='pool_0'
- ),
- subcollectionResources=self.pool_members
- )
- ]
- return result
-
- @property
- def pool_members(self):
- result = dict()
- result['members:5109c66dfbac'] = []
- for x in self.servers:
- member = dict(
- parameters=dict(
- port=x.get('port', 80),
- nodeReference=dict(
- link='#/resources/ltm:node:9e76a6323321/{0}'.format(x['address']),
- fullPath='# {0}'.format(x['address'])
- )
- )
- )
- result['members:5109c66dfbac'].append(member)
- return result
-
- @property
- def http_profile(self):
- result = dict()
- result['ltm:profile:http:03a4950ab656'] = [
- dict(
- parameters=dict(
- name='profile_http'
- )
- )
- ]
- return result
-
- @property
- def http_monitor(self):
- result = dict()
- result['ltm:monitor:http:ea4346e49cdf'] = [
- dict(
- parameters=dict(
- name='monitor-http'
- )
- )
- ]
- return result
-
- @property
- def nodes(self):
- result = dict()
- result['ltm:node:9e76a6323321'] = []
- for x in self.servers:
- tmp = dict(
- parameters=dict(
- name=x['address'],
- address=x['address']
- )
- )
- result['ltm:node:9e76a6323321'].append(tmp)
- return result
-
- @property
- def node_addresses(self):
- result = [x['address'] for x in self.servers]
- return result
-
-
-class ReportableChanges(Changes):
- pass
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(params=self.module.params)
- self.want.client = self.client
- self.have = ApiParameters()
- self.changes = UsableChanges()
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = UsableChanges(params=changed)
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def check_bigiq_version(self):
- version = bigiq_version(self.client)
- if LooseVersion(version) >= LooseVersion('6.1.0'):
- raise F5ModuleError(
- 'Module supports only BIGIQ version 6.0.x or lower.'
- )
-
- def exec_module(self):
- self.check_bigiq_version()
- changed = False
- result = dict()
- state = self.want.state
-
- if state == "present":
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.client.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def present(self):
- if self.exists():
- return False
- else:
- return self.create()
-
- def exists(self):
- uri = "https://{0}:{1}/mgmt/ap/query/v1/tenants/default/reports/AllApplicationsList?$filter=name+eq+'{2}'".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- self.want.name
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if resp.status == 200 and 'result' in response and 'totalItems' in response['result'] and response['result']['totalItems'] == 0:
- return False
- return True
-
- def remove(self):
- if self.module.check_mode:
- return True
- self_link = self.remove_from_device()
- if self.want.wait:
- self.wait_for_apply_template_task(self_link)
- if self.exists():
- raise F5ModuleError("Failed to delete the resource.")
- return True
-
- def has_no_service_environment(self):
- if self.want.default_device_reference is None and self.want.ssg_reference is None:
- return True
- return False
-
- def create(self):
- if self.want.service_environment is None:
- raise F5ModuleError(
- "A 'service_environment' must be specified when creating a new application."
- )
- if self.want.servers is None:
- raise F5ModuleError(
- "At least one 'servers' item is needed when creating a new application."
- )
- if self.want.inbound_virtual is None:
- raise F5ModuleError(
- "An 'inbound_virtual' must be specified when creating a new application."
- )
- self._set_changed_options()
-
- if self.has_no_service_environment():
- raise F5ModuleError(
- "The specified 'service_environment' ({0}) was not found.".format(self.want.service_environment)
- )
-
- if self.module.check_mode:
- return True
- self_link = self.create_on_device()
- if self.want.wait:
- self.wait_for_apply_template_task(self_link)
- if not self.exists():
- raise F5ModuleError(
- "Failed to deploy application."
- )
- return True
-
- def create_on_device(self):
- params = self.changes.api_params()
- params['mode'] = 'CREATE'
-
- uri = 'https://{0}:{1}/mgmt/cm/global/tasks/apply-template'.format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
-
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp._content)
- return response['selfLink']
-
- def absent(self):
- if self.exists():
- return self.remove()
- return False
-
- def remove_from_device(self):
- params = dict(
- configSetName=self.want.name,
- mode='DELETE'
- )
- uri = 'https://{0}:{1}/mgmt/cm/global/tasks/apply-template'.format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
-
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp._content)
- return response['selfLink']
-
- def wait_for_apply_template_task(self, self_link):
- host = 'https://{0}:{1}'.format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- uri = self_link.replace('https://localhost', host)
-
- while True:
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if response['status'] == 'FINISHED' and response.get('currentStep', None) == 'DONE':
- return True
- elif 'errorMessage' in response:
- raise F5ModuleError(response['errorMessage'])
- time.sleep(5)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- name=dict(required=True),
- description=dict(),
- servers=dict(
- type='list',
- options=dict(
- address=dict(required=True),
- port=dict(default=80)
- )
- ),
- inbound_virtual=dict(
- type='dict',
- options=dict(
- address=dict(required=True),
- netmask=dict(required=True),
- port=dict(default=80)
- )
- ),
- service_environment=dict(),
- add_analytics=dict(type='bool', default='no'),
- state=dict(
- default='present',
- choices=['present', 'absent']
- ),
- wait=dict(type='bool', default='yes')
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigiq_application_https_offload.py b/lib/ansible/modules/network/f5/bigiq_application_https_offload.py
deleted file mode 100644
index 6dff4a59be..0000000000
--- a/lib/ansible/modules/network/f5/bigiq_application_https_offload.py
+++ /dev/null
@@ -1,1011 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2018, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigiq_application_https_offload
-short_description: Manages BIG-IQ HTTPS offload applications
-description:
- - Manages BIG-IQ applications used for load balancing an HTTPS application on
- port 443 with SSL offloading on BIG-IP.
-version_added: 2.6
-options:
- name:
- description:
- - Name of the new application.
- type: str
- required: True
- description:
- description:
- - Description of the application.
- type: str
- servers:
- description:
- - A list of servers that the application is hosted on.
- - If you are familiar with other BIG-IP setting, you might also refer to this
- list as the list of pool members.
- - When creating a new application, at least one server is required.
- suboptions:
- address:
- description:
- - The IP address of the server.
- type: str
- port:
- description:
- - The port of the server.
- type: str
- default: 80
- type: list
- inbound_virtual:
- description:
- - Settings to configure the virtual which will receive the inbound connection.
- - This virtual will be used to host the HTTPS endpoint of the application.
- - Traffic destined to the C(redirect_virtual) will be offloaded to this
- parameter to ensure that proper redirection from insecure, to secure, occurs.
- suboptions:
- address:
- description:
- - Specifies destination IP address information to which the virtual server
- sends traffic.
- - This parameter is required when creating a new application.
- type: str
- netmask:
- description:
- - Specifies the netmask to associate with the given C(address).
- - This parameter is required when creating a new application.
- type: str
- port:
- description:
- - The port that the virtual listens for connections on.
- - When creating a new application, if this parameter is not specified, the
- default value of C(443) will be used.
- type: str
- default: 443
- type: dict
- redirect_virtual:
- description:
- - Settings to configure the virtual which will receive the connection to be
- redirected.
- - This virtual will be used to host the HTTP endpoint of the application.
- - Traffic destined to this parameter will be offloaded to the
- C(inbound_virtual) parameter to ensure that proper redirection from insecure,
- to secure, occurs.
- suboptions:
- address:
- description:
- - Specifies destination IP address information to which the virtual server
- sends traffic.
- - This parameter is required when creating a new application.
- type: str
- netmask:
- description:
- - Specifies the netmask to associate with the given C(address).
- - This parameter is required when creating a new application.
- type: str
- port:
- description:
- - The port that the virtual listens for connections on.
- - When creating a new application, if this parameter is not specified, the
- default value of C(80) will be used.
- type: str
- default: 80
- type: dict
- client_ssl_profile:
- description:
- - Specifies the SSL profile for managing client-side SSL traffic.
- suboptions:
- name:
- description:
- - The name of the client SSL profile to created and used.
- - When creating a new application, if this value is not specified, the
- default value of C(clientssl) will be used.
- cert_key_chain:
- description:
- - One or more certificates and keys to associate with the SSL profile.
- - This option is always a list. The keys in the list dictate the details
- of the client/key/chain/passphrase combination.
- - Note that BIG-IPs can only have one of each type of each certificate/key
- type. This means that you can only have one RSA, one DSA, and one ECDSA
- per profile.
- - If you attempt to assign two RSA, DSA, or ECDSA certificate/key combo,
- the device will reject this.
- - This list is a complex list that specifies a number of keys.
- - When creating a new profile, if this parameter is not specified, the
- default value of C(inherit) will be used.
- suboptions:
- cert:
- description:
- - Specifies a cert name for use.
- type: str
- required: True
- key:
- description:
- - Specifies a key name.
- type: str
- required: True
- chain:
- description:
- - Specifies a certificate chain that is relevant to the certificate and
- key mentioned earlier.
- - This key is optional.
- type: str
- passphrase:
- description:
- - Contains the passphrase of the key file, should it require one.
- - Passphrases are encrypted on the remote BIG-IP device.
- type: str
- type: raw
- type: dict
- service_environment:
- description:
- - Specifies the name of service environment or the hostname of the BIG-IP that
- the application will be deployed to.
- - When creating a new application, this parameter is required.
- type: str
- add_analytics:
- description:
- - Collects statistics of the BIG-IP that the application is deployed to.
- - This parameter is only relevant when specifying a C(service_environment) which
- is a BIG-IP; not an SSG.
- type: bool
- default: no
- state:
- description:
- - The state of the resource on the system.
- - When C(present), guarantees that the resource exists with the provided attributes.
- - When C(absent), removes the resource from the system.
- type: str
- choices:
- - absent
- - present
- default: present
- wait:
- description:
- - If the module should wait for the application to be created, deleted or updated.
- type: bool
- default: yes
-extends_documentation_fragment: f5
-notes:
- - This module will not work on BIGIQ version 6.1.x or greater.
-author:
- - Tim Rupp (@caphrim007)
-'''
-
-EXAMPLES = r'''
-- name: Load balance an HTTPS application on port 443 with SSL offloading on BIG-IP
- bigiq_application_https_offload:
- name: my-app
- description: Redirect HTTP to HTTPS
- service_environment: my-ssg
- servers:
- - address: 1.2.3.4
- port: 8080
- - address: 5.6.7.8
- port: 8080
- inbound_virtual:
- address: 2.2.2.2
- netmask: 255.255.255.255
- port: 443
- redirect_virtual:
- address: 2.2.2.2
- netmask: 255.255.255.255
- port: 80
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- state: present
- delegate_to: localhost
-'''
-
-RETURN = r'''
-description:
- description: The new description of the application of the resource.
- returned: changed
- type: str
- sample: My application
-service_environment:
- description: The environment which the service was deployed to.
- returned: changed
- type: str
- sample: my-ssg1
-inbound_virtual_destination:
- description: The destination of the virtual that was created.
- returned: changed
- type: str
- sample: 6.7.8.9
-inbound_virtual_netmask:
- description: The network mask of the provided inbound destination.
- returned: changed
- type: str
- sample: 255.255.255.0
-inbound_virtual_port:
- description: The port the inbound virtual address listens on.
- returned: changed
- type: int
- sample: 80
-servers:
- description: List of servers, and their ports, that make up the application.
- type: complex
- returned: changed
- contains:
- address:
- description: The IP address of the server.
- returned: changed
- type: str
- sample: 2.3.4.5
- port:
- description: The port that the server listens on.
- returned: changed
- type: int
- sample: 8080
- sample: hash/dictionary of values
-'''
-
-import time
-
-from distutils.version import LooseVersion
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.six import string_types
-
-try:
- from library.module_utils.network.f5.bigiq import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.common import fq_name
- from library.module_utils.network.f5.ipaddress import is_valid_ip
- from library.module_utils.network.f5.icontrol import bigiq_version
-except ImportError:
- from ansible.module_utils.network.f5.bigiq import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.common import fq_name
- from ansible.module_utils.network.f5.ipaddress import is_valid_ip
- from ansible.module_utils.network.f5.icontrol import bigiq_version
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'templateReference': 'template_reference',
- 'subPath': 'sub_path',
- 'ssgReference': 'ssg_reference',
- 'configSetName': 'config_set_name',
- 'defaultDeviceReference': 'default_device_reference',
- 'addAnalytics': 'add_analytics'
- }
-
- api_attributes = [
- 'resources', 'description', 'configSetName', 'subPath', 'templateReference',
- 'ssgReference', 'defaultDeviceReference', 'addAnalytics'
- ]
-
- returnables = [
- 'resources', 'description', 'config_set_name', 'sub_path', 'template_reference',
- 'ssg_reference', 'default_device_reference', 'servers', 'inbound_virtual',
- 'redirect_virtual', 'client_ssl_profile', 'add_analytics'
- ]
-
- updatables = [
- 'resources', 'description', 'config_set_name', 'sub_path', 'template_reference',
- 'ssg_reference', 'default_device_reference', 'servers', 'add_analytics'
- ]
-
-
-class ApiParameters(Parameters):
- pass
-
-
-class ModuleParameters(Parameters):
- @property
- def http_profile(self):
- return "profile_http"
-
- @property
- def config_set_name(self):
- return self.name
-
- @property
- def sub_path(self):
- return self.name
-
- @property
- def template_reference(self):
- filter = "name+eq+'Default-f5-HTTPS-offload-lb-template'"
- uri = "https://{0}:{1}/mgmt/cm/global/templates/?$filter={2}&$top=1&$select=selfLink".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- filter
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if resp.status == 200 and response['totalItems'] == 0:
- raise F5ModuleError(
- "No default HTTP LB template was found."
- )
- elif 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp._content)
-
- result = dict(
- link=response['items'][0]['selfLink']
- )
- return result
-
- @property
- def default_device_reference(self):
- if is_valid_ip(self.service_environment):
- # An IP address was specified
- filter = "address+eq+'{0}'".format(self.service_environment)
- else:
- # Assume a hostname was specified
- filter = "hostname+eq+'{0}'".format(self.service_environment)
-
- uri = "https://{0}:{1}/mgmt/shared/resolver/device-groups/cm-adccore-allbigipDevices/devices/?$filter={2}&$top=1&$select=selfLink".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- filter
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if resp.status == 200 and response['totalItems'] == 0:
- return None
- elif 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp._content)
- result = dict(
- link=response['items'][0]['selfLink']
- )
- return result
-
- @property
- def ssg_reference(self):
- filter = "name+eq+'{0}'".format(self.service_environment)
- uri = "https://{0}:{1}/mgmt/cm/cloud/service-scaling-groups/?$filter={2}&$top=1&$select=selfLink".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- filter
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if resp.status == 200 and response['totalItems'] == 0:
- return None
- elif 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp._content)
- result = dict(
- link=response['items'][0]['selfLink']
- )
- return result
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class UsableChanges(Changes):
- @property
- def resources(self):
- result = dict()
- result.update(self.http_profile)
- result.update(self.http_monitor)
- result.update(self.inbound_virtual_server)
- result.update(self.redirect_virtual_server)
- result.update(self.pool)
- result.update(self.nodes)
- result.update(self.ssl_profile)
- return result
-
- @property
- def inbound_virtual_server(self):
- result = dict()
- result['ltm:virtual:7a5f7da91996'] = [
- dict(
- parameters=dict(
- name='default_vs',
- destinationAddress=self.inbound_virtual['address'],
- mask=self.inbound_virtual['netmask'],
- destinationPort=self.inbound_virtual['port']
- ),
- subcollectionResources=self.inbound_profiles
- )
- ]
- return result
-
- @property
- def inbound_profiles(self):
- result = {
- 'profiles:14c995c33411': [
- dict(
- parameters=dict()
- )
- ],
- 'profiles:8ba4bb101701': [
- dict(
- parameters=dict()
- )
- ],
- 'profiles:9448fe71611e': [
- dict(
- parameters=dict()
- )
- ]
- }
- return result
-
- @property
- def redirect_virtual_server(self):
- result = dict()
- result['ltm:virtual:40e8c4a6f542'] = [
- dict(
- parameters=dict(
- name='default_redirect_vs',
- destinationAddress=self.redirect_virtual['address'],
- mask=self.redirect_virtual['netmask'],
- destinationPort=self.redirect_virtual['port']
- ),
- subcollectionResources=self.redirect_profiles
- )
- ]
- return result
-
- @property
- def redirect_profiles(self):
- result = {
- 'profiles:8ba4bb101701': [
- dict(
- parameters=dict()
- )
- ],
- 'profiles:9448fe71611e': [
- dict(
- parameters=dict()
- )
- ]
- }
- return result
-
- @property
- def pool(self):
- result = dict()
- result['ltm:pool:be70d46c6d73'] = [
- dict(
- parameters=dict(
- name='pool_0'
- ),
- subcollectionResources=self.pool_members
- )
- ]
- return result
-
- @property
- def pool_members(self):
- result = dict()
- result['members:dec6d24dc625'] = []
- for x in self.servers:
- member = dict(
- parameters=dict(
- port=x['port'],
- nodeReference=dict(
- link='#/resources/ltm:node:45391b57b104/{0}'.format(x['address']),
- fullPath='# {0}'.format(x['address'])
- )
- )
- )
- result['members:dec6d24dc625'].append(member)
- return result
-
- @property
- def http_profile(self):
- result = dict()
- result['ltm:profile:http:8ba4bb101701'] = [
- dict(
- parameters=dict(
- name='profile_http'
- )
- )
- ]
- return result
-
- @property
- def http_monitor(self):
- result = dict()
- result['ltm:monitor:http:fd07629373b0'] = [
- dict(
- parameters=dict(
- name='monitor-http'
- )
- )
- ]
- return result
-
- @property
- def nodes(self):
- result = dict()
- result['ltm:node:45391b57b104'] = []
- for x in self.servers:
- tmp = dict(
- parameters=dict(
- name=x['address'],
- address=x['address']
- )
- )
- result['ltm:node:45391b57b104'].append(tmp)
- return result
-
- @property
- def node_addresses(self):
- result = [x['address'] for x in self.servers]
- return result
-
- @property
- def ssl_profile(self):
- result = dict()
- result['ltm:profile:client-ssl:14c995c33411'] = [
- dict(
- parameters=dict(
- name='clientssl',
- certKeyChain=self.cert_key_chains
- )
- )
- ]
- return result
-
- def _get_cert_references(self):
- result = dict()
- uri = "https://{0}:{1}/mgmt/cm/adc-core/working-config/sys/file/ssl-cert/".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
-
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- for cert in response['items']:
- key = fq_name(cert['partition'], cert['name'])
- result[key] = cert['selfLink']
- return result
-
- def _get_key_references(self):
- result = dict()
- uri = "https://{0}:{1}/mgmt/cm/adc-core/working-config/sys/file/ssl-key/".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- for cert in response['items']:
- key = fq_name(cert['partition'], cert['name'])
- result[key] = cert['selfLink']
- return result
-
- @property
- def cert_key_chains(self):
- result = []
- if self.client_ssl_profile is None:
- return None
- if 'cert_key_chain' not in self.client_ssl_profile:
- return None
-
- kc = self.client_ssl_profile['cert_key_chain']
- if isinstance(kc, string_types) and kc != 'inherit':
- raise F5ModuleError(
- "Only the 'inherit' setting is available when 'cert_key_chain' is a string."
- )
-
- if not isinstance(kc, list):
- raise F5ModuleError(
- "The value of 'cert_key_chain' is not one of the supported types."
- )
-
- cert_references = self._get_cert_references()
- key_references = self._get_key_references()
-
- for idx, x in enumerate(kc):
- tmp = dict(
- name='clientssl{0}'.format(idx)
- )
- if 'cert' not in x:
- raise F5ModuleError(
- "A 'cert' option is required when specifying the 'cert_key_chain' parameter.."
- )
- elif x['cert'] not in cert_references:
- raise F5ModuleError(
- "The specified 'cert' was not found. Did you specify its full path?"
- )
- else:
- key = x['cert']
- tmp['certReference'] = dict(
- link=cert_references[key],
- fullPath=key
- )
-
- if 'key' not in x:
- raise F5ModuleError(
- "A 'key' option is required when specifying the 'cert_key_chain' parameter.."
- )
- elif x['key'] not in key_references:
- raise F5ModuleError(
- "The specified 'key' was not found. Did you specify its full path?"
- )
- else:
- key = x['key']
- tmp['keyReference'] = dict(
- link=key_references[key],
- fullPath=key
- )
-
- if 'chain' in x and x['chain'] not in cert_references:
- raise F5ModuleError(
- "The specified 'key' was not found. Did you specify its full path?"
- )
- else:
- key = x['chain']
- tmp['chainReference'] = dict(
- link=cert_references[key],
- fullPath=key
- )
-
- if 'passphrase' in x:
- tmp['passphrase'] = x['passphrase']
- result.append(tmp)
- return result
-
-
-class ReportableChanges(Changes):
- pass
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(params=self.module.params)
- self.want.client = self.client
- self.have = ApiParameters()
- self.changes = UsableChanges()
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = UsableChanges(params=changed)
- self.changes.client = self.client
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- self.changes.client = self.client
- return True
- return False
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def check_bigiq_version(self):
- version = bigiq_version(self.client)
- if LooseVersion(version) >= LooseVersion('6.1.0'):
- raise F5ModuleError(
- 'Module supports only BIGIQ version 6.0.x or lower.'
- )
-
- def exec_module(self):
- self.check_bigiq_version()
- changed = False
- result = dict()
- state = self.want.state
-
- if state == "present":
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.client.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def present(self):
- if self.exists():
- return False
- else:
- return self.create()
-
- def exists(self):
- uri = "https://{0}:{1}/mgmt/ap/query/v1/tenants/default/reports/AllApplicationsList?$filter=name+eq+'{2}'".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- self.want.name
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if resp.status == 200 and 'result' in response and 'totalItems' in response['result'] and response['result']['totalItems'] == 0:
- return False
- return True
-
- def remove(self):
- if self.module.check_mode:
- return True
- self_link = self.remove_from_device()
- if self.want.wait:
- self.wait_for_apply_template_task(self_link)
- if self.exists():
- raise F5ModuleError("Failed to delete the resource.")
- return True
-
- def has_no_service_environment(self):
- if self.want.default_device_reference is None and self.want.ssg_reference is None:
- return True
- return False
-
- def create(self):
- if self.want.service_environment is None:
- raise F5ModuleError(
- "A 'service_environment' must be specified when creating a new application."
- )
- if self.want.servers is None:
- raise F5ModuleError(
- "At least one 'servers' item is needed when creating a new application."
- )
- if self.want.inbound_virtual is None:
- raise F5ModuleError(
- "An 'inbound_virtual' must be specified when creating a new application."
- )
- self._set_changed_options()
-
- if self.has_no_service_environment():
- raise F5ModuleError(
- "The specified 'service_environment' ({0}) was not found.".format(self.want.service_environment)
- )
-
- if self.module.check_mode:
- return True
- self_link = self.create_on_device()
- if self.want.wait:
- self.wait_for_apply_template_task(self_link)
- if not self.exists():
- raise F5ModuleError(
- "Failed to deploy application."
- )
- return True
-
- def create_on_device(self):
- params = self.changes.api_params()
- params['mode'] = 'CREATE'
-
- uri = 'https://{0}:{1}/mgmt/cm/global/tasks/apply-template'.format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
-
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp._content)
- return response['selfLink']
-
- def absent(self):
- if self.exists():
- return self.remove()
- return False
-
- def remove_from_device(self):
- params = dict(
- configSetName=self.want.name,
- mode='DELETE'
- )
- uri = 'https://{0}:{1}/mgmt/cm/global/tasks/apply-template'.format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
-
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp._content)
- return response['selfLink']
-
- def wait_for_apply_template_task(self, self_link):
- host = 'https://{0}:{1}'.format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- uri = self_link.replace('https://localhost', host)
-
- while True:
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if response['status'] == 'FINISHED' and response.get('currentStep', None) == 'DONE':
- return True
- elif 'errorMessage' in response:
- raise F5ModuleError(response['errorMessage'])
- time.sleep(5)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- name=dict(required=True),
- description=dict(),
- servers=dict(
- type='list',
- options=dict(
- address=dict(required=True),
- port=dict(default=80)
- )
- ),
- inbound_virtual=dict(
- type='dict',
- options=dict(
- address=dict(required=True),
- netmask=dict(required=True),
- port=dict(default=443)
- )
- ),
- redirect_virtual=dict(
- type='dict',
- options=dict(
- address=dict(required=True),
- netmask=dict(required=True),
- port=dict(default=80)
- )
- ),
- service_environment=dict(),
- state=dict(
- default='present',
- choices=['present', 'absent']
- ),
- client_ssl_profile=dict(
- type='dict',
- name=dict(default='clientssl'),
- cert_key_chain=dict(
- type='raw',
- options=dict(
- cert=dict(),
- key=dict(),
- chain=dict(),
- passphrase=dict()
- )
- )
- ),
- add_analytics=dict(type='bool', default='no'),
- wait=dict(type='bool', default='yes')
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
- self.mutually_exclusive = [
- ['inherit_cert_key_chain', 'cert_key_chain']
- ]
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode,
- mutually_exclusive=spec.mutually_exclusive
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigiq_application_https_waf.py b/lib/ansible/modules/network/f5/bigiq_application_https_waf.py
deleted file mode 100644
index a4e18ea20d..0000000000
--- a/lib/ansible/modules/network/f5/bigiq_application_https_waf.py
+++ /dev/null
@@ -1,1038 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2018, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigiq_application_https_waf
-short_description: Manages BIG-IQ HTTPS WAF applications
-description:
- - Manages BIG-IQ applications used for load balancing an HTTPS application on port 443
- with a Web Application Firewall (WAF) using an ASM Rapid Deployment policy.
-version_added: 2.6
-options:
- name:
- description:
- - Name of the new application.
- type: str
- required: True
- description:
- description:
- - Description of the application.
- type: str
- servers:
- description:
- - A list of servers that the application is hosted on.
- - If you are familiar with other BIG-IP setting, you might also refer to this
- list as the list of pool members.
- - When creating a new application, at least one server is required.
- suboptions:
- address:
- description:
- - The IP address of the server.
- type: str
- port:
- description:
- - The port of the server.
- type: str
- default: 80
- type: list
- inbound_virtual:
- description:
- - Settings to configure the virtual which will receive the inbound connection.
- - This virtual will be used to host the HTTPS endpoint of the application.
- - Traffic destined to the C(redirect_virtual) will be offloaded to this
- parameter to ensure that proper redirection from insecure, to secure, occurs.
- suboptions:
- address:
- description:
- - Specifies destination IP address information to which the virtual server
- sends traffic.
- - This parameter is required when creating a new application.
- type: str
- netmask:
- description:
- - Specifies the netmask to associate with the given C(destination).
- - This parameter is required when creating a new application.
- type: str
- port:
- description:
- - The port that the virtual listens for connections on.
- - When creating a new application, if this parameter is not specified, the
- default value of C(443) will be used.
- type: str
- default: 443
- type: dict
- redirect_virtual:
- description:
- - Settings to configure the virtual which will receive the connection to be
- redirected.
- - This virtual will be used to host the HTTP endpoint of the application.
- - Traffic destined to this parameter will be offloaded to the
- C(inbound_virtual) parameter to ensure that proper redirection from insecure,
- to secure, occurs.
- suboptions:
- address:
- description:
- - Specifies destination IP address information to which the virtual server
- sends traffic.
- - This parameter is required when creating a new application.
- type: str
- netmask:
- description:
- - Specifies the netmask to associate with the given C(destination).
- - This parameter is required when creating a new application.
- type: str
- port:
- description:
- - The port that the virtual listens for connections on.
- - When creating a new application, if this parameter is not specified, the
- default value of C(80) will be used.
- type: str
- default: 80
- type: dict
- client_ssl_profile:
- description:
- - Specifies the SSL profile for managing client-side SSL traffic.
- suboptions:
- name:
- description:
- - The name of the client SSL profile to created and used.
- - When creating a new application, if this value is not specified, the
- default value of C(clientssl) will be used.
- type: str
- cert_key_chain:
- description:
- - One or more certificates and keys to associate with the SSL profile.
- - This option is always a list. The keys in the list dictate the details
- of the client/key/chain/passphrase combination.
- - Note that BIG-IPs can only have one of each type of each certificate/key
- type. This means that you can only have one RSA, one DSA, and one ECDSA
- per profile.
- - If you attempt to assign two RSA, DSA, or ECDSA certificate/key combo,
- the device will reject this.
- - This list is a complex list that specifies a number of keys.
- - When creating a new profile, if this parameter is not specified, the
- default value of C(inherit) will be used.
- suboptions:
- cert:
- description:
- - Specifies a cert name for use.
- type: str
- required: True
- key:
- description:
- - Specifies a key name.
- type: str
- required: True
- chain:
- description:
- - Specifies a certificate chain that is relevant to the certificate and
- key mentioned earlier.
- - This key is optional.
- type: str
- passphrase:
- description:
- - Contains the passphrase of the key file, should it require one.
- - Passphrases are encrypted on the remote BIG-IP device.
- type: str
- type: raw
- type: dict
- service_environment:
- description:
- - Specifies the name of service environment that the application will be
- deployed to.
- - When creating a new application, this parameter is required.
- type: str
- add_analytics:
- description:
- - Collects statistics of the BIG-IP that the application is deployed to.
- - This parameter is only relevant when specifying a C(service_environment) which
- is a BIG-IP; not an SSG.
- type: bool
- default: no
- domain_names:
- description:
- - Specifies host names that are used to access the web application that this
- security policy protects.
- - When creating a new application, this parameter is required.
- type: list
- state:
- description:
- - The state of the resource on the system.
- - When C(present), guarantees that the resource exists with the provided attributes.
- - When C(absent), removes the resource from the system.
- type: str
- choices:
- - absent
- - present
- default: present
- wait:
- description:
- - If the module should wait for the application to be created, deleted or updated.
- type: bool
- default: yes
-extends_documentation_fragment: f5
-notes:
- - This module will not work on BIGIQ version 6.1.x or greater.
-author:
- - Tim Rupp (@caphrim007)
-'''
-
-EXAMPLES = r'''
-- name: Load balance an HTTPS application on port 443 with a WAF using ASM
- bigiq_application_https_waf:
- name: my-app
- description: Redirect HTTP to HTTPS via WAF
- service_environment: my-ssg
- servers:
- - address: 1.2.3.4
- port: 8080
- - address: 5.6.7.8
- port: 8080
- inbound_virtual:
- address: 2.2.2.2
- netmask: 255.255.255.255
- port: 443
- redirect_virtual:
- address: 2.2.2.2
- netmask: 255.255.255.255
- port: 80
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- state: present
- delegate_to: localhost
-'''
-
-RETURN = r'''
-description:
- description: The new description of the application of the resource.
- returned: changed
- type: str
- sample: My application
-service_environment:
- description: The environment which the service was deployed to.
- returned: changed
- type: str
- sample: my-ssg1
-inbound_virtual_destination:
- description: The destination of the virtual that was created.
- returned: changed
- type: str
- sample: 6.7.8.9
-inbound_virtual_netmask:
- description: The network mask of the provided inbound destination.
- returned: changed
- type: str
- sample: 255.255.255.0
-inbound_virtual_port:
- description: The port the inbound virtual address listens on.
- returned: changed
- type: int
- sample: 80
-servers:
- description: List of servers, and their ports, that make up the application.
- type: complex
- returned: changed
- contains:
- address:
- description: The IP address of the server.
- returned: changed
- type: str
- sample: 2.3.4.5
- port:
- description: The port that the server listens on.
- returned: changed
- type: int
- sample: 8080
- sample: hash/dictionary of values
-'''
-
-import time
-
-from distutils.version import LooseVersion
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.six import string_types
-
-try:
- from library.module_utils.network.f5.bigiq import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.common import fq_name
- from library.module_utils.network.f5.ipaddress import is_valid_ip
- from library.module_utils.network.f5.icontrol import bigiq_version
-except ImportError:
- from ansible.module_utils.network.f5.bigiq import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.common import fq_name
- from ansible.module_utils.network.f5.ipaddress import is_valid_ip
- from ansible.module_utils.network.f5.icontrol import bigiq_version
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'templateReference': 'template_reference',
- 'subPath': 'sub_path',
- 'ssgReference': 'ssg_reference',
- 'configSetName': 'config_set_name',
- 'defaultDeviceReference': 'default_device_reference',
- 'addAnalytics': 'add_analytics',
- 'domains': 'domain_names'
- }
-
- api_attributes = [
- 'resources', 'description', 'configSetName', 'subPath', 'templateReference',
- 'ssgReference', 'defaultDeviceReference', 'addAnalytics', 'domains'
- ]
-
- returnables = [
- 'resources', 'description', 'config_set_name', 'sub_path', 'template_reference',
- 'ssg_reference', 'default_device_reference', 'servers', 'inbound_virtual',
- 'redirect_virtual', 'client_ssl_profile', 'add_analytics', 'domain_names'
- ]
-
- updatables = [
- 'resources', 'description', 'config_set_name', 'sub_path', 'template_reference',
- 'ssg_reference', 'default_device_reference', 'servers', 'add_analytics', 'domain_names'
- ]
-
-
-class ApiParameters(Parameters):
- pass
-
-
-class ModuleParameters(Parameters):
- @property
- def http_profile(self):
- return "profile_http"
-
- @property
- def config_set_name(self):
- return self.name
-
- @property
- def sub_path(self):
- return self.name
-
- @property
- def template_reference(self):
- filter = "name+eq+'Default-f5-HTTPS-WAF-lb-template'"
- uri = "https://{0}:{1}/mgmt/cm/global/templates/?$filter={2}&$top=1&$select=selfLink".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- filter
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if resp.status == 200 and response['totalItems'] == 0:
- raise F5ModuleError(
- "No default HTTP LB template was found."
- )
- elif 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp._content)
-
- result = dict(
- link=response['items'][0]['selfLink']
- )
- return result
-
- @property
- def default_device_reference(self):
- if is_valid_ip(self.service_environment):
- # An IP address was specified
- filter = "address+eq+'{0}'".format(self.service_environment)
- else:
- # Assume a hostname was specified
- filter = "hostname+eq+'{0}'".format(self.service_environment)
-
- uri = "https://{0}:{1}/mgmt/shared/resolver/device-groups/cm-adccore-allbigipDevices/devices/?$filter={2}&$top=1&$select=selfLink".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- filter
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if resp.status == 200 and response['totalItems'] == 0:
- return None
- elif 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp._content)
- result = dict(
- link=response['items'][0]['selfLink']
- )
- return result
-
- @property
- def ssg_reference(self):
- filter = "name+eq+'{0}'".format(self.service_environment)
- uri = "https://{0}:{1}/mgmt/cm/cloud/service-scaling-groups/?$filter={2}&$top=1&$select=selfLink".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- filter
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if resp.status == 200 and response['totalItems'] == 0:
- return None
- elif 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp._content)
- result = dict(
- link=response['items'][0]['selfLink']
- )
- return result
-
- @property
- def domain_names(self):
- if self._values['domain_names'] is None:
- return None
- result = []
- for domain in self._values['domain_names']:
- result.append(
- dict(
- domainName=domain
- )
- )
- return result
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class UsableChanges(Changes):
- @property
- def resources(self):
- result = dict()
- result.update(self.http_profile)
- result.update(self.http_monitor)
- result.update(self.inbound_virtual_server)
- result.update(self.redirect_virtual_server)
- result.update(self.pool)
- result.update(self.nodes)
- result.update(self.ssl_profile)
- return result
-
- @property
- def inbound_virtual_server(self):
- result = dict()
- result['ltm:virtual:90735960bf4b'] = [
- dict(
- parameters=dict(
- name='default_vs',
- destinationAddress=self.inbound_virtual['address'],
- mask=self.inbound_virtual['netmask'],
- destinationPort=self.inbound_virtual['port']
- ),
- subcollectionResources=self.inbound_profiles
- )
- ]
- return result
-
- @property
- def inbound_profiles(self):
- result = {
- 'profiles:78b1bcfdafad': [
- dict(
- parameters=dict()
- )
- ],
- 'profiles:2f52acac9fde': [
- dict(
- parameters=dict()
- )
- ],
- 'profiles:9448fe71611e': [
- dict(
- parameters=dict()
- )
- ]
- }
- return result
-
- @property
- def redirect_virtual_server(self):
- result = dict()
- result['ltm:virtual:3341f412b980'] = [
- dict(
- parameters=dict(
- name='default_redirect_vs',
- destinationAddress=self.redirect_virtual['address'],
- mask=self.redirect_virtual['netmask'],
- destinationPort=self.redirect_virtual['port']
- ),
- subcollectionResources=self.redirect_profiles
- )
- ]
- return result
-
- @property
- def redirect_profiles(self):
- result = {
- 'profiles:2f52acac9fde': [
- dict(
- parameters=dict()
- )
- ],
- 'profiles:9448fe71611e': [
- dict(
- parameters=dict()
- )
- ]
- }
- return result
-
- @property
- def pool(self):
- result = dict()
- result['ltm:pool:8bc5b256f9d1'] = [
- dict(
- parameters=dict(
- name='pool_0'
- ),
- subcollectionResources=self.pool_members
- )
- ]
- return result
-
- @property
- def pool_members(self):
- result = dict()
- result['members:dec6d24dc625'] = []
- for x in self.servers:
- member = dict(
- parameters=dict(
- port=x['port'],
- nodeReference=dict(
- link='#/resources/ltm:node:c072248f8e6a/{0}'.format(x['address']),
- fullPath='# {0}'.format(x['address'])
- )
- )
- )
- result['members:dec6d24dc625'].append(member)
- return result
-
- @property
- def http_profile(self):
- result = dict()
- result['ltm:profile:http:2f52acac9fde'] = [
- dict(
- parameters=dict(
- name='profile_http'
- )
- )
- ]
- return result
-
- @property
- def http_monitor(self):
- result = dict()
- result['ltm:monitor:http:18765a198150'] = [
- dict(
- parameters=dict(
- name='monitor-http'
- )
- )
- ]
- return result
-
- @property
- def nodes(self):
- result = dict()
- result['ltm:node:c072248f8e6a'] = []
- for x in self.servers:
- tmp = dict(
- parameters=dict(
- name=x['address'],
- address=x['address']
- )
- )
- result['ltm:node:c072248f8e6a'].append(tmp)
- return result
-
- @property
- def node_addresses(self):
- result = [x['address'] for x in self.servers]
- return result
-
- @property
- def ssl_profile(self):
- result = dict()
- result['ltm:profile:client-ssl:78b1bcfdafad'] = [
- dict(
- parameters=dict(
- name='clientssl',
- certKeyChain=self.cert_key_chains
- )
- )
- ]
- return result
-
- def _get_cert_references(self):
- result = dict()
- uri = "https://{0}:{1}/mgmt/cm/adc-core/working-config/sys/file/ssl-cert/".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
-
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- for cert in response['items']:
- key = fq_name(cert['partition'], cert['name'])
- result[key] = cert['selfLink']
- return result
-
- def _get_key_references(self):
- result = dict()
- uri = "https://{0}:{1}/mgmt/cm/adc-core/working-config/sys/file/ssl-key/".format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- for cert in response['items']:
- key = fq_name(cert['partition'], cert['name'])
- result[key] = cert['selfLink']
- return result
-
- @property
- def cert_key_chains(self):
- result = []
-
- if self.client_ssl_profile is None:
- return None
- if 'cert_key_chain' not in self.client_ssl_profile:
- return None
-
- kc = self.client_ssl_profile['cert_key_chain']
- if isinstance(kc, string_types) and kc != 'inherit':
- raise F5ModuleError(
- "Only the 'inherit' setting is available when 'cert_key_chain' is a string."
- )
-
- if not isinstance(kc, list):
- raise F5ModuleError(
- "The value of 'cert_key_chain' is not one of the supported types."
- )
-
- cert_references = self._get_cert_references()
- key_references = self._get_key_references()
-
- for idx, x in enumerate(kc):
- tmp = dict(
- name='clientssl{0}'.format(idx)
- )
- if 'cert' not in x:
- raise F5ModuleError(
- "A 'cert' option is required when specifying the 'cert_key_chain' parameter.."
- )
- elif x['cert'] not in cert_references:
- raise F5ModuleError(
- "The specified 'cert' was not found. Did you specify its full path?"
- )
- else:
- key = x['cert']
- tmp['certReference'] = dict(
- link=cert_references[key],
- fullPath=key
- )
-
- if 'key' not in x:
- raise F5ModuleError(
- "A 'key' option is required when specifying the 'cert_key_chain' parameter.."
- )
- elif x['key'] not in key_references:
- raise F5ModuleError(
- "The specified 'key' was not found. Did you specify its full path?"
- )
- else:
- key = x['key']
- tmp['keyReference'] = dict(
- link=key_references[key],
- fullPath=key
- )
-
- if 'chain' in x and x['chain'] not in cert_references:
- raise F5ModuleError(
- "The specified 'key' was not found. Did you specify its full path?"
- )
- else:
- key = x['chain']
- tmp['chainReference'] = dict(
- link=cert_references[key],
- fullPath=key
- )
-
- if 'passphrase' in x:
- tmp['passphrase'] = x['passphrase']
- result.append(tmp)
- return result
-
-
-class ReportableChanges(Changes):
- pass
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(params=self.module.params)
- self.want.client = self.client
- self.have = ApiParameters()
- self.changes = UsableChanges()
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = UsableChanges(params=changed)
- self.changes.client = self.client
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- self.changes.client = self.client
- return True
- return False
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def check_bigiq_version(self):
- version = bigiq_version(self.client)
- if LooseVersion(version) >= LooseVersion('6.1.0'):
- raise F5ModuleError(
- 'Module supports only BIGIQ version 6.0.x or lower.'
- )
-
- def exec_module(self):
- self.check_bigiq_version()
- changed = False
- result = dict()
- state = self.want.state
-
- if state == "present":
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.client.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def present(self):
- if self.exists():
- return False
- else:
- return self.create()
-
- def exists(self):
- uri = "https://{0}:{1}/mgmt/ap/query/v1/tenants/default/reports/AllApplicationsList?$filter=name+eq+'{2}'".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- self.want.name
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if resp.status == 200 and 'result' in response and 'totalItems' in response['result'] and response['result']['totalItems'] == 0:
- return False
- return True
-
- def remove(self):
- if self.module.check_mode:
- return True
- self_link = self.remove_from_device()
- if self.want.wait:
- self.wait_for_apply_template_task(self_link)
- if self.exists():
- raise F5ModuleError("Failed to delete the resource.")
- return True
-
- def has_no_service_environment(self):
- if self.want.default_device_reference is None and self.want.ssg_reference is None:
- return True
- return False
-
- def create(self):
- if self.want.service_environment is None:
- raise F5ModuleError(
- "A 'service_environment' must be specified when creating a new application."
- )
- if self.want.servers is None:
- raise F5ModuleError(
- "At least one 'servers' item is needed when creating a new application."
- )
- if self.want.inbound_virtual is None:
- raise F5ModuleError(
- "An 'inbound_virtual' must be specified when creating a new application."
- )
- if self.want.domain_names is None:
- raise F5ModuleError(
- "You must provide at least one value in the 'domain_names' parameter."
- )
- self._set_changed_options()
-
- if self.has_no_service_environment():
- raise F5ModuleError(
- "The specified 'service_environment' ({0}) was not found.".format(self.want.service_environment)
- )
-
- if self.module.check_mode:
- return True
- self_link = self.create_on_device()
- if self.want.wait:
- self.wait_for_apply_template_task(self_link)
- if not self.exists():
- raise F5ModuleError(
- "Failed to deploy application."
- )
- return True
-
- def create_on_device(self):
- params = self.changes.api_params()
- params['mode'] = 'CREATE'
-
- uri = 'https://{0}:{1}/mgmt/cm/global/tasks/apply-template'.format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
-
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp._content)
- return response['selfLink']
-
- def absent(self):
- if self.exists():
- return self.remove()
- return False
-
- def remove_from_device(self):
- params = dict(
- configSetName=self.want.name,
- mode='DELETE'
- )
- uri = 'https://{0}:{1}/mgmt/cm/global/tasks/apply-template'.format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
-
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp._content)
- return response['selfLink']
-
- def wait_for_apply_template_task(self, self_link):
- host = 'https://{0}:{1}'.format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- uri = self_link.replace('https://localhost', host)
-
- while True:
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if response['status'] == 'FINISHED' and response.get('currentStep', None) == 'DONE':
- return True
- elif 'errorMessage' in response:
- raise F5ModuleError(response['errorMessage'])
- time.sleep(5)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- name=dict(required=True),
- description=dict(),
- servers=dict(
- type='list',
- options=dict(
- address=dict(required=True),
- port=dict(default=80)
- )
- ),
- inbound_virtual=dict(
- type='dict',
- options=dict(
- address=dict(required=True),
- netmask=dict(required=True),
- port=dict(default=443)
- )
- ),
- redirect_virtual=dict(
- type='dict',
- options=dict(
- address=dict(required=True),
- netmask=dict(required=True),
- port=dict(default=80)
- )
- ),
- service_environment=dict(),
- state=dict(
- default='present',
- choices=['present', 'absent']
- ),
- client_ssl_profile=dict(
- type='dict',
- name=dict(default='clientssl'),
- cert_key_chain=dict(
- type='raw',
- options=dict(
- cert=dict(),
- key=dict(),
- chain=dict(),
- passphrase=dict()
- )
- )
- ),
- add_analytics=dict(type='bool', default='no'),
- domain_names=dict(type='list'),
- wait=dict(type='bool', default='yes')
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
- self.mutually_exclusive = [
- ['inherit_cert_key_chain', 'cert_key_chain']
- ]
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode,
- mutually_exclusive=spec.mutually_exclusive
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigiq_device_discovery.py b/lib/ansible/modules/network/f5/bigiq_device_discovery.py
deleted file mode 100644
index 3d76630dce..0000000000
--- a/lib/ansible/modules/network/f5/bigiq_device_discovery.py
+++ /dev/null
@@ -1,1240 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2019, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigiq_device_discovery
-short_description: Manage BIG-IP devices through BIG-IQ
-description:
- - Discovers and imports BIG-IP device configuration on the BIG-IQ.
-version_added: 2.8
-options:
- device_address:
- description:
- - The IP address of the BIG-IP device to be imported/managed.
- type: str
- required: True
- device_username:
- description:
- - The administrator username for the BIG-IP device.
- - This parameter is only required when adding a new BIG-IP device to be managed.
- type: str
- device_password:
- description:
- - The administrator password for the BIG-IP device.
- - This parameter is only required when adding a new BIG-IP device to be managed.
- type: str
- device_port:
- description:
- - The port on which a device trust setup between BIG-IQ and BIG-IP should happen.
- type: int
- default: 443
- ha_name:
- description:
- - DSC cluster name of the BIG-IP device to be managed.
- - This is optional if the managed device is not a part of a cluster group.
- - When C(use_bigiq_sync) is set to C(yes) then this parameter becomes mandatory.
- type: str
- use_bigiq_sync:
- description:
- - When set to true, BIG-IQ will manually synchronize configuration changes
- between members in a DSC cluster.
- type: bool
- default: no
- conflict_policy:
- description:
- - Sets the conflict resolution policy for shared objects across BIG-IP devices, except LTM profiles and monitors.
- type: str
- choices:
- - use_bigiq
- - use_bigip
- default: use_bigiq
- versioned_conflict_policy:
- description:
- - Sets the conflict resolution policy for LTM profile and monitor objects that are specific to a BIG-IP software
- version.
- type: str
- choices:
- - use_bigiq
- - use_bigip
- - keep_version
- device_conflict_policy:
- description:
- - Sets the conflict resolution policy for objects that are specific to a particular to a BIG-IP device
- and not shared among BIG-IP devices.
- type: str
- choices:
- - use_bigiq
- - use_bigip
- default: use_bigiq
- access_conflict_policy:
- description:
- - Sets the conflict resolution policy for Access module C(apm) objects, only used when C(apm) module is specified.
- type: str
- choices:
- - use_bigiq
- - use_bigip
- - keep_version
- access_group_name:
- description:
- - Access group name to import Access configuration for devices, once set it cannot be changed.
- type: str
- access_group_first_device:
- description:
- - Specifies if the imported device is the first device in the access group to import shared configuration for that
- access group.
- type: bool
- default: yes
- force:
- description:
- - Forces rediscovery and import of existing modules on the managed BIG-IP
- type: bool
- default: no
- modules:
- description:
- - List of modules to be discovered and imported into the device.
- - These modules must be provisioned on the target device otherwise operation will fail.
- - The C(ltm) module must always be specified when performing discovery or re-discovery of the device.
- - When C(asm) or C(afm) are specified C(shared_security) module needs to also be declared.
- type: list
- choices:
- - ltm
- - asm
- - apm
- - afm
- - dns
- - websafe
- - security_shared
- statistics:
- description:
- - Specify the statistics collection for discovered device.
- type: dict
- suboptions:
- enable:
- description:
- - Enables statistics collection on a device
- type: bool
- default: no
- interval:
- description:
- - Specify the interval in seconds the data is collected from the discovered device.
- type: int
- default: 60
- choices:
- - 30
- - 60
- - 120
- - 500
- zone:
- description:
- - Specify in which DCD zone is collecting the data from device.
- type: str
- default: default
- stat_modules:
- description:
- - Specifies for which modules the data is being collected.
- type: list
- default: ['device', 'ltm']
- choices:
- - device
- - ltm
- - dns
- state:
- description:
- - The state of the managed device on the system.
- - When C(present), enables new device addition as well as device rediscovery/import.
- - When C(absent), completely removes the device from the system.
- type: str
- choices:
- - absent
- - present
- default: present
-extends_documentation_fragment: f5
-notes:
- - BIG-IQ >= 6.1.0.
- - This module does not support atomic removal of discovered modules on the device.
-author:
- - Wojciech Wypior (@wojtek0806)
-'''
-
-EXAMPLES = r'''
-- name: Discover a new device and import config, use default conflict policy.
- bigiq_device_discovery:
- device_address: 192.168.1.1
- device_username: bigipadmin
- device_password: bigipsecret
- modules:
- - ltm
- - afm
- - shared_security
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-
-- name: Discover a new device and import config, use non- default conflict policy.
- bigiq_device_discovery:
- device_address: 192.168.1.1
- modules:
- - ltm
- - dns
- conflict_policy: use_bigip
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-
-- name: Force full device rediscovery
- bigiq_device_discovery:
- device_address: 192.168.1.1
- modules:
- - ltm
- - afm
- - dns
- - shared_security
- force: yes
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-
-- name: Remove discovered device and its config
- bigiq_device_discovery:
- device_address: 192.168.1.1
- state: absent
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-'''
-
-RETURN = r'''
-device_address:
- description: The IP address of the BIG-IP device to be imported/managed.
- returned: changed
- type: str
- sample: 192.168.1.1
-device_port:
- description: The port on which a device trust setup between BIG-IQ and BIG-IP should happen.
- returned: changed
- type: int
- sample: 10443
-ha_name:
- description: DSC cluster name of the BIG-IP device to be managed.
- returned: changed
- type: str
- sample: GROUP_1
-use_bigiq_sync:
- description: Indicate if BIG-IQ should manually synchronise DSC configuration.
- returned: changed
- type: bool
- sample: yes
-conflict_policy:
- description: Sets the conflict resolution policy for shared objects across BIG-IP devices.
- returned: changed
- type: str
- sample: use_bigip
-device_conflict_policy:
- description: Sets the conflict resolution policy for objects that are specific to a particular to a BIG-IP device.
- returned: changed
- type: str
- sample: use_bigip
-versioned_conflict_policy:
- description: Sets the conflict resolution policy for LTM profile and monitor objects.
- returned: changed
- type: str
- sample: keep_version
-access_conflict_policy:
- description: Sets the conflict resolution policy for Access module C(apm) objects.
- returned: changed
- type: str
- sample: keep_version
-access_group_name:
- description: Access group name to import Access configuration for devices.
- returned: changed
- type: str
- sample: foo_group
-access_group_first_device:
- description: First device in the access group to import shared configuration for that access group.
- returned: changed
- type: bool
- sample: yes
-modules:
- description: List of modules to be discovered and imported into the device.
- returned: changed
- type: list
- sample: ['ltm', 'dns']
-
-'''
-
-import time
-from distutils.version import LooseVersion
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.module_utils.network.f5.bigiq import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.common import flatten_boolean
- from library.module_utils.network.f5.ipaddress import is_valid_ip
- from library.module_utils.network.f5.icontrol import bigiq_version
-except ImportError:
- from ansible.module_utils.network.f5.bigiq import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.common import flatten_boolean
- from ansible.module_utils.network.f5.ipaddress import is_valid_ip
- from ansible.module_utils.network.f5.icontrol import bigiq_version
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'address': 'device_address',
- 'userName': 'device_username',
- 'password': 'device_password',
- 'httpsPort': 'device_port',
- 'clusterName': 'ha_name',
- 'useBigiqSync': 'use_bigiq_sync',
- }
-
- api_attributes = [
- 'address',
- 'userName',
- 'password',
- 'httpsPort',
- 'clusterName',
- 'useBigiqSync',
- ]
-
- returnables = [
- 'device_address',
- 'device_username',
- 'device_password',
- 'device_port',
- 'ha_name',
- 'use_bigiq_sync',
- 'modules',
- 'conflict_policy',
- 'versioned_conflict_policy',
- 'device_conflict_policy',
- 'access_group_name',
- 'access_group_first_device',
- 'access_conflict_policy',
- 'module_list',
- 'apm_properties',
- ]
-
- updatables = [
- 'modules',
- 'access_group_name',
- 'apm_properties',
- 'module_list',
- ]
-
-
-class ApiParameters(Parameters):
- module_map = {
- 'cm-security-shared-allSharedDevices': 'security_shared',
- 'cm-asm-allAsmDevices': 'asm',
- 'cm-firewall-allFirewallDevices': 'firewall',
- 'cm-websafe-allFpsDevices': 'fps',
- 'cm-dns-allBigIpDevices': 'dns',
- 'cm-adccore-allbigipDevices': 'adc_core',
- 'cm-access-allBigIpDevices': 'access',
- }
-
- @property
- def modules(self):
- raw_data = self._values['properties']
- if raw_data is None:
- return None
- result = list()
- for item in raw_data.keys():
- if item in self.module_map:
- if raw_data[item]['discovered'] is True and raw_data[item]['imported'] is True:
- result.append(self.module_map[item])
- return result
-
- @property
- def access_group_name(self):
- raw_data = self._values['properties']
- if raw_data is None:
- return None
- for item in raw_data.keys():
- if 'cm:access:access-group-name' in raw_data[item]:
- return raw_data[item]['cm:access:access-group-name']
- return None
-
-
-class ModuleParameters(Parameters):
- module_map = {
- 'ltm': 'adc_core',
- 'afm': 'firewall',
- 'websafe': 'fps',
- 'apm': 'access',
- }
-
- @property
- def device_password(self):
- if self._values['device_password'] is None:
- return None
- return self._values['device_password']
-
- @property
- def device_username(self):
- if self._values['device_username'] is None:
- return None
- return self._values['device_username']
-
- @property
- def device_address(self):
- if is_valid_ip(self._values['device_address']):
- return self._values['device_address']
- raise F5ModuleError(
- 'Provided device address: {0} is not a valid IP.'.format(self._values['device_address'])
- )
-
- @property
- def device_port(self):
- if self._values['device_port'] is None:
- return None
- return int(self._values['device_port'])
-
- @property
- def conflict_policy(self):
- return self._values['conflict_policy'].upper()
-
- @property
- def device_conflict_policy(self):
- return self._values['device_conflict_policy'].upper()
-
- @property
- def versioned_conflict_policy(self):
- if self._values['versioned_conflict_policy'] is None:
- return None
- return self._values['versioned_conflict_policy'].upper()
-
- @property
- def access_conflict_policy(self):
- if self._values['access_conflict_policy'] is None:
- return None
- return self._values['device_conflict_policy'].upper()
-
- @property
- def modules(self):
- if self._values['modules'] is None:
- return None
- result = list()
- if 'security_shared' not in self._values['modules']:
- if 'afm' in self._values['modules']:
- raise F5ModuleError(
- "Module 'shared_security' required for 'afm' module."
- )
- if 'asm' in self._values['modules']:
- raise F5ModuleError(
- "Module 'shared_security' required for 'asm' module."
- )
- if 'ltm' not in self._values['modules']:
- raise F5ModuleError(
- "LTM module must be specified for device discovery and import."
- )
- if 'apm' in self._values['modules']:
- if not self.access_group_name or not self.access_conflict_policy:
- raise F5ModuleError(
- "When importing APM 'access_group_name' and 'access_conflict_policy' must be specified."
- )
- for item in self._values['modules']:
- if item in self.module_map:
- result.append(self.module_map[item])
- else:
- result.append(item)
- return result
-
- @property
- def apm_properties(self):
- if self._values['modules'] is None:
- return None
- if 'apm' in self._values['modules']:
- result = {
- 'cm:access:conflict-resolution': self.access_conflict_policy,
- 'cm:access:access-group-name': self.access_group_name,
- 'cm:access:import-shared': self.access_group_first_device
- }
- return result
-
- @property
- def use_bigiq_sync(self):
- result = flatten_boolean(self._values['use_bigiq_sync'])
- if result:
- if result == 'yes':
- return True
- return False
-
- @property
- def access_group_first_device(self):
- result = flatten_boolean(self._values['access_group_first_device'])
- if result:
- if result == 'yes':
- return True
- return False
-
- @property
- def stats_enabled(self):
- if self._values['statistics'] is None:
- return None
- result = flatten_boolean(self._values['statistics']['enable'])
- if result:
- if result == 'yes':
- return True
- return False
-
- @property
- def interval(self):
- if self._values['statistics'] is None:
- return None
- return self._values['statistics']['interval']
-
- @property
- def zone(self):
- if self._values['statistics'] is None:
- return None
- return self._values['statistics']['zone']
-
- @property
- def stat_modules(self):
- if self._values['statistics'] is None:
- return None
- modules = self._values['statistics']['stat_modules']
- result = list()
- for module in modules:
- result.append((dict(module=module.upper())))
- return result
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class UsableChanges(Changes):
- @property
- def modules(self):
- if self._values['modules'] is None:
- return None
- result = list()
- for item in self._values['modules']:
- result.append(dict(module=item))
- return result
-
- @property
- def module_list(self):
- if self._values['modules'] is None:
- return None
- result = list()
- for item in self._values['modules']:
- if item == 'access':
- result.append(dict(module=item, properties=self._values['apm_properties']))
- else:
- result.append(dict(module=item))
- return result
-
-
-class ReportableChanges(Changes):
- @property
- def module_list(self):
- return None
-
- @property
- def apm_properties(self):
- return None
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
- @property
- def modules(self):
- if self.want.modules is None:
- return None
- if self.have.modules is None:
- return self.want.modules
- if set(self.want.modules).issubset(self.have.modules):
- return None
- if set(self.want.modules) != set(self.have.modules):
- return self.want.modules
-
- @property
- def access_group_name(self):
- if self.want.access_group_name != self.have.access_group_name:
- raise F5ModuleError(
- 'Access group name cannot be modified once it is set.'
- )
-
- @property
- def apm_properties(self):
- # This is required for idempotency and updates as we do not compare these properties
- return None
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(params=self.module.params)
- self.have = ApiParameters()
- self.changes = UsableChanges()
- self.device_id = None
- self.task_id = None
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = UsableChanges(params=changed)
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- changed['apm_properties'] = self.want.apm_properties
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.client.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def check_bigiq_version(self):
- version = bigiq_version(self.client)
- if LooseVersion(version) < LooseVersion('6.1.0'):
- raise F5ModuleError(
- 'Module supports only BIGIQ version 6.1.x or higher.'
- )
-
- def exec_module(self):
- self.check_bigiq_version()
- changed = False
- result = dict()
- state = self.want.state
-
- if state == "present":
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def present(self):
- if self.exists():
- return self.update()
- else:
- return self.create()
-
- def absent(self):
- if self.exists():
- return self.remove()
- return False
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def update(self):
- self.have = self.read_current_from_device()
- if not self.should_update() and not self.want.force:
- return False
- if self.module.check_mode:
- return True
- if self.want.force:
- self._set_changed_options()
- self.discover_on_device()
- self.import_modules_on_device()
- if self.want.stats_enabled:
- self.enable_stats_on_device()
- return True
-
- def remove(self):
- if self.module.check_mode:
- return True
- self.remove_autority_from_device()
- self.remove_trust_from_device()
- return True
-
- def create(self):
- if self.want.modules is None:
- raise F5ModuleError(
- 'List of modules cannot be empty if discovering a device.'
- )
- self._set_changed_options()
- if self.module.check_mode:
- return True
- self.set_trust_with_device()
- self.discover_on_device()
- self.import_modules_on_device()
- if self.want.stats_enabled:
- self.enable_stats_on_device()
- return True
-
- def exists(self):
- uri = "https://{0}:{1}/mgmt/cm/system/machineid-resolver".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
-
- query = "?$filter=address eq '{0}'".format(self.want.device_address)
- resp = self.client.api.get(uri + query)
-
- try:
- response = resp.json()
- except ValueError:
- return False
-
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- raise F5ModuleError(response.message)
-
- if 'items' in response:
- if not response['items']:
- return False
- self.device_id = response['items'][0]['machineId']
- return True
- return False
-
- def set_trust_with_device(self):
- params = self.changes.api_params()
- params['name'] = 'trust_{0}'.format(self.want.device_address)
- uri = "https://{0}:{1}/mgmt/cm/global/tasks/device-trust/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 409]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- task = "https://{0}:{1}/mgmt/cm/global/tasks/device-trust/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- response['id']
- )
- query = "?$select=status,currentStep,errorMessage"
-
- if self._wait_for_task(task + query):
- self._set_device_id(task)
- return True
-
- def _set_device_id(self, uri):
- resp = self.client.api.get(uri)
-
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- self.device_id = response['machineId']
-
- def _wait_for_task(self, uri):
- while True:
- resp = self.client.api.get(uri)
-
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- if response['status'] in ['FINISHED', 'FAILED', 'CANCELLED']:
- break
-
- time.sleep(1)
-
- if response['status'] == 'FAILED':
- raise F5ModuleError(response['errorMessage'])
- if response['status'] == 'CANCELLED':
- raise F5ModuleError(
- 'The task process has been cancelled.'
- )
- if response['status'] == 'FINISHED':
- return True
-
- def discover_on_device(self):
- tmp = self.changes.to_return()
- if self.reuse_task_on_device('discovery'):
- params = dict(
- moduleList=tmp['modules'],
- status='STARTED'
- )
- uri = "https://{0}:{1}/mgmt/cm/global/tasks/device-discovery/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- self.task_id
- )
- resp = self.client.api.patch(uri, json=params)
-
- else:
- params = dict(
- name='discovery_{0}'.format(self.want.device_address),
- moduleList=tmp['modules'],
- deviceReference=dict(link='https://localhost/mgmt/cm/system/machineid-resolver/{0}'.format(
- self.device_id
- )
- ),
- status='STARTED'
- )
- uri = "https://{0}:{1}/mgmt/cm/global/tasks/device-discovery".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.post(uri, json=params)
-
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 409]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- task = "https://{0}:{1}/mgmt/cm/global/tasks/device-discovery/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- response['id']
- )
- query = "?$select=status,currentStep,errorMessage"
-
- self._wait_for_task(task + query)
-
- return True
-
- def import_modules_on_device(self):
- tmp = self.changes.to_return()
- if self.reuse_task_on_device('import'):
- params = dict(
- moduleList=tmp['module_list'],
- conflictPolicy=self.want.conflict_policy,
- deviceConflictPolicy=self.want.device_conflict_policy,
- status='STARTED'
- )
-
- if self.want.versioned_conflict_policy:
- params['versionedConflictPolicy'] = self.want.versioned_conflict_policy
-
- uri = "https://{0}:{1}/mgmt/cm/global/tasks/device-import/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- self.task_id
- )
- resp = self.client.api.patch(uri, json=params)
-
- else:
- params = dict(
- name='import_{0}'.format(self.want.device_address),
- moduleList=tmp['module_list'],
- conflictPolicy=self.want.conflict_policy,
- deviceConflictPolicy=self.want.device_conflict_policy,
- deviceReference=dict(link='https://localhost/mgmt/cm/system/machineid-resolver/{0}'.format(
- self.device_id
- )
- ),
- status='STARTED'
- )
-
- if self.want.versioned_conflict_policy:
- params['versionedConflictPolicy'] = self.want.versioned_conflict_policy
-
- uri = "https://{0}:{1}/mgmt/cm/global/tasks/device-import".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.post(uri, json=params)
-
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 409]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- task = "https://{0}:{1}/mgmt/cm/global/tasks/device-import/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- response['id']
- )
- query = "?$select=status,currentStep,errorMessage"
-
- self._wait_for_task(task + query)
-
- return True
-
- def enable_stats_on_device(self):
- params = dict(
- enabled=self.want.stats_enabled,
- pushIntervalSecs=self.want.interval,
- zone=self.want.zone,
- modules=self.want.stat_modules,
- targetDeviceReference=dict(
- link='https://localhost/mgmt/cm/system/machineid-resolver/{0}'.format(
- self.device_id
- )
- ),
- )
-
- uri = "https://{0}:{1}/mgmt/cm/shared/stats-mgmt/agent-install-and-config-task".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.post(uri, json=params)
-
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 409]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- task = "https://{0}:{1}/mgmt/cm/shared/stats-mgmt/agent-install-and-config-task/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- response['id']
- )
- query = "?$select=status,currentStep,errorMessage"
-
- self._wait_for_task(task + query)
-
- return True
-
- def reuse_task_on_device(self, task):
- if task == 'discovery':
- uri = "https://{0}:{1}/mgmt/cm/global/tasks/device-discovery".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- else:
- uri = "https://{0}:{1}/mgmt/cm/global/tasks/device-import".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
-
- query = "?$filter=deviceReference/link eq '{0}'".format(self.device_id)
- resp = self.client.api.get(uri + query)
-
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 409]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- if 'items' in response:
- if response['items']:
- self.task_id = response['id']
- return True
- return False
-
- def remove_autority_from_device(self):
- # We can provide all of the modules for removal task, without ensuring they were discovered
- modules = [
- {'module': 'adc_core'},
- {'module': 'access'},
- {'module': 'asm'},
- {'module': 'fps'},
- {'module': 'firewall'},
- {'module': 'security_shared'},
- {'module': 'dns'}
- ]
- params = dict(
- moduleList=modules,
- deviceReference=dict(
- link="https://localhost/mgmt/cm/system/machineid-resolver/{0}".format(self.device_id)
- ),
- name='remove_auth_{0}'.format(self.want.device_address)
-
- )
- uri = "https://{0}:{1}/mgmt/cm/global/tasks/device-remove-mgmt-authority/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.post(uri, json=params)
-
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 409]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- task = "https://{0}:{1}/mgmt/cm/global/tasks/device-remove-mgmt-authority/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- response['id']
- )
- query = "?$select=status,currentStep,errorMessage"
-
- self._wait_for_task(task + query)
-
- def remove_trust_from_device(self):
- params = dict(
- deviceReference=dict(
- link="https://localhost/mgmt/cm/system/machineid-resolver/{0}".format(self.device_id)
- ),
- name='remove_auth_{0}'.format(self.want.device_address)
-
- )
- uri = "https://{0}:{1}/mgmt/cm/global/tasks/device-remove-trust/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.post(uri, json=params)
-
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 409]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- task = "https://{0}:{1}/mgmt/cm/global/tasks/device-remove-trust/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- response['id']
- )
- query = "?$select=status,currentStep,errorMessage"
-
- self._wait_for_task(task + query)
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/cm/system/machineid-resolver/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- self.device_id
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return ApiParameters(params=response)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- self.conflict = ['use_bigip', 'use_bigiq']
- argument_spec = dict(
- device_address=dict(
- required=True
- ),
- device_username=dict(
- no_log=True
- ),
- device_password=dict(
- no_log=True
- ),
- device_port=dict(
- type='int',
- default=443
- ),
- ha_name=dict(),
- use_bigiq_sync=dict(
- type='bool',
- default='no'
- ),
- conflict_policy=dict(
- choices=self.conflict,
- default='use_bigiq'
- ),
- versioned_conflict_policy=dict(
- choices=self.conflict + ['keep_version'],
- ),
- device_conflict_policy=dict(
- choices=self.conflict,
- default='use_bigiq'
- ),
- force=dict(
- type='bool',
- default='no'
- ),
- modules=dict(
- type='list',
- choices=[
- 'ltm', 'asm', 'afm', 'dns', 'websafe', 'security_shared', 'apm'
- ]
- ),
- access_conflict_policy=dict(
- choices=self.conflict + ['keep_version']
- ),
- access_group_name=dict(),
- access_group_first_device=dict(
- type='bool',
- default='yes'
- ),
- statistics=dict(
- type='dict',
- options=dict(
- enable=dict(
- type='bool',
- default='no'
- ),
- interval=dict(
- type='int',
- choices=[
- 30, 60, 120, 500
- ],
- default=60
- ),
- zone=dict(
- type='str',
- default='default'
- ),
- stat_modules=dict(
- type='list',
- choices=[
- 'device', 'ltm', 'dns'
- ],
- default=[
- 'device', 'ltm'
- ]
- )
- )
-
- ),
- state=dict(default='present', choices=['absent', 'present']),
- )
- self.required_if = [
- ['use_bigiq_sync', True, ['ha_name']]
- ]
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode,
- required_if=spec.required_if
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigiq_device_info.py b/lib/ansible/modules/network/f5/bigiq_device_info.py
deleted file mode 100644
index 817d81fded..0000000000
--- a/lib/ansible/modules/network/f5/bigiq_device_info.py
+++ /dev/null
@@ -1,2313 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright (c) 2018 F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigiq_device_info
-short_description: Collect information from F5 BIG-IQ devices
-description:
- - Collect information from F5 BIG-IQ devices.
- - This module was called C(bigiq_device_facts) before Ansible 2.9. The usage did not change.
-version_added: 2.8
-options:
- gather_subset:
- description:
- - When supplied, this argument will restrict the information returned to a given subset.
- - Can specify a list of values to include a larger subset.
- - Values can also be used with an initial C(!) to specify that a specific subset
- should not be collected.
- type: list
- required: True
- choices:
- - all
- - applications
- - managed-devices
- - purchased-pool-licenses
- - regkey-pools
- - system-info
- - vlans
- - "!all"
- - "!applications"
- - "!managed-devices"
- - "!purchased-pool-licenses"
- - "!regkey-pools"
- - "!system-info"
- - "!vlans"
-extends_documentation_fragment: f5
-author:
- - Tim Rupp (@caphrim007)
-'''
-
-EXAMPLES = r'''
-- name: Collect BIG-IQ information
- bigiq_device_info:
- gather_subset:
- - system-info
- - vlans
- provider:
- server: lb.mydomain.com
- user: admin
- password: secret
- delegate_to: localhost
-
-- name: Collect all BIG-IQ information
- bigiq_device_info:
- gather_subset:
- - all
- provider:
- server: lb.mydomain.com
- user: admin
- password: secret
- delegate_to: localhost
-
-- name: Collect all BIG-IP information except trunks
- bigiq_device_info:
- gather_subset:
- - all
- - "!trunks"
- provider:
- server: lb.mydomain.com
- user: admin
- password: secret
- delegate_to: localhost
-'''
-
-RETURN = r'''
-applications:
- description: Application related information
- returned: When C(managed-devices) is specified in C(gather_subset).
- type: complex
- contains:
- protection_mode:
- description:
- - The type of F5 Web Application Security Service protection on the application.
- returned: changed
- type: str
- sample: Not Protected
- id:
- description:
- - ID of the application as known to the BIG-IQ.
- returned: changed
- type: str
- sample: 996baae8-5d1d-3662-8a2d-3612fa2aceae
- name:
- description:
- - Name of the application.
- returned: changed
- type: str
- sample: site12http.example.com
- status:
- description:
- - Current state of the application.
- returned: changed
- type: str
- sample: DEPLOYED
- transactions_per_second:
- description:
- - Current measurement of Transactions Per second being handled by the application.
- returned: changed
- type: float
- sample: 0.87
- connections:
- description:
- - Current number of connections established to the application.
- returned: changed
- type: float
- sample: 3.06
- new_connections:
- description:
- - Number of new connections being established per second.
- returned: changed
- type: float
- sample: 0.35
- response_time:
- description:
- - Measured response time of the application in milliseconds.
- returned: changed
- type: float
- sample: 0.02
- health:
- description:
- - Health of the application.
- returned: changed
- type: str
- sample: Good
- active_alerts:
- description:
- - Number of alerts active on the application.
- returned: changed
- type: int
- sample: 0
- bad_traffic:
- description:
- - Percent of traffic to application that is determined to be 'bad'.
- - This value is dependent on C(protection_mode) being enabled.
- returned: changed
- type: float
- sample: 1.7498
- enhanced_analytics:
- description:
- - Whether enhanced analytics is enabled for the application or not.
- returned: changed
- type: bool
- sample: yes
- bad_traffic_growth:
- description:
- - Whether or not Bad Traffic Growth alerts are configured to be triggered or not.
- returned: changed
- type: bool
- sample: no
- sample: hash/dictionary of values
-managed_devices:
- description: Managed device related information.
- returned: When C(managed-devices) is specified in C(gather_subset).
- type: complex
- contains:
- address:
- description:
- - Address where the device was discovered.
- returned: changed
- type: str
- sample: 10.10.10.10
- build:
- description:
- - Build of the version.
- returned: changed
- type: str
- sample: 0.0.4
- device_uri:
- description:
- - URI to reach the management interface of the device.
- returned: changed
- type: str
- sample: "https://10.10.10.10:443"
- edition:
- description:
- - Edition string of the product version.
- returned: changed
- type: str
- sample: Final
- group_name:
- description:
- - BIG-IQ group that the device is a member of.
- returned: changed
- type: str
- sample: cm-bigip-allBigIpDevices
- hostname:
- description:
- - Discovered hostname of the device.
- returned: changed
- type: str
- sample: tier2labB1.lab.fp.foo.com
- https_port:
- description:
- - HTTPS port available on the management interface of the device.
- returned: changed
- type: int
- sample: 443
- is_clustered:
- description:
- - Whether the device is clustered or not.
- returned: changed
- type: bool
- sample: no
- is_license_expired:
- description:
- - Whether the license on the device is expired or not.
- returned: changed
- type: bool
- sample: yes
- is_virtual:
- description:
- - Whether the device is a virtual edition or not.
- returned: changed
- type: bool
- sample: yes
- machine_id:
- description:
- - Machine specific ID assigned to this device by BIG-IQ.
- returned: changed
- type: str
- sample: c141bc88-f734-4434-be64-a3e9ea98356e
- management_address:
- description:
- - IP address of the management interface on the device.
- returned: changed
- type: str
- sample: 10.10.10.10
- mcp_device_name:
- description:
- - Device name as known by MCPD on the BIG-IP.
- returned: changed
- type: str
- sample: /Common/tier2labB1.lab.fp.foo.com
- product:
- description:
- - Product that the managed device is identified as.
- returned: changed
- type: str
- sample: BIG-IP
- rest_framework_version:
- description:
- - REST framework version running on the device
- returned: changed
- type: str
- sample: 13.1.1-0.0.4
- self_link:
- description:
- - Internal reference to the managed device in BIG-IQ.
- returned: changed
- type: str
- sample: "https://localhost/mgmt/shared/resolver/device-groups/cm-bigip-allBigIpDevices/devices/c141bc88-f734-4434-be64-a3e9ea98356e"
- slots:
- description:
- - Volumes on the device and versions of software installed in those volumes.
- returned: changed
- type: complex
- sample: {"volume": "HD1.1", "product": "BIG-IP", "version": "13.1.1", "build": "0.0.4", "isActive": "yes"}
- state:
- description:
- - State of the device.
- returned: changed
- type: str
- sample: ACTIVE
- tags:
- description:
- - Misc tags that are assigned to the device.
- returned: changed
- type: complex
- sample: {'BIGIQ_tier_2_device': '2018-08-22T13:30:47.693-07:00', 'BIGIQ_SSG_name': 'tim-ssg'}
- trust_domain_guid:
- description:
- - GUID of the trust domain the device is part of.
- returned: changed
- type: str
- sample: 40ddf541-e604-4905-bde3005056813e36
- uuid:
- description:
- - UUID of the device in BIG-IQ.
- returned: changed
- type: str
- sample: c141bc88-f734-4434-be64-a3e9ea98356e
- version:
- description:
- - Version of TMOS installed on the device.
- returned: changed
- type: str
- sample: 13.1.1
- sample: hash/dictionary of values
-purchased_pool_licenses:
- description: Purchased Pool License related information.
- returned: When C(purchased-pool-licenses) is specified in C(gather_subset).
- type: complex
- contains:
- base_reg_key:
- description:
- - Base registration key of the purchased pool
- returned: changed
- type: str
- sample: XXXXX-XXXXX-XXXXX-XXXXX-XXXXXXX
- dossier:
- description:
- - Dossier of the purchased pool license
- returned: changed
- type: str
- sample: d6bd4b8ba5...e9a1a1199b73af9932948a
- free_device_licenses:
- description:
- - Number of free licenses remaining.
- returned: changed
- type: int
- sample: 34
- name:
- description:
- - Name of the purchased pool
- returned: changed
- type: str
- sample: my-pool1
- state:
- description:
- - State of the purchased pool license
- returned: changed
- type: str
- sample: LICENSED
- total_device_licenses:
- description:
- - Total number of licenses in the pool.
- returned: changed
- type: int
- sample: 40
- uuid:
- description:
- - UUID of the purchased pool license
- returned: changed
- type: str
- sample: b2112329-cba7-4f1f-9a26-fab9be416d60
- vendor:
- description:
- - Vendor who provided the license
- returned: changed
- type: str
- sample: F5 Networks, Inc
- licensed_date_time:
- description:
- - Timestamp that the pool was licensed.
- returned: changed
- type: str
- sample: "2018-09-10T00:00:00-07:00"
- licensed_version:
- description:
- - Version of BIG-IQ that is licensed.
- returned: changed
- type: str
- sample: 6.0.1
- evaluation_start_date_time:
- description:
- - Date that evaluation license starts.
- returned: changed
- type: str
- sample: "2018-09-09T00:00:00-07:00"
- evaluation_end_date_time:
- description:
- - Date that evaluation license ends.
- returned: changed
- type: str
- sample: "2018-10-11T00:00:00-07:00"
- license_end_date_time:
- description:
- - Date that the license expires.
- returned: changed
- type: str
- sample: "2018-10-11T00:00:00-07:00"
- license_start_date_time:
- description:
- - Date that the license starts.
- returned: changed
- type: str
- sample: "2018-09-09T00:00:00-07:00"
- registration_key:
- description:
- - Purchased pool license key.
- returned: changed
- type: str
- sample: XXXXX-XXXXX-XXXXX-XXXXX-XXXXXXX
- sample: hash/dictionary of values
-regkey_pools:
- description: Regkey Pool related information.
- returned: When C(regkey-pools) is specified in C(gather_subset).
- type: complex
- contains:
- name:
- description:
- - Name of the regkey pool.
- returned: changed
- type: str
- sample: pool1
- id:
- description:
- - ID of the regkey pool.
- returned: changed
- type: str
- sample: 4f9b565c-0831-4657-b6c2-6dde6182a502
- total_offerings:
- description:
- - Total number of offerings in the pool
- returned: changed
- type: int
- sample: 10
- offerings:
- description: List of the offerings in the pool.
- type: complex
- contains:
- dossier:
- description:
- - Dossier of the license.
- returned: changed
- type: str
- sample: d6bd4b8ba5...e9a1a1199b73af9932948a
- name:
- description:
- - Name of the regkey.
- returned: changed
- type: str
- sample: regkey1
- state:
- description:
- - State of the regkey license
- returned: changed
- type: str
- sample: LICENSED
- licensed_date_time:
- description:
- - Timestamp that the regkey was licensed.
- returned: changed
- type: str
- sample: "2018-09-10T00:00:00-07:00"
- licensed_version:
- description:
- - Version of BIG-IQ that is licensed.
- returned: changed
- type: str
- sample: 6.0.1
- evaluation_start_date_time:
- description:
- - Date that evaluation license starts.
- returned: changed
- type: str
- sample: "2018-09-09T00:00:00-07:00"
- evaluation_end_date_time:
- description:
- - Date that evaluation license ends.
- returned: changed
- type: str
- sample: "2018-10-11T00:00:00-07:00"
- license_end_date_time:
- description:
- - Date that the license expires.
- returned: changed
- type: str
- sample: "2018-10-11T00:00:00-07:00"
- license_start_date_time:
- description:
- - Date that the license starts.
- returned: changed
- type: str
- sample: "2018-09-09T00:00:00-07:00"
- registration_key:
- description:
- - Registration license key.
- returned: changed
- type: str
- sample: XXXXX-XXXXX-XXXXX-XXXXX-XXXXXXX
- sample: hash/dictionary of values
- sample: hash/dictionary of values
-system_info:
- description: System info related information.
- returned: When C(system-info) is specified in C(gather_subset).
- type: complex
- contains:
- base_mac_address:
- description:
- - Media Access Control address (MAC address) of the device.
- returned: changed
- type: str
- sample: "fa:16:3e:c3:42:6f"
- marketing_name:
- description:
- - Marketing name of the device platform.
- returned: changed
- type: str
- sample: BIG-IQ Virtual Edition
- time:
- description:
- - Mapping of the current time information to specific time-named keys.
- returned: changed
- type: complex
- contains:
- day:
- description:
- - The current day of the month, in numeric form.
- returned: changed
- type: int
- sample: 7
- hour:
- description:
- - The current hour of the day in 24-hour form.
- returned: changed
- type: int
- sample: 18
- minute:
- description:
- - The current minute of the hour.
- returned: changed
- type: int
- sample: 16
- month:
- description:
- - The current month, in numeric form.
- returned: changed
- type: int
- sample: 6
- second:
- description:
- - The current second of the minute.
- returned: changed
- type: int
- sample: 51
- year:
- description:
- - The current year in 4-digit form.
- returned: changed
- type: int
- sample: 2018
- hardware_information:
- description:
- - Information related to the hardware (drives and CPUs) of the system.
- type: complex
- returned: changed
- contains:
- model:
- description:
- - The model of the hardware.
- type: str
- sample: Virtual Disk
- name:
- description:
- - The name of the hardware.
- type: str
- sample: HD1
- type:
- description:
- - The type of hardware.
- type: str
- sample: physical-disk
- versions:
- description:
- - Hardware specific properties
- type: complex
- contains:
- name:
- description:
- - Name of the property
- type: str
- sample: Size
- version:
- description:
- - Value of the property
- type: str
- sample: 154.00G
- is_admin_password_changed:
- description:
- - Whether the admin password was changed from its default or not.
- returned: changed
- type: bool
- sample: yes
- is_root_password_changed:
- description:
- - Whether the root password was changed from its default or not.
- returned: changed
- type: bool
- sample: no
- is_system_setup:
- description:
- - Whether the system has been setup or not.
- returned: changed
- type: bool
- sample: yes
- package_edition:
- description:
- - Displays the software edition.
- returned: changed
- type: str
- sample: Point Release 7
- package_version:
- description:
- - A string combining the C(product_build) and C(product_build_date).
- type: str
- sample: "Build 0.0.1 - Tue May 15 15:26:30 PDT 2018"
- product_code:
- description:
- - Code identifying the product.
- type: str
- sample: BIG-IQ
- product_build:
- description:
- - Build version of the release version.
- type: str
- sample: 0.0.1
- product_version:
- description:
- - Major product version of the running software.
- type: str
- sample: 6.0.0
- product_built:
- description:
- - Unix timestamp of when the product was built.
- type: int
- sample: 180515152630
- product_build_date:
- description:
- - Human readable build date.
- type: str
- sample: "Tue May 15 15:26:30 PDT 2018"
- product_changelist:
- description:
- - Changelist that product branches from.
- type: int
- sample: 2557198
- product_jobid:
- description:
- - ID of the job that built the product version.
- type: int
- sample: 1012030
- chassis_serial:
- description:
- - Serial of the chassis
- type: str
- sample: 11111111-2222-3333-444444444444
- host_board_part_revision:
- description:
- - Revision of the host board.
- type: str
- host_board_serial:
- description:
- - Serial of the host board.
- type: str
- platform:
- description:
- - Platform identifier.
- type: str
- sample: Z100
- switch_board_part_revision:
- description:
- - Switch board revision.
- type: str
- switch_board_serial:
- description:
- - Serial of the switch board.
- type: str
- uptime:
- description:
- - Time, in seconds, since the system booted.
- type: int
- sample: 603202
- sample: hash/dictionary of values
-vlans:
- description: List of VLAN information.
- returned: When C(vlans) is specified in C(gather_subset).
- type: complex
- contains:
- auto_lasthop:
- description:
- - Allows the system to send return traffic to the MAC address that transmitted the
- request, even if the routing table points to a different network or interface.
- returned: changed
- type: str
- sample: enabled
- cmp_hash_algorithm:
- description:
- - Specifies how the traffic on the VLAN will be disaggregated.
- returned: changed
- type: str
- sample: default
- description:
- description:
- - Description of the VLAN.
- returned: changed
- type: str
- sample: My vlan
- failsafe_action:
- description:
- - Action for the system to take when the fail-safe mechanism is triggered.
- returned: changed
- type: str
- sample: reboot
- failsafe_enabled:
- description:
- - Whether failsafe is enabled or not.
- returned: changed
- type: bool
- sample: yes
- failsafe_timeout:
- description:
- - Number of seconds that an active unit can run without detecting network traffic
- on this VLAN before it starts a failover.
- returned: changed
- type: int
- sample: 90
- if_index:
- description:
- - Index assigned to this VLAN. It is a unique identifier assigned for all objects
- displayed in the SNMP IF-MIB.
- returned: changed
- type: int
- sample: 176
- learning_mode:
- description:
- - Whether switch ports placed in the VLAN are configured for switch learning,
- forwarding only, or dropped.
- returned: changed
- type: str
- sample: enable-forward
- interfaces:
- description:
- - List of tagged or untagged interfaces and trunks that you want to configure for the VLAN.
- returned: changed
- type: complex
- contains:
- full_path:
- description:
- - Full name of the resource as known to BIG-IP.
- returned: changed
- type: str
- sample: 1.3
- name:
- description:
- - Relative name of the resource in BIG-IP.
- returned: changed
- type: str
- sample: 1.3
- tagged:
- description:
- - Whether the interface is tagged or not.
- returned: changed
- type: bool
- sample: no
- mtu:
- description:
- - Specific maximum transition unit (MTU) for the VLAN.
- returned: changed
- type: int
- sample: 1500
- sflow_poll_interval:
- description:
- - Maximum interval in seconds between two pollings.
- returned: changed
- type: int
- sample: 0
- sflow_poll_interval_global:
- description:
- - Whether the global VLAN poll-interval setting, overrides the object-level
- poll-interval setting.
- returned: changed
- type: bool
- sample: no
- sflow_sampling_rate:
- description:
- - Ratio of packets observed to the samples generated.
- returned: changed
- type: int
- sample: 0
- sflow_sampling_rate_global:
- description:
- - Whether the global VLAN sampling-rate setting, overrides the object-level
- sampling-rate setting.
- returned: changed
- type: bool
- sample: yes
- source_check_enabled:
- description:
- - Specifies that only connections that have a return route in the routing table are accepted.
- returned: changed
- type: bool
- sample: yes
- true_mac_address:
- description:
- - Media access control (MAC) address for the lowest-numbered interface assigned to this VLAN.
- returned: changed
- type: str
- sample: "fa:16:3e:10:da:ff"
- tag:
- description:
- - Tag number for the VLAN.
- returned: changed
- type: int
- sample: 30
- sample: hash/dictionary of values
-'''
-
-import datetime
-import math
-import re
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.six import iteritems
-from ansible.module_utils.six import string_types
-
-try:
- from library.module_utils.network.f5.bigiq import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.common import fq_name
- from library.module_utils.network.f5.common import flatten_boolean
- from library.module_utils.network.f5.ipaddress import is_valid_ip
- from library.module_utils.network.f5.common import transform_name
-except ImportError:
- from ansible.module_utils.network.f5.bigiq import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.common import fq_name
- from ansible.module_utils.network.f5.common import flatten_boolean
- from ansible.module_utils.network.f5.ipaddress import is_valid_ip
- from ansible.module_utils.network.f5.common import transform_name
-
-
-def parseStats(entry):
- if 'description' in entry:
- return entry['description']
- elif 'value' in entry:
- return entry['value']
- elif 'entries' in entry or 'nestedStats' in entry and 'entries' in entry['nestedStats']:
- if 'entries' in entry:
- entries = entry['entries']
- else:
- entries = entry['nestedStats']['entries']
- result = None
-
- for name in entries:
- entry = entries[name]
- if 'https://localhost' in name:
- name = name.split('/')
- name = name[-1]
- if result and isinstance(result, list):
- result.append(parseStats(entry))
- elif result and isinstance(result, dict):
- result[name] = parseStats(entry)
- else:
- try:
- int(name)
- result = list()
- result.append(parseStats(entry))
- except ValueError:
- result = dict()
- result[name] = parseStats(entry)
- else:
- if '.' in name:
- names = name.split('.')
- key = names[0]
- value = names[1]
- if not result[key]:
- result[key] = {}
- result[key][value] = parseStats(entry)
- else:
- if result and isinstance(result, list):
- result.append(parseStats(entry))
- elif result and isinstance(result, dict):
- result[name] = parseStats(entry)
- else:
- try:
- int(name)
- result = list()
- result.append(parseStats(entry))
- except ValueError:
- result = dict()
- result[name] = parseStats(entry)
- return result
-
-
-class BaseManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = kwargs.get('client', None)
- self.kwargs = kwargs
-
- def exec_module(self):
- results = []
- facts = self.read_facts()
- for item in facts:
- attrs = item.to_return()
- results.append(attrs)
- return results
-
-
-class Parameters(AnsibleF5Parameters):
- @property
- def gather_subset(self):
- if isinstance(self._values['gather_subset'], string_types):
- self._values['gather_subset'] = [self._values['gather_subset']]
- elif not isinstance(self._values['gather_subset'], list):
- raise F5ModuleError(
- "The specified gather_subset must be a list."
- )
- tmp = list(set(self._values['gather_subset']))
- tmp.sort()
- self._values['gather_subset'] = tmp
-
- return self._values['gather_subset']
-
-
-class BaseParameters(Parameters):
- @property
- def enabled(self):
- return flatten_boolean(self._values['enabled'])
-
- @property
- def disabled(self):
- return flatten_boolean(self._values['disabled'])
-
- def _remove_internal_keywords(self, resource):
- resource.pop('kind', None)
- resource.pop('generation', None)
- resource.pop('selfLink', None)
- resource.pop('isSubcollection', None)
- resource.pop('fullPath', None)
-
- def to_return(self):
- result = {}
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- return result
-
-
-class ApplicationsParameters(BaseParameters):
- api_map = {
- 'protectionMode': 'protection_mode',
- 'transactionsPerSecond': 'transactions_per_second',
- 'newConnections': 'new_connections',
- 'responseTime': 'response_time',
- 'activeAlerts': 'active_alerts',
- 'badTraffic': 'bad_traffic',
- 'enhancedAnalytics': 'enhanced_analytics',
- 'badTrafficGrowth': 'bad_traffic_growth'
- }
-
- returnables = [
- 'protection_mode',
- 'id',
- 'name',
- 'status',
- 'transactions_per_second',
- 'connections',
- 'new_connections',
- 'response_time',
- 'health',
- 'active_alerts',
- 'bad_traffic',
- 'enhanced_analytics',
- 'bad_traffic_growth',
- ]
-
- @property
- def enhanced_analytics(self):
- return flatten_boolean(self._values['enhanced_analytics'])
-
- @property
- def bad_traffic_growth(self):
- return flatten_boolean(self._values['bad_traffic_growth'])
-
-
-class ApplicationsFactManager(BaseManager):
- def __init__(self, *args, **kwargs):
- self.client = kwargs.get('client', None)
- self.module = kwargs.get('module', None)
- super(ApplicationsFactManager, self).__init__(**kwargs)
- self.want = ApplicationsParameters(params=self.module.params)
-
- def exec_module(self):
- facts = self._exec_module()
- result = dict(applications=facts)
- return result
-
- def _exec_module(self):
- results = []
- facts = self.read_facts()
- for item in facts:
- attrs = item.to_return()
- results.append(attrs)
- results = sorted(results, key=lambda k: k['name'])
- return results
-
- def read_facts(self):
- results = []
- collection = self.read_collection_from_device()
- for resource in collection:
- params = ApplicationsParameters(params=resource)
- results.append(params)
- return results
-
- def read_collection_from_device(self):
- uri = "https://{0}:{1}/mgmt/ap/query/v1/tenants/default/reports/AllApplicationsList".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- try:
- return response['result']['items']
- except KeyError:
- return []
-
-
-class ManagedDevicesParameters(BaseParameters):
- api_map = {
- 'deviceUri': 'device_uri',
- 'groupName': 'group_name',
- 'httpsPort': 'https_port',
- 'isClustered': 'is_clustered',
- 'isLicenseExpired': 'is_license_expired',
- 'isVirtual': 'is_virtual',
- 'machineId': 'machine_id',
- 'managementAddress': 'management_address',
- 'mcpDeviceName': 'mcp_device_name',
- 'restFrameworkVersion': 'rest_framework_version',
- 'selfLink': 'self_link',
- 'trustDomainGuid': 'trust_domain_guid',
- }
-
- returnables = [
- 'address',
- 'build',
- 'device_uri',
- 'edition',
- 'group_name',
- 'hostname',
- 'https_port',
- 'is_clustered',
- 'is_license_expired',
- 'is_virtual',
- 'machine_id',
- 'management_address',
- 'mcp_device_name',
- 'product',
- 'rest_framework_version',
- 'self_link',
- 'slots',
- 'state',
- 'tags',
- 'trust_domain_guid',
- 'uuid',
- 'version',
- ]
-
- @property
- def slots(self):
- result = []
- if self._values['slots'] is None:
- return None
- for x in self._values['slots']:
- x['is_active'] = flatten_boolean(x.pop('isActive', False))
- result.append(x)
- return result
-
- @property
- def tags(self):
- if self._values['tags'] is None:
- return None
- result = dict((x['name'], x['value']) for x in self._values['tags'])
- return result
-
- @property
- def https_port(self):
- return int(self._values['https_port'])
-
- @property
- def is_clustered(self):
- return flatten_boolean(self._values['is_clustered'])
-
- @property
- def is_license_expired(self):
- return flatten_boolean(self._values['is_license_expired'])
-
- @property
- def is_virtual(self):
- return flatten_boolean(self._values['is_virtual'])
-
-
-class ManagedDevicesFactManager(BaseManager):
- def __init__(self, *args, **kwargs):
- self.client = kwargs.get('client', None)
- self.module = kwargs.get('module', None)
- super(ManagedDevicesFactManager, self).__init__(**kwargs)
- self.want = ManagedDevicesParameters(params=self.module.params)
-
- def exec_module(self):
- facts = self._exec_module()
- result = dict(managed_devices=facts)
- return result
-
- def _exec_module(self):
- results = []
- facts = self.read_facts()
- for item in facts:
- attrs = item.to_return()
- results.append(attrs)
- results = sorted(results, key=lambda k: k['hostname'])
- return results
-
- def read_facts(self):
- results = []
- collection = self.read_collection_from_device()
- for resource in collection:
- params = ManagedDevicesParameters(params=resource)
- results.append(params)
- return results
-
- def read_collection_from_device(self):
- uri = "https://{0}:{1}/mgmt/shared/resolver/device-groups/cm-bigip-allBigIpDevices/devices".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- if 'items' not in response:
- return []
- result = response['items']
- return result
-
-
-class PurchasedPoolLicensesParameters(BaseParameters):
- api_map = {
- 'baseRegKey': 'base_reg_key',
- 'freeDeviceLicenses': 'free_device_licenses',
- 'licenseState': 'license_state',
- 'totalDeviceLicenses': 'total_device_licenses',
- }
-
- returnables = [
- 'base_reg_key',
- 'dossier',
- 'free_device_licenses',
- 'name',
- 'state',
- 'total_device_licenses',
- 'uuid',
-
- # license_state facts
- 'vendor',
- 'licensed_date_time',
- 'licensed_version',
- 'evaluation_start_date_time',
- 'evaluation_end_date_time',
- 'license_end_date_time',
- 'license_start_date_time',
- 'registration_key',
- ]
-
- @property
- def registration_key(self):
- try:
- return self._values['license_state']['registrationKey']
- except KeyError:
- return None
-
- @property
- def license_start_date_time(self):
- try:
- return self._values['license_state']['licenseStartDateTime']
- except KeyError:
- return None
-
- @property
- def license_end_date_time(self):
- try:
- return self._values['license_state']['licenseEndDateTime']
- except KeyError:
- return None
-
- @property
- def evaluation_end_date_time(self):
- try:
- return self._values['license_state']['evaluationEndDateTime']
- except KeyError:
- return None
-
- @property
- def evaluation_start_date_time(self):
- try:
- return self._values['license_state']['evaluationStartDateTime']
- except KeyError:
- return None
-
- @property
- def licensed_version(self):
- try:
- return self._values['license_state']['licensedVersion']
- except KeyError:
- return None
-
- @property
- def licensed_date_time(self):
- try:
- return self._values['license_state']['licensedDateTime']
- except KeyError:
- return None
-
- @property
- def vendor(self):
- try:
- return self._values['license_state']['vendor']
- except KeyError:
- return None
-
-
-class PurchasedPoolLicensesFactManager(BaseManager):
- def __init__(self, *args, **kwargs):
- self.client = kwargs.get('client', None)
- self.module = kwargs.get('module', None)
- super(PurchasedPoolLicensesFactManager, self).__init__(**kwargs)
- self.want = PurchasedPoolLicensesParameters(params=self.module.params)
-
- def exec_module(self):
- facts = self._exec_module()
- result = dict(purchased_pool_licenses=facts)
- return result
-
- def _exec_module(self):
- results = []
- facts = self.read_facts()
- for item in facts:
- attrs = item.to_return()
- results.append(attrs)
- results = sorted(results, key=lambda k: k['name'])
- return results
-
- def read_facts(self):
- results = []
- collection = self.read_collection_from_device()
- for resource in collection:
- params = PurchasedPoolLicensesParameters(params=resource)
- results.append(params)
- return results
-
- def read_collection_from_device(self):
- uri = "https://{0}:{1}/mgmt/cm/device/licensing/pool/purchased-pool/licenses".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- try:
- return response['items']
- except KeyError:
- return []
-
-
-class RegkeyPoolsParameters(BaseParameters):
- api_map = {
-
- }
-
- returnables = [
- 'name',
- 'id',
- 'offerings',
- 'total_offerings',
- ]
-
-
-class RegkeyPoolsOfferingParameters(BaseParameters):
- api_map = {
- 'regKey': 'registration_key',
- 'licenseState': 'license_state',
- 'status': 'state',
- }
-
- returnables = [
- 'name',
- 'dossier',
- 'state',
-
- # license_state facts
- 'licensed_date_time',
- 'licensed_version',
- 'evaluation_start_date_time',
- 'evaluation_end_date_time',
- 'license_end_date_time',
- 'license_start_date_time',
- 'registration_key',
- ]
-
- @property
- def registration_key(self):
- try:
- return self._values['license_state']['registrationKey']
- except KeyError:
- return None
-
- @property
- def license_start_date_time(self):
- try:
- return self._values['license_state']['licenseStartDateTime']
- except KeyError:
- return None
-
- @property
- def license_end_date_time(self):
- try:
- return self._values['license_state']['licenseEndDateTime']
- except KeyError:
- return None
-
- @property
- def evaluation_end_date_time(self):
- try:
- return self._values['license_state']['evaluationEndDateTime']
- except KeyError:
- return None
-
- @property
- def evaluation_start_date_time(self):
- try:
- return self._values['license_state']['evaluationStartDateTime']
- except KeyError:
- return None
-
- @property
- def licensed_version(self):
- try:
- return self._values['license_state']['licensedVersion']
- except KeyError:
- return None
-
- @property
- def licensed_date_time(self):
- try:
- return self._values['license_state']['licensedDateTime']
- except KeyError:
- return None
-
- @property
- def vendor(self):
- try:
- return self._values['license_state']['vendor']
- except KeyError:
- return None
-
-
-class RegkeyPoolsFactManager(BaseManager):
- def __init__(self, *args, **kwargs):
- self.client = kwargs.get('client', None)
- self.module = kwargs.get('module', None)
- super(RegkeyPoolsFactManager, self).__init__(**kwargs)
- self.want = RegkeyPoolsParameters(params=self.module.params)
-
- def exec_module(self):
- facts = self._exec_module()
- result = dict(regkey_pools=facts)
- return result
-
- def _exec_module(self):
- results = []
- facts = self.read_facts()
- for item in facts:
- attrs = item.to_return()
- results.append(attrs)
- results = sorted(results, key=lambda k: k['name'])
- return results
-
- def read_facts(self):
- results = []
- collection = self.read_collection_from_device()
- for resource in collection:
- params = RegkeyPoolsParameters(params=resource)
- offerings = self.read_offerings_from_device(resource['id'])
- params.update({'total_offerings': len(offerings)})
- for offering in offerings:
- params2 = RegkeyPoolsOfferingParameters(params=offering)
- params.update({'offerings': params2.to_return()})
- results.append(params)
- return results
-
- def read_collection_from_device(self):
- uri = "https://{0}:{1}/mgmt/cm/device/licensing/pool/regkey/licenses".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- try:
- return response['items']
- except KeyError:
- return []
-
- def read_offerings_from_device(self, license):
- uri = "https://{0}:{1}/mgmt/cm/device/licensing/pool/regkey/licenses/{2}/offerings".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- license,
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- try:
- return response['items']
- except KeyError:
- return []
-
-
-class SystemInfoParameters(BaseParameters):
- api_map = {
- 'isSystemSetup': 'is_system_setup',
- 'isAdminPasswordChanged': 'is_admin_password_changed',
- 'isRootPasswordChanged': 'is_root_password_changed'
- }
-
- returnables = [
- 'base_mac_address',
- 'chassis_serial',
- 'hardware_information',
- 'host_board_part_revision',
- 'host_board_serial',
- 'is_admin_password_changed',
- 'is_root_password_changed',
- 'is_system_setup',
- 'marketing_name',
- 'package_edition',
- 'package_version',
- 'platform',
- 'product_build',
- 'product_build_date',
- 'product_built',
- 'product_changelist',
- 'product_code',
- 'product_information',
- 'product_jobid',
- 'product_version',
- 'switch_board_part_revision',
- 'switch_board_serial',
- 'time',
- 'uptime',
- ]
-
- @property
- def is_admin_password_changed(self):
- return flatten_boolean(self._values['is_admin_password_changed'])
-
- @property
- def is_root_password_changed(self):
- return flatten_boolean(self._values['is_root_password_changed'])
-
- @property
- def is_system_setup(self):
- if self._values['is_system_setup'] is None:
- return 'no'
- return flatten_boolean(self._values['is_system_setup'])
-
- @property
- def chassis_serial(self):
- if self._values['system-info'] is None:
- return None
-
- # Yes, this is still called "bigip" even though this is querying the BIG-IQ
- # product. This is likely due to BIG-IQ inheriting TMOS.
- if 'bigipChassisSerialNum' not in self._values['system-info'][0]:
- return None
- return self._values['system-info'][0]['bigipChassisSerialNum']
-
- @property
- def switch_board_serial(self):
- if self._values['system-info'] is None:
- return None
- if 'switchBoardSerialNum' not in self._values['system-info'][0]:
- return None
- if self._values['system-info'][0]['switchBoardSerialNum'].strip() == '':
- return None
- return self._values['system-info'][0]['switchBoardSerialNum']
-
- @property
- def switch_board_part_revision(self):
- if self._values['system-info'] is None:
- return None
- if 'switchBoardPartRevNum' not in self._values['system-info'][0]:
- return None
- if self._values['system-info'][0]['switchBoardPartRevNum'].strip() == '':
- return None
- return self._values['system-info'][0]['switchBoardPartRevNum']
-
- @property
- def platform(self):
- if self._values['system-info'] is None:
- return None
- return self._values['system-info'][0]['platform']
-
- @property
- def host_board_serial(self):
- if self._values['system-info'] is None:
- return None
- if 'hostBoardSerialNum' not in self._values['system-info'][0]:
- return None
- if self._values['system-info'][0]['hostBoardSerialNum'].strip() == '':
- return None
- return self._values['system-info'][0]['hostBoardSerialNum']
-
- @property
- def host_board_part_revision(self):
- if self._values['system-info'] is None:
- return None
- if 'hostBoardPartRevNum' not in self._values['system-info'][0]:
- return None
- if self._values['system-info'][0]['hostBoardPartRevNum'].strip() == '':
- return None
- return self._values['system-info'][0]['hostBoardPartRevNum']
-
- @property
- def package_edition(self):
- return self._values['Edition']
-
- @property
- def package_version(self):
- return 'Build {0} - {1}'.format(self._values['Build'], self._values['Date'])
-
- @property
- def product_build(self):
- return self._values['Build']
-
- @property
- def product_build_date(self):
- return self._values['Date']
-
- @property
- def product_built(self):
- if 'version_info' not in self._values:
- return None
- if 'Built' in self._values['version_info']:
- return int(self._values['version_info']['Built'])
-
- @property
- def product_changelist(self):
- if 'version_info' not in self._values:
- return None
- if 'Changelist' in self._values['version_info']:
- return int(self._values['version_info']['Changelist'])
-
- @property
- def product_jobid(self):
- if 'version_info' not in self._values:
- return None
- if 'JobID' in self._values['version_info']:
- return int(self._values['version_info']['JobID'])
-
- @property
- def product_code(self):
- return self._values['Product']
-
- @property
- def product_version(self):
- return self._values['Version']
-
- @property
- def hardware_information(self):
- if self._values['hardware-version'] is None:
- return None
- self._transform_name_attribute(self._values['hardware-version'])
- result = [v for k, v in iteritems(self._values['hardware-version'])]
- return result
-
- def _transform_name_attribute(self, entry):
- if isinstance(entry, dict):
- for k, v in iteritems(entry):
- if k == 'tmName':
- entry['name'] = entry.pop('tmName')
- self._transform_name_attribute(v)
- elif isinstance(entry, list):
- for k in entry:
- if k == 'tmName':
- entry['name'] = entry.pop('tmName')
- self._transform_name_attribute(k)
- else:
- return
-
- @property
- def time(self):
- if self._values['fullDate'] is None:
- return None
- date = datetime.datetime.strptime(self._values['fullDate'], "%Y-%m-%dT%H:%M:%SZ")
- result = dict(
- day=date.day,
- hour=date.hour,
- minute=date.minute,
- month=date.month,
- second=date.second,
- year=date.year
- )
- return result
-
- @property
- def marketing_name(self):
- if self._values['platform'] is None:
- return None
- return self._values['platform'][0]['marketingName']
-
- @property
- def base_mac_address(self):
- if self._values['platform'] is None:
- return None
- return self._values['platform'][0]['baseMac']
-
-
-class SystemInfoFactManager(BaseManager):
- def __init__(self, *args, **kwargs):
- self.client = kwargs.get('client', None)
- self.module = kwargs.get('module', None)
- super(SystemInfoFactManager, self).__init__(**kwargs)
- self.want = SystemInfoParameters(params=self.module.params)
-
- def exec_module(self):
- facts = self._exec_module()
- result = dict(system_info=facts)
- return result
-
- def _exec_module(self):
- facts = self.read_facts()
- results = facts.to_return()
- return results
-
- def read_facts(self):
- collection = self.read_collection_from_device()
- params = SystemInfoParameters(params=collection)
- return params
-
- def read_collection_from_device(self):
- result = dict()
- tmp = self.read_hardware_info_from_device()
- if tmp:
- result.update(tmp)
-
- tmp = self.read_system_setup_from_device()
- if tmp:
- result.update(tmp)
-
- tmp = self.read_clock_info_from_device()
- if tmp:
- result.update(tmp)
-
- tmp = self.read_version_info_from_device()
- if tmp:
- result.update(tmp)
-
- tmp = self.read_uptime_info_from_device()
- if tmp:
- result.update(tmp)
-
- tmp = self.read_version_file_info_from_device()
- if tmp:
- result.update(tmp)
-
- return result
-
- def read_system_setup_from_device(self):
- uri = "https://{0}:{1}/mgmt/shared/system/setup".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- return response
-
- def read_version_file_info_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/util/bash".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- args = dict(
- command='run',
- utilCmdArgs='-c "cat /VERSION"'
- )
- resp = self.client.api.post(uri, json=args)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- try:
- pattern = r'^(?P<key>(Product|Build|Sequence|BaseBuild|Edition|Date|Built|Changelist|JobID))\:(?P<value>.*)'
- result = response['commandResult'].strip()
- except KeyError:
- return None
-
- if 'No such file or directory' in result:
- return None
-
- lines = response['commandResult'].split("\n")
- result = dict()
- for line in lines:
- if not line:
- continue
- matches = re.match(pattern, line)
- if matches:
- result[matches.group('key')] = matches.group('value').strip()
-
- if result:
- return dict(
- version_info=result
- )
-
- def read_uptime_info_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/util/bash".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- args = dict(
- command='run',
- utilCmdArgs='-c "cat /proc/uptime"'
- )
- resp = self.client.api.post(uri, json=args)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- try:
- parts = response['commandResult'].strip().split(' ')
- return dict(
- uptime=math.floor(float(parts[0]))
- )
- except KeyError:
- pass
-
- def read_hardware_info_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/sys/hardware".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- result = parseStats(response)
- return result
-
- def read_clock_info_from_device(self):
- """Parses clock info from the REST API
-
- The clock stat returned from the REST API (at the time of 13.1.0.7)
- is similar to the following.
-
- {
- "kind": "tm:sys:clock:clockstats",
- "selfLink": "https://localhost/mgmt/tm/sys/clock?ver=13.1.0.4",
- "entries": {
- "https://localhost/mgmt/tm/sys/clock/0": {
- "nestedStats": {
- "entries": {
- "fullDate": {
- "description": "2018-06-05T13:38:33Z"
- }
- }
- }
- }
- }
- }
-
- Parsing this data using the ``parseStats`` method, yields a list of
- the clock stats in a format resembling that below.
-
- [{'fullDate': '2018-06-05T13:41:05Z'}]
-
- Therefore, this method cherry-picks the first entry from this list
- and returns it. There can be no other items in this list.
-
- Returns:
- A dict mapping keys to the corresponding clock stats. For
- example:
-
- {'fullDate': '2018-06-05T13:41:05Z'}
-
- There should never not be a clock stat, unless by chance it
- is removed from the API in the future, or changed to a different
- API endpoint.
-
- Raises:
- F5ModuleError: A non-successful HTTP code was returned or a JSON
- response was not found.
- """
- uri = "https://{0}:{1}/mgmt/tm/sys/clock".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- result = parseStats(response)
- if result is None:
- return None
- return result[0]
-
- def read_version_info_from_device(self):
- """Parses version info from the REST API
-
- The version stat returned from the REST API (at the time of 13.1.0.7)
- is similar to the following.
-
- {
- "kind": "tm:sys:version:versionstats",
- "selfLink": "https://localhost/mgmt/tm/sys/version?ver=13.1.0.4",
- "entries": {
- "https://localhost/mgmt/tm/sys/version/0": {
- "nestedStats": {
- "entries": {
- "Build": {
- "description": "0.0.6"
- },
- "Date": {
- "description": "Tue Mar 13 20:10:42 PDT 2018"
- },
- "Edition": {
- "description": "Point Release 4"
- },
- "Product": {
- "description": "BIG-IP"
- },
- "Title": {
- "description": "Main Package"
- },
- "Version": {
- "description": "13.1.0.4"
- }
- }
- }
- }
- }
- }
-
- Parsing this data using the ``parseStats`` method, yields a list of
- the clock stats in a format resembling that below.
-
- [{'Build': '0.0.6', 'Date': 'Tue Mar 13 20:10:42 PDT 2018',
- 'Edition': 'Point Release 4', 'Product': 'BIG-IP', 'Title': 'Main Package',
- 'Version': '13.1.0.4'}]
-
- Therefore, this method cherry-picks the first entry from this list
- and returns it. There can be no other items in this list.
-
- Returns:
- A dict mapping keys to the corresponding clock stats. For
- example:
-
- {'Build': '0.0.6', 'Date': 'Tue Mar 13 20:10:42 PDT 2018',
- 'Edition': 'Point Release 4', 'Product': 'BIG-IP', 'Title': 'Main Package',
- 'Version': '13.1.0.4'}
-
- There should never not be a version stat, unless by chance it
- is removed from the API in the future, or changed to a different
- API endpoint.
-
- Raises:
- F5ModuleError: A non-successful HTTP code was returned or a JSON
- response was not found.
- """
- uri = "https://{0}:{1}/mgmt/tm/sys/version".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- result = parseStats(response)
- if result is None:
- return None
- return result[0]
-
-
-class VlansParameters(BaseParameters):
- api_map = {
- 'autoLasthop': 'auto_lasthop',
- 'cmpHash': 'cmp_hash_algorithm',
- 'failsafeAction': 'failsafe_action',
- 'failsafe': 'failsafe_enabled',
- 'failsafeTimeout': 'failsafe_timeout',
- 'ifIndex': 'if_index',
- 'learning': 'learning_mode',
- 'interfacesReference': 'interfaces',
- 'sourceChecking': 'source_check_enabled',
- 'fullPath': 'full_path'
- }
-
- returnables = [
- 'full_path',
- 'name',
- 'auto_lasthop',
- 'cmp_hash_algorithm',
- 'description',
- 'failsafe_action',
- 'failsafe_enabled',
- 'failsafe_timeout',
- 'if_index',
- 'learning_mode',
- 'interfaces',
- 'mtu',
- 'sflow_poll_interval',
- 'sflow_poll_interval_global',
- 'sflow_sampling_rate',
- 'sflow_sampling_rate_global',
- 'source_check_enabled',
- 'true_mac_address',
- 'tag',
- ]
-
- @property
- def interfaces(self):
- if self._values['interfaces'] is None:
- return None
- if 'items' not in self._values['interfaces']:
- return None
- result = []
- for item in self._values['interfaces']['items']:
- tmp = dict(
- name=item['name'],
- full_path=item['fullPath']
- )
- if 'tagged' in item:
- tmp['tagged'] = 'yes'
- else:
- tmp['tagged'] = 'no'
- result.append(tmp)
- return result
-
- @property
- def sflow_poll_interval(self):
- return int(self._values['sflow']['pollInterval'])
-
- @property
- def sflow_poll_interval_global(self):
- return flatten_boolean(self._values['sflow']['pollIntervalGlobal'])
-
- @property
- def sflow_sampling_rate(self):
- return int(self._values['sflow']['samplingRate'])
-
- @property
- def sflow_sampling_rate_global(self):
- return flatten_boolean(self._values['sflow']['samplingRateGlobal'])
-
- @property
- def source_check_state(self):
- return flatten_boolean(self._values['source_check_state'])
-
- @property
- def true_mac_address(self):
- if self._values['stats']['macTrue'] in [None, 'none']:
- return None
- return self._values['stats']['macTrue']
-
- @property
- def tag(self):
- return self._values['stats']['id']
-
- @property
- def failsafe_enabled(self):
- return flatten_boolean(self._values['failsafe_enabled'])
-
-
-class VlansFactManager(BaseManager):
- def __init__(self, *args, **kwargs):
- self.client = kwargs.get('client', None)
- self.module = kwargs.get('module', None)
- super(VlansFactManager, self).__init__(**kwargs)
- self.want = VlansParameters(params=self.module.params)
-
- def exec_module(self):
- facts = self._exec_module()
- result = dict(vlans=facts)
- return result
-
- def _exec_module(self):
- results = []
- facts = self.read_facts()
- for item in facts:
- attrs = item.to_return()
- results.append(attrs)
- results = sorted(results, key=lambda k: k['full_path'])
- return results
-
- def read_facts(self):
- results = []
- collection = self.read_collection_from_device()
- for resource in collection:
- resource.update(self.read_stats(resource['fullPath']))
- params = VlansParameters(params=resource)
- results.append(params)
- return results
-
- def read_stats(self, resource):
- uri = "https://{0}:{1}/mgmt/tm/net/vlan/{2}/stats".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- transform_name(name=resource)
-
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- result = parseStats(response)
- return result
-
- def read_collection_from_device(self):
- uri = "https://{0}:{1}/mgmt/tm/net/vlan/?expandSubcollections=true".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- if 'items' not in response:
- return []
- result = response['items']
- return result
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = kwargs.get('client', None)
- self.kwargs = kwargs
- self.want = Parameters(params=self.module.params)
- self.managers = {
- 'applications': dict(
- manager=ApplicationsFactManager,
- client=F5RestClient,
- ),
- 'managed-devices': dict(
- manager=ManagedDevicesFactManager,
- client=F5RestClient,
- ),
- 'purchased-pool-licenses': dict(
- manager=PurchasedPoolLicensesFactManager,
- client=F5RestClient,
- ),
- 'regkey-pools': dict(
- manager=RegkeyPoolsFactManager,
- client=F5RestClient,
- ),
- 'system-info': dict(
- manager=SystemInfoFactManager,
- client=F5RestClient,
- ),
- 'vlans': dict(
- manager=VlansFactManager,
- client=F5RestClient,
- ),
- }
-
- def exec_module(self):
- self.handle_all_keyword()
- res = self.check_valid_gather_subset(self.want.gather_subset)
- if res:
- invalid = ','.join(res)
- raise F5ModuleError(
- "The specified 'gather_subset' options are invalid: {0}".format(invalid)
- )
- result = self.filter_excluded_facts()
-
- managers = []
- for name in result:
- manager = self.get_manager(name)
- if manager:
- managers.append(manager)
-
- if not managers:
- result = dict(
- changed=False
- )
- return result
-
- result = self.execute_managers(managers)
- if result:
- result['changed'] = True
- else:
- result['changed'] = False
- return result
-
- def filter_excluded_facts(self):
- # Remove the excluded entries from the list of possible facts
- exclude = [x[1:] for x in self.want.gather_subset if x[0] == '!']
- include = [x for x in self.want.gather_subset if x[0] != '!']
- result = [x for x in include if x not in exclude]
- return result
-
- def handle_all_keyword(self):
- if 'all' not in self.want.gather_subset:
- return
- managers = list(self.managers.keys()) + self.want.gather_subset
- managers.remove('all')
- self.want.update({'gather_subset': managers})
-
- def check_valid_gather_subset(self, includes):
- """Check that the specified subset is valid
-
- The ``gather_subset`` parameter is specified as a "raw" field which means that
- any Python type could technically be provided
-
- :param includes:
- :return:
- """
- keys = self.managers.keys()
- result = []
- for x in includes:
- if x not in keys:
- if x[0] == '!':
- if x[1:] not in keys:
- result.append(x)
- else:
- result.append(x)
- return result
-
- def execute_managers(self, managers):
- results = dict()
- for manager in managers:
- result = manager.exec_module()
- results.update(result)
- return results
-
- def get_manager(self, which):
- result = {}
- info = self.managers.get(which, None)
- if not info:
- return result
- kwargs = dict()
- kwargs.update(self.kwargs)
-
- manager = info.get('manager', None)
- client = info.get('client', None)
- kwargs['client'] = client(**self.module.params)
- result = manager(**kwargs)
- return result
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = False
- argument_spec = dict(
- gather_subset=dict(
- type='list',
- required=True,
- choices=[
- # Meta choices
- 'all',
-
- # Non-meta choices
- 'applications',
- 'managed-devices',
- 'purchased-pool-licenses',
- 'regkey-pools',
- 'system-info',
- 'vlans',
-
- # Negations of meta choices
- '!all',
-
- # Negations of non-meta-choices
- '!applications',
- '!managed-devices',
- '!purchased-pool-licenses',
- '!regkey-pools',
- '!system-info',
- '!vlans',
- ]
- ),
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode
- )
- if module._name == 'bigiq_device_facts':
- module.deprecate("The 'bigiq_device_facts' module has been renamed to 'bigiq_device_info'", version='2.13')
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigiq_regkey_license.py b/lib/ansible/modules/network/f5/bigiq_regkey_license.py
deleted file mode 100644
index 616ea2e7ce..0000000000
--- a/lib/ansible/modules/network/f5/bigiq_regkey_license.py
+++ /dev/null
@@ -1,482 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigiq_regkey_license
-short_description: Manages licenses in a BIG-IQ registration key pool
-description:
- - Manages licenses in a BIG-IQ registration key pool.
-version_added: 2.5
-options:
- regkey_pool:
- description:
- - The registration key pool that you want to place the license in.
- - You must be mindful to name your registration pools unique names. While
- BIG-IQ does not require this, this module does. If you do not do this,
- the behavior of the module is undefined and you may end up putting
- licenses in the wrong registration key pool.
- type: str
- required: True
- license_key:
- description:
- - The license key to put in the pool.
- type: str
- required: True
- description:
- description:
- - Description of the license.
- type: str
- accept_eula:
- description:
- - A key that signifies that you accept the F5 EULA for this license.
- - A copy of the EULA can be found here https://askf5.f5.com/csp/article/K12902
- - This is required when C(state) is C(present).
- type: bool
- state:
- description:
- - The state of the regkey license in the pool on the system.
- - When C(present), guarantees that the license exists in the pool.
- - When C(absent), removes the license from the pool.
- type: str
- choices:
- - absent
- - present
- default: present
-requirements:
- - BIG-IQ >= 5.3.0
-extends_documentation_fragment: f5
-author:
- - Tim Rupp (@caphrim007)
-'''
-
-EXAMPLES = r'''
-- name: Add a registration key license to a pool
- bigiq_regkey_license:
- regkey_pool: foo-pool
- license_key: XXXXX-XXXXX-XXXXX-XXXXX-XXXXX
- accept_eula: yes
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-
-- name: Remove a registration key license from a pool
- bigiq_regkey_license:
- regkey_pool: foo-pool
- license_key: XXXXX-XXXXX-XXXXX-XXXXX-XXXXX
- state: absent
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-'''
-
-RETURN = r'''
-description:
- description: The new description of the license key.
- returned: changed
- type: str
- sample: My license for BIG-IP 1
-'''
-
-import time
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.module_utils.network.f5.bigiq import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import f5_argument_spec
-except ImportError:
- from ansible.module_utils.network.f5.bigiq import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import f5_argument_spec
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'regKey': 'license_key'
- }
-
- api_attributes = [
- 'regKey', 'description'
- ]
-
- returnables = [
- 'description'
- ]
-
- updatables = [
- 'description'
- ]
-
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class ApiParameters(Parameters):
- pass
-
-
-class ModuleParameters(Parameters):
- @property
- def regkey_pool_uuid(self):
- if self._values['regkey_pool_uuid']:
- return self._values['regkey_pool_uuid']
- collection = self.read_current_from_device()
- resource = next((x for x in collection if x.name == self.regkey_pool), None)
- if resource is None:
- raise F5ModuleError("Could not find the specified regkey pool.")
- self._values['regkey_pool_uuid'] = resource.id
- return resource.id
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/cm/device/licensing/pool/regkey/licenses".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- if 'items' not in response:
- return []
- result = [ApiParameters(params=r) for r in response['items']]
- return result
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class UsableChanges(Changes):
- pass
-
-
-class ReportableChanges(Changes):
- pass
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(client=self.client, params=self.module.params)
- self.have = ApiParameters()
- self.changes = UsableChanges()
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = UsableChanges(params=changed)
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def exec_module(self):
- changed = False
- result = dict()
- state = self.want.state
-
- if state == "present":
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def present(self):
- if self.exists():
- return self.update()
- else:
- return self.create()
-
- def exists(self):
- uri = "https://{0}:{1}/mgmt/cm/device/licensing/pool/regkey/licenses/{2}/offerings/{3}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- self.want.regkey_pool_uuid,
- self.want.license_key
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def update(self):
- self.have = self.read_current_from_device()
- if not self.should_update():
- return False
- if self.module.check_mode:
- return True
- self.update_on_device()
- return True
-
- def remove(self):
- if self.module.check_mode:
- return True
- self.remove_from_device()
- if self.exists():
- raise F5ModuleError("Failed to delete the resource.")
- return True
-
- def create(self):
- self._set_changed_options()
- if self.module.check_mode:
- return True
- if self.want.accept_eula is False:
- raise F5ModuleError(
- "To add a license, you must accept its EULA. Please see the module documentation for a link to this."
- )
- self.create_on_device()
- return True
-
- def create_on_device(self):
- params = self.want.api_params()
- params['name'] = self.want.name
- params['status'] = 'ACTIVATING_AUTOMATIC'
- uri = "https://{0}:{1}/mgmt/cm/device/licensing/pool/regkey/licenses/{2}/offerings".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- self.want.regkey_pool_uuid,
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- for x in range(60):
- resource = self.read_current_from_device()
- if resource.status == 'READY':
- break
- elif resource.status == 'ACTIVATING_AUTOMATIC_NEED_EULA_ACCEPT':
- params = dict(
- status='ACTIVATING_AUTOMATIC_EULA_ACCEPTED',
- eulaText=resource.eulaText
- )
- uri = "https://{0}:{1}/mgmt/cm/device/licensing/pool/regkey/licenses/{2}/offerings/{3}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- self.want.regkey_pool_uuid,
- self.want.license_key
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- elif resource.status == 'ACTIVATION_FAILED':
- raise F5ModuleError(str(resource.message))
- time.sleep(1)
-
- def update_on_device(self):
- params = self.changes.api_params()
- uri = "https://{0}:{1}/mgmt/cm/device/licensing/pool/regkey/licenses/{2}/offerings/{3}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- self.want.regkey_pool_uuid,
- self.want.license_key
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def absent(self):
- if self.exists():
- return self.remove()
- return False
-
- def remove_from_device(self):
- uri = "https://{0}:{1}/mgmt/cm/device/licensing/pool/regkey/licenses/{2}/offerings/{3}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- self.want.regkey_pool_uuid,
- self.want.license_key
- )
- resp = self.client.api.delete(uri)
- if resp.status == 200:
- return True
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/cm/device/licensing/pool/regkey/licenses/{2}/offerings/{3}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- self.want.regkey_pool_uuid,
- self.want.license_key
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return ApiParameters(params=response)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- regkey_pool=dict(required=True),
- license_key=dict(required=True, no_log=True),
- description=dict(),
- accept_eula=dict(type='bool'),
- state=dict(
- default='present',
- choices=['present', 'absent']
- ),
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
- self.required_if = [
- ['state', 'present', ['accept_eula']]
- ]
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode,
- required_if=spec.required_if,
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigiq_regkey_license_assignment.py b/lib/ansible/modules/network/f5/bigiq_regkey_license_assignment.py
deleted file mode 100644
index d2788eea91..0000000000
--- a/lib/ansible/modules/network/f5/bigiq_regkey_license_assignment.py
+++ /dev/null
@@ -1,635 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigiq_regkey_license_assignment
-short_description: Manage regkey license assignment on BIG-IPs from a BIG-IQ
-description:
- - Manages the assignment of regkey licenses on a BIG-IQ. Assignment means that
- the license is assigned to a BIG-IP, or, it needs to be assigned to a BIG-IP.
- Additionally, this module supported revoking the assignments from BIG-IP devices.
-version_added: 2.6
-options:
- pool:
- description:
- - The registration key pool to use.
- type: str
- required: True
- key:
- description:
- - The registration key that you want to assign from the pool.
- type: str
- required: True
- device:
- description:
- - When C(managed) is C(no), specifies the address, or hostname, where the BIG-IQ
- can reach the remote device to register.
- - When C(managed) is C(yes), specifies the managed device, or device UUID, that
- you want to register.
- - If C(managed) is C(yes), it is very important that you do not have more than
- one device with the same name. BIG-IQ internally recognizes devices by their ID,
- and therefore, this module's cannot guarantee that the correct device will be
- registered. The device returned is the device that will be used.
- type: str
- managed:
- description:
- - Whether the specified device is a managed or un-managed device.
- - When C(state) is C(present), this parameter is required.
- type: bool
- device_port:
- description:
- - Specifies the port of the remote device to connect to.
- - If this parameter is not specified, the default of C(443) will be used.
- type: int
- default: 443
- device_username:
- description:
- - The username used to connect to the remote device.
- - This username should be one that has sufficient privileges on the remote device
- to do licensing. Usually this is the C(Administrator) role.
- - When C(managed) is C(no), this parameter is required.
- type: str
- device_password:
- description:
- - The password of the C(device_username).
- - When C(managed) is C(no), this parameter is required.
- type: str
- state:
- description:
- - When C(present), ensures that the device is assigned the specified license.
- - When C(absent), ensures the license is revokes from the remote device and freed
- on the BIG-IQ.
- type: str
- choices:
- - present
- - absent
- default: present
-extends_documentation_fragment: f5
-author:
- - Tim Rupp (@caphrim007)
-'''
-
-EXAMPLES = r'''
-- name: Register an unmanaged device
- bigiq_regkey_license_assignment:
- pool: my-regkey-pool
- key: XXXX-XXXX-XXXX-XXXX-XXXX
- device: 1.1.1.1
- managed: no
- device_username: admin
- device_password: secret
- state: present
- provider:
- user: admin
- password: secret
- server: lb.mydomain.com
- delegate_to: localhost
-
-- name: Register a managed device, by name
- bigiq_regkey_license_assignment:
- pool: my-regkey-pool
- key: XXXX-XXXX-XXXX-XXXX-XXXX
- device: bigi1.foo.com
- managed: yes
- state: present
- provider:
- user: admin
- password: secret
- server: lb.mydomain.com
- delegate_to: localhost
-
-- name: Register a managed device, by UUID
- bigiq_regkey_license_assignment:
- pool: my-regkey-pool
- key: XXXX-XXXX-XXXX-XXXX-XXXX
- device: 7141a063-7cf8-423f-9829-9d40599fa3e0
- managed: yes
- state: present
- provider:
- user: admin
- password: secret
- server: lb.mydomain.com
- delegate_to: localhost
-'''
-
-RETURN = r'''
-# only common fields returned
-'''
-
-import re
-import time
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.module_utils.network.f5.bigiq import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.ipaddress import is_valid_ip
-except ImportError:
- from ansible.module_utils.network.f5.bigiq import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.ipaddress import is_valid_ip
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'deviceReference': 'device_reference',
- 'deviceAddress': 'device_address',
- 'httpsPort': 'device_port'
- }
-
- api_attributes = [
- 'deviceReference', 'deviceAddress', 'httpsPort', 'managed'
- ]
-
- returnables = [
- 'device_address', 'device_reference', 'device_username', 'device_password',
- 'device_port', 'managed'
- ]
-
- updatables = [
- 'device_reference', 'device_address', 'device_username', 'device_password',
- 'device_port', 'managed'
- ]
-
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class ApiParameters(Parameters):
- pass
-
-
-class ModuleParameters(Parameters):
- @property
- def device_password(self):
- if self._values['device_password'] is None:
- return None
- return self._values['device_password']
-
- @property
- def device_username(self):
- if self._values['device_username'] is None:
- return None
- return self._values['device_username']
-
- @property
- def device_address(self):
- if self.device_is_address:
- return self._values['device']
-
- @property
- def device_port(self):
- if self._values['device_port'] is None:
- return None
- return int(self._values['device_port'])
-
- @property
- def device_is_address(self):
- if is_valid_ip(self.device):
- return True
- return False
-
- @property
- def device_is_id(self):
- pattern = r'[A-Za-z0-9]{8}-[A-Za-z0-9]{4}-[A-Za-z0-9]{4}-[A-Za-z0-9]{4}-[A-Za-z0-9]{12}'
- if re.match(pattern, self.device):
- return True
- return False
-
- @property
- def device_is_name(self):
- if not self.device_is_address and not self.device_is_id:
- return True
- return False
-
- @property
- def device_reference(self):
- if not self.managed:
- return None
- if self.device_is_address:
- # This range lookup is how you do lookups for single IP addresses. Weird.
- filter = "address+eq+'{0}...{0}'".format(self.device)
- elif self.device_is_name:
- filter = "hostname+eq+'{0}'".format(self.device)
- elif self.device_is_id:
- filter = "uuid+eq+'{0}'".format(self.device)
- else:
- raise F5ModuleError(
- "Unknown device format '{0}'".format(self.device)
- )
-
- uri = "https://{0}:{1}/mgmt/shared/resolver/device-groups/cm-bigip-allBigIpDevices/devices/?$filter={2}&$top=1".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- filter
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if resp.status == 200 and response['totalItems'] == 0:
- raise F5ModuleError(
- "No device with the specified address was found."
- )
- elif 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp._content)
- id = response['items'][0]['uuid']
- result = dict(
- link='https://localhost/mgmt/shared/resolver/device-groups/cm-bigip-allBigIpDevices/devices/{0}'.format(id)
- )
- return result
-
- @property
- def pool_id(self):
- filter = "(name eq '{0}')".format(self.pool)
- uri = 'https://{0}:{1}/mgmt/cm/device/licensing/pool/regkey/licenses?$filter={2}&$top=1'.format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- filter
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if resp.status == 200 and response['totalItems'] == 0:
- raise F5ModuleError(
- "No pool with the specified name was found."
- )
- elif 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp._content)
- return response['items'][0]['id']
-
- @property
- def member_id(self):
- if self.device_is_address:
- # This range lookup is how you do lookups for single IP addresses. Weird.
- filter = "deviceAddress+eq+'{0}...{0}'".format(self.device)
- elif self.device_is_name:
- filter = "deviceName+eq+'{0}'".format(self.device)
- elif self.device_is_id:
- filter = "deviceMachineId+eq+'{0}'".format(self.device)
- else:
- raise F5ModuleError(
- "Unknown device format '{0}'".format(self.device)
- )
- uri = 'https://{0}:{1}/mgmt/cm/device/licensing/pool/regkey/licenses/{2}/offerings/{3}/members/?$filter={4}'.format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- self.pool_id,
- self.key,
- filter
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if resp.status == 200 and response['totalItems'] == 0:
- return None
- elif 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp._content)
- result = response['items'][0]['id']
- return result
-
-
-class Changes(Parameters):
- pass
-
-
-class UsableChanges(Changes):
- @property
- def device_port(self):
- if self._values['managed']:
- return None
- return self._values['device_port']
-
- @property
- def device_username(self):
- if self._values['managed']:
- return None
- return self._values['device_username']
-
- @property
- def device_password(self):
- if self._values['managed']:
- return None
- return self._values['device_password']
-
- @property
- def device_reference(self):
- if not self._values['managed']:
- return None
- return self._values['device_reference']
-
- @property
- def device_address(self):
- if self._values['managed']:
- return None
- return self._values['device_address']
-
- @property
- def managed(self):
- return None
-
-
-class ReportableChanges(Changes):
- pass
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(params=self.module.params, client=self.client)
- self.have = ApiParameters()
- self.changes = UsableChanges()
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = UsableChanges(params=changed)
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def exec_module(self):
- changed = False
- result = dict()
- state = self.want.state
-
- if state == "present":
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def present(self):
- if self.exists():
- return False
- return self.create()
-
- def exists(self):
- if self.want.member_id is None:
- return False
- uri = 'https://{0}:{1}/mgmt/cm/device/licensing/pool/regkey/licenses/{2}/offerings/{3}/members/{4}'.format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- self.want.pool_id,
- self.want.key,
- self.want.member_id
- )
- resp = self.client.api.get(uri)
- if resp.status == 200:
- return True
- return False
-
- def remove(self):
- self._set_changed_options()
- if self.module.check_mode:
- return True
- self.remove_from_device()
- if self.exists():
- raise F5ModuleError("Failed to delete the resource.")
- # Artificial sleeping to wait for remote licensing (on BIG-IP) to complete
- #
- # This should be something that BIG-IQ can do natively in 6.1-ish time.
- time.sleep(60)
- return True
-
- def create(self):
- self._set_changed_options()
- if not self.want.managed:
- if self.want.device_username is None:
- raise F5ModuleError(
- "You must specify a 'device_username' when working with unmanaged devices."
- )
- if self.want.device_password is None:
- raise F5ModuleError(
- "You must specify a 'device_password' when working with unmanaged devices."
- )
- if self.module.check_mode:
- return True
- self.create_on_device()
- if not self.exists():
- raise F5ModuleError(
- "Failed to license the remote device."
- )
- self.wait_for_device_to_be_licensed()
-
- # Artificial sleeping to wait for remote licensing (on BIG-IP) to complete
- #
- # This should be something that BIG-IQ can do natively in 6.1-ish time.
- time.sleep(60)
- return True
-
- def create_on_device(self):
- params = self.changes.api_params()
- uri = 'https://{0}:{1}/mgmt/cm/device/licensing/pool/regkey/licenses/{2}/offerings/{3}/members/'.format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- self.want.pool_id,
- self.want.key
- )
-
- if not self.want.managed:
- params['username'] = self.want.device_username
- params['password'] = self.want.device_password
-
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def wait_for_device_to_be_licensed(self):
- count = 0
- uri = 'https://{0}:{1}/mgmt/cm/device/licensing/pool/regkey/licenses/{2}/offerings/{3}/members/{4}'.format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- self.want.pool_id,
- self.want.key,
- self.want.member_id
- )
- while count < 3:
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- if response['status'] == 'LICENSED':
- count += 1
- else:
- count = 0
-
- def absent(self):
- if self.exists():
- return self.remove()
- return False
-
- def remove_from_device(self):
- uri = 'https://{0}:{1}/mgmt/cm/device/licensing/pool/regkey/licenses/{2}/offerings/{3}/members/{4}'.format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- self.want.pool_id,
- self.want.key,
- self.want.member_id
- )
- params = {}
- if not self.want.managed:
- params.update(self.changes.api_params())
- params['id'] = self.want.member_id
- params['username'] = self.want.device_username
- params['password'] = self.want.device_password
- self.client.api.delete(uri, json=params)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- pool=dict(required=True),
- key=dict(required=True, no_log=True),
- device=dict(required=True),
- managed=dict(type='bool'),
- device_port=dict(type='int', default=443),
- device_username=dict(no_log=True),
- device_password=dict(no_log=True),
- state=dict(default='present', choices=['absent', 'present'])
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
- self.required_if = [
- ['state', 'present', ['key', 'managed']],
- ['managed', False, ['device', 'device_username', 'device_password']],
- ['managed', True, ['device']]
- ]
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode,
- required_if=spec.required_if
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigiq_regkey_pool.py b/lib/ansible/modules/network/f5/bigiq_regkey_pool.py
deleted file mode 100644
index 07f3414d42..0000000000
--- a/lib/ansible/modules/network/f5/bigiq_regkey_pool.py
+++ /dev/null
@@ -1,417 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright (c) 2017 F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigiq_regkey_pool
-short_description: Manages registration key pools on BIG-IQ
-description:
- - Manages registration key (regkey) pools on a BIG-IQ. These pools function as
- a container in-which you will add lists of registration keys. To add registration
- keys, use the C(bigiq_regkey_license) module.
-version_added: 2.5
-options:
- name:
- description:
- - Specifies the name of the registration key pool.
- - You must be mindful to name your registration pools unique names. While
- BIG-IQ does not require this, this module does. If you do not do this,
- the behavior of the module is undefined and you may end up putting
- licenses in the wrong registration key pool.
- type: str
- required: True
- description:
- description:
- - A description to attach to the pool.
- type: str
- state:
- description:
- - The state of the regkey pool on the system.
- - When C(present), guarantees that the pool exists.
- - When C(absent), removes the pool, and the licenses it contains, from the
- system.
- type: str
- choices:
- - absent
- - present
- default: present
-requirements:
- - BIG-IQ >= 5.3.0
-extends_documentation_fragment: f5
-author:
- - Tim Rupp (@caphrim007)
-'''
-
-EXAMPLES = r'''
-- name: Create a registration key (regkey) pool to hold individual device licenses
- bigiq_regkey_pool:
- name: foo-pool
- state: present
- provider:
- user: admin
- password: secret
- server: lb.mydomain.com
- delegate_to: localhost
-'''
-
-RETURN = r'''
-description:
- description: New description of the regkey pool.
- returned: changed
- type: str
- sample: My description
-'''
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.module_utils.network.f5.bigiq import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import f5_argument_spec
-except ImportError:
- from ansible.module_utils.network.f5.bigiq import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import f5_argument_spec
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
-
- }
-
- api_attributes = [
- 'description'
- ]
-
- returnables = [
- 'description'
- ]
-
- updatables = [
- 'description'
- ]
-
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class ModuleParameters(Parameters):
- @property
- def uuid(self):
- """Returns UUID of a given name
-
- Will search for a given name and return the first one returned to us. If no name,
- and therefore no ID, is found, will return the string "none". The string "none"
- is returned because if we were to return the None value, it would cause the
- license loading code to append a None string to the URI; essentially asking the
- remote device for its collection (which we dont want and which would cause the SDK
- to return an False error.
-
- :return:
- """
- collection = self.read_current_from_device()
- resource = next((x for x in collection if x.name == self._values['name']), None)
- if resource:
- return resource.id
- else:
- return "none"
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/cm/device/licensing/pool/regkey/licenses".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- if 'items' not in response:
- return []
- result = [ApiParameters(params=r) for r in response['items']]
- return result
-
-
-class ApiParameters(Parameters):
- @property
- def uuid(self):
- return self._values['id']
-
-
-class Changes(Parameters):
- pass
-
-
-class ReportableChanges(Changes):
- pass
-
-
-class UsableChanges(Changes):
- pass
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(client=self.client, params=self.module.params)
- self.have = ApiParameters()
- self.changes = UsableChanges()
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = UsableChanges(params=changed)
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = Changes(params=changed)
- return True
- return False
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def exec_module(self):
- changed = False
- result = dict()
- state = self.want.state
-
- if state == "present":
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def present(self):
- if self.exists():
- return self.update()
- else:
- return self.create()
-
- def exists(self):
- uri = "https://{0}:{1}/mgmt/cm/device/licensing/pool/regkey/licenses/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- self.want.uuid,
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError:
- return False
- if resp.status == 404 or 'code' in response and response['code'] == 404:
- return False
- return True
-
- def update(self):
- self.have = self.read_current_from_device()
- if not self.should_update():
- return False
- if self.module.check_mode:
- return True
- self.update_on_device()
- return True
-
- def remove(self):
- if self.module.check_mode:
- return True
- self.remove_from_device()
- if self.exists():
- raise F5ModuleError("Failed to delete the resource.")
- return True
-
- def create(self):
- self._set_changed_options()
- if self.module.check_mode:
- return True
- self.create_on_device()
- return True
-
- def create_on_device(self):
- params = self.want.api_params()
- params['name'] = self.want.name
- uri = "https://{0}:{1}/mgmt/cm/device/licensing/pool/regkey/licenses/".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 403]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def update_on_device(self):
- params = self.changes.api_params()
- uri = "https://{0}:{1}/mgmt/cm/device/licensing/pool/regkey/licenses/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- self.want.uuid
- )
- resp = self.client.api.patch(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def absent(self):
- if self.exists():
- return self.remove()
- return False
-
- def remove_from_device(self):
- uri = "https://{0}:{1}/mgmt/cm/device/licensing/pool/regkey/licenses/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- self.want.uuid
- )
- resp = self.client.api.delete(uri)
- if resp.status == 200:
- return True
-
- def read_current_from_device(self):
- uri = "https://{0}:{1}/mgmt/cm/device/licensing/pool/regkey/licenses/{2}".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- self.want.uuid
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- return ApiParameters(params=response)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- name=dict(required=True),
- description=dict(),
- state=dict(
- default='present',
- choices=['absent', 'present']
- )
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode,
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigiq_utility_license.py b/lib/ansible/modules/network/f5/bigiq_utility_license.py
deleted file mode 100644
index 3034565ba6..0000000000
--- a/lib/ansible/modules/network/f5/bigiq_utility_license.py
+++ /dev/null
@@ -1,462 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigiq_utility_license
-short_description: Manage utility licenses on a BIG-IQ
-description:
- - Manages utility licenses on a BIG-IQ. Utility licenses are one form of licenses
- that BIG-IQ can distribute. These licenses, unlike regkey licenses, do not require
- a pool to be created before creation. Additionally, when assigning them, you assign
- by offering instead of key.
-version_added: 2.6
-options:
- license_key:
- description:
- - The license key to install and activate.
- type: str
- required: True
- accept_eula:
- description:
- - A key that signifies that you accept the F5 EULA for this license.
- - A copy of the EULA can be found here https://askf5.f5.com/csp/article/K12902
- - This is required when C(state) is C(present).
- type: bool
- state:
- description:
- - The state of the utility license on the system.
- - When C(present), guarantees that the license exists.
- - When C(absent), removes the license from the system.
- type: str
- choices:
- - absent
- - present
- default: present
-requirements:
- - BIG-IQ >= 5.3.0
-extends_documentation_fragment: f5
-author:
- - Tim Rupp (@caphrim007)
-'''
-
-EXAMPLES = r'''
-- name: Add a utility license to the system
- bigiq_utility_license:
- license_key: XXXXX-XXXXX-XXXXX-XXXXX-XXXXX
- accept_eula: yes
- state: present
- provider:
- user: admin
- password: secret
- server: lb.mydomain.com
- delegate_to: localhost
-
-- name: Remove a utility license from the system
- bigiq_utility_license:
- license_key: XXXXX-XXXXX-XXXXX-XXXXX-XXXXX
- state: absent
- provider:
- user: admin
- password: secret
- server: lb.mydomain.com
- delegate_to: localhost
-'''
-
-RETURN = r'''
-# only common fields returned
-'''
-
-import time
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.module_utils.network.f5.bigiq import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import f5_argument_spec
-except ImportError:
- from ansible.module_utils.network.f5.bigiq import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import f5_argument_spec
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'regKey': 'license_key'
- }
-
- api_attributes = [
- 'regKey'
- ]
-
- returnables = [
- 'license_key'
- ]
-
- updatables = [
- 'license_key'
- ]
-
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class ApiParameters(Parameters):
- pass
-
-
-class ModuleParameters(Parameters):
- pass
-
-
-class Changes(Parameters):
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class UsableChanges(Changes):
- pass
-
-
-class ReportableChanges(Changes):
- @property
- def license_key(self):
- return None
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(client=self.client, params=self.module.params)
- self.have = ApiParameters()
- self.changes = UsableChanges()
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = UsableChanges(params=changed)
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = UsableChanges(params=changed)
- return True
- return False
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def exec_module(self):
- changed = False
- result = dict()
- state = self.want.state
-
- if state == "present":
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def present(self):
- if self.exists():
- return False
- else:
- return self.create()
-
- def exists(self):
- uri = "https://{0}:{1}/mgmt/cm/device/licensing/pool/utility/licenses/?$filter=regKey+eq+'{2}'".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- self.want.license_key
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if resp.status == 200 and response['totalItems'] == 0:
- return False
- elif 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp._content)
- return True
-
- def remove(self):
- if self.module.check_mode:
- return True
- self.remove_from_device()
- self.wait_for_removal()
- if self.exists():
- raise F5ModuleError("Failed to delete the resource.")
- return True
-
- def create(self):
- self._set_changed_options()
- if self.module.check_mode:
- return True
- if self.want.accept_eula is False:
- raise F5ModuleError(
- "To add a license, you must accept its EULA. Please see the module documentation for a link to this."
- )
- self.create_on_device()
- self.wait_for_initial_license_activation()
- self.wait_for_utility_license_activation()
- if not self.exists():
- raise F5ModuleError(
- "Failed to activate the license."
- )
- return True
-
- def create_on_device(self):
- params = self.changes.api_params()
- uri = 'https://{0}:{1}/mgmt/cm/device/licensing/pool/initial-activation'.format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- )
-
- params['name'] = self.want.license_key
- params['status'] = 'ACTIVATING_AUTOMATIC'
-
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp._content)
-
- def wait_for_removal(self):
- count = 0
-
- while count < 3:
- if not self.exists():
- count += 1
- else:
- count = 0
- time.sleep(1)
-
- def wait_for_initial_license_activation(self):
- count = 0
- uri = 'https://{0}:{1}/mgmt/cm/device/licensing/pool/initial-activation/{2}'.format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- self.want.license_key
- )
-
- while count < 3:
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp._content)
-
- if response['status'] == 'READY':
- count += 1
- elif response['status'] == 'ACTIVATING_AUTOMATIC_NEED_EULA_ACCEPT':
- uri = response['selfLink'].replace(
- 'https://localhost',
- 'https://{0}:{1}'.format(
- self.client.provider['server'],
- self.client.provider['server_port']
- )
- )
- self.client.api.patch(uri, json=dict(
- status='ACTIVATING_AUTOMATIC_EULA_ACCEPTED',
- eulaText=response['eulaText']
- ))
- elif response['status'] == 'ACTIVATION_FAILED':
- raise F5ModuleError(str(response['message']))
- else:
- count = 0
- time.sleep(1)
-
- def wait_for_utility_license_activation(self):
- count = 0
- uri = 'https://{0}:{1}/mgmt/cm/device/licensing/pool/utility/licenses/{2}'.format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- self.want.license_key
- )
-
- while count < 3:
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] in [400, 401]:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp._content)
-
- if response['status'] == 'READY':
- count += 1
- elif response['status'] == 'ACTIVATION_FAILED':
- raise F5ModuleError(str(response['message']))
- else:
- count = 0
- time.sleep(1)
-
- def absent(self):
- if self.exists():
- return self.remove()
- return False
-
- def remove_from_device(self):
- uri = 'https://{0}:{1}/mgmt/cm/device/licensing/pool/utility/licenses/{2}'.format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- self.want.license_key
- )
-
- resp = self.client.api.delete(uri)
- try:
-
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp._content)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- license_key=dict(required=True, no_log=True),
- accept_eula=dict(type='bool'),
- state=dict(
- default='present',
- choices=['present', 'absent']
- ),
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
- self.required_if = [
- ['state', 'present', ['accept_eula']]
- ]
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode,
- required_if=spec.required_if
- )
-
- client = F5RestClient(**module.params)
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/network/f5/bigiq_utility_license_assignment.py b/lib/ansible/modules/network/f5/bigiq_utility_license_assignment.py
deleted file mode 100644
index dc2edaad93..0000000000
--- a/lib/ansible/modules/network/f5/bigiq_utility_license_assignment.py
+++ /dev/null
@@ -1,645 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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
-
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'certified'}
-
-DOCUMENTATION = r'''
----
-module: bigiq_utility_license_assignment
-short_description: Manage utility license assignment on BIG-IPs from a BIG-IQ
-description:
- - Manages the assignment of utility licenses on a BIG-IQ. Assignment means that
- the license is assigned to a BIG-IP, or, it needs to be assigned to a BIG-IP.
- Additionally, this module supported revoking the assignments from BIG-IP devices.
-version_added: 2.7
-options:
- unit_of_measure:
- description:
- - Sets the rate at which this license usage is billed.
- - Depending on your license, you may have different units of measures
- available to you. If a particular unit is not available to you, the module
- will notify you at licensing time.
- type: str
- choices:
- - hourly
- - daily
- - monthly
- - yearly
- default: hourly
- key:
- description:
- - The registration key that you want choose an offering from.
- type: str
- required: True
- offering:
- description:
- - Name of the license offering to assign to the device.
- type: str
- device:
- description:
- - When C(managed) is C(no), specifies the address, or hostname, where the BIG-IQ
- can reach the remote device to register.
- - When C(managed) is C(yes), specifies the managed device, or device UUID, that
- you want to register.
- - If C(managed) is C(yes), it is very important that you do not have more than
- one device with the same name. BIG-IQ internally recognizes devices by their ID,
- and therefore, this module's cannot guarantee that the correct device will be
- registered. The device returned is the device that will be used.
- type: str
- managed:
- description:
- - Whether the specified device is a managed or un-managed device.
- - When C(state) is C(present), this parameter is required.
- type: bool
- device_port:
- description:
- - Specifies the port of the remote device to connect to.
- - If this parameter is not specified, the default of C(443) will be used.
- type: int
- default: 443
- device_username:
- description:
- - The username used to connect to the remote device.
- - This username should be one that has sufficient privileges on the remote device
- to do licensing. Usually this is the C(Administrator) role.
- - When C(managed) is C(no), this parameter is required.
- type: str
- device_password:
- description:
- - The password of the C(device_username).
- - When C(managed) is C(no), this parameter is required.
- type: str
- state:
- description:
- - When C(present), ensures that the device is assigned the specified license.
- - When C(absent), ensures the license is revokes from the remote device and freed
- on the BIG-IQ.
- type: str
- choices:
- - present
- - absent
- default: present
-extends_documentation_fragment: f5
-author:
- - Tim Rupp (@caphrim007)
-'''
-
-EXAMPLES = r'''
-- name: Register an unmanaged device
- bigiq_utility_license_assignment:
- key: XXXX-XXXX-XXXX-XXXX-XXXX
- offering: F5-BIG-MSP-AFM-10G-LIC
- device: 1.1.1.1
- managed: no
- device_username: admin
- device_password: secret
- state: present
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-
-- name: Register a managed device, by name
- bigiq_utility_license_assignment:
- key: XXXX-XXXX-XXXX-XXXX-XXXX
- offering: F5-BIG-MSP-AFM-10G-LIC
- device: bigi1.foo.com
- managed: yes
- state: present
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-
-- name: Register a managed device, by UUID
- bigiq_utility_license_assignment:
- key: XXXX-XXXX-XXXX-XXXX-XXXX
- offering: F5-BIG-MSP-AFM-10G-LIC
- device: 7141a063-7cf8-423f-9829-9d40599fa3e0
- managed: yes
- state: present
- provider:
- password: secret
- server: lb.mydomain.com
- user: admin
- delegate_to: localhost
-'''
-
-RETURN = r'''
-# only common fields returned
-'''
-
-import re
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.module_utils.network.f5.bigiq import F5RestClient
- from library.module_utils.network.f5.common import F5ModuleError
- from library.module_utils.network.f5.common import AnsibleF5Parameters
- from library.module_utils.network.f5.common import f5_argument_spec
- from library.module_utils.network.f5.ipaddress import is_valid_ip
-except ImportError:
- from ansible.module_utils.network.f5.bigiq import F5RestClient
- from ansible.module_utils.network.f5.common import F5ModuleError
- from ansible.module_utils.network.f5.common import AnsibleF5Parameters
- from ansible.module_utils.network.f5.common import f5_argument_spec
- from ansible.module_utils.network.f5.ipaddress import is_valid_ip
-
-
-class Parameters(AnsibleF5Parameters):
- api_map = {
- 'deviceReference': 'device_reference',
- 'deviceAddress': 'device_address',
- 'httpsPort': 'device_port',
- 'unitOfMeasure': 'unit_of_measure'
- }
-
- api_attributes = [
- 'deviceReference', 'deviceAddress', 'httpsPort', 'managed', 'unitOfMeasure'
- ]
-
- returnables = [
- 'device_address', 'device_reference', 'device_username', 'device_password',
- 'device_port', 'managed', 'unit_of_measure'
- ]
-
- updatables = [
- 'device_reference', 'device_address', 'device_username', 'device_password',
- 'device_port', 'managed', 'unit_of_measure'
- ]
-
- def to_return(self):
- result = {}
- try:
- for returnable in self.returnables:
- result[returnable] = getattr(self, returnable)
- result = self._filter_params(result)
- except Exception:
- pass
- return result
-
-
-class ApiParameters(Parameters):
- pass
-
-
-class ModuleParameters(Parameters):
- @property
- def device_password(self):
- if self._values['device_password'] is None:
- return None
- return self._values['device_password']
-
- @property
- def device_username(self):
- if self._values['device_username'] is None:
- return None
- return self._values['device_username']
-
- @property
- def device_address(self):
- if self.device_is_address:
- return self._values['device']
-
- @property
- def device_port(self):
- if self._values['device_port'] is None:
- return None
- return int(self._values['device_port'])
-
- @property
- def device_is_address(self):
- if is_valid_ip(self.device):
- return True
- return False
-
- @property
- def device_is_id(self):
- pattern = r'[A-Za-z0-9]{8}-[A-Za-z0-9]{4}-[A-Za-z0-9]{4}-[A-Za-z0-9]{4}-[A-Za-z0-9]{12}'
- if re.match(pattern, self.device):
- return True
- return False
-
- @property
- def device_is_name(self):
- if not self.device_is_address and not self.device_is_id:
- return True
- return False
-
- @property
- def device_reference(self):
- if not self.managed:
- return None
- if self.device_is_address:
- # This range lookup is how you do lookups for single IP addresses. Weird.
- filter = "address+eq+'{0}...{0}'".format(self.device)
- elif self.device_is_name:
- filter = "hostname+eq+'{0}'".format(self.device)
- elif self.device_is_id:
- filter = "uuid+eq+'{0}'".format(self.device)
- else:
- raise F5ModuleError(
- "Unknown device format '{0}'".format(self.device)
- )
-
- uri = "https://{0}:{1}/mgmt/shared/resolver/device-groups/cm-bigip-allBigIpDevices/devices/?$filter={2}&$top=1".format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- filter
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if resp.status == 200 and response['totalItems'] == 0:
- raise F5ModuleError(
- "No device with the specified address was found."
- )
- elif 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp._content)
- id = response['items'][0]['uuid']
- result = dict(
- link='https://localhost/mgmt/shared/resolver/device-groups/cm-bigip-allBigIpDevices/devices/{0}'.format(id)
- )
- return result
-
- @property
- def offering_id(self):
- filter = "(name+eq+'{0}')".format(self.offering)
- uri = 'https://{0}:{1}/mgmt/cm/device/licensing/pool/utility/licenses/{2}/offerings?$filter={3}&$top=1'.format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- self.key,
- filter
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
- if resp.status == 200 and response['totalItems'] == 0:
- raise F5ModuleError(
- "No offering with the specified name was found."
- )
- elif 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp._content)
- return response['items'][0]['id']
-
- @property
- def member_id(self):
- if self.device_is_address:
- # This range lookup is how you do lookups for single IP addresses. Weird.
- filter = "deviceAddress+eq+'{0}...{0}'".format(self.device)
- elif self.device_is_name:
- filter = "deviceName+eq+'{0}'".format(self.device)
- elif self.device_is_id:
- filter = "deviceMachineId+eq+'{0}'".format(self.device)
- else:
- raise F5ModuleError(
- "Unknown device format '{0}'".format(self.device)
- )
- uri = 'https://{0}:{1}/mgmt/cm/device/licensing/pool/utility/licenses/{2}/offerings/{3}/members/?$filter={4}'.format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- self.key,
- self.offering_id,
- filter
- )
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if resp.status == 200 and response['totalItems'] == 0:
- return None
- elif 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp._content)
- result = response['items'][0]['id']
- return result
-
-
-class Changes(Parameters):
- pass
-
-
-class UsableChanges(Changes):
- @property
- def device_port(self):
- if self._values['managed']:
- return None
- return self._values['device_port']
-
- @property
- def device_username(self):
- if self._values['managed']:
- return None
- return self._values['device_username']
-
- @property
- def device_password(self):
- if self._values['managed']:
- return None
- return self._values['device_password']
-
- @property
- def device_reference(self):
- if not self._values['managed']:
- return None
- return self._values['device_reference']
-
- @property
- def device_address(self):
- if self._values['managed']:
- return None
- return self._values['device_address']
-
- @property
- def managed(self):
- return None
-
-
-class ReportableChanges(Changes):
- pass
-
-
-class Difference(object):
- def __init__(self, want, have=None):
- self.want = want
- self.have = have
-
- def compare(self, param):
- try:
- result = getattr(self, param)
- return result
- except AttributeError:
- return self.__default(param)
-
- def __default(self, param):
- attr1 = getattr(self.want, param)
- try:
- attr2 = getattr(self.have, param)
- if attr1 != attr2:
- return attr1
- except AttributeError:
- return attr1
-
-
-class ModuleManager(object):
- def __init__(self, *args, **kwargs):
- self.module = kwargs.get('module', None)
- self.client = F5RestClient(**self.module.params)
- self.want = ModuleParameters(params=self.module.params, client=self.client)
- self.have = ApiParameters()
- self.changes = UsableChanges()
-
- def _set_changed_options(self):
- changed = {}
- for key in Parameters.returnables:
- if getattr(self.want, key) is not None:
- changed[key] = getattr(self.want, key)
- if changed:
- self.changes = Changes(params=changed)
-
- def _update_changed_options(self):
- diff = Difference(self.want, self.have)
- updatables = Parameters.updatables
- changed = dict()
- for k in updatables:
- change = diff.compare(k)
- if change is None:
- continue
- else:
- if isinstance(change, dict):
- changed.update(change)
- else:
- changed[k] = change
- if changed:
- self.changes = Changes(params=changed)
- return True
- return False
-
- def should_update(self):
- result = self._update_changed_options()
- if result:
- return True
- return False
-
- def exec_module(self):
- changed = False
- result = dict()
- state = self.want.state
-
- if state == "present":
- changed = self.present()
- elif state == "absent":
- changed = self.absent()
-
- reportable = ReportableChanges(params=self.changes.to_return())
- changes = reportable.to_return()
- result.update(**changes)
- result.update(dict(changed=changed))
- self._announce_deprecations(result)
- return result
-
- def _announce_deprecations(self, result):
- warnings = result.pop('__warnings', [])
- for warning in warnings:
- self.module.deprecate(
- msg=warning['msg'],
- version=warning['version']
- )
-
- def present(self):
- if self.exists():
- return False
- return self.create()
-
- def exists(self):
- if self.want.member_id is None:
- return False
- uri = 'https://{0}:{1}/mgmt/cm/device/licensing/pool/utility/licenses/{2}/offerings/{3}/members/{4}'.format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- self.want.key,
- self.want.offering_id,
- self.want.member_id
- )
- resp = self.client.api.get(uri)
- if resp.status == 200:
- return True
- return False
-
- def remove(self):
- self._set_changed_options()
- if self.module.check_mode:
- return True
- self.remove_from_device()
- if self.exists():
- raise F5ModuleError("Failed to delete the resource.")
- return True
-
- def create(self):
- self._set_changed_options()
- if not self.want.managed:
- if self.want.device_username is None:
- raise F5ModuleError(
- "You must specify a 'device_username' when working with unmanaged devices."
- )
- if self.want.device_password is None:
- raise F5ModuleError(
- "You must specify a 'device_password' when working with unmanaged devices."
- )
- if self.module.check_mode:
- return True
- self.create_on_device()
- if not self.exists():
- raise F5ModuleError(
- "Failed to license the remote device."
- )
- self.wait_for_device_to_be_licensed()
- return True
-
- def create_on_device(self):
- params = self.changes.api_params()
- uri = 'https://{0}:{1}/mgmt/cm/device/licensing/pool/utility/licenses/{2}/offerings/{3}/members/'.format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- self.want.key,
- self.want.offering_id,
- )
-
- if not self.want.managed:
- params['username'] = self.want.device_username
- params['password'] = self.want.device_password
-
- resp = self.client.api.post(uri, json=params)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
-
- def wait_for_device_to_be_licensed(self):
- count = 0
- uri = 'https://{0}:{1}/mgmt/cm/device/licensing/pool/utility/licenses/{2}/offerings/{3}/members/{4}'.format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- self.want.key,
- self.want.offering_id,
- self.want.member_id,
- )
- while count < 3:
- resp = self.client.api.get(uri)
- try:
- response = resp.json()
- except ValueError as ex:
- raise F5ModuleError(str(ex))
-
- if 'code' in response and response['code'] == 400:
- if 'message' in response:
- raise F5ModuleError(response['message'])
- else:
- raise F5ModuleError(resp.content)
- if response['status'] == 'LICENSED':
- count += 1
- else:
- count = 0
-
- def absent(self):
- if self.exists():
- return self.remove()
- return False
-
- def remove_from_device(self):
- uri = 'https://{0}:{1}/mgmt/cm/device/licensing/pool/utility/licenses/{2}/offerings/{3}/members/{4}'.format(
- self.client.provider['server'],
- self.client.provider['server_port'],
- self.want.key,
- self.want.offering_id,
- self.want.member_id
- )
- params = {}
- if not self.want.managed:
- params.update(self.changes.api_params())
- params['id'] = self.want.member_id
- params['username'] = self.want.device_username
- params['password'] = self.want.device_password
- self.client.api.delete(uri, json=params)
-
-
-class ArgumentSpec(object):
- def __init__(self):
- self.supports_check_mode = True
- argument_spec = dict(
- offering=dict(required=True),
- unit_of_measure=dict(
- default='hourly',
- choices=[
- 'hourly', 'daily', 'monthly', 'yearly'
- ]
- ),
- key=dict(required=True, no_log=True),
- device=dict(required=True),
- managed=dict(type='bool'),
- device_port=dict(type='int', default=443),
- device_username=dict(no_log=True),
- device_password=dict(no_log=True),
- state=dict(default='present', choices=['absent', 'present'])
- )
- self.argument_spec = {}
- self.argument_spec.update(f5_argument_spec)
- self.argument_spec.update(argument_spec)
- self.required_if = [
- ['state', 'present', ['key', 'managed']],
- ['managed', False, ['device', 'device_username', 'device_password']],
- ['managed', True, ['device']]
- ]
-
-
-def main():
- spec = ArgumentSpec()
-
- module = AnsibleModule(
- argument_spec=spec.argument_spec,
- supports_check_mode=spec.supports_check_mode,
- required_if=spec.required_if
- )
-
- try:
- mm = ModuleManager(module=module)
- results = mm.exec_module()
- module.exit_json(**results)
- except F5ModuleError as ex:
- module.fail_json(msg=str(ex))
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/plugins/action/bigip.py b/lib/ansible/plugins/action/bigip.py
deleted file mode 100644
index e400a2f917..0000000000
--- a/lib/ansible/plugins/action/bigip.py
+++ /dev/null
@@ -1,101 +0,0 @@
-#
-# (c) 2016 Red Hat Inc.
-#
-# This file is part of Ansible
-#
-# Ansible is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# Ansible is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
-#
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-import os
-import sys
-import copy
-
-from ansible import constants as C
-from ansible.module_utils._text import to_text
-from ansible.module_utils.connection import Connection
-from ansible.module_utils.network.common.utils import load_provider
-from ansible.plugins.action.network import ActionModule as ActionNetworkModule
-from ansible.utils.display import Display
-
-try:
- from library.module_utils.network.f5.common import f5_provider_spec
-except Exception:
- from ansible.module_utils.network.f5.common import f5_provider_spec
-
-display = Display()
-
-
-class ActionModule(ActionNetworkModule):
-
- def run(self, tmp=None, task_vars=None):
- del tmp # tmp no longer has any effect
-
- module_name = self._task.action.split('.')[-1]
- self._config_module = True if module_name == 'bigip_imish_config' else False
- persistent_connection = self._play_context.connection.split('.')[-1]
- socket_path = None
- transport = 'rest'
-
- if persistent_connection == 'network_cli':
- provider = self._task.args.get('provider', {})
- if any(provider.values()):
- display.warning("'provider' is unnecessary when using 'network_cli' and will be ignored")
- elif self._play_context.connection == 'local':
- provider = load_provider(f5_provider_spec, self._task.args)
- transport = provider['transport'] or transport
-
- display.vvvv('connection transport is %s' % transport, self._play_context.remote_addr)
-
- if transport == 'cli':
- pc = copy.deepcopy(self._play_context)
- pc.connection = 'network_cli'
- pc.network_os = 'bigip'
- pc.remote_addr = provider.get('server', self._play_context.remote_addr)
- pc.port = int(provider['server_port'] or self._play_context.port or 22)
- pc.remote_user = provider.get('user', self._play_context.connection_user)
- pc.password = provider.get('password', self._play_context.password)
- pc.private_key_file = provider['ssh_keyfile'] or self._play_context.private_key_file
- command_timeout = int(provider['timeout'] or C.PERSISTENT_COMMAND_TIMEOUT)
-
- display.vvv('using connection plugin %s' % pc.connection, pc.remote_addr)
- connection = self._shared_loader_obj.connection_loader.get('persistent', pc, sys.stdin, task_uuid=self._task._uuid)
- connection.set_options(direct={'persistent_command_timeout': command_timeout})
-
- socket_path = connection.run()
- display.vvvv('socket_path: %s' % socket_path, pc.remote_addr)
- if not socket_path:
- return {
- 'failed': True,
- 'msg': 'Unable to open shell. Please see: '
- 'https://docs.ansible.com/ansible/network_debug_troubleshooting.html#unable-to-open-shell'
- }
-
- task_vars['ansible_socket'] = socket_path
-
- if (self._play_context.connection == 'local' and transport == 'cli') or persistent_connection == 'network_cli':
- # make sure we are in the right cli context which should be
- # enable mode and not config module
- if socket_path is None:
- socket_path = self._connection.socket_path
- conn = Connection(socket_path)
- out = conn.get_prompt()
- while '(config' in to_text(out, errors='surrogate_then_replace').strip():
- display.vvvv('wrong context, sending exit to device', self._play_context.remote_addr)
- conn.send_command('exit')
- out = conn.get_prompt()
-
- result = super(ActionModule, self).run(task_vars=task_vars)
- return result
diff --git a/lib/ansible/plugins/action/bigiq.py b/lib/ansible/plugins/action/bigiq.py
deleted file mode 100644
index f4bf8d09e9..0000000000
--- a/lib/ansible/plugins/action/bigiq.py
+++ /dev/null
@@ -1,95 +0,0 @@
-#
-# (c) 2016 Red Hat Inc.
-#
-# This file is part of Ansible
-#
-# Ansible is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# Ansible is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
-#
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-import os
-import sys
-import copy
-
-from ansible import constants as C
-from ansible.module_utils._text import to_text
-from ansible.module_utils.connection import Connection
-from ansible.module_utils.network.common.utils import load_provider
-from ansible.plugins.action.normal import ActionModule as _ActionModule
-from ansible.utils.display import Display
-
-try:
- from library.module_utils.network.f5.common import f5_provider_spec
-except Exception:
- from ansible.module_utils.network.f5.common import f5_provider_spec
-
-display = Display()
-
-
-class ActionModule(_ActionModule):
-
- def run(self, tmp=None, task_vars=None):
- socket_path = None
- transport = 'rest'
- persistent_connection = self._play_context.connection.split('.')[-1]
-
- if persistent_connection == 'network_cli':
- provider = self._task.args.get('provider', {})
- if any(provider.values()):
- display.warning("'provider' is unnecessary when using 'network_cli' and will be ignored")
- elif self._play_context.connection == 'local':
- provider = load_provider(f5_provider_spec, self._task.args)
- transport = provider['transport'] or transport
-
- display.vvvv('connection transport is %s' % transport, self._play_context.remote_addr)
-
- if transport == 'cli':
- pc = copy.deepcopy(self._play_context)
- pc.connection = 'network_cli'
- pc.network_os = 'bigiq'
- pc.remote_addr = provider.get('server', self._play_context.remote_addr)
- pc.port = int(provider['server_port'] or self._play_context.port or 22)
- pc.remote_user = provider.get('user', self._play_context.connection_user)
- pc.password = provider.get('password', self._play_context.password)
- pc.private_key_file = provider['ssh_keyfile'] or self._play_context.private_key_file
- command_timeout = int(provider['timeout'] or C.PERSISTENT_COMMAND_TIMEOUT)
-
- display.vvv('using connection plugin %s' % pc.connection, pc.remote_addr)
- connection = self._shared_loader_obj.connection_loader.get('persistent', pc, sys.stdin, task_uuid=self._task._uuid)
- connection.set_options(direct={'persistent_command_timeout': command_timeout})
-
- socket_path = connection.run()
- display.vvvv('socket_path: %s' % socket_path, pc.remote_addr)
- if not socket_path:
- return {'failed': True,
- 'msg': 'Unable to open shell. Please see: '
- 'https://docs.ansible.com/ansible/network_debug_troubleshooting.html#unable-to-open-shell'}
-
- task_vars['ansible_socket'] = socket_path
-
- if (self._play_context.connection == 'local' and transport == 'cli') or persistent_connection == 'network_cli':
- # make sure we are in the right cli context which should be
- # enable mode and not config module
- if socket_path is None:
- socket_path = self._connection.socket_path
- conn = Connection(socket_path)
- out = conn.get_prompt()
- while '(config' in to_text(out, errors='surrogate_then_replace').strip():
- display.vvvv('wrong context, sending exit to device', self._play_context.remote_addr)
- conn.send_command('exit')
- out = conn.get_prompt()
-
- result = super(ActionModule, self).run(tmp, task_vars)
- return result
diff --git a/lib/ansible/plugins/doc_fragments/f5.py b/lib/ansible/plugins/doc_fragments/f5.py
deleted file mode 100644
index e247021e3c..0000000000
--- a/lib/ansible/plugins/doc_fragments/f5.py
+++ /dev/null
@@ -1,80 +0,0 @@
-# -*- coding: utf-8 -*-
-
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-
-class ModuleDocFragment(object):
- # Standard F5 documentation fragment
- DOCUMENTATION = r'''
-options:
- provider:
- description:
- - A dict object containing connection details.
- type: dict
- version_added: '2.5'
- suboptions:
- password:
- description:
- - The password for the user account used to connect to the BIG-IP.
- - You may omit this option by setting the environment variable C(F5_PASSWORD).
- type: str
- required: true
- aliases: [ pass, pwd ]
- server:
- description:
- - The BIG-IP host.
- - You may omit this option by setting the environment variable C(F5_SERVER).
- type: str
- required: true
- server_port:
- description:
- - The BIG-IP server port.
- - You may omit this option by setting the environment variable C(F5_SERVER_PORT).
- type: int
- default: 443
- user:
- description:
- - The username to connect to the BIG-IP with. This user must have
- administrative privileges on the device.
- - You may omit this option by setting the environment variable C(F5_USER).
- type: str
- required: true
- validate_certs:
- description:
- - If C(no), SSL certificates are not validated. Use this only
- on personally controlled sites using self-signed certificates.
- - You may omit this option by setting the environment variable C(F5_VALIDATE_CERTS).
- type: bool
- default: yes
- timeout:
- description:
- - Specifies the timeout in seconds for communicating with the network device
- for either connecting or sending commands. If the timeout is
- exceeded before the operation is completed, the module will error.
- type: int
- ssh_keyfile:
- description:
- - Specifies the SSH keyfile to use to authenticate the connection to
- the remote device. This argument is only used for I(cli) transports.
- - You may omit this option by setting the environment variable C(ANSIBLE_NET_SSH_KEYFILE).
- type: path
- transport:
- description:
- - Configures the transport connection to use when connecting to the
- remote device.
- type: str
- choices: [ cli, rest ]
- default: rest
- auth_provider:
- description:
- - Configures the auth provider for to obtain authentication tokens from the remote device.
- - This option is really used when working with BIG-IQ devices.
- type: str
-notes:
- - For more information on using Ansible to manage F5 Networks devices see U(https://www.ansible.com/integrations/networks/f5).
- - Requires BIG-IP software version >= 12.
- - The F5 modules only manipulate the running configuration of the F5 product. To ensure that BIG-IP
- specific configuration persists to disk, be sure to include at least one task that uses the
- M(bigip_config) module to save the running configuration. Refer to the module's documentation for
- the correct usage of the module to save your running configuration.
-'''
diff --git a/lib/ansible/plugins/terminal/bigip.py b/lib/ansible/plugins/terminal/bigip.py
deleted file mode 100644
index d810659e15..0000000000
--- a/lib/ansible/plugins/terminal/bigip.py
+++ /dev/null
@@ -1,62 +0,0 @@
-#
-# (c) 2016 Red Hat Inc.
-#
-# This file is part of Ansible
-#
-# Ansible is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# Ansible is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
-#
-from __future__ import (absolute_import, division, print_function)
-__metaclass__ = type
-
-import re
-
-from ansible.plugins.terminal import TerminalBase
-from ansible.errors import AnsibleConnectionFailure
-
-
-class TerminalModule(TerminalBase):
-
- terminal_stdout_re = [
- re.compile(br"[\r\n]?(?:\([^\)]+\)){,5}(?:>|#) ?$"),
- re.compile(br"[\r\n]?[\w+\-\.:\/\[\]]+(?:\([^\)]+\)){,3}(?:>|#) ?$"),
- re.compile(br"\[\w+\@[\w\-\.]+(?: [^\]])\] ?[>#\$] ?$"),
- re.compile(br"(?:new|confirm) password:")
- ]
-
- terminal_stderr_re = [
- re.compile(br"% ?Error"),
- re.compile(br"Syntax Error", re.I),
- re.compile(br"% User not present"),
- re.compile(br"% ?Bad secret"),
- re.compile(br"invalid input", re.I),
- re.compile(br"(?:incomplete|ambiguous) command", re.I),
- re.compile(br"connection timed out", re.I),
- re.compile(br"the new password was not confirmed", re.I),
- re.compile(br"[^\r\n]+ not found", re.I),
- re.compile(br"'[^']' +returned error code: ?\d+"),
- re.compile(br"[^\r\n]\/bin\/(?:ba)?sh")
- ]
-
- def on_open_shell(self):
- try:
- self._exec_cli_command(b'modify cli preference display-threshold 0 pager disabled')
- self._exec_cli_command(b'run /util bash -c "stty cols 1000000" 2> /dev/null')
- except AnsibleConnectionFailure as ex:
- output = str(ex)
- if 'modify: command not found' in output:
- try:
- self._exec_cli_command(b'tmsh modify cli preference display-threshold 0 pager disabled')
- self._exec_cli_command(b'stty cols 1000000 2> /dev/null')
- except AnsibleConnectionFailure as ex:
- raise AnsibleConnectionFailure('unable to set terminal parameters')
diff --git a/test/sanity/ignore.txt b/test/sanity/ignore.txt
index 6064efe478..6a2fa5c9ef 100644
--- a/test/sanity/ignore.txt
+++ b/test/sanity/ignore.txt
@@ -1498,269 +1498,6 @@ lib/ansible/modules/network/dellos9/dellos9_facts.py validate-modules:doc-requir
lib/ansible/modules/network/dellos9/dellos9_facts.py validate-modules:parameter-list-no-elements
lib/ansible/modules/network/dellos9/dellos9_facts.py validate-modules:parameter-type-not-in-doc
lib/ansible/modules/network/dellos9/dellos9_facts.py validate-modules:undocumented-parameter
-lib/ansible/modules/network/f5/bigip_apm_acl.py validate-modules:doc-elements-mismatch
-lib/ansible/modules/network/f5/bigip_apm_acl.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_apm_network_access.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_apm_network_access.py validate-modules:parameter-list-no-elements
-lib/ansible/modules/network/f5/bigip_apm_policy_fetch.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_apm_policy_import.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_appsvcs_extension.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_asm_dos_application.py validate-modules:doc-elements-mismatch
-lib/ansible/modules/network/f5/bigip_asm_dos_application.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_asm_dos_application.py validate-modules:parameter-list-no-elements
-lib/ansible/modules/network/f5/bigip_asm_policy_fetch.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_asm_policy_import.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_asm_policy_manage.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_asm_policy_server_technology.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_asm_policy_signature_set.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_cli_alias.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_cli_script.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_command.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_command.py validate-modules:parameter-list-no-elements
-lib/ansible/modules/network/f5/bigip_config.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_configsync_action.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_data_group.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_data_group.py validate-modules:invalid-ansiblemodule-schema
-lib/ansible/modules/network/f5/bigip_data_group.py validate-modules:mutually_exclusive-unknown
-lib/ansible/modules/network/f5/bigip_data_group.py validate-modules:parameter-list-no-elements
-lib/ansible/modules/network/f5/bigip_device_auth.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_device_auth_ldap.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_device_auth_ldap.py validate-modules:parameter-list-no-elements
-lib/ansible/modules/network/f5/bigip_device_certificate.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_device_connectivity.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_device_connectivity.py validate-modules:parameter-list-no-elements
-lib/ansible/modules/network/f5/bigip_device_dns.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_device_dns.py validate-modules:parameter-list-no-elements
-lib/ansible/modules/network/f5/bigip_device_group.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_device_group_member.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_device_ha_group.py validate-modules:doc-elements-mismatch
-lib/ansible/modules/network/f5/bigip_device_ha_group.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_device_httpd.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_device_httpd.py validate-modules:parameter-list-no-elements
-lib/ansible/modules/network/f5/bigip_device_info.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_device_info.py validate-modules:parameter-list-no-elements
-lib/ansible/modules/network/f5/bigip_device_info.py validate-modules:return-syntax-error
-lib/ansible/modules/network/f5/bigip_device_license.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_device_ntp.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_device_ntp.py validate-modules:parameter-list-no-elements
-lib/ansible/modules/network/f5/bigip_device_sshd.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_device_sshd.py validate-modules:parameter-list-no-elements
-lib/ansible/modules/network/f5/bigip_device_syslog.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_device_traffic_group.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_device_traffic_group.py validate-modules:parameter-list-no-elements
-lib/ansible/modules/network/f5/bigip_device_trust.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_dns_cache_resolver.py validate-modules:doc-elements-mismatch
-lib/ansible/modules/network/f5/bigip_dns_cache_resolver.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_dns_nameserver.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_dns_resolver.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_dns_zone.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_dns_zone.py validate-modules:parameter-list-no-elements
-lib/ansible/modules/network/f5/bigip_file_copy.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_firewall_address_list.py validate-modules:doc-choices-do-not-match-spec
-lib/ansible/modules/network/f5/bigip_firewall_address_list.py validate-modules:doc-elements-mismatch
-lib/ansible/modules/network/f5/bigip_firewall_address_list.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_firewall_address_list.py validate-modules:parameter-list-no-elements
-lib/ansible/modules/network/f5/bigip_firewall_dos_profile.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_firewall_dos_vector.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_firewall_global_rules.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_firewall_log_profile.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_firewall_log_profile_network.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_firewall_log_profile_network.py validate-modules:implied-parameter-type-mismatch
-lib/ansible/modules/network/f5/bigip_firewall_log_profile_network.py validate-modules:parameter-list-no-elements
-lib/ansible/modules/network/f5/bigip_firewall_policy.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_firewall_policy.py validate-modules:parameter-list-no-elements
-lib/ansible/modules/network/f5/bigip_firewall_port_list.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_firewall_port_list.py validate-modules:parameter-list-no-elements
-lib/ansible/modules/network/f5/bigip_firewall_rule.py validate-modules:doc-elements-mismatch
-lib/ansible/modules/network/f5/bigip_firewall_rule.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_firewall_rule_list.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_firewall_rule_list.py validate-modules:parameter-list-no-elements
-lib/ansible/modules/network/f5/bigip_firewall_schedule.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_firewall_schedule.py validate-modules:parameter-list-no-elements
-lib/ansible/modules/network/f5/bigip_gtm_datacenter.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_gtm_global.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_gtm_monitor_bigip.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_gtm_monitor_external.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_gtm_monitor_firepass.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_gtm_monitor_http.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_gtm_monitor_https.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_gtm_monitor_tcp.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_gtm_monitor_tcp_half_open.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_gtm_pool.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_gtm_pool.py validate-modules:parameter-list-no-elements
-lib/ansible/modules/network/f5/bigip_gtm_pool_member.py validate-modules:doc-choices-do-not-match-spec
-lib/ansible/modules/network/f5/bigip_gtm_pool_member.py validate-modules:doc-elements-mismatch
-lib/ansible/modules/network/f5/bigip_gtm_pool_member.py validate-modules:doc-missing-type
-lib/ansible/modules/network/f5/bigip_gtm_pool_member.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_gtm_pool_member.py validate-modules:missing-suboption-docs
-lib/ansible/modules/network/f5/bigip_gtm_pool_member.py validate-modules:parameter-type-not-in-doc
-lib/ansible/modules/network/f5/bigip_gtm_pool_member.py validate-modules:undocumented-parameter
-lib/ansible/modules/network/f5/bigip_gtm_server.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_gtm_server.py validate-modules:parameter-list-no-elements
-lib/ansible/modules/network/f5/bigip_gtm_topology_record.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_gtm_topology_region.py validate-modules:doc-elements-mismatch
-lib/ansible/modules/network/f5/bigip_gtm_topology_region.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_gtm_virtual_server.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_gtm_virtual_server.py validate-modules:parameter-list-no-elements
-lib/ansible/modules/network/f5/bigip_gtm_wide_ip.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_gtm_wide_ip.py validate-modules:parameter-list-no-elements
-lib/ansible/modules/network/f5/bigip_hostname.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_iapp_service.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_iapp_service.py validate-modules:parameter-list-no-elements
-lib/ansible/modules/network/f5/bigip_iapp_template.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_ike_peer.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_ike_peer.py validate-modules:parameter-list-no-elements
-lib/ansible/modules/network/f5/bigip_imish_config.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_imish_config.py validate-modules:parameter-list-no-elements
-lib/ansible/modules/network/f5/bigip_imish_config.py validate-modules:parameter-type-not-in-doc
-lib/ansible/modules/network/f5/bigip_imish_config.py validate-modules:undocumented-parameter
-lib/ansible/modules/network/f5/bigip_ipsec_policy.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_irule.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_log_destination.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_log_destination.py validate-modules:invalid-ansiblemodule-schema
-lib/ansible/modules/network/f5/bigip_log_publisher.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_log_publisher.py validate-modules:parameter-list-no-elements
-lib/ansible/modules/network/f5/bigip_lx_package.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_management_route.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_message_routing_peer.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_message_routing_protocol.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_message_routing_route.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_message_routing_route.py validate-modules:parameter-list-no-elements
-lib/ansible/modules/network/f5/bigip_message_routing_router.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_message_routing_router.py validate-modules:parameter-list-no-elements
-lib/ansible/modules/network/f5/bigip_message_routing_transport_config.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_message_routing_transport_config.py validate-modules:parameter-list-no-elements
-lib/ansible/modules/network/f5/bigip_monitor_dns.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_monitor_external.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_monitor_gateway_icmp.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_monitor_http.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_monitor_https.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_monitor_ldap.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_monitor_snmp_dca.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_monitor_tcp.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_monitor_tcp_echo.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_monitor_tcp_half_open.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_monitor_udp.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_node.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_node.py validate-modules:parameter-list-no-elements
-lib/ansible/modules/network/f5/bigip_partition.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_password_policy.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_policy.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_policy.py validate-modules:parameter-list-no-elements
-lib/ansible/modules/network/f5/bigip_policy_rule.py validate-modules:doc-elements-mismatch
-lib/ansible/modules/network/f5/bigip_policy_rule.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_policy_rule.py validate-modules:parameter-list-no-elements
-lib/ansible/modules/network/f5/bigip_pool.py validate-modules:doc-choices-do-not-match-spec
-lib/ansible/modules/network/f5/bigip_pool.py validate-modules:doc-elements-mismatch
-lib/ansible/modules/network/f5/bigip_pool.py validate-modules:doc-missing-type
-lib/ansible/modules/network/f5/bigip_pool.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_pool.py validate-modules:missing-suboption-docs
-lib/ansible/modules/network/f5/bigip_pool.py validate-modules:parameter-list-no-elements
-lib/ansible/modules/network/f5/bigip_pool.py validate-modules:parameter-type-not-in-doc
-lib/ansible/modules/network/f5/bigip_pool.py validate-modules:undocumented-parameter
-lib/ansible/modules/network/f5/bigip_pool_member.py validate-modules:doc-choices-do-not-match-spec
-lib/ansible/modules/network/f5/bigip_pool_member.py validate-modules:doc-elements-mismatch
-lib/ansible/modules/network/f5/bigip_pool_member.py validate-modules:doc-missing-type
-lib/ansible/modules/network/f5/bigip_pool_member.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_pool_member.py validate-modules:missing-suboption-docs
-lib/ansible/modules/network/f5/bigip_pool_member.py validate-modules:parameter-list-no-elements
-lib/ansible/modules/network/f5/bigip_pool_member.py validate-modules:parameter-type-not-in-doc
-lib/ansible/modules/network/f5/bigip_pool_member.py validate-modules:undocumented-parameter
-lib/ansible/modules/network/f5/bigip_profile_analytics.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_profile_analytics.py validate-modules:parameter-list-no-elements
-lib/ansible/modules/network/f5/bigip_profile_client_ssl.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_profile_client_ssl.py validate-modules:parameter-list-no-elements
-lib/ansible/modules/network/f5/bigip_profile_dns.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_profile_fastl4.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_profile_http.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_profile_http.py validate-modules:parameter-list-no-elements
-lib/ansible/modules/network/f5/bigip_profile_http2.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_profile_http2.py validate-modules:invalid-ansiblemodule-schema
-lib/ansible/modules/network/f5/bigip_profile_http2.py validate-modules:parameter-list-no-elements
-lib/ansible/modules/network/f5/bigip_profile_http_compression.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_profile_oneconnect.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_profile_persistence_cookie.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_profile_persistence_src_addr.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_profile_server_ssl.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_profile_tcp.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_profile_udp.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_provision.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_provision.py validate-modules:mutually_exclusive-unknown
-lib/ansible/modules/network/f5/bigip_qkview.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_qkview.py validate-modules:parameter-list-no-elements
-lib/ansible/modules/network/f5/bigip_remote_role.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_remote_syslog.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_remote_user.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_routedomain.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_routedomain.py validate-modules:parameter-list-no-elements
-lib/ansible/modules/network/f5/bigip_selfip.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_selfip.py validate-modules:parameter-list-no-elements
-lib/ansible/modules/network/f5/bigip_service_policy.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_smtp.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_snat_pool.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_snat_pool.py validate-modules:parameter-list-no-elements
-lib/ansible/modules/network/f5/bigip_snat_translation.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_snmp.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_snmp_community.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_snmp_trap.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_software_image.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_software_install.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_software_update.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_ssl_certificate.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_ssl_key.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_ssl_ocsp.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_static_route.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_sys_daemon_log_tmm.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_sys_db.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_sys_global.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_timer_policy.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_timer_policy.py validate-modules:invalid-ansiblemodule-schema
-lib/ansible/modules/network/f5/bigip_timer_policy.py validate-modules:parameter-list-no-elements
-lib/ansible/modules/network/f5/bigip_traffic_selector.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_trunk.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_trunk.py validate-modules:parameter-list-no-elements
-lib/ansible/modules/network/f5/bigip_tunnel.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_tunnel.py validate-modules:invalid-ansiblemodule-schema
-lib/ansible/modules/network/f5/bigip_ucs.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_ucs_fetch.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_ucs_fetch.py validate-modules:parameter-type-not-in-doc
-lib/ansible/modules/network/f5/bigip_ucs_fetch.py validate-modules:undocumented-parameter
-lib/ansible/modules/network/f5/bigip_user.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_user.py validate-modules:parameter-list-no-elements
-lib/ansible/modules/network/f5/bigip_vcmp_guest.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_vcmp_guest.py validate-modules:parameter-list-no-elements
-lib/ansible/modules/network/f5/bigip_virtual_address.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_virtual_server.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_virtual_server.py validate-modules:parameter-list-no-elements
-lib/ansible/modules/network/f5/bigip_vlan.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigip_vlan.py validate-modules:parameter-list-no-elements
-lib/ansible/modules/network/f5/bigip_wait.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigiq_application_fasthttp.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigiq_application_fasthttp.py validate-modules:parameter-list-no-elements
-lib/ansible/modules/network/f5/bigiq_application_fastl4_tcp.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigiq_application_fastl4_tcp.py validate-modules:parameter-list-no-elements
-lib/ansible/modules/network/f5/bigiq_application_fastl4_udp.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigiq_application_fastl4_udp.py validate-modules:parameter-list-no-elements
-lib/ansible/modules/network/f5/bigiq_application_http.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigiq_application_http.py validate-modules:parameter-list-no-elements
-lib/ansible/modules/network/f5/bigiq_application_https_offload.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigiq_application_https_offload.py validate-modules:invalid-ansiblemodule-schema
-lib/ansible/modules/network/f5/bigiq_application_https_offload.py validate-modules:mutually_exclusive-unknown
-lib/ansible/modules/network/f5/bigiq_application_https_offload.py validate-modules:parameter-list-no-elements
-lib/ansible/modules/network/f5/bigiq_application_https_waf.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigiq_application_https_waf.py validate-modules:invalid-ansiblemodule-schema
-lib/ansible/modules/network/f5/bigiq_application_https_waf.py validate-modules:mutually_exclusive-unknown
-lib/ansible/modules/network/f5/bigiq_application_https_waf.py validate-modules:parameter-list-no-elements
-lib/ansible/modules/network/f5/bigiq_device_discovery.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigiq_device_discovery.py validate-modules:parameter-list-no-elements
-lib/ansible/modules/network/f5/bigiq_device_info.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigiq_device_info.py validate-modules:parameter-list-no-elements
-lib/ansible/modules/network/f5/bigiq_device_info.py validate-modules:return-syntax-error
-lib/ansible/modules/network/f5/bigiq_regkey_license.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigiq_regkey_license_assignment.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigiq_regkey_pool.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigiq_utility_license.py validate-modules:doc-required-mismatch
-lib/ansible/modules/network/f5/bigiq_utility_license_assignment.py validate-modules:doc-required-mismatch
lib/ansible/modules/network/junos/_junos_interface.py validate-modules:doc-choices-do-not-match-spec
lib/ansible/modules/network/junos/_junos_interface.py validate-modules:doc-default-does-not-match-spec
lib/ansible/modules/network/junos/_junos_interface.py validate-modules:doc-elements-mismatch
@@ -2248,8 +1985,6 @@ lib/ansible/playbook/base.py pylint:blacklisted-name
lib/ansible/playbook/collectionsearch.py required-and-default-attributes # https://github.com/ansible/ansible/issues/61460
lib/ansible/playbook/helpers.py pylint:blacklisted-name
lib/ansible/playbook/role/__init__.py pylint:blacklisted-name
-lib/ansible/plugins/action/bigip.py action-plugin-docs # undocumented action plugin to fix, existed before sanity test was added
-lib/ansible/plugins/action/bigiq.py action-plugin-docs # undocumented action plugin to fix, existed before sanity test was added
lib/ansible/plugins/action/dellos10.py action-plugin-docs # base class for deprecated network platform modules using `connection: local`
lib/ansible/plugins/action/dellos6.py action-plugin-docs # base class for deprecated network platform modules using `connection: local`
lib/ansible/plugins/action/dellos9.py action-plugin-docs # base class for deprecated network platform modules using `connection: local`
@@ -2275,8 +2010,6 @@ lib/ansible/plugins/doc_fragments/dellos6.py future-import-boilerplate
lib/ansible/plugins/doc_fragments/dellos6.py metaclass-boilerplate
lib/ansible/plugins/doc_fragments/dellos9.py future-import-boilerplate
lib/ansible/plugins/doc_fragments/dellos9.py metaclass-boilerplate
-lib/ansible/plugins/doc_fragments/f5.py future-import-boilerplate
-lib/ansible/plugins/doc_fragments/f5.py metaclass-boilerplate
lib/ansible/plugins/doc_fragments/files.py future-import-boilerplate
lib/ansible/plugins/doc_fragments/files.py metaclass-boilerplate
lib/ansible/plugins/doc_fragments/hcloud.py future-import-boilerplate
diff --git a/test/units/modules/network/f5/fixtures/MyApp-0.1.0-0001.noarch.rpm b/test/units/modules/network/f5/fixtures/MyApp-0.1.0-0001.noarch.rpm
deleted file mode 100644
index 1692813534..0000000000
--- a/test/units/modules/network/f5/fixtures/MyApp-0.1.0-0001.noarch.rpm
+++ /dev/null
Binary files differ
diff --git a/test/units/modules/network/f5/fixtures/basic-iapp.tmpl b/test/units/modules/network/f5/fixtures/basic-iapp.tmpl
deleted file mode 100644
index 7f9a681b74..0000000000
--- a/test/units/modules/network/f5/fixtures/basic-iapp.tmpl
+++ /dev/null
@@ -1,25 +0,0 @@
-sys application template good_templ {
- actions {
- definition {
- html-help {
- # HTML Help for the template
- }
- implementation {
- # TMSH implementation code
- }
- macro {
- # TMSH macro code
- }
- presentation {
- # APL presentation language
- }
- role-acl { admin manager resource-admin }
- run-as none
- }
- }
- description "My basic template"
- partition Common
- requires-modules { ltm }
- ignore-verification true
- requires-bigip-version-min 11.6.0
-}
diff --git a/test/units/modules/network/f5/fixtures/cert1.crt b/test/units/modules/network/f5/fixtures/cert1.crt
deleted file mode 100644
index 1d22f30289..0000000000
--- a/test/units/modules/network/f5/fixtures/cert1.crt
+++ /dev/null
@@ -1,101 +0,0 @@
-Certificate:
- Data:
- Version: 3 (0x2)
- Serial Number: 1 (0x1)
- Signature Algorithm: sha256WithRSAEncryption
- Issuer: C=US, ST=New York, L=New York, O=ACME CA, OU=Coyote, CN=ourca.domain.local
- Validity
- Not Before: Jun 30 16:46:09 2016 GMT
- Not After : Jun 25 16:46:09 2036 GMT
- Subject: C=US, ST=New York, O=ACME, OU=Coyote, CN=cert1.domain.local
- Subject Public Key Info:
- Public Key Algorithm: rsaEncryption
- Public-Key: (2048 bit)
- Modulus:
- 00:d6:0f:bd:26:ef:14:4d:09:f6:db:8b:01:f5:4e:
- 6c:03:b1:35:20:16:b8:1b:7c:e6:b6:8d:97:1b:b0:
- 4f:8a:b6:cb:54:7e:7a:ff:fd:af:02:db:bf:9d:cf:
- 9a:4c:0d:87:93:8b:cc:61:f3:23:a9:6f:8e:d4:82:
- 2c:93:b6:e2:fa:37:ed:8a:d3:23:8f:6d:b5:78:4a:
- 38:ba:93:f9:4a:1c:40:06:33:d7:c0:98:20:d4:16:
- ac:a4:a5:6b:41:20:4c:3a:55:7e:c7:50:e7:95:07:
- 4e:86:15:86:7a:0f:6c:57:d2:07:1c:97:24:51:5b:
- 4e:f5:52:3a:f8:4f:95:6b:6c:83:1f:34:4e:ee:b0:
- ae:fe:46:90:38:f1:4d:85:72:8b:46:bc:d1:62:37:
- 65:5a:de:bb:16:51:1e:f5:cb:a0:ef:d6:7b:11:6f:
- 3b:0c:49:17:bc:4d:8c:f5:d9:f0:35:6b:f7:b6:4d:
- 50:eb:47:81:e3:06:f2:bd:ec:67:4f:ab:2b:03:aa:
- e2:1e:42:22:a9:c9:59:dc:0d:19:fb:c5:02:1d:d7:
- 58:e4:04:53:0a:1d:79:bb:c1:33:f1:cd:b7:10:2e:
- b4:6e:9b:dc:60:66:05:50:9f:20:66:a1:71:00:51:
- 54:cf:0a:70:f4:7c:45:c6:f0:a7:1c:11:2f:3e:a3:
- 1f:bf
- Exponent: 65537 (0x10001)
- X509v3 extensions:
- X509v3 Basic Constraints:
- CA:FALSE
- Netscape Comment:
- OpenSSL Generated Certificate
- X509v3 Subject Key Identifier:
- 2D:FB:27:C7:B4:32:FF:F7:87:DB:2D:A7:76:AE:F0:96:7E:DA:DC:17
- X509v3 Authority Key Identifier:
- keyid:4F:2A:15:49:E6:CC:05:2F:2B:F4:0E:CC:BA:2E:4C:DF:13:90:F0:78
-
- Signature Algorithm: sha256WithRSAEncryption
- 3f:46:1c:3b:58:b4:99:f3:75:00:47:d2:fe:ba:ba:9a:04:46:
- 62:b6:2d:a0:0f:8f:c0:95:2a:58:8b:61:f5:14:90:30:26:37:
- 94:a1:a6:29:20:c9:b5:08:d7:f9:15:cb:9d:9c:19:ed:2f:a4:
- e6:91:48:85:1a:f7:ab:17:5e:79:23:69:b8:3c:0c:48:ae:c8:
- ba:90:d0:05:fb:33:7e:86:fd:12:f8:2d:0f:ff:16:15:9a:dc:
- 76:48:7d:65:5b:4e:93:14:e8:be:37:d1:13:f7:a7:b1:cd:ad:
- ae:4f:e1:72:b9:53:2d:cd:e6:42:76:44:93:21:28:58:c0:44:
- ab:3c:da:5b:e5:55:ab:04:86:4d:9c:4c:33:f4:4e:13:98:e9:
- 0f:d1:a3:70:2b:1d:11:20:47:26:f6:d8:45:7f:88:ad:f2:c1:
- 81:0f:be:cd:6c:79:80:94:30:eb:8d:cc:f3:7d:a1:3e:6c:6f:
- fa:8f:f3:1f:2e:76:97:3f:8a:1b:67:3b:e0:f9:b1:3c:6b:dc:
- 64:1b:00:73:e9:89:81:f6:7f:51:f3:51:c8:b9:96:5f:fd:55:
- f8:77:6f:88:bc:65:b3:e2:30:a4:00:7a:79:68:e0:36:8b:a9:
- 1b:06:9b:20:fe:fe:98:aa:56:58:c8:08:a4:7b:12:59:ff:3d:
- bd:5e:13:3b:c6:c7:8a:00:5b:cb:27:18:02:ee:cb:38:c2:b7:
- a9:51:04:ef:31:ca:49:09:48:14:13:eb:91:e2:26:8c:88:5f:
- 1c:78:e1:0d:90:29:d7:c1:fc:c8:89:fd:4d:53:0b:99:58:c2:
- 1a:24:3d:c0:a2:4c:a3:d9:c7:95:c5:bc:72:fa:02:f1:ab:dd:
- aa:2b:9e:a0:bb:1a:68:2d:09:8c:a2:99:0d:26:ec:9e:30:19:
- 01:5a:41:45:63:b3:c5:db:24:32:4c:fe:7f:f3:ce:e9:4d:00:
- 64:cf:bb:15:34:2d:31:6e:4f:c0:96:40:9b:32:35:65:92:01:
- 29:7e:74:02:50:fd:3b:3b:3a:a3:9f:6a:c0:a5:be:3f:c3:07:
- d6:8c:2a:c6:f4:0f:32:bd:3b:fc:45:90:d2:46:ee:6f:c3:2f:
- 26:8c:97:0c:e8:da:9a:97:03:0b:86:17:45:a6:62:69:4e:8d:
- cf:f8:bf:ea:2f:dc:ff:95:14:15:bd:92:2d:8a:08:cf:ce:8a:
- b0:f6:34:0a:a2:0e:49:31:44:e1:47:fb:37:52:53:59:93:25:
- 40:cc:ac:67:2d:a2:b6:9b:75:fd:13:a5:a7:93:4f:72:05:75:
- cd:b1:37:f6:3b:69:3b:24:a1:1f:23:f0:cd:bb:ae:18:b3:aa:
- eb:9f:d7:97:06:ba:fd:44
------BEGIN CERTIFICATE-----
-MIIExjCCAq6gAwIBAgIBATANBgkqhkiG9w0BAQsFADBzMQswCQYDVQQGEwJVUzER
-MA8GA1UECAwITmV3IFlvcmsxETAPBgNVBAcMCE5ldyBZb3JrMRAwDgYDVQQKDAdB
-Q01FIENBMQ8wDQYDVQQLDAZDb3lvdGUxGzAZBgNVBAMMEm91cmNhLmRvbWFpbi5s
-b2NhbDAeFw0xNjA2MzAxNjQ2MDlaFw0zNjA2MjUxNjQ2MDlaMF0xCzAJBgNVBAYT
-AlVTMREwDwYDVQQIDAhOZXcgWW9yazENMAsGA1UECgwEQUNNRTEPMA0GA1UECwwG
-Q295b3RlMRswGQYDVQQDDBJjZXJ0MS5kb21haW4ubG9jYWwwggEiMA0GCSqGSIb3
-DQEBAQUAA4IBDwAwggEKAoIBAQDWD70m7xRNCfbbiwH1TmwDsTUgFrgbfOa2jZcb
-sE+KtstUfnr//a8C27+dz5pMDYeTi8xh8yOpb47UgiyTtuL6N+2K0yOPbbV4Sji6
-k/lKHEAGM9fAmCDUFqykpWtBIEw6VX7HUOeVB06GFYZ6D2xX0gcclyRRW071Ujr4
-T5VrbIMfNE7usK7+RpA48U2FcotGvNFiN2Va3rsWUR71y6Dv1nsRbzsMSRe8TYz1
-2fA1a/e2TVDrR4HjBvK97GdPqysDquIeQiKpyVncDRn7xQId11jkBFMKHXm7wTPx
-zbcQLrRum9xgZgVQnyBmoXEAUVTPCnD0fEXG8KccES8+ox+/AgMBAAGjezB5MAkG
-A1UdEwQCMAAwLAYJYIZIAYb4QgENBB8WHU9wZW5TU0wgR2VuZXJhdGVkIENlcnRp
-ZmljYXRlMB0GA1UdDgQWBBQt+yfHtDL/94fbLad2rvCWftrcFzAfBgNVHSMEGDAW
-gBRPKhVJ5swFLyv0Dsy6LkzfE5DweDANBgkqhkiG9w0BAQsFAAOCAgEAP0YcO1i0
-mfN1AEfS/rq6mgRGYrYtoA+PwJUqWIth9RSQMCY3lKGmKSDJtQjX+RXLnZwZ7S+k
-5pFIhRr3qxdeeSNpuDwMSK7IupDQBfszfob9EvgtD/8WFZrcdkh9ZVtOkxTovjfR
-E/ensc2trk/hcrlTLc3mQnZEkyEoWMBEqzzaW+VVqwSGTZxMM/ROE5jpD9GjcCsd
-ESBHJvbYRX+IrfLBgQ++zWx5gJQw643M832hPmxv+o/zHy52lz+KG2c74PmxPGvc
-ZBsAc+mJgfZ/UfNRyLmWX/1V+HdviLxls+IwpAB6eWjgNoupGwabIP7+mKpWWMgI
-pHsSWf89vV4TO8bHigBbyycYAu7LOMK3qVEE7zHKSQlIFBPrkeImjIhfHHjhDZAp
-18H8yIn9TVMLmVjCGiQ9wKJMo9nHlcW8cvoC8avdqiueoLsaaC0JjKKZDSbsnjAZ
-AVpBRWOzxdskMkz+f/PO6U0AZM+7FTQtMW5PwJZAmzI1ZZIBKX50AlD9Ozs6o59q
-wKW+P8MH1owqxvQPMr07/EWQ0kbub8MvJoyXDOjampcDC4YXRaZiaU6Nz/i/6i/c
-/5UUFb2SLYoIz86KsPY0CqIOSTFE4Uf7N1JTWZMlQMysZy2itpt1/ROlp5NPcgV1
-zbE39jtpOyShHyPwzbuuGLOq65/Xlwa6/UQ=
------END CERTIFICATE-----
diff --git a/test/units/modules/network/f5/fixtures/cert1.key b/test/units/modules/network/f5/fixtures/cert1.key
deleted file mode 100644
index a89a29161c..0000000000
--- a/test/units/modules/network/f5/fixtures/cert1.key
+++ /dev/null
@@ -1,27 +0,0 @@
------BEGIN RSA PRIVATE KEY-----
-MIIEpQIBAAKCAQEA1g+9Ju8UTQn224sB9U5sA7E1IBa4G3zmto2XG7BPirbLVH56
-//2vAtu/nc+aTA2Hk4vMYfMjqW+O1IIsk7bi+jftitMjj221eEo4upP5ShxABjPX
-wJgg1BaspKVrQSBMOlV+x1DnlQdOhhWGeg9sV9IHHJckUVtO9VI6+E+Va2yDHzRO
-7rCu/kaQOPFNhXKLRrzRYjdlWt67FlEe9cug79Z7EW87DEkXvE2M9dnwNWv3tk1Q
-60eB4wbyvexnT6srA6riHkIiqclZ3A0Z+8UCHddY5ARTCh15u8Ez8c23EC60bpvc
-YGYFUJ8gZqFxAFFUzwpw9HxFxvCnHBEvPqMfvwIDAQABAoIBAQCjQ7PP+y8vpvbp
-8bbXoy2ND15mkA1xoazR9WIYEzxHny2rzx//GTyfYH1gXtPfR75tEYYb+vbrJxP4
-DyTysN2jXH7HkEwh+9oZ2fo0i+Hp3WwTjvzyftUjDfw1Q5lvPbQGFekxGgrXRpBk
-ggxkEllfDeiwrLJdftfVEhe6BfD/0YibwQeHN7VoC4V8wOanKtDmx74W/1f7WhwQ
-nKQnCrbYqNJa2nGvWiKU5Suvfb0v7tCnQYlfnCpUfj+wcnxlgmGkcyq1L+qC1qC8
-PO5i3T3LM5Yg8CSeGhO/q6gw/fUowuBN1cluTqN97oLHiEM5tLdjeVWwa1Vp0liv
-1WXGT4eBAoGBAPtumMmyVTIorvV6KGNI/Eo6jfE0HOXVdXtm4iToDDuiYwto7/Ge
-/kV+11Fpu0lV+eYPfZn175Of8FnQPwczQF1OOH/aQ/ViY8j87bZUbCy25mWrfNkh
-2rRlyI3/OsSfL5SkyWpYB0yhSJZV9mSQJTZolB4GQRNPKtqi7NpB4WxBAoGBANnz
-VS4JBJO75yeSG5BzPp5VVKm+nu0Betlva8GsHdEic8OM9bGpVozGysAW3Xdxp7q6
-gLJGyyuzpsxldCc/IdIlF5fz7gkLl4NoYanz9PSEr2XZLh9+2yXGkPFlC3IeHAUB
-E+2UO9MFpWrmfKoAnYZCR6vJDxtQBpAlTUvJEYv/AoGBAPha62K32327P+7MJl7D
-9ijgI9rwjebcbbpiCtlHuOWi5lCb6/7v/NvqiYcqeEvdOAXuoTNWAbsBTel5UPis
-wFQp8pcfouccs9IRPEFQrLWSSIx+0sirrxtoOq1AQe18DAS4rRd1MmiYG1ocOVBm
-LcvLixsJNHh9R6hFLM3+K0vBAoGANkmJ+gF9Bl9TYGPgQcay3jVa9Tzp0RcBRo+e
-Q4tfkewG8bp2qF4JlN8fOWF4oHvKz5QM4lsH2EbTUS4kFHKBNhrPGaZEsDQW9UBW
-s0J0zUMPfUrvViD+7RXcnIQSqcYeLJDsKc02aYWKgmoOuzmUAxEXUQ6vmJoCSH1C
-F5JpsHkCgYEArwTSzb1+/ThQhK1JN8hJ4jMjQ8E7PzLTMILrdDALn2g1T4VzL7N7
-UG6oUieMlo/UH6cv6330dwaGVklXZbyDKSDROIafFcOpVfcvDUgJCjp3CaY9A2zG
-+EPkRpeHKXAIgG+QuOwVOtYWcWltnBf61slTqiY2vKX1+ZGmrMrw1Zw=
------END RSA PRIVATE KEY-----
diff --git a/test/units/modules/network/f5/fixtures/cert2.crt b/test/units/modules/network/f5/fixtures/cert2.crt
deleted file mode 100644
index 30674bc8e7..0000000000
--- a/test/units/modules/network/f5/fixtures/cert2.crt
+++ /dev/null
@@ -1,101 +0,0 @@
-Certificate:
- Data:
- Version: 3 (0x2)
- Serial Number: 2 (0x2)
- Signature Algorithm: sha256WithRSAEncryption
- Issuer: C=US, ST=New York, L=New York, O=ACME CA, OU=Coyote, CN=ourca.domain.local
- Validity
- Not Before: Jun 30 16:49:00 2016 GMT
- Not After : Jun 25 16:49:00 2036 GMT
- Subject: C=US, ST=New York, O=ACME, OU=Coyote, CN=cert2.domain.local
- Subject Public Key Info:
- Public Key Algorithm: rsaEncryption
- Public-Key: (2048 bit)
- Modulus:
- 00:c6:9e:84:99:4d:69:98:c2:42:95:ed:43:ca:24:
- 05:64:9d:67:81:1c:ff:56:7b:ad:d1:cb:09:39:28:
- 4f:ac:aa:1b:34:61:3a:b1:e3:57:d4:9e:15:40:77:
- 91:20:2b:e8:7e:d3:91:1e:46:50:6c:2f:4b:00:c2:
- f2:3a:43:89:d9:81:73:84:5f:02:db:49:ac:3b:9e:
- fe:c0:77:2e:53:ea:ce:da:ff:49:98:21:1d:31:4d:
- 0f:14:20:30:36:9a:23:b4:28:08:06:59:81:30:03:
- 86:09:0b:5b:e1:72:63:5e:54:ac:90:b1:82:55:b8:
- 12:00:d5:01:26:be:6a:eb:fc:58:5b:8a:7a:fe:46:
- 23:a3:eb:5d:6c:e0:f6:79:00:5d:5b:49:82:42:62:
- e2:58:e8:65:54:14:be:99:25:8b:b7:df:cf:53:26:
- f2:7a:fd:b9:f9:f3:d5:af:06:d6:1e:ba:66:4d:41:
- 8c:5d:aa:23:41:7f:f4:27:21:a0:30:09:86:13:c4:
- 57:1b:13:45:63:6b:3b:a3:7f:d1:1a:cd:fd:07:51:
- 0f:1a:e1:d9:25:3e:d2:77:e1:c7:60:db:12:df:ef:
- 71:65:c8:c7:1a:42:94:6f:57:2a:d7:67:30:0f:33:
- 31:ba:90:4d:d1:80:38:08:e7:90:7a:04:0e:8f:b0:
- 2a:73
- Exponent: 65537 (0x10001)
- X509v3 extensions:
- X509v3 Basic Constraints:
- CA:FALSE
- Netscape Comment:
- OpenSSL Generated Certificate
- X509v3 Subject Key Identifier:
- 43:71:A9:16:2B:DA:DC:5F:FD:82:87:78:26:48:4E:77:21:47:44:D6
- X509v3 Authority Key Identifier:
- keyid:4F:2A:15:49:E6:CC:05:2F:2B:F4:0E:CC:BA:2E:4C:DF:13:90:F0:78
-
- Signature Algorithm: sha256WithRSAEncryption
- 15:ac:f9:cb:bc:88:c0:d3:74:83:88:cd:19:94:bb:87:7e:fd:
- 4d:25:09:9b:08:84:64:c5:37:c7:99:b3:25:ee:6e:82:46:b0:
- 13:f9:05:ad:4d:4a:b2:e3:29:5d:0d:55:9e:9c:62:1d:95:f2:
- 19:49:5e:d3:5b:58:98:ce:e8:f5:e5:c1:ce:b5:a8:7a:b1:f8:
- 14:fe:25:10:12:5b:41:53:d2:47:ab:20:e5:50:da:b6:ba:00:
- 21:94:6b:dd:0b:24:15:dc:c0:4e:b8:1d:cc:9e:5f:10:5e:46:
- 3f:96:c9:f8:28:bb:13:31:d6:d2:6c:48:41:bb:23:ab:23:64:
- 73:d6:2b:2e:9a:77:d4:08:fb:e0:e8:50:2c:49:7f:98:9e:f6:
- 37:30:2b:7c:97:c6:a7:1e:5b:dc:ce:bb:1e:58:e4:bd:05:4c:
- ad:07:d6:03:c5:a9:57:a4:26:e2:10:f7:f9:63:1a:2a:6a:9c:
- 52:98:33:bf:ea:70:cd:c0:86:32:80:6e:70:54:87:74:3c:41:
- 53:a1:c6:53:44:c7:74:a6:11:b6:48:66:86:f9:04:ca:ec:5d:
- 4f:ce:7f:64:51:34:52:53:98:a8:70:62:f7:3b:fb:39:11:9a:
- e1:e2:d3:00:0b:6b:d2:33:3c:44:de:c3:6b:e1:6f:c9:be:d2:
- 2c:8a:f0:b3:d3:4c:12:2f:ad:9d:6b:40:89:23:94:93:6d:12:
- 6c:38:89:fa:fe:ad:02:55:55:8b:c3:86:7f:15:c4:3a:a9:70:
- e9:06:6c:26:09:28:9f:6e:94:f2:a1:27:5c:89:4c:42:ac:65:
- 90:92:d2:6d:09:7c:d8:a1:bf:5b:25:e4:db:ed:71:41:d7:e2:
- 61:47:89:9e:46:29:9d:f9:f4:94:cf:f5:b3:e8:df:6a:47:34:
- d1:ed:fc:a4:58:fe:82:e1:6e:e9:05:65:f5:d2:57:9a:d1:42:
- 64:ae:0c:bb:07:14:39:a2:c0:85:e4:25:a5:c4:e6:3f:e6:da:
- d0:18:4f:e0:01:ba:99:2e:1f:75:35:c3:fa:a3:e7:e1:75:1b:
- 1c:19:93:cc:96:eb:3f:ce:8b:10:40:36:63:f5:66:dc:6d:75:
- 31:ba:db:27:21:b4:15:00:e9:ce:d0:08:e3:b0:1c:e3:29:c9:
- 63:5a:c8:5c:ca:db:ce:51:b7:87:22:c6:ba:42:d7:ab:29:b4:
- 87:fa:27:9a:18:22:90:9f:da:c0:90:c4:49:64:38:38:2e:a2:
- ea:87:c1:8b:4e:8b:ff:a7:53:45:4f:d8:8b:86:69:ea:87:1d:
- f6:e6:44:14:1f:69:ee:2c:de:5a:a1:df:a8:57:13:65:4d:5b:
- ce:6e:f2:15:2a:c5:32:08
------BEGIN CERTIFICATE-----
-MIIExjCCAq6gAwIBAgIBAjANBgkqhkiG9w0BAQsFADBzMQswCQYDVQQGEwJVUzER
-MA8GA1UECAwITmV3IFlvcmsxETAPBgNVBAcMCE5ldyBZb3JrMRAwDgYDVQQKDAdB
-Q01FIENBMQ8wDQYDVQQLDAZDb3lvdGUxGzAZBgNVBAMMEm91cmNhLmRvbWFpbi5s
-b2NhbDAeFw0xNjA2MzAxNjQ5MDBaFw0zNjA2MjUxNjQ5MDBaMF0xCzAJBgNVBAYT
-AlVTMREwDwYDVQQIDAhOZXcgWW9yazENMAsGA1UECgwEQUNNRTEPMA0GA1UECwwG
-Q295b3RlMRswGQYDVQQDDBJjZXJ0Mi5kb21haW4ubG9jYWwwggEiMA0GCSqGSIb3
-DQEBAQUAA4IBDwAwggEKAoIBAQDGnoSZTWmYwkKV7UPKJAVknWeBHP9We63Rywk5
-KE+sqhs0YTqx41fUnhVAd5EgK+h+05EeRlBsL0sAwvI6Q4nZgXOEXwLbSaw7nv7A
-dy5T6s7a/0mYIR0xTQ8UIDA2miO0KAgGWYEwA4YJC1vhcmNeVKyQsYJVuBIA1QEm
-vmrr/Fhbinr+RiOj611s4PZ5AF1bSYJCYuJY6GVUFL6ZJYu3389TJvJ6/bn589Wv
-BtYeumZNQYxdqiNBf/QnIaAwCYYTxFcbE0Vjazujf9Eazf0HUQ8a4dklPtJ34cdg
-2xLf73FlyMcaQpRvVyrXZzAPMzG6kE3RgDgI55B6BA6PsCpzAgMBAAGjezB5MAkG
-A1UdEwQCMAAwLAYJYIZIAYb4QgENBB8WHU9wZW5TU0wgR2VuZXJhdGVkIENlcnRp
-ZmljYXRlMB0GA1UdDgQWBBRDcakWK9rcX/2Ch3gmSE53IUdE1jAfBgNVHSMEGDAW
-gBRPKhVJ5swFLyv0Dsy6LkzfE5DweDANBgkqhkiG9w0BAQsFAAOCAgEAFaz5y7yI
-wNN0g4jNGZS7h379TSUJmwiEZMU3x5mzJe5ugkawE/kFrU1KsuMpXQ1VnpxiHZXy
-GUle01tYmM7o9eXBzrWoerH4FP4lEBJbQVPSR6sg5VDatroAIZRr3QskFdzATrgd
-zJ5fEF5GP5bJ+Ci7EzHW0mxIQbsjqyNkc9YrLpp31Aj74OhQLEl/mJ72NzArfJfG
-px5b3M67HljkvQVMrQfWA8WpV6Qm4hD3+WMaKmqcUpgzv+pwzcCGMoBucFSHdDxB
-U6HGU0THdKYRtkhmhvkEyuxdT85/ZFE0UlOYqHBi9zv7ORGa4eLTAAtr0jM8RN7D
-a+Fvyb7SLIrws9NMEi+tnWtAiSOUk20SbDiJ+v6tAlVVi8OGfxXEOqlw6QZsJgko
-n26U8qEnXIlMQqxlkJLSbQl82KG/WyXk2+1xQdfiYUeJnkYpnfn0lM/1s+jfakc0
-0e38pFj+guFu6QVl9dJXmtFCZK4MuwcUOaLAheQlpcTmP+ba0BhP4AG6mS4fdTXD
-+qPn4XUbHBmTzJbrP86LEEA2Y/Vm3G11MbrbJyG0FQDpztAI47Ac4ynJY1rIXMrb
-zlG3hyLGukLXqym0h/onmhgikJ/awJDESWQ4OC6i6ofBi06L/6dTRU/Yi4Zp6ocd
-9uZEFB9p7izeWqHfqFcTZU1bzm7yFSrFMgg=
------END CERTIFICATE-----
diff --git a/test/units/modules/network/f5/fixtures/cert2.key b/test/units/modules/network/f5/fixtures/cert2.key
deleted file mode 100644
index 6d4bdf1526..0000000000
--- a/test/units/modules/network/f5/fixtures/cert2.key
+++ /dev/null
@@ -1,30 +0,0 @@
------BEGIN RSA PRIVATE KEY-----
-Proc-Type: 4,ENCRYPTED
-DEK-Info: AES-256-CBC,C56C8101A9C8D6B9AD0975807D4793BB
-
-rhV1cJee3XAlY83zIXytJOlvXFrsHmzyTVoOn26eOwgza8CuE5gQQzLXiT12zK0q
-YAbYyyyEXJJogVU61s1vuCQRNiezUCwT4SBj7ni4rXqu5BYUxKh0wD0gjE519yNP
-nqnPUYKdLkFY7I6RJjqCqkk8xnJm64g5zCqN58aR98Mkqr1898+lZ2OHqAsAYBNH
-dM/SE7B7E4Mr1sAjpsn6L4PJ93WSwmEtH3nZTnPF9qtFuJwjUcHCN/r/s3QXki95
-eFX+7qW460lBfDeRUKXKqz4gO017AXu1kccrlHhdQoJGf3D+x9zwofG/uFeAH3iN
-f9IRaiR2IN6SS67QFmOkI9S95tsFb4N8bmmfGV4w8wfxvDzGJuxzIb4gByX5xov4
-S22pDpkfn5YqxgC5ItSiFYpg01HEi2l79HwZqAn1kowLsuF1JJKAYL5IMS3DlrdH
-AyA9CN28G6pYEjwFBbFgpOg64UNmrkxRncHxC4FuH7iGZNJL9+HQve/J5nlrnx6M
-IU2myiZZhgbsl/V45ddXBDSlEdWFLHtEhcG+ICJP3EZAXHR0e9vyrWDk7T5zKhLP
-ch9PNmIw+5zzpRuPu5NYw7V0ax8UOf2AydyBHeIQWuY52bai+QMDyQauomqpPXRY
-tpCcW85P9jstY/F6TV32XQu/cHWolziJXI/QzWF5+uvnLMAsb3p5mriCG4DOTWF3
-KFSytTGnDQUUCLgaYSSKXL5Z52PVYmTjoqX8M6cvqSEdjK84wILQE0JMItQjGSIM
-y5qHD7Mthf9YOJy1D86qtVumbaOBLw/rGPQS5QlK/m256xZ10LUslYczMpw1orN3
-3Uv8zHKk790XduHTllR0LwQXMJXG59hgiWAu3V3rsAkVSRpC3MI6IUZ2cfJvZ0Ds
-FmUhCJ34JQxD4E/sT9uGAk6VIq/fAmM7/gq0oF4oqOFg4Zy1r3rc1Kvdoy1yKUi6
-JCI5bKCkgIthx4XUKQVtFMkHBDZAHr6i5Lzy4nM6I4S4/qL3JH4Q+739D1rjGVlq
-OWcaeOzkkbJrE8h+A94UQao4R50LavKgq/o2n56tHG0RhXXyV5MC/X9rbSVipihR
-rwNKnogdhAjY96IrOzdiHTArg8qZBGvHPoGUl3zjWFqNbHEs4NLSrEl6oEs6F/vC
-zEZmi8gxqraw4u1GJnpoMuLO45PuhcxcXgJSvTh/OKDaR1u0ggEn7TxfAygm0ahP
-i6NBgoZ/upTHAWqWht2JjSmQHQW7doVkp/BgNJq13oYF7FEUEg/ZtBTPKPR3CjM0
-ZKDGvKqWRVRyrw9FSwXn6WlSFfT3vhPMoW2jq1Kq5o/ZyhcquCVE8i+xq6hilcb5
-sNiV1tPWsZOFHx4T5hBVK+QnC8t7pCj38YpyEoY4/gffMtY85jsrLMlPYd5bmJ6O
-x1tKiQauK+aX6IMu38YnHjCGnCkw1fF2OMSohbG2QfaKsmfkt8YLRuf2PTtjLtke
-xGt0Irjac/sEZPc4SEIqnehNfXadiuMV3+4v6ey9vf782r76KH8gInY2gDsQ4X6d
-1LVNCNAd/AGlitopL4hYomaeTjTzqIy5fMlGmTrpZjokenu/ILXsljZVAX2iyOAs
------END RSA PRIVATE KEY-----
diff --git a/test/units/modules/network/f5/fixtures/chain1.crt b/test/units/modules/network/f5/fixtures/chain1.crt
deleted file mode 100644
index 38dd8dc9cf..0000000000
--- a/test/units/modules/network/f5/fixtures/chain1.crt
+++ /dev/null
@@ -1,68 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIF2DCCA8CgAwIBAgIJAKql/ua7JdaGMA0GCSqGSIb3DQEBCwUAMHkxCzAJBgNV
-BAYTAkdCMRAwDgYDVQQIDAdFbmdsYW5kMRIwEAYDVQQKDAlBbGljZSBMdGQxKDAm
-BgNVBAsMH0FsaWNlIEx0ZCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkxGjAYBgNVBAMM
-EUFsaWNlIEx0ZCBSb290IENBMB4XDTE3MDcyNTAzMTcwNloXDTM3MDcyMDAzMTcw
-NloweTELMAkGA1UEBhMCR0IxEDAOBgNVBAgMB0VuZ2xhbmQxEjAQBgNVBAoMCUFs
-aWNlIEx0ZDEoMCYGA1UECwwfQWxpY2UgTHRkIENlcnRpZmljYXRlIEF1dGhvcml0
-eTEaMBgGA1UEAwwRQWxpY2UgTHRkIFJvb3QgQ0EwggIiMA0GCSqGSIb3DQEBAQUA
-A4ICDwAwggIKAoICAQC7grIMGI9e11lKh++bhyhTAU4qsKgM52xkl4sctSkK5hyT
-jY8YYfD9ERrrJov6LLCt8QiwFypoqdILTht4g6sGACoVGXigFbLNyhEhX64kIWwT
-PNFFXezYJv87qxPeT0I+6oHwai3smrUsPzsK73vwWOlnAW0mxvSzWpzvc3CgCB1J
-+vRhdPm0VgT5HuR20WDPvx0T+ftQRrhIHz/UZSTHo/CEcuJ9zjhEmQlZRhfxZiBW
-FY8Mgs6bgAKC+KtAsFTqRAuXq++xOnIIBzXACluFxp7Fee1CZh2GPxmtzFSIJVH0
-pH6wf9Kxkr0zuiAt3nq3xQcQZVdRP3bWscxp0lYG8BjuMZppI+r+gG1k/7WsRU/A
-SUiHi4EogznIuJ7o1LbcULpIKjHsHVKXYz+ff+hx7npisHIE9BoyBe9SbalJxIcS
-7n9/Mw6UmKk/zxspXCwMLraaeoyy2vUoC/zXW2WQHq67IarSAVbCPEPliqydVZ9k
-y1ZQKGdrpxxLdsbasNv3xnS50DBd4GsSnxdhzCXUUhvLQ8dZ/NRXvZ6wwcdeQ6PV
-5+dQNgnm7yd4mxyBbqv6RBAa37uNKWNf4yAQ9j9QN8pzW+qzuusAcLxTdDbtyeMi
-Dz5UHzF912m3KLlF/Aad2TbjrCR4K0CEozVT8lhFpZlNl+IdZyuSbZQ6tYrJ0wID
-AQABo2MwYTAdBgNVHQ4EFgQUk2h12cau/s1k/IGR0OAUWZbf8a8wHwYDVR0jBBgw
-FoAUk2h12cau/s1k/IGR0OAUWZbf8a8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8B
-Af8EBAMCAYYwDQYJKoZIhvcNAQELBQADggIBADSBpj8O7Wrs0gpciOmJ7cmVUIoX
-XTd+WgzustaUJoqpeCmzkeC7O9/a9Eat2LrmKIBoY6uzH1hnYwOxSdSdodBuUcOv
-6hBl7rFCgg+ACRn7zaaInFRPdx4P+ovbfFFetKmg54XA8ZDb7YRpwj3zMtlV38Ca
-WC1jP36ocn8UZ8av1ki7KNz/0PqzJ4sVs6IZrj2Lo0lDcu+29Nh5VJ7AZnOfUeas
-4sQr3dPHPaMQBxz0rKr/FN4qx63kd9GmoGz4DEDnPeUl2v52i/48ym0Q7JrntD5J
-qJaaoU4uxUMkmnD8wOmBBtXQ3eRpHE6W8ZcJGWkL8bRPrFnwxMk71N1guetetzoY
-xX7E3/CtSV7CSJMF74hE/ULNG8XdWAYY3zojSStA8UzYzO/pCA/PcmxBzxnkch4W
-3LetTSKH9mN9k2p51jGLWIbRGod5qffmtb76xRzhyhgryCV/afwfJxKeXwjDz8ty
-J6qFBXclDjTWVHHOU8hGvu4Z4PD6cbQ68tLlfFoDRq6nqKufFKpxOyw9ioLcPWbz
-+rJsnqE1+5QR4tisplmSQtQ5nI45Wns+UCmsEJm+gPkyp9pBQVudkEo1OSyCSSwZ
-evwZgkD2YclUpxcQRQR/Sy4Kvrwv3D+6zfgovClqpI3SHvQ1v/TXa3wB/RTB1H0q
-0Qn4FWp63AaOBNrC
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIF3TCCA8WgAwIBAgICEAAwDQYJKoZIhvcNAQELBQAweTELMAkGA1UEBhMCR0Ix
-EDAOBgNVBAgMB0VuZ2xhbmQxEjAQBgNVBAoMCUFsaWNlIEx0ZDEoMCYGA1UECwwf
-QWxpY2UgTHRkIENlcnRpZmljYXRlIEF1dGhvcml0eTEaMBgGA1UEAwwRQWxpY2Ug
-THRkIFJvb3QgQ0EwHhcNMTcwNzI1MDMxNzE0WhcNMjcwNzIzMDMxNzE0WjCBgTEL
-MAkGA1UEBhMCR0IxEDAOBgNVBAgMB0VuZ2xhbmQxEjAQBgNVBAoMCUFsaWNlIEx0
-ZDEoMCYGA1UECwwfQWxpY2UgTHRkIENlcnRpZmljYXRlIEF1dGhvcml0eTEiMCAG
-A1UEAwwZQWxpY2UgTHRkIEludGVybWVkaWF0ZSBDQTCCAiIwDQYJKoZIhvcNAQEB
-BQADggIPADCCAgoCggIBAL1whyll1+/qWhAUdy6U5vtopX0wzJrg3dk8tIlpDChh
-khTEK779aQNapRKpZmJ6hnCkg7buVOSBP2WqqGQ1s9cakBSFkDyy5hrqeSzIR93w
-9n2sTc4EBD0b8QWn5D0hdoWLT3+OwFHCBf/vb+qA9Vz0P/PRPYUnKttQH6nXTj9C
-+AzegfS4SbfDJ4XdhbzCewgUvr3rqP61AQuEwZq7qoVCA3bFSASUfbJgMBxJgfBG
-KynueJ62L+wbZLXUDq9G3T0KIUlxgGIcPQ0tu2kW7uSeY5wZazuvNJCHM9HKsjUf
-wb8GgavQRlgunE9zXAEr+iP2DQrmZXdhJkkb4EyG1vuTMK3DtGjlpXAVGsiuuZ1o
-PVYZDVKhfKFN9tyop/dppxDTHyJlp2prtsudhtqwzYDqrUsMu4/LMWvxgUcTK4U7
-mPSBcvOb4fTqXirNRYsqi8BK/nxt/hUBVG0vEnoIH0ppzqWvMcsMtMi3535sErUJ
-k8IVKYIGB9OKb9SzpERYT6+BH9sUURZ/xyhRd2pj7EiVAEVxrrVoedZJzLRuXH99
-qhFG2HnDAaDC9LX09GveTzgUVUfif5fJgGBkzslpM3z8t3THz9RjrqtrzKOCHcZF
-cgt46oQByT0UjhIPCz3/6h04XzSszue8aTAwi1JaYhHoXEPolgJRoLeuFdsJtfyt
-AgMBAAGjZjBkMB0GA1UdDgQWBBSiTrrHxly7SsSV+MqprYstABOIjDAfBgNVHSME
-GDAWgBSTaHXZxq7+zWT8gZHQ4BRZlt/xrzASBgNVHRMBAf8ECDAGAQH/AgEAMA4G
-A1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAakyu4lsOWz2+VHI0S6xb
-M/afSDgnmI+i/1lSQ7UHM1XIvuINIzAcWndU1XuHyFjT7p9ZDPZ52gcseIenrKOD
-EsJWKO3u33to3YUMfBCJi9VbTCtd6rkjuFggN6EKM1esqs0kgenWmvEQSv73OOii
-UCAbif4fSva6C5PhgK7X0zE+hTsPxRZnN8baRlL01IHEraG+PfYCEpjvzExzoaW6
-aLNS0DAS1escb9K5u6Cf4KIxkdqpcYIW7v7tehj5KS3E0cRv3QAaMUBkMWTWlSP3
-irzC0OB8BFuYZ1OxDYnxhSY1mfwfI8kWrvA83okS8qwfjq/rty53VG3tON9GzGXg
-P1SQ3xB/6yxSvskcbN1blfHJfJRpOIxBvAydhdBCh7PO0WJzTP8kmffMhOiT5AdE
-jcJVxWSjwqUetomlNiErEvo7ZmxEwQZQE5wnuGM4eAbV87zLVrnj+viRo1dP7RFN
-iRUwjrxKpozUY5AGY2hZdFrWObBe1AvLDQcNDUc+oMwgnIBC2YtO1cTKJ3IFru0f
-Av48lyJ88AfO2W7pEfoVqAAZszu2s0VZB5W9fBOQLizvkjK8s5YeUPdhW3epEYF9
-I1PsTSNdN+abV5qNdIjgRVtNlV63+1y0Ez7J7RvO847ZYTuqHnfaRG03p10YnxBs
-WcSe5ozInV3EZ9TxFcGQR+E=
------END CERTIFICATE-----
diff --git a/test/units/modules/network/f5/fixtures/create_gtm_irule.tcl b/test/units/modules/network/f5/fixtures/create_gtm_irule.tcl
deleted file mode 100644
index d2283646c5..0000000000
--- a/test/units/modules/network/f5/fixtures/create_gtm_irule.tcl
+++ /dev/null
@@ -1,8 +0,0 @@
-when LB_SELECTED {
- # Capture IP address chosen by WIP load balancing
- set wipHost [LB::server addr]
-}
-
-when LB_FAILED {
- set wipHost [LB::server addr]
-}
diff --git a/test/units/modules/network/f5/fixtures/create_iapp_service_parameters_f5_http.json b/test/units/modules/network/f5/fixtures/create_iapp_service_parameters_f5_http.json
deleted file mode 100644
index 31fce52a7e..0000000000
--- a/test/units/modules/network/f5/fixtures/create_iapp_service_parameters_f5_http.json
+++ /dev/null
@@ -1,199 +0,0 @@
-{
- "name": "http_example",
- "partition": "Common",
- "template": "/Common/f5.http",
- "inheritedDevicegroup": "true",
- "deviceGroup": "none",
- "inheritedTrafficGroup": "true",
- "trafficGroup": "/Common/traffic-group-local-only",
- "lists": [
- {
- "name": "irules__irules",
- "encrypted": "no",
- "value": [
- "/Common/lgyft"
- ]
- },
- {
- "name": "net__client_vlan",
- "encrypted": "no",
- "value": [
- "/Common/net2"
- ]
- }
- ],
- "tables": [
- {
- "columnNames": [
- "name"
- ],
- "name": "pool__hosts",
- "rows": [
- {
- "row": [
- "demo.example.com"
- ]
- }
- ]
- },
- {
- "columnNames": [
- "addr",
- "connection_limit"
- ],
- "name": "pool__members",
- "rows": [
- {
- "row": [
- "10.1.1.1",
- "0"
- ]
- },
- {
- "row": [
- "10.1.1.2",
- "0"
- ]
- }
- ]
- }
- ],
- "variables": [
- {
- "name": "afm__policy",
- "value": "/#do_not_use#"
- },
- {
- "name": "afm__dos_security_profile",
- "value": "/#do_not_use#"
- },
- {
- "name": "afm__protocol_security_profile",
- "value": "/#do_not_use#"
- },
- {
- "name": "asm__use_asm",
- "value": "/#do_not_use#"
- },
- {
- "name": "client__http_compression",
- "value": "/#do_not_use#"
- },
- {
- "name": "client__standard_caching_without_wa",
- "value": "/#do_not_use#"
- },
- {
- "name": "client__tcp_wan_opt",
- "value": "/#create_new#"
- },
- {
- "name": "monitor__monitor",
- "value": "/#create_new#"
- },
- {
- "name": "monitor__frequency",
- "value": "30"
- },
- {
- "name": "monitor__uri",
- "value": "/my/path"
- },
- {
- "name": "monitor__response",
- "value": ""
- },
- {
- "name": "net__client_mode",
- "value": "wan"
- },
- {
- "name": "net__server_mode",
- "value": "lan"
- },
- {
- "name": "net__vlan_mode",
- "value": "all"
- },
- {
- "name": "pool__addr",
- "value": "10.10.10.10"
- },
- {
- "name": "pool__http",
- "value": "/#create_new#"
- },
- {
- "name": "pool__mask",
- "value": ""
- },
- {
- "name": "pool__persist",
- "value": "/#cookie#"
- },
- {
- "name": "pool__lb_method",
- "value": "least-connections-member"
- },
- {
- "name": "pool__pool_to_use",
- "value": "/#create_new#"
- },
- {
- "name": "pool__port_secure",
- "value": "443"
- },
- {
- "name": "pool__redirect_port",
- "value": "80"
- },
- {
- "name": "pool__redirect_to_https",
- "value": "yes"
- },
- {
- "name": "pool__xff",
- "value": "yes"
- },
- {
- "name": "server__oneconnect",
- "value": "/#create_new#"
- },
- {
- "name": "server__tcp_lan_opt",
- "value": "/#create_new#"
- },
- {
- "name": "ssl__cert",
- "value": "/Common/default.crt"
- },
- {
- "name": "ssl__client_ssl_profile",
- "value": "/#create_new#"
- },
- {
- "name": "ssl__key",
- "value": "/Common/default.key"
- },
- {
- "name": "ssl__mode",
- "value": "client_ssl"
- },
- {
- "name": "ssl__use_chain_cert",
- "value": "/#do_not_use#"
- },
- {
- "name": "ssl_encryption_questions__advanced",
- "value": "yes"
- },
- {
- "name": "stats__analytics",
- "value": "/#do_not_use#"
- },
- {
- "name": "stats__request_logging",
- "value": "/#do_not_use#"
- }
- ]
-}
diff --git a/test/units/modules/network/f5/fixtures/create_iapp_template.iapp b/test/units/modules/network/f5/fixtures/create_iapp_template.iapp
deleted file mode 100644
index 995bd4d636..0000000000
--- a/test/units/modules/network/f5/fixtures/create_iapp_template.iapp
+++ /dev/null
@@ -1,56 +0,0 @@
-cli admin-partitions {
- update-partition Common
-}
-
-sys application template foo.iapp {
-
- actions {
- definition {
-
- implementation {
- set cfg { ltm virtual forwarding-repro {
- destination 0.0.0.0:any
- description "something 1"
- mask any
- profiles {
- fastL4 { }
- }
- source 1.1.1.1/32
- translate-address disabled
- translate-port disabled
- vlans { __forwarding_vlans__ }
- vlans-enabled
-} }
-
-
- if {![info exists {::var__forwarding_vlans}] || (${::var__forwarding_vlans} == "")} {
- set {::var__forwarding_vlans} "{}"
- puts "Info: assigning empty string to variable {::var__forwarding_vlans}"
- }
-
-
- set cfg [string map "__forwarding_vlans__ ${::var__forwarding_vlans} __app_service__ $tmsh::app_name.app/$tmsh::app_name " $cfg]
- set fileId [open /var/tmp/demo.repro.cfg "w"]
- puts -nonewline $fileId $cfg
- close $fileId
-
-
- tmsh::load sys config merge file /var/tmp/demo.repro.cfg
- }
-
- presentation {
-
- include "/Common/f5.apl_common"
- section var {
- string forwarding_vlans display "xxlarge"
- }
-
- text {
- var "General variables"
- var.forwarding_vlans "__var__forwarding_vlans__"
- }
- }
- role-acl { admin manager resource-admin }
- }
- }
-}
diff --git a/test/units/modules/network/f5/fixtures/create_insecure_cert1.crt b/test/units/modules/network/f5/fixtures/create_insecure_cert1.crt
deleted file mode 100644
index 1d22f30289..0000000000
--- a/test/units/modules/network/f5/fixtures/create_insecure_cert1.crt
+++ /dev/null
@@ -1,101 +0,0 @@
-Certificate:
- Data:
- Version: 3 (0x2)
- Serial Number: 1 (0x1)
- Signature Algorithm: sha256WithRSAEncryption
- Issuer: C=US, ST=New York, L=New York, O=ACME CA, OU=Coyote, CN=ourca.domain.local
- Validity
- Not Before: Jun 30 16:46:09 2016 GMT
- Not After : Jun 25 16:46:09 2036 GMT
- Subject: C=US, ST=New York, O=ACME, OU=Coyote, CN=cert1.domain.local
- Subject Public Key Info:
- Public Key Algorithm: rsaEncryption
- Public-Key: (2048 bit)
- Modulus:
- 00:d6:0f:bd:26:ef:14:4d:09:f6:db:8b:01:f5:4e:
- 6c:03:b1:35:20:16:b8:1b:7c:e6:b6:8d:97:1b:b0:
- 4f:8a:b6:cb:54:7e:7a:ff:fd:af:02:db:bf:9d:cf:
- 9a:4c:0d:87:93:8b:cc:61:f3:23:a9:6f:8e:d4:82:
- 2c:93:b6:e2:fa:37:ed:8a:d3:23:8f:6d:b5:78:4a:
- 38:ba:93:f9:4a:1c:40:06:33:d7:c0:98:20:d4:16:
- ac:a4:a5:6b:41:20:4c:3a:55:7e:c7:50:e7:95:07:
- 4e:86:15:86:7a:0f:6c:57:d2:07:1c:97:24:51:5b:
- 4e:f5:52:3a:f8:4f:95:6b:6c:83:1f:34:4e:ee:b0:
- ae:fe:46:90:38:f1:4d:85:72:8b:46:bc:d1:62:37:
- 65:5a:de:bb:16:51:1e:f5:cb:a0:ef:d6:7b:11:6f:
- 3b:0c:49:17:bc:4d:8c:f5:d9:f0:35:6b:f7:b6:4d:
- 50:eb:47:81:e3:06:f2:bd:ec:67:4f:ab:2b:03:aa:
- e2:1e:42:22:a9:c9:59:dc:0d:19:fb:c5:02:1d:d7:
- 58:e4:04:53:0a:1d:79:bb:c1:33:f1:cd:b7:10:2e:
- b4:6e:9b:dc:60:66:05:50:9f:20:66:a1:71:00:51:
- 54:cf:0a:70:f4:7c:45:c6:f0:a7:1c:11:2f:3e:a3:
- 1f:bf
- Exponent: 65537 (0x10001)
- X509v3 extensions:
- X509v3 Basic Constraints:
- CA:FALSE
- Netscape Comment:
- OpenSSL Generated Certificate
- X509v3 Subject Key Identifier:
- 2D:FB:27:C7:B4:32:FF:F7:87:DB:2D:A7:76:AE:F0:96:7E:DA:DC:17
- X509v3 Authority Key Identifier:
- keyid:4F:2A:15:49:E6:CC:05:2F:2B:F4:0E:CC:BA:2E:4C:DF:13:90:F0:78
-
- Signature Algorithm: sha256WithRSAEncryption
- 3f:46:1c:3b:58:b4:99:f3:75:00:47:d2:fe:ba:ba:9a:04:46:
- 62:b6:2d:a0:0f:8f:c0:95:2a:58:8b:61:f5:14:90:30:26:37:
- 94:a1:a6:29:20:c9:b5:08:d7:f9:15:cb:9d:9c:19:ed:2f:a4:
- e6:91:48:85:1a:f7:ab:17:5e:79:23:69:b8:3c:0c:48:ae:c8:
- ba:90:d0:05:fb:33:7e:86:fd:12:f8:2d:0f:ff:16:15:9a:dc:
- 76:48:7d:65:5b:4e:93:14:e8:be:37:d1:13:f7:a7:b1:cd:ad:
- ae:4f:e1:72:b9:53:2d:cd:e6:42:76:44:93:21:28:58:c0:44:
- ab:3c:da:5b:e5:55:ab:04:86:4d:9c:4c:33:f4:4e:13:98:e9:
- 0f:d1:a3:70:2b:1d:11:20:47:26:f6:d8:45:7f:88:ad:f2:c1:
- 81:0f:be:cd:6c:79:80:94:30:eb:8d:cc:f3:7d:a1:3e:6c:6f:
- fa:8f:f3:1f:2e:76:97:3f:8a:1b:67:3b:e0:f9:b1:3c:6b:dc:
- 64:1b:00:73:e9:89:81:f6:7f:51:f3:51:c8:b9:96:5f:fd:55:
- f8:77:6f:88:bc:65:b3:e2:30:a4:00:7a:79:68:e0:36:8b:a9:
- 1b:06:9b:20:fe:fe:98:aa:56:58:c8:08:a4:7b:12:59:ff:3d:
- bd:5e:13:3b:c6:c7:8a:00:5b:cb:27:18:02:ee:cb:38:c2:b7:
- a9:51:04:ef:31:ca:49:09:48:14:13:eb:91:e2:26:8c:88:5f:
- 1c:78:e1:0d:90:29:d7:c1:fc:c8:89:fd:4d:53:0b:99:58:c2:
- 1a:24:3d:c0:a2:4c:a3:d9:c7:95:c5:bc:72:fa:02:f1:ab:dd:
- aa:2b:9e:a0:bb:1a:68:2d:09:8c:a2:99:0d:26:ec:9e:30:19:
- 01:5a:41:45:63:b3:c5:db:24:32:4c:fe:7f:f3:ce:e9:4d:00:
- 64:cf:bb:15:34:2d:31:6e:4f:c0:96:40:9b:32:35:65:92:01:
- 29:7e:74:02:50:fd:3b:3b:3a:a3:9f:6a:c0:a5:be:3f:c3:07:
- d6:8c:2a:c6:f4:0f:32:bd:3b:fc:45:90:d2:46:ee:6f:c3:2f:
- 26:8c:97:0c:e8:da:9a:97:03:0b:86:17:45:a6:62:69:4e:8d:
- cf:f8:bf:ea:2f:dc:ff:95:14:15:bd:92:2d:8a:08:cf:ce:8a:
- b0:f6:34:0a:a2:0e:49:31:44:e1:47:fb:37:52:53:59:93:25:
- 40:cc:ac:67:2d:a2:b6:9b:75:fd:13:a5:a7:93:4f:72:05:75:
- cd:b1:37:f6:3b:69:3b:24:a1:1f:23:f0:cd:bb:ae:18:b3:aa:
- eb:9f:d7:97:06:ba:fd:44
------BEGIN CERTIFICATE-----
-MIIExjCCAq6gAwIBAgIBATANBgkqhkiG9w0BAQsFADBzMQswCQYDVQQGEwJVUzER
-MA8GA1UECAwITmV3IFlvcmsxETAPBgNVBAcMCE5ldyBZb3JrMRAwDgYDVQQKDAdB
-Q01FIENBMQ8wDQYDVQQLDAZDb3lvdGUxGzAZBgNVBAMMEm91cmNhLmRvbWFpbi5s
-b2NhbDAeFw0xNjA2MzAxNjQ2MDlaFw0zNjA2MjUxNjQ2MDlaMF0xCzAJBgNVBAYT
-AlVTMREwDwYDVQQIDAhOZXcgWW9yazENMAsGA1UECgwEQUNNRTEPMA0GA1UECwwG
-Q295b3RlMRswGQYDVQQDDBJjZXJ0MS5kb21haW4ubG9jYWwwggEiMA0GCSqGSIb3
-DQEBAQUAA4IBDwAwggEKAoIBAQDWD70m7xRNCfbbiwH1TmwDsTUgFrgbfOa2jZcb
-sE+KtstUfnr//a8C27+dz5pMDYeTi8xh8yOpb47UgiyTtuL6N+2K0yOPbbV4Sji6
-k/lKHEAGM9fAmCDUFqykpWtBIEw6VX7HUOeVB06GFYZ6D2xX0gcclyRRW071Ujr4
-T5VrbIMfNE7usK7+RpA48U2FcotGvNFiN2Va3rsWUR71y6Dv1nsRbzsMSRe8TYz1
-2fA1a/e2TVDrR4HjBvK97GdPqysDquIeQiKpyVncDRn7xQId11jkBFMKHXm7wTPx
-zbcQLrRum9xgZgVQnyBmoXEAUVTPCnD0fEXG8KccES8+ox+/AgMBAAGjezB5MAkG
-A1UdEwQCMAAwLAYJYIZIAYb4QgENBB8WHU9wZW5TU0wgR2VuZXJhdGVkIENlcnRp
-ZmljYXRlMB0GA1UdDgQWBBQt+yfHtDL/94fbLad2rvCWftrcFzAfBgNVHSMEGDAW
-gBRPKhVJ5swFLyv0Dsy6LkzfE5DweDANBgkqhkiG9w0BAQsFAAOCAgEAP0YcO1i0
-mfN1AEfS/rq6mgRGYrYtoA+PwJUqWIth9RSQMCY3lKGmKSDJtQjX+RXLnZwZ7S+k
-5pFIhRr3qxdeeSNpuDwMSK7IupDQBfszfob9EvgtD/8WFZrcdkh9ZVtOkxTovjfR
-E/ensc2trk/hcrlTLc3mQnZEkyEoWMBEqzzaW+VVqwSGTZxMM/ROE5jpD9GjcCsd
-ESBHJvbYRX+IrfLBgQ++zWx5gJQw643M832hPmxv+o/zHy52lz+KG2c74PmxPGvc
-ZBsAc+mJgfZ/UfNRyLmWX/1V+HdviLxls+IwpAB6eWjgNoupGwabIP7+mKpWWMgI
-pHsSWf89vV4TO8bHigBbyycYAu7LOMK3qVEE7zHKSQlIFBPrkeImjIhfHHjhDZAp
-18H8yIn9TVMLmVjCGiQ9wKJMo9nHlcW8cvoC8avdqiueoLsaaC0JjKKZDSbsnjAZ
-AVpBRWOzxdskMkz+f/PO6U0AZM+7FTQtMW5PwJZAmzI1ZZIBKX50AlD9Ozs6o59q
-wKW+P8MH1owqxvQPMr07/EWQ0kbub8MvJoyXDOjampcDC4YXRaZiaU6Nz/i/6i/c
-/5UUFb2SLYoIz86KsPY0CqIOSTFE4Uf7N1JTWZMlQMysZy2itpt1/ROlp5NPcgV1
-zbE39jtpOyShHyPwzbuuGLOq65/Xlwa6/UQ=
------END CERTIFICATE-----
diff --git a/test/units/modules/network/f5/fixtures/create_insecure_key1.key b/test/units/modules/network/f5/fixtures/create_insecure_key1.key
deleted file mode 100644
index a89a29161c..0000000000
--- a/test/units/modules/network/f5/fixtures/create_insecure_key1.key
+++ /dev/null
@@ -1,27 +0,0 @@
------BEGIN RSA PRIVATE KEY-----
-MIIEpQIBAAKCAQEA1g+9Ju8UTQn224sB9U5sA7E1IBa4G3zmto2XG7BPirbLVH56
-//2vAtu/nc+aTA2Hk4vMYfMjqW+O1IIsk7bi+jftitMjj221eEo4upP5ShxABjPX
-wJgg1BaspKVrQSBMOlV+x1DnlQdOhhWGeg9sV9IHHJckUVtO9VI6+E+Va2yDHzRO
-7rCu/kaQOPFNhXKLRrzRYjdlWt67FlEe9cug79Z7EW87DEkXvE2M9dnwNWv3tk1Q
-60eB4wbyvexnT6srA6riHkIiqclZ3A0Z+8UCHddY5ARTCh15u8Ez8c23EC60bpvc
-YGYFUJ8gZqFxAFFUzwpw9HxFxvCnHBEvPqMfvwIDAQABAoIBAQCjQ7PP+y8vpvbp
-8bbXoy2ND15mkA1xoazR9WIYEzxHny2rzx//GTyfYH1gXtPfR75tEYYb+vbrJxP4
-DyTysN2jXH7HkEwh+9oZ2fo0i+Hp3WwTjvzyftUjDfw1Q5lvPbQGFekxGgrXRpBk
-ggxkEllfDeiwrLJdftfVEhe6BfD/0YibwQeHN7VoC4V8wOanKtDmx74W/1f7WhwQ
-nKQnCrbYqNJa2nGvWiKU5Suvfb0v7tCnQYlfnCpUfj+wcnxlgmGkcyq1L+qC1qC8
-PO5i3T3LM5Yg8CSeGhO/q6gw/fUowuBN1cluTqN97oLHiEM5tLdjeVWwa1Vp0liv
-1WXGT4eBAoGBAPtumMmyVTIorvV6KGNI/Eo6jfE0HOXVdXtm4iToDDuiYwto7/Ge
-/kV+11Fpu0lV+eYPfZn175Of8FnQPwczQF1OOH/aQ/ViY8j87bZUbCy25mWrfNkh
-2rRlyI3/OsSfL5SkyWpYB0yhSJZV9mSQJTZolB4GQRNPKtqi7NpB4WxBAoGBANnz
-VS4JBJO75yeSG5BzPp5VVKm+nu0Betlva8GsHdEic8OM9bGpVozGysAW3Xdxp7q6
-gLJGyyuzpsxldCc/IdIlF5fz7gkLl4NoYanz9PSEr2XZLh9+2yXGkPFlC3IeHAUB
-E+2UO9MFpWrmfKoAnYZCR6vJDxtQBpAlTUvJEYv/AoGBAPha62K32327P+7MJl7D
-9ijgI9rwjebcbbpiCtlHuOWi5lCb6/7v/NvqiYcqeEvdOAXuoTNWAbsBTel5UPis
-wFQp8pcfouccs9IRPEFQrLWSSIx+0sirrxtoOq1AQe18DAS4rRd1MmiYG1ocOVBm
-LcvLixsJNHh9R6hFLM3+K0vBAoGANkmJ+gF9Bl9TYGPgQcay3jVa9Tzp0RcBRo+e
-Q4tfkewG8bp2qF4JlN8fOWF4oHvKz5QM4lsH2EbTUS4kFHKBNhrPGaZEsDQW9UBW
-s0J0zUMPfUrvViD+7RXcnIQSqcYeLJDsKc02aYWKgmoOuzmUAxEXUQ6vmJoCSH1C
-F5JpsHkCgYEArwTSzb1+/ThQhK1JN8hJ4jMjQ8E7PzLTMILrdDALn2g1T4VzL7N7
-UG6oUieMlo/UH6cv6330dwaGVklXZbyDKSDROIafFcOpVfcvDUgJCjp3CaY9A2zG
-+EPkRpeHKXAIgG+QuOwVOtYWcWltnBf61slTqiY2vKX1+ZGmrMrw1Zw=
------END RSA PRIVATE KEY-----
diff --git a/test/units/modules/network/f5/fixtures/create_ltm_irule.tcl b/test/units/modules/network/f5/fixtures/create_ltm_irule.tcl
deleted file mode 100644
index 5f7624a33f..0000000000
--- a/test/units/modules/network/f5/fixtures/create_ltm_irule.tcl
+++ /dev/null
@@ -1,18 +0,0 @@
-when RULE_INIT {
- set static::FormBaseURL "/sp-ofba-form"
- set static::FormReturnURL "/sp-ofba-completed"
- set static::HeadAuthReq "X-FORMS_BASED_AUTH_REQUIRED"
- set static::HeadAuthRet "X-FORMS_BASED_AUTH_RETURN_URL"
- set static::HeadAuthSize "X-FORMS_BASED_AUTH_DIALOG_SIZE"
- set static::HeadAuthSizeVal "800x600"
- set static::ckname "MRHSession_SP"
- set static::Basic_Realm_Text "SharePoint Authentication"
-}
-
-when HTTP_REQUEST {
- set apmsessionid [HTTP::cookie value MRHSession]
-}
-
-when HTTP_RESPONSE {
- # Insert persistent cookie for html content type and private session
-}
diff --git a/test/units/modules/network/f5/fixtures/data-group-address.txt b/test/units/modules/network/f5/fixtures/data-group-address.txt
deleted file mode 100644
index d2f5a16877..0000000000
--- a/test/units/modules/network/f5/fixtures/data-group-address.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-network 10.0.0.0 prefixlen 8 := "Network1",
-network 172.16.0.0 prefixlen 12 := "Network2",
-network 192.168.0.0 prefixlen 16 := "Network3",
-host 192.168.20.1 := "Host1",
-host 172.16.1.1 := "Host2",
diff --git a/test/units/modules/network/f5/fixtures/data-group-integer.txt b/test/units/modules/network/f5/fixtures/data-group-integer.txt
deleted file mode 100644
index 711ac1987b..0000000000
--- a/test/units/modules/network/f5/fixtures/data-group-integer.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-1 := alpha
-2 := bravo
-3 := charlie
-4 := x-ray
-5 := yankee
-6 := zulu
diff --git a/test/units/modules/network/f5/fixtures/data-group-string.txt b/test/units/modules/network/f5/fixtures/data-group-string.txt
deleted file mode 100644
index c30fca282c..0000000000
--- a/test/units/modules/network/f5/fixtures/data-group-string.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-a := alpha
-b := bravo
-c := charlie
-x := x-ray
-y := yankee
-z := zulu
diff --git a/test/units/modules/network/f5/fixtures/fake_policy.tar.gz b/test/units/modules/network/f5/fixtures/fake_policy.tar.gz
deleted file mode 100644
index cdc6202779..0000000000
--- a/test/units/modules/network/f5/fixtures/fake_policy.tar.gz
+++ /dev/null
Binary files differ
diff --git a/test/units/modules/network/f5/fixtures/fake_policy.xml b/test/units/modules/network/f5/fixtures/fake_policy.xml
deleted file mode 100644
index 590944a484..0000000000
--- a/test/units/modules/network/f5/fixtures/fake_policy.xml
+++ /dev/null
@@ -1,12174 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<policy bigip_version="11.5.4" integrity_check="d7ed8cbd2414d6ab935e5f837ef0f93e" name="/Common/fake_policy">
- <policy_version>
- <timestamp>2017-04-11T08:05:22Z</timestamp>
- <device_name>ltm4restlab.lab.local</device_name>
- <policy_name>/Common/fake_policy</policy_name>
- <last_change>Allowed Response Code 503 [add]: Response Code was set to 503.</last_change>
- </policy_version>
- <encoding>utf-8</encoding>
- <maximum_http_length>8192</maximum_http_length>
- <maximum_cookie_length>8192</maximum_cookie_length>
- <description></description>
- <trigger_asm_irule_event>Disabled</trigger_asm_irule_event>
- <case_insensitive>false</case_insensitive>
- <whitehat>false</whitehat>
- <owa>false</owa>
- <inspect_http_uploads>false</inspect_http_uploads>
- <protocol_free>false</protocol_free>
- <path_parameter_handling>as parameters</path_parameter_handling>
- <mask_sensitive>true</mask_sensitive>
- <trust_xff>false</trust_xff>
- <learning>
- <learning_type>policy based</learning_type>
- </learning>
- <csrf>
- <enabled>false</enabled>
- <ssl_only>false</ssl_only>
- <enforcement_mode>enforcing</enforcement_mode>
- <expiration_time_in_seconds>0</expiration_time_in_seconds>
- </csrf>
- <allowed_response_code>400</allowed_response_code>
- <allowed_response_code>401</allowed_response_code>
- <allowed_response_code>404</allowed_response_code>
- <allowed_response_code>407</allowed_response_code>
- <allowed_response_code>417</allowed_response_code>
- <allowed_response_code>503</allowed_response_code>
- <web_scraping>
- <grace_threshold>100</grace_threshold>
- <session_prevention_threshold>100</session_prevention_threshold>
- <revalidation_threshold>2000</revalidation_threshold>
- <rapid_surf_max_time_duration>1000</rapid_surf_max_time_duration>
- <rapid_surf_max_page_changes>5</rapid_surf_max_page_changes>
- <web_scraping_alarm>false</web_scraping_alarm>
- <web_scraping_block>false</web_scraping_block>
- <session_opening_anomaly_block>false</session_opening_anomaly_block>
- <session_opening_anomaly_alarm>false</session_opening_anomaly_alarm>
- <session_transactions_anomaly_alarm>false</session_transactions_anomaly_alarm>
- <session_transactions_anomaly_block>false</session_transactions_anomaly_block>
- <opening_client_side_integrity_defense>false</opening_client_side_integrity_defense>
- <opening_rate_limiting>false</opening_rate_limiting>
- <sessions_opened_per_second_increase_rate>500</sessions_opened_per_second_increase_rate>
- <sessions_opened_per_second_maximum>50</sessions_opened_per_second_maximum>
- <sessions_opened_per_second_minimum>25</sessions_opened_per_second_minimum>
- <opening_max_prevention_duration>1800</opening_max_prevention_duration>
- <opening_drop_ip_with_reputation>false</opening_drop_ip_with_reputation>
- <transactions_tps_increase_rate>500</transactions_tps_increase_rate>
- <transactions_per_second_maximum>400</transactions_per_second_maximum>
- <transactions_per_second_minimum>200</transactions_per_second_minimum>
- <transactions_max_prevention_duration>1800</transactions_max_prevention_duration>
- <opening_persistent_storage_inconsistency>true</opening_persistent_storage_inconsistency>
- <opening_persistent_storage_resets>true</opening_persistent_storage_resets>
- <opening_persistent_storage_inconsistency_events_maximum>3</opening_persistent_storage_inconsistency_events_maximum>
- <opening_persistent_storage_inconsistency_events_duration>600</opening_persistent_storage_inconsistency_events_duration>
- <opening_persistent_storage_resets_maximum>2</opening_persistent_storage_resets_maximum>
- <opening_persistent_storage_resets_duration>600</opening_persistent_storage_resets_duration>
- <persistent_storage_max_prevention_duration>1800</persistent_storage_max_prevention_duration>
- <use_persistent_storage>false</use_persistent_storage>
- <persistent_data_validity_period>120</persistent_data_validity_period>
- <session_opening_anomaly_enable>true</session_opening_anomaly_enable>
- <suspicious_clients_alarm>false</suspicious_clients_alarm>
- <suspicious_clients_block>false</suspicious_clients_block>
- <fingerprinting_enable>false</fingerprinting_enable>
- <fingerprint_resets_enabled>false</fingerprint_resets_enabled>
- <fingerprint_resets_threshold>5</fingerprint_resets_threshold>
- <fingerprint_resets_time_window>600</fingerprint_resets_time_window>
- <detect_plugins>false</detect_plugins>
- <suspicious_clients_prevention_duration>300</suspicious_clients_prevention_duration>
- </web_scraping>
- <blocking>
- <enforcement_mode>transparent</enforcement_mode>
- <maximum_decoding_passes>2</maximum_decoding_passes>
- <maximum_headers>20</maximum_headers>
- <maximum_parameters>500</maximum_parameters>
- <response_page cause="default">
- <response_type>default</response_type>
- <response_header>HTTP/1.1 200 OK
-Cache-Control: no-cache
-Pragma: no-cache
-Connection: close</response_header>
- <response_html_code>&lt;html>&lt;head>&lt;title>Request Rejected&lt;/title>&lt;/head>&lt;body>The requested URL was rejected. Please consult with your administrator.&lt;br>&lt;br>Your support ID is: &lt;%TS.request.ID()%>&lt;/body>&lt;/html></response_html_code>
- </response_page>
- <response_page cause="XML">
- <response_type>soap fault</response_type>
- <response_header>HTTP/1.1 200 OK
-Cache-Control: no-cache
-Pragma: no-cache
-Content-type: text/xml
-Connection: close</response_header>
- <response_html_code>&lt;?xml version='1.0' encoding='utf-8'?>&lt;soap:Envelope xmlns:soap='http://schemas.xmlsoap.org/soap/envelope/'>&lt;soap:Body>&lt;soap:Fault>&lt;faultcode>soap:Client&lt;/faultcode>&lt;faultstring>The requested operation was rejected. Please consult with your administrator.Your support ID is: &lt;%TS.request.ID()%>&lt;/faultstring>&lt;detail/>&lt;/soap:Fault>&lt;/soap:Body>&lt;/soap:Envelope></response_html_code>
- </response_page>
- <response_page cause="Ajax">
- <response_type>default</response_type>
- <response_header>HTTP/1.1 200 OK
-Cache-Control: no-cache
-Pragma: no-cache
-Connection: close</response_header>
- <response_html_code>&lt;html>&lt;head>&lt;title>Request Rejected&lt;/title>&lt;/head>&lt;body>The requested URL was rejected. Please consult with your administrator.&lt;br>&lt;br>Your support ID is: &lt;%TS.request.ID()%>&lt;/body>&lt;/html></response_html_code>
- <ajax_action_type>alert_popup</ajax_action_type>
- <ajax_popup_message>The requested URL was rejected. Please consult with your administrator. Your support ID is: &lt;%TS.request.ID()%></ajax_popup_message>
- </response_page>
- <response_page cause="Ajax_login">
- <response_type>default</response_type>
- <response_header>HTTP/1.1 200 OK
-Cache-Control: no-cache
-Pragma: no-cache
-Connection: close</response_header>
- <response_html_code>&lt;html>&lt;head>&lt;title>Request Rejected&lt;/title>&lt;/head>&lt;body>The requested URL was rejected. Please consult with your administrator.&lt;br>&lt;br>Your support ID is: &lt;%TS.request.ID()%>&lt;/body>&lt;/html></response_html_code>
- <ajax_action_type>alert_popup</ajax_action_type>
- <ajax_popup_message>The requested URL was rejected. Please consult with your administrator. Your support ID is: &lt;%TS.request.ID()%></ajax_popup_message>
- </response_page>
- <response_page_settings>
- <flg_ajax_enabled>disabled</flg_ajax_enabled>
- </response_page_settings>
- </blocking>
- <session_awareness>
- <enabled>false</enabled>
- <use_apm_username>false</use_apm_username>
- <lifetime_window>900</lifetime_window>
- <violation_actions_enabled>false</violation_actions_enabled>
- <session>
- <track_all_threshold>5</track_all_threshold>
- <block_illegal_threshold>5</block_illegal_threshold>
- <block_all_threshold>20</block_all_threshold>
- <track_all_threshold_enabled>true</track_all_threshold_enabled>
- <block_illegal_threshold_enabled>false</block_illegal_threshold_enabled>
- <block_all_threshold_enabled>true</block_all_threshold_enabled>
- </session>
- <ip_address>
- <track_all_threshold>15</track_all_threshold>
- <block_illegal_threshold>15</block_illegal_threshold>
- <block_all_threshold>60</block_all_threshold>
- <track_all_threshold_enabled>false</track_all_threshold_enabled>
- <block_illegal_threshold_enabled>false</block_illegal_threshold_enabled>
- <block_all_threshold_enabled>false</block_all_threshold_enabled>
- </ip_address>
- <user>
- <track_all_threshold>5</track_all_threshold>
- <block_illegal_threshold>5</block_illegal_threshold>
- <block_all_threshold>20</block_all_threshold>
- <track_all_threshold_enabled>true</track_all_threshold_enabled>
- <block_illegal_threshold_enabled>false</block_illegal_threshold_enabled>
- <block_all_threshold_enabled>true</block_all_threshold_enabled>
- </user>
- <track_all_period>600</track_all_period>
- <block_illegal_period>600</block_illegal_period>
- <block_all_period>600</block_all_period>
- <block_all_period_enabled>false</block_all_period_enabled>
- <block_only_autheticated>false</block_only_autheticated>
- </session_awareness>
- <gwt_profiles>
- <character_set/>
- </gwt_profiles>
- <json_profiles>
- <character_set/>
- </json_profiles>
- <xml_profiles>
- <character_set/>
- </xml_profiles>
- <file_types>
- <file_type name="*" type="wildcard">
- <learning_mode>Always</learning_mode>
- <url_length>100</url_length>
- <request_length>5000</request_length>
- <query_string_length>1000</query_string_length>
- <post_data_length>1000</post_data_length>
- <check_response>false</check_response>
- <in_staging>false</in_staging>
- <last_updated>2017-04-11T08:05:13Z</last_updated>
- <check_url_length>false</check_url_length>
- <check_request_length>false</check_request_length>
- <check_query_string_length>false</check_query_string_length>
- <check_post_data_length>false</check_post_data_length>
- </file_type>
- </file_types>
- <urls>
- <url name="*" protocol="HTTPS" type="wildcard">
- <learning_mode>Never</learning_mode>
- <check_flows>false</check_flows>
- <is_entry_point>false</is_entry_point>
- <is_referrer>false</is_referrer>
- <can_change_domain_cookie>false</can_change_domain_cookie>
- <user_config_level>basic</user_config_level>
- <check_metachars>true</check_metachars>
- <in_staging>true</in_staging>
- <last_updated>2017-04-11T08:05:13Z</last_updated>
- <clickjacking_protection>
- <enabled>false</enabled>
- <allow_rendering_in_frames>N/A</allow_rendering_in_frames>
- </clickjacking_protection>
- <cors_enforcement_enable>false</cors_enforcement_enable>
- <allow_cors>true</allow_cors>
- <cors_allow_credentials_handling>unmodified</cors_allow_credentials_handling>
- <cors_allow_credentials>allow</cors_allow_credentials>
- <cors_check_maximum_age>false</cors_check_maximum_age>
- <cors_maximum_age>1800</cors_maximum_age>
- <cors_allowed_origins_handling>unmodified</cors_allowed_origins_handling>
- <cors_allowed_methods_handling>unmodified</cors_allowed_methods_handling>
- <cors_allowed_headers_handling>unmodified</cors_allowed_headers_handling>
- <cors_exposed_headers_handling>unmodified</cors_exposed_headers_handling>
- <flg_wildcard_includes_slash>true</flg_wildcard_includes_slash>
- <parameter/>
- <content_profile>
- <header_name>*</header_name>
- <header_value>*</header_value>
- <header_order>0</header_order>
- <enforcement_type>http</enforcement_type>
- <in_classification>false</in_classification>
- </content_profile>
- </url>
- <url name="*" protocol="HTTP" type="wildcard">
- <learning_mode>Never</learning_mode>
- <check_flows>false</check_flows>
- <is_entry_point>false</is_entry_point>
- <is_referrer>false</is_referrer>
- <can_change_domain_cookie>false</can_change_domain_cookie>
- <user_config_level>basic</user_config_level>
- <check_metachars>true</check_metachars>
- <in_staging>true</in_staging>
- <last_updated>2017-04-11T08:05:13Z</last_updated>
- <clickjacking_protection>
- <enabled>false</enabled>
- <allow_rendering_in_frames>N/A</allow_rendering_in_frames>
- </clickjacking_protection>
- <cors_enforcement_enable>false</cors_enforcement_enable>
- <allow_cors>true</allow_cors>
- <cors_allow_credentials_handling>unmodified</cors_allow_credentials_handling>
- <cors_allow_credentials>allow</cors_allow_credentials>
- <cors_check_maximum_age>false</cors_check_maximum_age>
- <cors_maximum_age>1800</cors_maximum_age>
- <cors_allowed_origins_handling>unmodified</cors_allowed_origins_handling>
- <cors_allowed_methods_handling>unmodified</cors_allowed_methods_handling>
- <cors_allowed_headers_handling>unmodified</cors_allowed_headers_handling>
- <cors_exposed_headers_handling>unmodified</cors_exposed_headers_handling>
- <flg_wildcard_includes_slash>true</flg_wildcard_includes_slash>
- <parameter/>
- <content_profile>
- <header_name>*</header_name>
- <header_value>*</header_value>
- <header_order>0</header_order>
- <enforcement_type>http</enforcement_type>
- <in_classification>false</in_classification>
- </content_profile>
- </url>
- <character_set/>
- </urls>
- <parameters>
- <parameter name="*" type="wildcard">
- <learning_mode>When Violation Detected</learning_mode>
- <is_mandatory>false</is_mandatory>
- <allow_empty_value>true</allow_empty_value>
- <value_type>user input</value_type>
- <user_input_format></user_input_format>
- <match_regular_expression></match_regular_expression>
- <is_sensitive>false</is_sensitive>
- <in_staging>true</in_staging>
- <last_updated>2017-04-11T08:05:13Z</last_updated>
- <parameter_name_metachars>
- <check_metachars>true</check_metachars>
- </parameter_name_metachars>
- <check_maximum_length>false</check_maximum_length>
- <check_metachars>true</check_metachars>
- <check_attack_signatures>true</check_attack_signatures>
- <allow_repeated_parameter_name>false</allow_repeated_parameter_name>
- <in_classification>false</in_classification>
- <disallow_file_upload_of_executables>true</disallow_file_upload_of_executables>
- <is_base64>false</is_base64>
- </parameter>
- <character_set/>
- <parameter_name_metachars>
- <character_set/>
- </parameter_name_metachars>
- </parameters>
- <sensitive_parameters>
- <parameter_name>password</parameter_name>
- </sensitive_parameters>
- <flows>
- <flow_access>
- <expiration_period>0</expiration_period>
- <response_page>
- <response_type>default</response_type>
- <response_header>HTTP/1.1 200 OK
-Cache-Control: no-cache
-Pragma: no-cache
-Connection: close</response_header>
- <response_html_code>&lt;html>&lt;head>&lt;title>Request Rejected&lt;/title>&lt;/head>&lt;body>The requested URL was rejected. Please consult with your administrator.&lt;br>&lt;br>Your support ID is: &lt;%TS.request.ID()%>&lt;/body>&lt;/html></response_html_code>
- </response_page>
- </flow_access>
- </flows>
- <methods>
- <method name="GET">
- <act_as>GET</act_as>
- <user_config_level>basic</user_config_level>
- </method>
- <method name="POST">
- <act_as>POST</act_as>
- <user_config_level>basic</user_config_level>
- </method>
- <method name="HEAD">
- <act_as>GET</act_as>
- <user_config_level>basic</user_config_level>
- </method>
- </methods>
- <headers>
- <allowed_modified_cookie name="*" type="wildcard">
- <learning_mode>When Violation Detected</learning_mode>
- <in_staging>true</in_staging>
- <enforcement_mode>allow</enforcement_mode>
- <http_only>false</http_only>
- <secure>false</secure>
- <check_signatures>true</check_signatures>
- <is_base64>false</is_base64>
- </allowed_modified_cookie>
- <character_set/>
- </headers>
- <attack_signatures>
- <signature_set>
- <set id="1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"></set>
- <alarm>true</alarm>
- <block>true</block>
- <learn>true</learn>
- </signature_set>
- <enable_staging>true</enable_staging>
- <staging_period_in_days>7</staging_period_in_days>
- <signature signature_id="200000001">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000002">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000003">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000004">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000005">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000006">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000007">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000008">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000009">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000011">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000012">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000013">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000014">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000015">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000016">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000017">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000018">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000019">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000020">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000021">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000022">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000023">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000024">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000025">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000026">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000027">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000028">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000029">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000030">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000031">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000032">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000034">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000035">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000036">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000037">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000041">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000042">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000043">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000059">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000060">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000063">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000067">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000068">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000070">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000071">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000072">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000073">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000074">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000075">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000076">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000081">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000082">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000083">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000084">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000085">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000086">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000089">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000090">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000091">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000093">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000094">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000095">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000096">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000097">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000098">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000099">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000101">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000102">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000103">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000104">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000105">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000106">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000107">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000108">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000109">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000110">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000111">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000112">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000113">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000114">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000115">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000116">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000117">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000118">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000119">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000120">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000121">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000122">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000123">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000124">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000125">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000126">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000127">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000128">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000129">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000130">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000131">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000132">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000133">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000134">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000135">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000136">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000137">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000138">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000139">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000140">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000141">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000145">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000146">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000147">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000151">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000152">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000153">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000156">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000157">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000158">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000159">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000160">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000161">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000162">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000163">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000164">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000165">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000167">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000168">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000169">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000170">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000171">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000172">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000173">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000174">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000175">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000176">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000177">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000178">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000179">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000180">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000181">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000182">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000183">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000187">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000188">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200000190">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001001">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001015">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001016">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001017">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001018">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001019">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001020">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001021">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001022">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001023">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001024">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001025">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001026">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001027">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001028">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001029">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001030">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001031">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001032">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001033">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001034">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001035">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001036">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001037">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001038">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001039">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001040">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001041">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001042">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001043">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001044">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001045">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001046">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001047">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001048">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001049">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001050">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001051">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001052">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001053">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001054">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001055">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001056">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001057">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001058">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001059">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001060">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001061">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001062">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001063">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001064">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001065">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001069">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001070">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001071">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001072">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001073">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001074">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001075">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001076">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001077">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001078">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001079">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001080">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001081">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001082">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001083">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001084">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001085">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001086">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001087">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001088">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001089">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001090">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001091">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001092">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001093">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001094">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001095">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001096">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001097">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001098">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001099">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001100">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001101">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001111">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001112">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001113">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001114">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001115">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001116">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001117">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001118">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001119">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001120">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001121">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001122">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001123">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001124">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001125">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001126">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001127">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001128">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001129">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001130">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001131">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001132">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001133">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001134">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001135">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001136">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001137">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001138">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001139">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001140">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001141">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001142">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001143">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001144">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001145">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001146">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001147">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001148">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001149">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001150">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001151">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001152">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001153">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001154">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001155">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001156">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001157">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001158">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001159">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001160">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001161">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001162">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001163">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001164">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001165">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001166">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001167">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001168">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001169">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001170">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001171">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001172">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001173">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001174">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001175">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001176">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001177">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001178">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001179">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001180">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001181">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001182">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001183">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001184">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001185">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001186">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001187">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001188">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001189">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001190">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001191">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001192">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001193">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001194">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001195">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001196">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001197">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001198">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001199">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001200">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001201">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001202">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001203">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001204">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001205">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001206">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001207">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001208">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001209">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001210">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001211">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001212">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001213">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001214">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001215">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001216">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001217">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001218">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001219">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001220">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001221">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001222">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001223">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001224">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001225">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001226">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001227">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001228">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001229">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001230">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001231">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001232">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001233">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001234">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001235">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001236">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001237">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001238">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001239">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001240">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001241">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001242">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001243">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001244">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001245">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001246">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001247">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001248">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001249">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001250">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001251">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001252">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001253">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001254">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001255">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001256">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001257">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001258">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001259">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001260">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001261">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001262">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001263">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001264">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001265">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001266">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001267">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001268">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001269">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001270">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001271">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001272">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001273">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001274">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001275">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001276">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001277">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001278">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001279">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001280">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001281">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001282">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001283">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001284">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001285">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001286">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001287">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001288">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001289">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001290">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001291">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001292">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001293">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001294">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001295">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001296">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001297">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001298">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001299">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001300">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001301">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001302">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001303">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001304">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001305">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001306">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001307">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001308">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001309">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001310">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001311">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001312">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001313">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001314">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001315">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001316">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001317">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001318">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001319">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001320">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001321">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001322">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001323">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001324">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001325">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001326">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001327">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001328">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001329">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001330">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001331">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001332">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001333">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001334">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001335">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001336">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001337">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001338">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001339">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001340">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001341">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001342">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001343">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001344">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001345">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001346">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001347">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001348">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001349">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001350">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001351">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001352">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001353">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001354">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001355">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001356">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001357">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001358">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001359">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001360">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001361">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001362">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001363">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001364">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001365">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001366">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001367">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001368">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001369">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001370">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001371">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001372">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001373">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001374">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001375">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001376">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001377">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001378">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001379">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001380">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001381">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001382">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001383">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001384">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001385">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001386">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001387">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001388">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001389">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001391">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001392">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001393">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001394">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001395">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001396">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001397">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001398">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001399">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001400">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001401">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001402">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001403">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001404">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001405">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001406">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001407">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001408">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001409">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001410">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001411">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001412">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001413">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001414">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001415">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001416">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001417">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001418">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001419">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001420">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001421">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001422">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001423">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001424">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001425">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001426">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001427">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001428">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001429">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001430">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001431">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001432">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001433">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001434">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001435">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001436">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001437">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001438">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001439">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001440">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001441">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001442">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001443">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001444">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001445">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001446">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001447">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001448">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001449">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001450">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001451">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001452">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001453">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001454">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001455">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001456">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001457">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001458">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001459">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001460">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001461">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001462">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001463">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001464">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001465">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001466">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001467">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001468">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001469">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001470">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001471">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001474">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001475">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001476">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001477">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001478">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001480">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001481">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001482">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001483">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001484">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001485">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001486">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001487">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001488">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001489">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001490">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001491">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001492">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001493">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001494">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001496">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001497">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001498">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001499">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001500">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001504">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001505">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001506">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001507">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001508">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001509">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001510">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001511">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001512">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001513">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001514">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001515">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001516">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001517">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001518">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001519">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001520">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001521">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001522">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001523">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001524">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001525">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001526">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001527">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001528">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001529">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001530">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001531">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001532">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001533">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001534">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001535">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001536">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001537">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001538">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001539">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001540">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001541">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001542">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001543">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001544">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001545">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001546">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001547">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001548">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001549">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001550">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001551">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001552">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001553">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001554">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001555">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001556">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001557">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001558">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001559">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001560">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001561">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001562">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001563">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001564">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001565">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001566">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001567">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001568">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001569">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001570">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001571">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001572">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001573">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001574">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001575">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001576">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001577">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001578">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001579">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001580">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001581">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001582">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001583">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001584">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001585">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001586">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001587">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001588">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001589">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001590">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001591">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001592">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001593">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001594">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001595">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001596">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001597">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001598">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001599">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001600">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001601">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001602">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001603">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001604">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001605">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001606">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001607">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001608">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001609">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001610">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001611">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001612">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001613">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001614">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001615">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001616">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001617">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001618">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001619">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001620">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001621">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001622">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001623">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001624">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001625">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001626">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001627">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001628">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001629">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001630">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001631">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001632">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001633">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001634">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001635">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001636">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001637">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001638">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001639">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001640">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001641">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001642">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001643">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001644">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001645">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001646">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001647">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001648">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001649">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001650">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001651">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001652">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001653">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001654">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001655">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001657">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001658">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001659">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001660">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001661">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001662">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001663">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001664">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001665">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001666">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001667">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001668">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001669">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001670">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001671">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001672">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001673">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001674">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001675">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001676">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001677">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001678">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001679">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001680">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001681">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001682">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001683">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001684">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001685">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001686">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001687">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001688">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001689">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001690">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001691">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001692">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001693">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001694">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001695">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001696">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001697">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001698">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001699">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001715">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001716">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200001717">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002024">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002025">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002026">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002027">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002028">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002029">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002030">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002031">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002032">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002033">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002034">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002035">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002038">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002040">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002042">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002043">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002044">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002045">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002046">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002048">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002049">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002050">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002053">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002054">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002055">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002056">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002057">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002058">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002060">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002061">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002062">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002063">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002064">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002065">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002066">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002067">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002068">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002069">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002070">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002071">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002073">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002074">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002075">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002076">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002077">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002078">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002079">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002080">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002081">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002082">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002083">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002084">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002085">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002086">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002087">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002088">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002089">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002090">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002091">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002092">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002093">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002094">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002095">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002101">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002102">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002103">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002104">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002105">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002106">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002107">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002108">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002110">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002111">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002113">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002114">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002115">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002116">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002117">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002118">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002119">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002120">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002121">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002122">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002123">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002124">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002125">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002126">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002127">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002128">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002129">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002130">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002131">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002133">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002134">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002135">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002137">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002138">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002139">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002140">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002141">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002142">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002143">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002145">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002147">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002149">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002151">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002153">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002154">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002155">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002156">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002157">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002158">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002160">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002161">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002162">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002163">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002164">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002165">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002166">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002167">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002168">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002169">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002170">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002171">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002172">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002173">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002174">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002175">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002176">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002177">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002178">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002179">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002180">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002181">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002182">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002183">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002184">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002185">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002186">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002187">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002188">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002189">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002190">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002191">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002192">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002193">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002195">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002196">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002197">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002198">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002199">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002200">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002201">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002202">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002203">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002204">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002206">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002207">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002208">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002210">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002213">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002214">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002225">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002226">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002227">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002228">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002229">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002230">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002231">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002232">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002234">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002236">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002237">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002240">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002241">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002242">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002243">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002244">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002247">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002248">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002249">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002251">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002252">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002253">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002254">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002255">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002256">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002257">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002258">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002259">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002260">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002261">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002262">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002263">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002264">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002265">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002266">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002267">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002268">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002269">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002270">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002271">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002272">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002273">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002274">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002275">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002276">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002277">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002278">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002279">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002280">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002282">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002283">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002284">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002285">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002286">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002287">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002288">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002289">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002290">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002291">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002292">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002293">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002294">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002295">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002296">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002297">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002298">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002299">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002300">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002301">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002302">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002303">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002305">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002306">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002307">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002308">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002309">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002310">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002311">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002312">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002313">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002314">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002315">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002316">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002317">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002318">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002319">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002320">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002321">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002322">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002323">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002324">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002325">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002326">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002327">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002328">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002329">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002330">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002331">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002332">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002333">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002334">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002335">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002336">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002337">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002338">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002339">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002340">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002341">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002342">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002343">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002344">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002345">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002346">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002347">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002348">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002349">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002350">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002351">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002352">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002353">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002354">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002355">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002356">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002357">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002358">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002359">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002360">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002361">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002362">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002363">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002364">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002365">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002366">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002367">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002368">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002369">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002370">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002371">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002372">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002373">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002374">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002375">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002376">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002377">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002378">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002379">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002380">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002381">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002382">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002383">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002384">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002385">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002386">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002387">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002388">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002389">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002390">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002391">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002392">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002393">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002394">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002395">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002396">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002397">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002398">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002399">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002400">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002401">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002402">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002403">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002404">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002405">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002406">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002408">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002409">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002410">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002411">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002412">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002413">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002414">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002415">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002416">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002419">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002420">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002421">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002422">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002423">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002424">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002425">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002426">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002427">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002428">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002429">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002430">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002431">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002432">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002433">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002434">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002435">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002436">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002437">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002438">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002439">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002440">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002441">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002442">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002443">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002444">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002446">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002447">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002448">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002449">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002450">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002451">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002452">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002453">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002454">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002455">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002456">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002457">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002458">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002459">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002460">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002461">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002462">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002463">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002464">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002465">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002466">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002467">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002468">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002469">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002470">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002471">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002472">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002473">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002474">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002475">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002476">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002477">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002478">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002479">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002480">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002481">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002482">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002483">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002484">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002485">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002486">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002487">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002488">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002489">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002490">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002491">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002492">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002493">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002494">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002495">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002496">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002497">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002498">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002499">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002500">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002501">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002502">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002503">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002504">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002505">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002506">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002507">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002508">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002509">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002510">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002511">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002512">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002513">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002514">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002515">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002516">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002517">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002518">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002519">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002520">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002521">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002522">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002523">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002524">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002525">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002526">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002527">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002528">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002529">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002530">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002531">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002532">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002533">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002534">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002535">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002536">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002537">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002538">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002539">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002540">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002541">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002542">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002543">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002544">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002545">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002546">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002547">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002548">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002549">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002550">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002551">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002552">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002553">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002554">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002555">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002556">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002557">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002558">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002559">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002560">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002561">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002562">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002563">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002564">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002565">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002566">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002567">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002568">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002569">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002570">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002571">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002572">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002573">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002574">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002575">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002576">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002577">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002578">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002579">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002580">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002581">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002582">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002583">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002584">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002585">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002586">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002587">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002588">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002589">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002590">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002591">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002592">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002593">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002594">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002595">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002596">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002597">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002598">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002599">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002600">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002601">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002602">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002603">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002604">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002605">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200002606">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003000">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003001">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003002">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003003">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003004">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003005">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003006">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003007">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003008">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003009">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003010">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003011">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003013">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003014">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003015">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003016">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003017">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003018">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003019">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003020">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003022">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003023">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003024">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003025">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003026">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003027">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003028">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003029">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003030">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003031">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003032">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003033">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003034">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003035">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003036">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003037">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003038">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003039">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003040">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003041">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003042">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003043">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003044">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003045">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003046">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003047">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003048">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003049">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003050">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003051">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003052">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003053">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003054">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003055">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003056">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003057">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003058">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003059">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003060">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003061">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003062">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003063">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003064">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003065">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003066">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003067">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003068">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003069">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003071">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003072">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003073">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003074">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003075">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003076">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003077">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003078">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003079">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003080">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003081">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003082">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003083">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003084">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003085">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003086">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003087">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003088">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003089">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003090">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003091">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003092">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003093">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003094">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003095">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003096">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003097">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003098">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003099">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003100">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003101">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003102">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003103">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003104">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003105">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003106">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003107">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003108">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003109">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003110">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003111">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003112">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003113">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003114">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003115">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003116">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003117">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003118">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003119">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003120">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003121">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003122">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003123">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003124">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003125">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003126">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003127">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003128">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003129">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003130">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003131">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003132">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003133">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003134">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003135">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003136">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003137">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003138">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003139">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003140">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003141">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003142">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003143">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003144">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003145">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003146">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003147">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003148">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003149">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003150">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003151">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003152">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003153">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003154">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003155">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003156">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003157">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003158">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003159">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003160">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003161">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003162">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003163">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003164">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003165">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003166">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003167">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003168">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003169">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003170">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003171">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003172">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003174">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003175">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003176">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003177">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003178">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003180">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003182">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003183">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003184">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003185">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003186">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003187">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003188">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003189">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003190">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003191">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003192">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003193">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003194">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003195">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003196">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003197">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003198">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003199">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003200">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003202">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003203">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003204">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003205">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003206">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003207">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003208">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003209">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003210">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003212">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003213">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003214">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003215">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003216">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003217">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003218">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003219">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003220">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003221">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003222">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003223">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003224">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003225">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003226">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003228">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003229">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003230">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003231">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003232">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003233">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003234">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003235">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003236">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003237">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003238">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003239">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003240">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003241">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003242">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003243">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003244">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003245">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003246">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003247">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003248">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003249">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003250">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003251">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003252">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003253">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003254">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003255">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003256">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003257">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003258">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003259">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003261">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003262">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003264">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003266">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003267">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003268">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003269">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003270">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003271">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003272">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003273">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003274">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003275">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003276">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003277">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003278">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003279">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003280">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003281">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003282">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003284">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003285">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003286">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003287">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003288">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003289">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003290">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003291">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003292">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003293">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003294">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003295">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003296">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003297">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003298">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003299">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003300">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003301">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003302">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003303">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003304">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003305">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003306">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003307">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003308">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003309">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003310">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003311">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003312">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003313">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003314">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003315">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003316">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003317">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003318">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003319">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003320">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003321">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003322">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003323">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003324">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003325">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003326">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003327">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003328">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003329">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003330">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003332">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003333">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003334">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003335">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003336">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003337">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003338">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003339">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003340">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003341">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003342">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003343">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003344">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003345">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003346">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003347">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003348">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003349">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003350">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003351">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003352">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003353">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003354">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003355">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003356">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003357">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003358">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003359">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003360">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003361">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003362">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003363">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003364">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003365">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003366">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003367">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003368">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003369">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003370">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003371">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003372">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003373">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003374">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003375">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003376">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003377">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003378">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003379">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003380">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003381">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003382">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003384">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003385">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003386">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003387">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003388">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003389">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003390">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003391">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003392">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003394">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003396">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003397">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003398">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003399">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003400">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003401">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003402">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003403">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003404">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003405">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003406">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003407">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003408">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003410">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003411">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003412">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003414">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003415">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003416">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003417">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003418">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003419">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003420">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003421">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003422">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003423">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003424">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003425">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003426">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003427">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003428">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003429">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003430">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003431">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003432">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003433">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003434">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003435">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003436">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003437">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003438">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003439">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003440">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003441">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003442">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003443">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003444">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003445">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003446">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003447">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003448">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003449">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003450">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003451">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003452">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003453">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003454">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003455">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003456">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003457">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003458">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003459">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003460">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003461">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003462">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003463">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003464">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003465">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003466">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003467">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003468">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003469">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003470">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003471">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003472">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003473">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003474">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003475">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200003476">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004000">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004001">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004002">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004003">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004004">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004005">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004006">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004007">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004008">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004009">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004010">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004011">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004012">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004013">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004014">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004015">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004016">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004017">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004018">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004019">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004020">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004021">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004022">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004023">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004024">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004025">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004026">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004027">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004028">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004029">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004030">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004031">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004032">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004033">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004034">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004035">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004036">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004037">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004038">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004039">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004040">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004041">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004042">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004043">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004044">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004045">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004046">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004047">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004048">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004049">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004051">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004052">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004053">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004054">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004055">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004056">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004057">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004058">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004059">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004106">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004107">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004108">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004109">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004110">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004111">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004112">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004113">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004114">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004115">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004116">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004117">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004118">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004119">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004120">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004121">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004122">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004123">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004124">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004125">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004126">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004127">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004128">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004129">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004130">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004131">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004132">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004133">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004134">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004135">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004136">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004137">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004138">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004139">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004140">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004141">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004142">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004143">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004144">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004145">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004146">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004147">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004148">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004149">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004150">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004151">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004152">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004153">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004154">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004155">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004156">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004157">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004158">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004159">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004160">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004161">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004162">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004163">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004165">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004166">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004167">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004168">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004169">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004170">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004171">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004172">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004174">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004175">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004176">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004177">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004178">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004179">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004180">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004181">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004182">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004183">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004184">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004185">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004186">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004187">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004188">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004189">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004190">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004191">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200004198">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200005000">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200005001">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200005002">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200005003">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200005004">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200005005">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200005007">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200005008">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200006000">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200006001">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200006002">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200006003">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200006004">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200006005">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200006006">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200006007">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200006008">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200006009">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200006010">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200006011">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200006012">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200006013">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200006014">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200006015">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200006016">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200006017">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200006018">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200006019">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200006020">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200006021">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200006022">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200006023">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200006024">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200006025">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200006026">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200006027">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200006028">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200006029">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200006030">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200006031">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200007000">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200007002">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200007003">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200007004">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200007005">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200007006">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200007007">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200007008">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200007009">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200007010">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200007011">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200007012">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200007013">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200008000">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200008001">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200008002">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200008003">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009000">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009001">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009002">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009003">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009004">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009005">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009006">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009007">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009008">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009009">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009010">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009011">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009012">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009013">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009014">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009015">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009016">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009017">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009018">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009019">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009020">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009021">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009022">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009023">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009024">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009025">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009026">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009027">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009028">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009029">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009030">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009031">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009032">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009033">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009034">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009035">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009036">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009037">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009038">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009039">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009040">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009041">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009042">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009043">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009044">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009045">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009046">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009047">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009048">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009049">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009050">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009051">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009052">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009053">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009054">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009055">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009056">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009057">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009058">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009059">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009060">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009061">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009062">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009063">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009064">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009065">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009066">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009067">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009068">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009069">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009070">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009071">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009072">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009073">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009074">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009075">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009076">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009077">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009078">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009079">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009080">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009081">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009082">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009083">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009084">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009085">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009086">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009087">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009088">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009089">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009090">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009091">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009092">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009093">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009094">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009095">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009096">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009097">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009098">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009099">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009100">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009101">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009102">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009103">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009104">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009105">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009106">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009107">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009108">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009109">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009110">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009111">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009112">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009113">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009114">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009115">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009116">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009117">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009118">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009119">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009120">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009121">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009122">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009123">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009124">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009125">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009126">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009127">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009128">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009129">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009130">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009131">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009132">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009133">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009134">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009135">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009136">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009137">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009138">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009139">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009140">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009141">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009142">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009143">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009144">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009145">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009146">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009147">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009148">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009149">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009150">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009151">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009152">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009153">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009154">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009155">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009156">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009157">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009158">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009159">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009160">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009161">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009162">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009163">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009164">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009165">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009166">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009167">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009168">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009169">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009170">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009171">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009172">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009173">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009174">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009175">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009176">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009177">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009178">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009179">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009180">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009181">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009182">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009183">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009184">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009185">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009186">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009187">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009188">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009189">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009190">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009191">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009192">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009193">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009194">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009195">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009196">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009197">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009198">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009199">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009200">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009201">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009202">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009203">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009204">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009205">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009206">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009207">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009208">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009209">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009210">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009211">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009212">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009213">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009214">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009215">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009216">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009217">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009218">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009219">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009220">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009221">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009222">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009223">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009224">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009225">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009226">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009227">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009228">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009229">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009230">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009231">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009232">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009233">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009234">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009235">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009236">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009237">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009238">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009239">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009240">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009241">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009242">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009243">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009244">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009245">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009246">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009247">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009248">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009249">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009250">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009251">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009252">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009253">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009254">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009255">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200009256">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200010000">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200010001">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200010002">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200010003">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200010004">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200010005">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200010007">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200010008">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200010009">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200010010">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200010011">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200010012">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200010013">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200010014">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200010015">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200010016">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200010017">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200010018">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200010019">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200010020">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200010021">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200010022">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200010023">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200010024">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200010025">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200010026">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200010027">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200010028">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200010029">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200010030">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200010031">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200010032">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200010033">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200010034">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200010035">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200010036">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200010037">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200010038">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200010039">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200010040">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200010041">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200010042">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200010043">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200010044">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200010045">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200010046">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200010047">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200010048">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200010049">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200010050">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200010051">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200010052">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200010053">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200010054">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200010055">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200010056">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200010057">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200010058">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200010059">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200010060">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200010061">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200010062">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200010063">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200010064">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200010065">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200010066">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200010067">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200010068">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200010069">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200011000">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200011026">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200011027">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200011028">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200011029">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200011030">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200011031">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200011032">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200011033">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200011034">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200011035">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200011036">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200011037">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200011038">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200011039">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200011040">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200011041">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200011042">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200011043">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200011044">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200011045">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200011046">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200011047">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200011048">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200011049">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200011050">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200011051">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200011052">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200011053">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200011054">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200012001">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200012002">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200012003">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200012004">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200012005">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200012006">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200012007">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200012008">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200012009">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200012010">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200012011">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200012012">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200012013">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200012014">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200012015">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200012016">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200012017">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200012018">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200012019">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200012020">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200013001">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200014000">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200014001">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200014002">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200014003">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200015000">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200015001">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200015002">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200015003">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200015004">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200015005">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200015006">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200015007">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200015008">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200015009">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200015010">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200015011">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200015012">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200015013">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200015014">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200015015">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200015016">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200015017">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200015018">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200015019">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200015020">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200015021">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200015022">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200015023">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200015024">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200015025">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200015026">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200015027">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200015028">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200015029">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200015030">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200015031">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200015032">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200015033">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200015035">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200015036">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200015037">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200015038">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200015039">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200015040">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200015041">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200015042">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200015043">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200015044">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200015045">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200015046">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200015047">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200015048">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200015049">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200015050">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200015051">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200015052">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200015053">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200015054">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200015055">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200015056">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200015057">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200015058">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200015059">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200015060">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200015061">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200015062">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200015063">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200015064">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200015065">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200015066">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200015067">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200015068">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200015069">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200015070">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200015071">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200015072">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200015073">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200015074">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200015075">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200015076">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200015077">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200015078">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200015079">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200015080">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200016000">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200016001">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200016002">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200016003">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200016004">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200016005">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200016006">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200016007">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200018000">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200018001">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200018002">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200018003">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200018004">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200018005">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200018006">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200018007">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200018008">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200018010">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200018011">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200018016">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200018018">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200018019">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200018020">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200018021">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200018022">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200018023">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200018025">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200018026">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200018027">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200018028">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200018029">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200018030">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019000">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019001">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019002">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019003">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019004">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019005">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019006">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019007">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019008">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019009">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019010">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019011">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019012">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019013">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019014">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019015">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019016">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019017">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019018">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019019">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019020">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019021">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019022">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019023">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019024">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019025">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019027">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019028">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019029">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019030">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019031">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019032">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019033">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019034">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019035">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019036">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019037">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019038">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019039">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019040">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019041">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019042">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019043">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019044">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019045">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019046">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019047">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019048">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019049">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019050">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019051">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019052">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019053">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019054">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019055">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019056">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019057">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019058">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019059">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019060">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019061">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019062">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019063">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019064">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019065">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019066">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019067">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019068">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019069">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019070">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019071">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019072">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019073">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019074">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019075">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019076">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019077">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019078">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019079">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019080">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019081">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019082">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019083">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019084">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019085">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019086">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019087">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019088">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019089">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019090">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019091">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019092">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019093">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019094">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019095">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019096">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019097">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019098">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019099">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019100">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019101">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019102">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019103">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019104">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019105">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019106">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019107">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019108">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019109">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019110">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019111">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019112">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019113">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019114">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019115">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019116">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019117">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019118">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019119">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019120">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019121">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019122">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019123">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019124">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019125">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019126">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019127">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019128">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019129">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019130">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019131">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019132">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019133">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019134">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019135">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200019136">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021001">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021002">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021004">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021005">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021006">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021007">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021008">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021009">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021010">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021011">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021012">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021013">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021014">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021015">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021016">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021017">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021018">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021019">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021020">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021021">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021022">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021023">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021024">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021025">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021026">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021027">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021028">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021029">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021030">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021031">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021032">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021033">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021034">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021035">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021036">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021037">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021038">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021039">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021040">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021041">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021042">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021043">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021045">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021046">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021047">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021048">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021049">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021051">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021052">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021053">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021054">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021055">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021056">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021057">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021058">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021059">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021060">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021061">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021062">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021063">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021064">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021065">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021066">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021067">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021069">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021070">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021072">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021074">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021075">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021076">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021077">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021078">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021079">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021080">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021081">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021082">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021083">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021084">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021085">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021086">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021087">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021088">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021089">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021090">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021091">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021092">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021093">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021094">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021095">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021096">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021097">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021098">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021099">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021100">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021101">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021102">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021103">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021104">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021105">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021106">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021107">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021108">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021109">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021112">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021113">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021114">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021115">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021116">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021117">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021118">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021119">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021120">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021121">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021122">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021123">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021124">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021125">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021126">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021127">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021128">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021129">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021130">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021131">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021132">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021133">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021134">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021135">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021136">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021137">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021138">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021139">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021140">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021141">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021142">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200021143">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200022001">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200022002">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200022003">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200022004">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200022005">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200022006">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200022007">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200022008">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200022009">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200022010">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200022011">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200022012">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200022013">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200022014">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200022015">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200022016">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200022017">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200022018">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200022019">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200023001">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200023002">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200023003">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200023004">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100000">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100001">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100002">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100004">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100005">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100006">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100007">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100008">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100009">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100010">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100011">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100013">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100014">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100015">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100018">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100019">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100020">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100021">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100022">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100025">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100026">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100027">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100028">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100029">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100030">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100031">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100032">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100033">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100034">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100035">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100036">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100037">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100038">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100039">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100040">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100041">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100042">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100043">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100044">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100045">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100046">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100047">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100048">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100049">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100050">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100051">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100053">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100054">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100055">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100056">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100057">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100058">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100059">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100060">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100061">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100062">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100063">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100064">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100065">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100066">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100067">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100069">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100071">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100072">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100073">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100074">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100075">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100077">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100078">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100079">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100080">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100081">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100082">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100083">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100084">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100085">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100086">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100087">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100088">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100089">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100090">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100091">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100092">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100093">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100094">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100095">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100096">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100097">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100098">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100099">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100100">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100101">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100102">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100103">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100104">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100105">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100106">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100107">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100108">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100109">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100110">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100111">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100300">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100304">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100305">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100306">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100307">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100308">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100309">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100310">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100311">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100312">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100313">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100314">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100315">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100316">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100317">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100318">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100319">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100320">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100321">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100322">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100323">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100324">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100330">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200100332">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200200001">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="200200002">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- <signature signature_id="299999999">
- <enabled>true</enabled>
- <in_staging>true</in_staging>
- </signature>
- </attack_signatures>
- <data_guard>
- <enabled>false</enabled>
- <credit_card_numbers>false</credit_card_numbers>
- <social_security_numbers>false</social_security_numbers>
- <file_content>false</file_content>
- <mask_data>false</mask_data>
- <check_custom_patterns>false</check_custom_patterns>
- <check_exception_patterns>false</check_exception_patterns>
- <enforcement_mode>enforce_all_except_url_list</enforcement_mode>
- </data_guard>
- <policy_builder>
- <enabled>false</enabled>
- <http_protocol_compliance>true</http_protocol_compliance>
- <evasion_techniques_detected>true</evasion_techniques_detected>
- <learn_file_types>Always</learn_file_types>
- <file_types_lengths>true</file_types_lengths>
- <attack_signatures>true</attack_signatures>
- <learn_urls>Never</learn_urls>
- <urls_metachars>false</urls_metachars>
- <learn_parameters>When Violation Detected</learn_parameters>
- <learn_cookies>When Violation Detected</learn_cookies>
- <learn_redirection_domains>Always</learn_redirection_domains>
- <maximum_redirection_domains>100</maximum_redirection_domains>
- <parameters_value_lengths>false</parameters_value_lengths>
- <parameters_name_meta_characters>false</parameters_name_meta_characters>
- <parameters_value_meta_characters>false</parameters_value_meta_characters>
- <parameters_integer_value>true</parameters_integer_value>
- <allowed_methods>false</allowed_methods>
- <request_length_exceeds_buffer_size>true</request_length_exceeds_buffer_size>
- <client_side_policy_building>false</client_side_policy_building>
- <maximum_file_types>250</maximum_file_types>
- <maximum_urls>10000</maximum_urls>
- <maximum_parameters>10000</maximum_parameters>
- <maximum_allowed_modified_cookies>100</maximum_allowed_modified_cookies>
- <content_profiles>false</content_profiles>
- <content_profile_classification>false</content_profile_classification>
- <track_site_changes>
- <untrusted>
- <enabled>true</enabled>
- <distinct_sessions>10</distinct_sessions>
- <distinct_ips>10</distinct_ips>
- <minimum_interval>300</minimum_interval>
- <maximum_interval>604800</maximum_interval>
- </untrusted>
- <trusted>
- <enabled>true</enabled>
- <distinct_sessions>1</distinct_sessions>
- <distinct_ips>1</distinct_ips>
- <minimum_interval>0</minimum_interval>
- <maximum_interval>604800</maximum_interval>
- </trusted>
- </track_site_changes>
- <loosen_rule>
- <untrusted>
- <distinct_sessions>20</distinct_sessions>
- <distinct_ips>20</distinct_ips>
- <minimum_interval>3600</minimum_interval>
- <maximum_interval>604800</maximum_interval>
- </untrusted>
- <trusted>
- <distinct_sessions>1</distinct_sessions>
- <distinct_ips>1</distinct_ips>
- <minimum_interval>0</minimum_interval>
- <maximum_interval>604800</maximum_interval>
- </trusted>
- </loosen_rule>
- <tighten_rule>
- <untrusted>
- <distinct_sessions>500</distinct_sessions>
- <distinct_ips>500</distinct_ips>
- <total_requests>5000</total_requests>
- <minimum_interval>86400</minimum_interval>
- </untrusted>
- <trusted>
- <distinct_sessions>500</distinct_sessions>
- <distinct_ips>500</distinct_ips>
- <total_requests>5000</total_requests>
- <minimum_interval>86400</minimum_interval>
- </trusted>
- </tighten_rule>
- <dynamic_parameters>
- <unique_value_sets>10</unique_value_sets>
- <hidden_fields>false</hidden_fields>
- <use_statistics_forms>false</use_statistics_forms>
- <use_statistics_links>false</use_statistics_links>
- </dynamic_parameters>
- <parameter_level>global</parameter_level>
- <collapse_to_global_occurrences>10</collapse_to_global_occurrences>
- <all_trusted_ips>list</all_trusted_ips>
- <valid_host_names>true</valid_host_names>
- <csrf_urls>false</csrf_urls>
- <learn_from_responses>true</learn_from_responses>
- <encoding_failed_to_convert>false</encoding_failed_to_convert>
- <check_max_cookie_header_length>false</check_max_cookie_header_length>
- <check_max_http_header_length>false</check_max_http_header_length>
- <collapse_urls>true</collapse_urls>
- <collapse_urls_occurrences>500</collapse_urls_occurrences>
- <collapse_urls_depth>2</collapse_urls_depth>
- <response_code>1xx</response_code>
- <response_code>2xx</response_code>
- <response_code>3xx</response_code>
- <filetype>bmp</filetype>
- <filetype>gif</filetype>
- <filetype>ico</filetype>
- <filetype>jpeg</filetype>
- <filetype>jpg</filetype>
- <filetype>pcx</filetype>
- <filetype>pdf</filetype>
- <filetype>png</filetype>
- <filetype>swf</filetype>
- <filetype>wav</filetype>
- </policy_builder>
- <geolocation>
- <enforcement_mode>
- <mode>disallow</mode>
- </enforcement_mode>
- </geolocation>
- <ip_reputation>
- <enabled>false</enabled>
- </ip_reputation>
- <database_protection>
- <enabled>false</enabled>
- <user_source>APM Usernames and Session ID</user_source>
- </database_protection>
- <header name="*" type="wildcard">
- <is_mandatory>false</is_mandatory>
- <check_signatures>true</check_signatures>
- <is_base64>false</is_base64>
- <percent_normalization>false</percent_normalization>
- <uri_normalization>false</uri_normalization>
- <html_normalization>false</html_normalization>
- <enable_normalization_violation>false</enable_normalization_violation>
- <is_default>true</is_default>
- </header>
- <header name="referer" type="explicit">
- <is_mandatory>false</is_mandatory>
- <check_signatures>true</check_signatures>
- <is_base64>false</is_base64>
- <percent_normalization>false</percent_normalization>
- <uri_normalization>true</uri_normalization>
- <html_normalization>false</html_normalization>
- <enable_normalization_violation>true</enable_normalization_violation>
- <is_default>true</is_default>
- </header>
- <header name="cookie" type="explicit">
- <is_mandatory>false</is_mandatory>
- <check_signatures>false</check_signatures>
- <is_base64>false</is_base64>
- <percent_normalization>false</percent_normalization>
- <uri_normalization>false</uri_normalization>
- <html_normalization>false</html_normalization>
- <enable_normalization_violation>false</enable_normalization_violation>
- <is_default>true</is_default>
- </header>
- <header name="authorization" type="explicit">
- <is_mandatory>false</is_mandatory>
- <check_signatures>true</check_signatures>
- <is_base64>false</is_base64>
- <percent_normalization>false</percent_normalization>
- <uri_normalization>false</uri_normalization>
- <html_normalization>false</html_normalization>
- <enable_normalization_violation>false</enable_normalization_violation>
- <is_default>true</is_default>
- </header>
- <redirection_domain name="*" type="wildcard">
- <include_subdomains>false</include_subdomains>
- <learning_mode>Always</learning_mode>
- </redirection_domain>
- <redirection_protection>
- <enabled>true</enabled>
- </redirection_protection>
-</policy>
diff --git a/test/units/modules/network/f5/fixtures/load_afm_global_network_log_network.json b/test/units/modules/network/f5/fixtures/load_afm_global_network_log_network.json
deleted file mode 100644
index cc4ef0d391..0000000000
--- a/test/units/modules/network/f5/fixtures/load_afm_global_network_log_network.json
+++ /dev/null
@@ -1,31 +0,0 @@
-{
- "kind": "tm:security:log:profile:network:networkstate",
- "name": "global-network",
- "fullPath": "global-network",
- "generation": 839,
- "selfLink": "https://localhost/mgmt/tm/security/log/profile/~Common~global-network/network/global-network?ver=12.1.4",
- "filter": {
- "logAclMatchAccept": "disabled",
- "logAclMatchDrop": "disabled",
- "logAclMatchReject": "disabled",
- "logAclToBoxDeny": "disabled",
- "logGeoAlways": "disabled",
- "logIpErrors": "disabled",
- "logTcpErrors": "disabled",
- "logTcpEvents": "disabled",
- "logTranslationFields": "disabled"
- },
- "format": {
- "fieldListDelimiter": ",",
- "type": "none"
- },
- "rateLimit": {
- "aclMatchAccept": 4294967295,
- "aclMatchDrop": 4294967295,
- "aclMatchReject": 4294967295,
- "aggregateRate": 4294967295,
- "ipErrors": 4294967295,
- "tcpErrors": 4294967295,
- "tcpEvents": 4294967295
- }
-}
diff --git a/test/units/modules/network/f5/fixtures/load_afm_log_global_network_profile.json b/test/units/modules/network/f5/fixtures/load_afm_log_global_network_profile.json
deleted file mode 100644
index 205af5b8c5..0000000000
--- a/test/units/modules/network/f5/fixtures/load_afm_log_global_network_profile.json
+++ /dev/null
@@ -1,50 +0,0 @@
-{
- "kind": "tm:security:log:profile:profilestate",
- "name": "global-network",
- "partition": "Common",
- "fullPath": "/Common/global-network",
- "generation": 1,
- "selfLink": "https://localhost/mgmt/tm/security/log/profile/~Common~global-network?ver=12.1.4",
- "description": "Default logging profile for network events",
- "ipIntelligence": {
- "aggregateRate": 4294967295,
- "logRtbh": "disabled",
- "logShun": "disabled",
- "logTranslationFields": "disabled"
- },
- "nat": {
- "endInboundSession": "disabled",
- "endOutboundSession": {
- "action": "disabled"
- },
- "errors": "disabled",
- "lsnLegacyMode": "disabled",
- "quotaExceeded": "disabled",
- "startInboundSession": "disabled",
- "startOutboundSession": {
- "action": "disabled"
- }
- },
- "portMisuse": {
- "aggregateRate": 4294967295
- },
- "trafficStatistics": {
- "activeFlows": "disabled",
- "missedFlows": "disabled",
- "reapedFlows": "disabled",
- "syncookies": "disabled",
- "syncookiesWhitelist": "disabled"
- },
- "networkReference": {
- "link": "https://localhost/mgmt/tm/security/log/profile/~Common~global-network/network?ver=12.1.4",
- "isSubcollection": true
- },
- "protocolDnsReference": {
- "link": "https://localhost/mgmt/tm/security/log/profile/~Common~global-network/protocol-dns?ver=12.1.4",
- "isSubcollection": true
- },
- "protocolSipReference": {
- "link": "https://localhost/mgmt/tm/security/log/profile/~Common~global-network/protocol-sip?ver=12.1.4",
- "isSubcollection": true
- }
-}
diff --git a/test/units/modules/network/f5/fixtures/load_afm_schedule.json b/test/units/modules/network/f5/fixtures/load_afm_schedule.json
deleted file mode 100644
index c9d51ebffc..0000000000
--- a/test/units/modules/network/f5/fixtures/load_afm_schedule.json
+++ /dev/null
@@ -1,19 +0,0 @@
-{
- "kind": "tm:security:firewall:schedule:schedulestate",
- "name": "foobar",
- "partition": "Common",
- "fullPath": "/Common/foobar",
- "generation": 1835,
- "selfLink": "https://localhost/mgmt/tm/security/firewall/schedule/~Common~foobar?ver=12.1.4",
- "dailyHourEnd": "12:00",
- "dailyHourStart": "6:00",
- "dateValidEnd": "2019-06-13T16:00:00Z",
- "dateValidStart": "2019-05-31T07:00:00Z",
- "daysOfWeek": [
- "sunday",
- "monday",
- "friday",
- "saturday"
- ],
- "description": "some description"
-}
diff --git a/test/units/modules/network/f5/fixtures/load_apm_acl.json b/test/units/modules/network/f5/fixtures/load_apm_acl.json
deleted file mode 100644
index 564784dbf2..0000000000
--- a/test/units/modules/network/f5/fixtures/load_apm_acl.json
+++ /dev/null
@@ -1,27 +0,0 @@
-{
- "kind": "tm:apm:acl:aclstate",
- "name": "lastone",
- "partition": "Common",
- "fullPath": "/Common/lastone",
- "generation": 495,
- "selfLink": "https://localhost/mgmt/tm/apm/acl/~Common~lastone?ver=12.1.4",
- "aclOrder": 2,
- "description": "foobar",
- "locationSpecific": "true",
- "pathMatchCase": "false",
- "type": "static",
- "entries": [
- {
- "action": "discard",
- "dstEndPort": 0,
- "dstStartPort": 0,
- "dstSubnet": "0.0.0.0/0",
- "log": "none",
- "protocol": 1,
- "scheme": "any",
- "srcEndPort": 0,
- "srcStartPort": 0,
- "srcSubnet": "0.0.0.0/0"
- }
- ]
-}
diff --git a/test/units/modules/network/f5/fixtures/load_apm_network_access.json b/test/units/modules/network/f5/fixtures/load_apm_network_access.json
deleted file mode 100644
index 9c8b897f73..0000000000
--- a/test/units/modules/network/f5/fixtures/load_apm_network_access.json
+++ /dev/null
@@ -1,98 +0,0 @@
-{
- "kind": "tm:apm:resource:network-access:network-accessstate",
- "name": "test",
- "partition": "Common",
- "fullPath": "/Common/test",
- "generation": 1140,
- "selfLink": "https://localhost/mgmt/tm/apm/resource/network-access/~Common~test?ver=12.1.4",
- "addressSpaceDhcpRequestsExcluded": "true",
- "addressSpaceExcludeDnsName": [
- "baz.com",
- "bazfoo.com"
- ],
- "addressSpaceIncludeDnsName": [
- "foo.com",
- "bar.com"
- ],
- "addressSpaceLocDnsServersExcluded": "true",
- "addressSpaceLocalSubnetsExcluded": "true",
- "addressSpaceProtect": "false",
- "applicationLaunchWarning": "true",
- "autoLaunch": "false",
- "clientInterfaceSpeed": 100000000,
- "clientIpFilterEngine": "false",
- "clientPowerManagement": "ignore",
- "clientProxy": "false",
- "clientProxyAddress": "any6",
- "clientProxyEnforceSubnets": "true",
- "clientProxyIgnoreAutoConfigError": "false",
- "clientProxyLocalBypass": "false",
- "clientProxyPort": 0,
- "clientProxyUseHttpPac": "false",
- "clientProxyUseLocalProxy": "false",
- "clientTrayIcon": "true",
- "compression": "none",
- "customizationGroup": "/Common/test_resource_network_access_customization",
- "customizationGroupReference": {
- "link": "https://localhost/mgmt/tm/apm/policy/customization-group/~Common~test_resource_network_access_customization?ver=12.1.4"
- },
- "dnsEnforceSearchOrder": "true",
- "dnsPrimary": "any6",
- "dnsRegisterConnection": "false",
- "dnsSecondary": "any6",
- "dnsUseDnsSuffixForRegistration": "false",
- "dtls": "false",
- "dtlsPort": 4433,
- "executeLogoffScripts": "false",
- "idleTimeoutThreshold": 0,
- "idleTimeoutWindow": 0,
- "ipv6DnsPrimary": "any6",
- "ipv6DnsSecondary": "any6",
- "ipv6LeasepoolName": "/Common/ipv6lease",
- "ipv6LeasepoolNameReference": {
- "link": "https://localhost/mgmt/tm/apm/resource/ipv6-leasepool/~Common~ipv6lease?ver=12.1.4"
- },
- "leasepoolName": "/Common/ipv4lease",
- "leasepoolNameReference": {
- "link": "https://localhost/mgmt/tm/apm/resource/leasepool/~Common~ipv4lease?ver=12.1.4"
- },
- "locationSpecific": "true",
- "microsoftNetworkClient": "true",
- "microsoftNetworkServer": "false",
- "networkTunnel": "enabled",
- "preserveSourcePortStrict": "none",
- "provideClientCert": "true",
- "proxyArp": "false",
- "snat": "automap",
- "splitTunneling": "true",
- "supportedIpVersion": "ipv4-ipv6",
- "syncWithActiveDirectory": "false",
- "type": "network-access",
- "winsPrimary": "any6",
- "winsSecondary": "any6",
- "addressSpaceExcludeSubnet": [
- {
- "subnet": "192.168.1.0/24"
- },
- {
- "subnet": "192.168.2.1/32"
- }
- ],
- "addressSpaceIncludeSubnet": [
- {
- "subnet": "10.10.10.1/32"
- },
- {
- "subnet": "10.11.11.0/24"
- }
- ],
- "ipv6AddressSpaceIncludeSubnet": [
- {
- "subnet": "2607:f0d0:1002:51::4/128"
- }
- ],
- "optimizedAppReference": {
- "link": "https://localhost/mgmt/tm/apm/resource/network-access/~Common~test/optimized-app?ver=12.1.4",
- "isSubcollection": true
- }
-}
diff --git a/test/units/modules/network/f5/fixtures/load_asm_dos.json b/test/units/modules/network/f5/fixtures/load_asm_dos.json
deleted file mode 100644
index cab7b71ff2..0000000000
--- a/test/units/modules/network/f5/fixtures/load_asm_dos.json
+++ /dev/null
@@ -1,276 +0,0 @@
-{
- "kind": "tm:security:dos:profile:application:applicationstate",
- "name": "test",
- "fullPath": "test",
- "generation": 1442,
- "selfLink": "https://localhost/mgmt/tm/security/dos/profile/~Common~test/application/test?ver=13.1.1.4",
- "botDefense": {
- "browserLegitCaptcha": "enabled",
- "browserLegitEnabled": "enabled",
- "crossDomainRequests": "allow-all",
- "gracePeriod": 300,
- "mode": "disabled"
- },
- "botSignatures": {
- "check": "disabled",
- "categories": [
- {
- "name": "DOS Tool",
- "partition": "Common",
- "action": "block",
- "nameReference": {
- "link": "https://localhost/mgmt/tm/security/dos/bot-signature-category/~Common~DOS%20Tool?ver=13.1.1.4"
- }
- },
- {
- "name": "E-Mail Collector",
- "partition": "Common",
- "action": "block",
- "nameReference": {
- "link": "https://localhost/mgmt/tm/security/dos/bot-signature-category/~Common~E-Mail%20Collector?ver=13.1.1.4"
- }
- },
- {
- "name": "Exploit Tool",
- "partition": "Common",
- "action": "block",
- "nameReference": {
- "link": "https://localhost/mgmt/tm/security/dos/bot-signature-category/~Common~Exploit%20Tool?ver=13.1.1.4"
- }
- },
- {
- "name": "Network Scanner",
- "partition": "Common",
- "action": "block",
- "nameReference": {
- "link": "https://localhost/mgmt/tm/security/dos/bot-signature-category/~Common~Network%20Scanner?ver=13.1.1.4"
- }
- },
- {
- "name": "Search Engine",
- "partition": "Common",
- "action": "report",
- "nameReference": {
- "link": "https://localhost/mgmt/tm/security/dos/bot-signature-category/~Common~Search%20Engine?ver=13.1.1.4"
- }
- },
- {
- "name": "Spam Bot",
- "partition": "Common",
- "action": "block",
- "nameReference": {
- "link": "https://localhost/mgmt/tm/security/dos/bot-signature-category/~Common~Spam%20Bot?ver=13.1.1.4"
- }
- },
- {
- "name": "Spyware",
- "partition": "Common",
- "action": "block",
- "nameReference": {
- "link": "https://localhost/mgmt/tm/security/dos/bot-signature-category/~Common~Spyware?ver=13.1.1.4"
- }
- },
- {
- "name": "Vulnerability Scanner",
- "partition": "Common",
- "action": "block",
- "nameReference": {
- "link": "https://localhost/mgmt/tm/security/dos/bot-signature-category/~Common~Vulnerability%20Scanner?ver=13.1.1.4"
- }
- },
- {
- "name": "Web Spider",
- "partition": "Common",
- "action": "block",
- "nameReference": {
- "link": "https://localhost/mgmt/tm/security/dos/bot-signature-category/~Common~Web%20Spider?ver=13.1.1.4"
- }
- },
- {
- "name": "Webserver Stress Tool",
- "partition": "Common",
- "action": "block",
- "nameReference": {
- "link": "https://localhost/mgmt/tm/security/dos/bot-signature-category/~Common~Webserver%20Stress%20Tool?ver=13.1.1.4"
- }
- }
- ]
- },
- "captchaResponse": {
- "failure": {
- "body": "You have entered an invalid answer for the question. Please, try again.\n<br>\n%DOSL7.captcha.image% %DOSL7.captcha.change%\n<br>\n<b>What code is in the image\\?</b>\n%DOSL7.captcha.solution%\n<br>\n%DOSL7.captcha.submit%\n<br>\n<br>\nYour support ID is: %DOSL7.captcha.support_id%.",
- "type": "default"
- },
- "first": {
- "body": "This question is for testing whether you are a human visitor and to prevent automated spam submission.\n<br>\n%DOSL7.captcha.image% %DOSL7.captcha.change%\n<br>\n<b>What code is in the image\\?</b>\n%DOSL7.captcha.solution%\n<br>\n%DOSL7.captcha.submit%\n<br>\n<br>\nYour support ID is: %DOSL7.captcha.support_id%.",
- "type": "default"
- }
- },
- "heavyUrls": {
- "automaticDetection": "enabled",
- "exclude": [
- "/exclude.html"
- ],
- "latencyThreshold": 1000,
- "protection": "disabled",
- "includeList": [
- {
- "name": "URL/test.htm",
- "threshold": "auto",
- "url": "/test.htm"
- },
- {
- "name": "URL/testy.htm",
- "threshold": "auto",
- "url": "/testy.htm"
- }
- ]
- },
- "mobileDetection": {
- "allowAndroidRootedDevice": "false",
- "allowAnyAndroidPackage": "false",
- "allowAnyIosPackage": "false",
- "allowEmulators": "true",
- "allowJailbrokenDevices": "true",
- "clientSideChallengeMode": "pass",
- "enabled": "disabled",
- "iosAllowedPackageNames": [
- "foobarapp"
- ],
- "androidPublishers": [
- {
- "name": "ca-bundle.crt",
- "partition": "Common",
- "nameReference": {
- "link": "https://localhost/mgmt/tm/sys/file/ssl-cert/~Common~ca-bundle.crt?ver=13.1.1.4"
- }
- }
- ]
- },
- "rtbhDurationSec": 300,
- "rtbhEnable": "enabled",
- "scrubbingDurationSec": 60,
- "scrubbingEnable": "enabled",
- "singlePageApplication": "enabled",
- "stressBased": {
- "behavioral": {
- "dosDetection": "disabled",
- "mitigationMode": "none",
- "signatures": "disabled",
- "signaturesApprovedOnly": "disabled"
- },
- "deEscalationPeriod": 7200,
- "deviceCaptchaChallenge": "disabled",
- "deviceClientSideDefense": "disabled",
- "deviceMaximumAutoTps": 5000,
- "deviceMaximumTps": 200,
- "deviceMinimumAutoTps": 5,
- "deviceMinimumTps": 40,
- "deviceRateLimiting": "disabled",
- "deviceRequestBlockingMode": "rate-limit",
- "deviceTpsIncreaseRate": 500,
- "escalationPeriod": 120,
- "geoCaptchaChallenge": "disabled",
- "geoClientSideDefense": "disabled",
- "geoMaximumAutoTps": 20000,
- "geoMinimumAutoTps": 50,
- "geoMinimumShare": 10,
- "geoRateLimiting": "disabled",
- "geoRequestBlockingMode": "rate-limit",
- "geoShareIncreaseRate": 500,
- "ipCaptchaChallenge": "disabled",
- "ipClientSideDefense": "disabled",
- "ipMaximumAutoTps": 5000,
- "ipMaximumTps": 200,
- "ipMinimumAutoTps": 5,
- "ipMinimumTps": 40,
- "ipRateLimiting": "enabled",
- "ipRequestBlockingMode": "rate-limit",
- "ipTpsIncreaseRate": 500,
- "mode": "off",
- "siteCaptchaChallenge": "disabled",
- "siteClientSideDefense": "disabled",
- "siteMaximumAutoTps": 20000,
- "siteMaximumTps": 10000,
- "siteMinimumAutoTps": 50,
- "siteMinimumTps": 2000,
- "siteRateLimiting": "disabled",
- "siteTpsIncreaseRate": 500,
- "thresholdsMode": "manual",
- "urlCaptchaChallenge": "disabled",
- "urlClientSideDefense": "disabled",
- "urlEnableHeavy": "enabled",
- "urlMaximumAutoTps": 5000,
- "urlMaximumTps": 1000,
- "urlMinimumAutoTps": 50,
- "urlMinimumTps": 200,
- "urlRateLimiting": "enabled",
- "urlTpsIncreaseRate": 500
- },
- "tcpDump": {
- "maximumDuration": 30,
- "maximumSize": 10,
- "recordTraffic": "disabled",
- "repetitionInterval": "120"
- },
- "tpsBased": {
- "deEscalationPeriod": 7200,
- "deviceCaptchaChallenge": "disabled",
- "deviceClientSideDefense": "disabled",
- "deviceMaximumAutoTps": 5000,
- "deviceMaximumTps": 200,
- "deviceMinimumAutoTps": 5,
- "deviceMinimumTps": 40,
- "deviceRateLimiting": "disabled",
- "deviceRequestBlockingMode": "rate-limit",
- "deviceTpsIncreaseRate": 500,
- "escalationPeriod": 120,
- "geoCaptchaChallenge": "disabled",
- "geoClientSideDefense": "disabled",
- "geoMaximumAutoTps": 20000,
- "geoMinimumAutoTps": 50,
- "geoMinimumShare": 10,
- "geoRateLimiting": "disabled",
- "geoRequestBlockingMode": "rate-limit",
- "geoShareIncreaseRate": 500,
- "ipCaptchaChallenge": "disabled",
- "ipClientSideDefense": "disabled",
- "ipMaximumAutoTps": 5000,
- "ipMaximumTps": 200,
- "ipMinimumAutoTps": 5,
- "ipMinimumTps": 40,
- "ipRateLimiting": "enabled",
- "ipRequestBlockingMode": "rate-limit",
- "ipTpsIncreaseRate": 500,
- "mode": "off",
- "siteCaptchaChallenge": "disabled",
- "siteClientSideDefense": "disabled",
- "siteMaximumAutoTps": 20000,
- "siteMaximumTps": 10000,
- "siteMinimumAutoTps": 50,
- "siteMinimumTps": 2000,
- "siteRateLimiting": "disabled",
- "siteTpsIncreaseRate": 500,
- "thresholdsMode": "manual",
- "urlCaptchaChallenge": "disabled",
- "urlClientSideDefense": "disabled",
- "urlEnableHeavy": "enabled",
- "urlMaximumAutoTps": 5000,
- "urlMaximumTps": 1000,
- "urlMinimumAutoTps": 50,
- "urlMinimumTps": 200,
- "urlRateLimiting": "enabled",
- "urlTpsIncreaseRate": 500
- },
- "triggerIrule": "enabled",
- "geolocations": [
- {
- "name": "Afghanistan",
- "blackListed": true
- },
- {
- "name": "Aland Islands",
- "whiteListed": true
- }
- ]
-}
diff --git a/test/units/modules/network/f5/fixtures/load_asm_policy_active.json b/test/units/modules/network/f5/fixtures/load_asm_policy_active.json
deleted file mode 100644
index 001daa757a..0000000000
--- a/test/units/modules/network/f5/fixtures/load_asm_policy_active.json
+++ /dev/null
@@ -1,197 +0,0 @@
-{
- "plainTextProfileReference": {
- "link": "https://localhost/mgmt/tm/asm/policies/0EHlYeS5noAOZLY3YsJjEw/plain-text-profiles?ver=12.1.2",
- "isSubCollection": true
- },
- "learningMode": "manual",
- "dataGuardReference": {
- "link": "https://localhost/mgmt/tm/asm/policies/0EHlYeS5noAOZLY3YsJjEw/data-guard?ver=12.1.2"
- },
- "stagingSettings": {
- "signatureStaging": true,
- "placeSignaturesInStaging": false,
- "enforcementReadinessPeriod": 7
- },
- "createdDatetime": "2017-09-21T11:52:24Z",
- "geolocationEnforcementReference": {
- "link": "https://localhost/mgmt/tm/asm/policies/0EHlYeS5noAOZLY3YsJjEw/geolocation-enforcement?ver=12.1.2"
- },
- "versionLastChange": "Allowed Response Code 503 [add]: Response Code was set to 503.",
- "name": "fake_policy",
- "caseInsensitive": false,
- "loginPageReference": {
- "link": "https://localhost/mgmt/tm/asm/policies/0EHlYeS5noAOZLY3YsJjEw/login-pages?ver=12.1.2",
- "isSubCollection": true
- },
- "fullPath": "/Common/fake_policy",
- "description": "",
- "attributes": {
- "pathParameterHandling": "as-parameters",
- "triggerAsmIruleEvent": "disabled",
- "inspectHttpUploads": false,
- "maskCreditCardNumbersInRequest": true,
- "maximumHttpHeaderLength": "8192",
- "useDynamicSessionIdInUrl": false,
- "maximumCookieHeaderLength": "8192"
- },
- "partition": "Common",
- "webScrapingReference": {
- "link": "https://localhost/mgmt/tm/asm/policies/0EHlYeS5noAOZLY3YsJjEw/web-scraping?ver=12.1.2"
- },
- "csrfProtectionReference": {
- "link": "https://localhost/mgmt/tm/asm/policies/0EHlYeS5noAOZLY3YsJjEw/csrf-protection?ver=12.1.2"
- },
- "customXffHeaders": [],
- "kind": "tm:asm:policies:policystate",
- "virtualServers": [],
- "ipIntelligenceReference": {
- "link": "https://localhost/mgmt/tm/asm/policies/0EHlYeS5noAOZLY3YsJjEw/ip-intelligence?ver=12.1.2"
- },
- "protocolIndependent": false,
- "sessionAwarenessSettingsReference": {
- "link": "https://localhost/mgmt/tm/asm/policies/0EHlYeS5noAOZLY3YsJjEw/session-tracking?ver=12.1.2"
- },
- "signatureSetReference": {
- "link": "https://localhost/mgmt/tm/asm/policies/0EHlYeS5noAOZLY3YsJjEw/signature-sets?ver=12.1.2",
- "isSubCollection": true
- },
- "parameterReference": {
- "link": "https://localhost/mgmt/tm/asm/policies/0EHlYeS5noAOZLY3YsJjEw/parameters?ver=12.1.2",
- "isSubCollection": true
- },
- "allowedResponseCodes": [
- 400,
- 401,
- 404,
- 407,
- 417,
- 503
- ],
- "applicationLanguage": "utf-8",
- "enforcementMode": "transparent",
- "loginEnforcementReference": {
- "link": "https://localhost/mgmt/tm/asm/policies/0EHlYeS5noAOZLY3YsJjEw/login-enforcement?ver=12.1.2"
- },
- "navigationParameterReference": {
- "link": "https://localhost/mgmt/tm/asm/policies/0EHlYeS5noAOZLY3YsJjEw/navigation-parameters?ver=12.1.2",
- "isSubCollection": true
- },
- "gwtProfileReference": {
- "link": "https://localhost/mgmt/tm/asm/policies/0EHlYeS5noAOZLY3YsJjEw/gwt-profiles?ver=12.1.2",
- "isSubCollection": true
- },
- "whitelistIpReference": {
- "link": "https://localhost/mgmt/tm/asm/policies/0EHlYeS5noAOZLY3YsJjEw/whitelist-ips?ver=12.1.2",
- "isSubCollection": true
- },
- "historyRevisionReference": {
- "link": "https://localhost/mgmt/tm/asm/policies/0EHlYeS5noAOZLY3YsJjEw/history-revisions?ver=12.1.2",
- "isSubCollection": true
- },
- "policyBuilderReference": {
- "link": "https://localhost/mgmt/tm/asm/policies/0EHlYeS5noAOZLY3YsJjEw/policy-builder?ver=12.1.2"
- },
- "responsePageReference": {
- "link": "https://localhost/mgmt/tm/asm/policies/0EHlYeS5noAOZLY3YsJjEw/response-pages?ver=12.1.2",
- "isSubCollection": true
- },
- "vulnerabilityAssessmentReference": {
- "link": "https://localhost/mgmt/tm/asm/policies/0EHlYeS5noAOZLY3YsJjEw/vulnerability-assessment?ver=12.1.2"
- },
- "blockingSettingReference": {
- "link": "https://localhost/mgmt/tm/asm/policies/0EHlYeS5noAOZLY3YsJjEw/blocking-settings?ver=12.1.2",
- "isSubCollection": true
- },
- "cookieReference": {
- "link": "https://localhost/mgmt/tm/asm/policies/0EHlYeS5noAOZLY3YsJjEw/cookies?ver=12.1.2",
- "isSubCollection": true
- },
- "hostNameReference": {
- "link": "https://localhost/mgmt/tm/asm/policies/0EHlYeS5noAOZLY3YsJjEw/host-names?ver=12.1.2",
- "isSubCollection": true
- },
- "versionDeviceName": "ltm4restlab.lab.local",
- "selfLink": "https://localhost/mgmt/tm/asm/policies/0EHlYeS5noAOZLY3YsJjEw?ver=12.1.2",
- "signatureReference": {
- "link": "https://localhost/mgmt/tm/asm/policies/0EHlYeS5noAOZLY3YsJjEw/signatures?ver=12.1.2",
- "isSubCollection": true
- },
- "filetypeReference": {
- "link": "https://localhost/mgmt/tm/asm/policies/0EHlYeS5noAOZLY3YsJjEw/filetypes?ver=12.1.2",
- "isSubCollection": true
- },
- "id": "0EHlYeS5noAOZLY3YsJjEw",
- "manualVirtualServers": [],
- "modifierName": "admin",
- "versionDatetime": "2017-04-11T08:05:22Z",
- "subPath": "/Common",
- "sessionTrackingStatusReference": {
- "link": "https://localhost/mgmt/tm/asm/policies/0EHlYeS5noAOZLY3YsJjEw/session-tracking-statuses?ver=12.1.2",
- "isSubCollection": true
- },
- "active": true,
- "auditLogReference": {
- "link": "https://localhost/mgmt/tm/asm/policies/0EHlYeS5noAOZLY3YsJjEw/audit-logs?ver=12.1.2",
- "isSubCollection": true
- },
- "trustXff": false,
- "websocketUrlReference": {
- "link": "https://localhost/mgmt/tm/asm/policies/0EHlYeS5noAOZLY3YsJjEw/websocket-urls?ver=12.1.2",
- "isSubCollection": true
- },
- "xmlProfileReference": {
- "link": "https://localhost/mgmt/tm/asm/policies/0EHlYeS5noAOZLY3YsJjEw/xml-profiles?ver=12.1.2",
- "isSubCollection": true
- },
- "methodReference": {
- "link": "https://localhost/mgmt/tm/asm/policies/0EHlYeS5noAOZLY3YsJjEw/methods?ver=12.1.2",
- "isSubCollection": true
- },
- "redirectionProtectionReference": {
- "link": "https://localhost/mgmt/tm/asm/policies/0EHlYeS5noAOZLY3YsJjEw/redirection-protection?ver=12.1.2"
- },
- "vulnerabilityReference": {
- "link": "https://localhost/mgmt/tm/asm/policies/0EHlYeS5noAOZLY3YsJjEw/vulnerabilities?ver=12.1.2",
- "isSubCollection": true
- },
- "creatorName": "SYSTEM",
- "urlReference": {
- "link": "https://localhost/mgmt/tm/asm/policies/0EHlYeS5noAOZLY3YsJjEw/urls?ver=12.1.2",
- "isSubCollection": true
- },
- "headerReference": {
- "link": "https://localhost/mgmt/tm/asm/policies/0EHlYeS5noAOZLY3YsJjEw/headers?ver=12.1.2",
- "isSubCollection": true
- },
- "xmlValidationFileReference": {
- "link": "https://localhost/mgmt/tm/asm/policies/0EHlYeS5noAOZLY3YsJjEw/xml-validation-files?ver=12.1.2",
- "isSubCollection": true
- },
- "lastUpdateMicros": 1.506250903e+15,
- "jsonProfileReference": {
- "link": "https://localhost/mgmt/tm/asm/policies/0EHlYeS5noAOZLY3YsJjEw/json-profiles?ver=12.1.2",
- "isSubCollection": true
- },
- "bruteForceAttackPreventionReference": {
- "link": "https://localhost/mgmt/tm/asm/policies/0EHlYeS5noAOZLY3YsJjEw/brute-force-attack-preventions?ver=12.1.2",
- "isSubCollection": true
- },
- "extractionReference": {
- "link": "https://localhost/mgmt/tm/asm/policies/0EHlYeS5noAOZLY3YsJjEw/extractions?ver=12.1.2",
- "isSubCollection": true
- },
- "characterSetReference": {
- "link": "https://localhost/mgmt/tm/asm/policies/0EHlYeS5noAOZLY3YsJjEw/character-sets?ver=12.1.2",
- "isSubCollection": true
- },
- "isModified": false,
- "suggestionReference": {
- "link": "https://localhost/mgmt/tm/asm/policies/0EHlYeS5noAOZLY3YsJjEw/suggestions?ver=12.1.2",
- "isSubCollection": true
- },
- "sensitiveParameterReference": {
- "link": "https://localhost/mgmt/tm/asm/policies/0EHlYeS5noAOZLY3YsJjEw/sensitive-parameters?ver=12.1.2",
- "isSubCollection": true
- },
- "versionPolicyName": "/Common/fake_policy"
-}
diff --git a/test/units/modules/network/f5/fixtures/load_asm_policy_inactive.json b/test/units/modules/network/f5/fixtures/load_asm_policy_inactive.json
deleted file mode 100644
index 5198888142..0000000000
--- a/test/units/modules/network/f5/fixtures/load_asm_policy_inactive.json
+++ /dev/null
@@ -1,197 +0,0 @@
-{
- "plainTextProfileReference": {
- "link": "https://localhost/mgmt/tm/asm/policies/0EHlYeS5noAOZLY3YsJjEw/plain-text-profiles?ver=12.1.2",
- "isSubCollection": true
- },
- "learningMode": "manual",
- "dataGuardReference": {
- "link": "https://localhost/mgmt/tm/asm/policies/0EHlYeS5noAOZLY3YsJjEw/data-guard?ver=12.1.2"
- },
- "stagingSettings": {
- "signatureStaging": true,
- "placeSignaturesInStaging": false,
- "enforcementReadinessPeriod": 7
- },
- "createdDatetime": "2017-09-21T11:52:24Z",
- "geolocationEnforcementReference": {
- "link": "https://localhost/mgmt/tm/asm/policies/0EHlYeS5noAOZLY3YsJjEw/geolocation-enforcement?ver=12.1.2"
- },
- "versionLastChange": "Allowed Response Code 503 [add]: Response Code was set to 503.",
- "name": "fake_policy",
- "caseInsensitive": false,
- "loginPageReference": {
- "link": "https://localhost/mgmt/tm/asm/policies/0EHlYeS5noAOZLY3YsJjEw/login-pages?ver=12.1.2",
- "isSubCollection": true
- },
- "fullPath": "/Common/fake_policy",
- "description": "",
- "attributes": {
- "pathParameterHandling": "as-parameters",
- "triggerAsmIruleEvent": "disabled",
- "inspectHttpUploads": false,
- "maskCreditCardNumbersInRequest": true,
- "maximumHttpHeaderLength": "8192",
- "useDynamicSessionIdInUrl": false,
- "maximumCookieHeaderLength": "8192"
- },
- "partition": "Common",
- "webScrapingReference": {
- "link": "https://localhost/mgmt/tm/asm/policies/0EHlYeS5noAOZLY3YsJjEw/web-scraping?ver=12.1.2"
- },
- "csrfProtectionReference": {
- "link": "https://localhost/mgmt/tm/asm/policies/0EHlYeS5noAOZLY3YsJjEw/csrf-protection?ver=12.1.2"
- },
- "customXffHeaders": [],
- "kind": "tm:asm:policies:policystate",
- "virtualServers": [],
- "ipIntelligenceReference": {
- "link": "https://localhost/mgmt/tm/asm/policies/0EHlYeS5noAOZLY3YsJjEw/ip-intelligence?ver=12.1.2"
- },
- "protocolIndependent": false,
- "sessionAwarenessSettingsReference": {
- "link": "https://localhost/mgmt/tm/asm/policies/0EHlYeS5noAOZLY3YsJjEw/session-tracking?ver=12.1.2"
- },
- "signatureSetReference": {
- "link": "https://localhost/mgmt/tm/asm/policies/0EHlYeS5noAOZLY3YsJjEw/signature-sets?ver=12.1.2",
- "isSubCollection": true
- },
- "parameterReference": {
- "link": "https://localhost/mgmt/tm/asm/policies/0EHlYeS5noAOZLY3YsJjEw/parameters?ver=12.1.2",
- "isSubCollection": true
- },
- "allowedResponseCodes": [
- 400,
- 401,
- 404,
- 407,
- 417,
- 503
- ],
- "applicationLanguage": "utf-8",
- "enforcementMode": "transparent",
- "loginEnforcementReference": {
- "link": "https://localhost/mgmt/tm/asm/policies/0EHlYeS5noAOZLY3YsJjEw/login-enforcement?ver=12.1.2"
- },
- "navigationParameterReference": {
- "link": "https://localhost/mgmt/tm/asm/policies/0EHlYeS5noAOZLY3YsJjEw/navigation-parameters?ver=12.1.2",
- "isSubCollection": true
- },
- "gwtProfileReference": {
- "link": "https://localhost/mgmt/tm/asm/policies/0EHlYeS5noAOZLY3YsJjEw/gwt-profiles?ver=12.1.2",
- "isSubCollection": true
- },
- "whitelistIpReference": {
- "link": "https://localhost/mgmt/tm/asm/policies/0EHlYeS5noAOZLY3YsJjEw/whitelist-ips?ver=12.1.2",
- "isSubCollection": true
- },
- "historyRevisionReference": {
- "link": "https://localhost/mgmt/tm/asm/policies/0EHlYeS5noAOZLY3YsJjEw/history-revisions?ver=12.1.2",
- "isSubCollection": true
- },
- "policyBuilderReference": {
- "link": "https://localhost/mgmt/tm/asm/policies/0EHlYeS5noAOZLY3YsJjEw/policy-builder?ver=12.1.2"
- },
- "responsePageReference": {
- "link": "https://localhost/mgmt/tm/asm/policies/0EHlYeS5noAOZLY3YsJjEw/response-pages?ver=12.1.2",
- "isSubCollection": true
- },
- "vulnerabilityAssessmentReference": {
- "link": "https://localhost/mgmt/tm/asm/policies/0EHlYeS5noAOZLY3YsJjEw/vulnerability-assessment?ver=12.1.2"
- },
- "blockingSettingReference": {
- "link": "https://localhost/mgmt/tm/asm/policies/0EHlYeS5noAOZLY3YsJjEw/blocking-settings?ver=12.1.2",
- "isSubCollection": true
- },
- "cookieReference": {
- "link": "https://localhost/mgmt/tm/asm/policies/0EHlYeS5noAOZLY3YsJjEw/cookies?ver=12.1.2",
- "isSubCollection": true
- },
- "hostNameReference": {
- "link": "https://localhost/mgmt/tm/asm/policies/0EHlYeS5noAOZLY3YsJjEw/host-names?ver=12.1.2",
- "isSubCollection": true
- },
- "versionDeviceName": "ltm4restlab.lab.local",
- "selfLink": "https://localhost/mgmt/tm/asm/policies/0EHlYeS5noAOZLY3YsJjEw?ver=12.1.2",
- "signatureReference": {
- "link": "https://localhost/mgmt/tm/asm/policies/0EHlYeS5noAOZLY3YsJjEw/signatures?ver=12.1.2",
- "isSubCollection": true
- },
- "filetypeReference": {
- "link": "https://localhost/mgmt/tm/asm/policies/0EHlYeS5noAOZLY3YsJjEw/filetypes?ver=12.1.2",
- "isSubCollection": true
- },
- "id": "0EHlYeS5noAOZLY3YsJjEw",
- "manualVirtualServers": [],
- "modifierName": "",
- "versionDatetime": "2017-04-11T08:05:22Z",
- "subPath": "/Common",
- "sessionTrackingStatusReference": {
- "link": "https://localhost/mgmt/tm/asm/policies/0EHlYeS5noAOZLY3YsJjEw/session-tracking-statuses?ver=12.1.2",
- "isSubCollection": true
- },
- "active": false,
- "auditLogReference": {
- "link": "https://localhost/mgmt/tm/asm/policies/0EHlYeS5noAOZLY3YsJjEw/audit-logs?ver=12.1.2",
- "isSubCollection": true
- },
- "trustXff": false,
- "websocketUrlReference": {
- "link": "https://localhost/mgmt/tm/asm/policies/0EHlYeS5noAOZLY3YsJjEw/websocket-urls?ver=12.1.2",
- "isSubCollection": true
- },
- "xmlProfileReference": {
- "link": "https://localhost/mgmt/tm/asm/policies/0EHlYeS5noAOZLY3YsJjEw/xml-profiles?ver=12.1.2",
- "isSubCollection": true
- },
- "methodReference": {
- "link": "https://localhost/mgmt/tm/asm/policies/0EHlYeS5noAOZLY3YsJjEw/methods?ver=12.1.2",
- "isSubCollection": true
- },
- "redirectionProtectionReference": {
- "link": "https://localhost/mgmt/tm/asm/policies/0EHlYeS5noAOZLY3YsJjEw/redirection-protection?ver=12.1.2"
- },
- "vulnerabilityReference": {
- "link": "https://localhost/mgmt/tm/asm/policies/0EHlYeS5noAOZLY3YsJjEw/vulnerabilities?ver=12.1.2",
- "isSubCollection": true
- },
- "creatorName": "SYSTEM",
- "urlReference": {
- "link": "https://localhost/mgmt/tm/asm/policies/0EHlYeS5noAOZLY3YsJjEw/urls?ver=12.1.2",
- "isSubCollection": true
- },
- "headerReference": {
- "link": "https://localhost/mgmt/tm/asm/policies/0EHlYeS5noAOZLY3YsJjEw/headers?ver=12.1.2",
- "isSubCollection": true
- },
- "xmlValidationFileReference": {
- "link": "https://localhost/mgmt/tm/asm/policies/0EHlYeS5noAOZLY3YsJjEw/xml-validation-files?ver=12.1.2",
- "isSubCollection": true
- },
- "lastUpdateMicros": 0,
- "jsonProfileReference": {
- "link": "https://localhost/mgmt/tm/asm/policies/0EHlYeS5noAOZLY3YsJjEw/json-profiles?ver=12.1.2",
- "isSubCollection": true
- },
- "bruteForceAttackPreventionReference": {
- "link": "https://localhost/mgmt/tm/asm/policies/0EHlYeS5noAOZLY3YsJjEw/brute-force-attack-preventions?ver=12.1.2",
- "isSubCollection": true
- },
- "extractionReference": {
- "link": "https://localhost/mgmt/tm/asm/policies/0EHlYeS5noAOZLY3YsJjEw/extractions?ver=12.1.2",
- "isSubCollection": true
- },
- "characterSetReference": {
- "link": "https://localhost/mgmt/tm/asm/policies/0EHlYeS5noAOZLY3YsJjEw/character-sets?ver=12.1.2",
- "isSubCollection": true
- },
- "isModified": false,
- "suggestionReference": {
- "link": "https://localhost/mgmt/tm/asm/policies/0EHlYeS5noAOZLY3YsJjEw/suggestions?ver=12.1.2",
- "isSubCollection": true
- },
- "sensitiveParameterReference": {
- "link": "https://localhost/mgmt/tm/asm/policies/0EHlYeS5noAOZLY3YsJjEw/sensitive-parameters?ver=12.1.2",
- "isSubCollection": true
- },
- "versionPolicyName": "/Common/fake_policy"
-}
diff --git a/test/units/modules/network/f5/fixtures/load_auth_remote_role_role_info_1.json b/test/units/modules/network/f5/fixtures/load_auth_remote_role_role_info_1.json
deleted file mode 100644
index b4d6038ef8..0000000000
--- a/test/units/modules/network/f5/fixtures/load_auth_remote_role_role_info_1.json
+++ /dev/null
@@ -1,16 +0,0 @@
-{
- "kind": "tm:auth:remote-role:role-info:role-infostate",
- "name": "/Common/ldap_group",
- "fullPath": "/Common/ldap_group",
- "generation": 0,
- "selfLink": "https://localhost/mgmt/tm/auth/remote-role/role-info/~Common~ldap_group?ver=13.1.0.7",
- "attribute": "memberOf=cn=ldap_group,cn=ldap.group,ou=ldap",
- "console": "disable",
- "deny": "enabled",
- "lineOrder": 1,
- "role": "firewallmanager",
- "userPartition": "All",
- "userPartitionReference": {
- "link": "https://localhost/mgmt/tm/auth/partition/All?ver=13.1.0.7"
- }
-}
diff --git a/test/units/modules/network/f5/fixtures/load_auth_user_no_pass.json b/test/units/modules/network/f5/fixtures/load_auth_user_no_pass.json
deleted file mode 100644
index 79a51a79dd..0000000000
--- a/test/units/modules/network/f5/fixtures/load_auth_user_no_pass.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "kind": "tm:auth:user:userstate",
- "name": "someuser",
- "fullPath": "someuser",
- "generation": 76,
- "selfLink": "https://localhost/mgmt/tm/auth/user/someuser?ver=13.0.0",
- "description": "someuser",
- "encryptedPassword": "!!",
- "partitionAccess": [
- {
- "name": "Common",
- "role": "guest",
- "nameReference": {
- "link": "https://localhost/mgmt/tm/auth/partition/Common?ver=13.0.0"
- }
- }
- ]
-}
diff --git a/test/units/modules/network/f5/fixtures/load_auth_user_with_pass.json b/test/units/modules/network/f5/fixtures/load_auth_user_with_pass.json
deleted file mode 100644
index 8c8256c2ea..0000000000
--- a/test/units/modules/network/f5/fixtures/load_auth_user_with_pass.json
+++ /dev/null
@@ -1,19 +0,0 @@
-{
- "kind": "tm:auth:user:userstate",
- "name": "someuser",
- "fullPath": "someuser",
- "generation": 1,
- "selfLink": "https://localhost/mgmt/tm/auth/user/someuser?ver=13.0.0",
- "description": "someuser",
- "encryptedPassword": "$6$PiA0g2.L$M02nqo3eVvj22PbEUONdzFQq4tXp930FsBB0sZ94OJTDruobY/BhyEN1rHfw2udVKKlGtom1rNiCP/3nIVfde1",
- "shell": "bash",
- "partitionAccess": [
- {
- "name": "all-partitions",
- "role": "admin",
- "nameReference": {
- "link": "https://localhost/mgmt/tm/auth/partition/all-partitions?ver=13.0.0"
- }
- }
- ]
-}
diff --git a/test/units/modules/network/f5/fixtures/load_generic_parser.json b/test/units/modules/network/f5/fixtures/load_generic_parser.json
deleted file mode 100644
index c7bdc5fba9..0000000000
--- a/test/units/modules/network/f5/fixtures/load_generic_parser.json
+++ /dev/null
@@ -1,16 +0,0 @@
-{
- "kind": "tm:ltm:message-routing:generic:protocol:protocolstate",
- "name": "foobar",
- "partition": "Common",
- "fullPath": "/Common/foobar",
- "generation": 534,
- "selfLink": "https://localhost/mgmt/tm/ltm/message-routing/generic/protocol/~Common~foobar?ver=14.1.0.3",
- "defaultsFrom": "/Common/genericmsg",
- "defaultsFromReference": {
- "link": "https://localhost/mgmt/tm/ltm/message-routing/generic/protocol/~Common~genericmsg?ver=14.1.0.3"
- },
- "disableParser": "no",
- "maxEgressBuffer": 32768,
- "maxMessageSize": 32768,
- "noResponse": "no"
-}
diff --git a/test/units/modules/network/f5/fixtures/load_generic_peer.json b/test/units/modules/network/f5/fixtures/load_generic_peer.json
deleted file mode 100644
index bda5b8e587..0000000000
--- a/test/units/modules/network/f5/fixtures/load_generic_peer.json
+++ /dev/null
@@ -1,22 +0,0 @@
-{
- "kind": "tm:ltm:message-routing:generic:peer:peerstate",
- "name": "test",
- "partition": "Common",
- "fullPath": "/Common/test",
- "generation": 177,
- "selfLink": "https://localhost/mgmt/tm/ltm/message-routing/generic/peer/~Common~test?ver=14.1.0.3",
- "autoInitialization": "disabled",
- "autoInitializationInterval": 5000,
- "connectionMode": "per-peer",
- "description": "foobar",
- "numberConnections": 1,
- "pool": "/Common/example",
- "poolReference": {
- "link": "https://localhost/mgmt/tm/ltm/pool/~Common~example?ver=14.1.0.3"
- },
- "ratio": 1,
- "transportConfig": "/Common/test_tranport",
- "transportConfigReference": {
- "link": "https://localhost/mgmt/tm/ltm/message-routing/generic/transport-config/~Common~test_tranport?ver=14.1.0.3"
- }
-}
diff --git a/test/units/modules/network/f5/fixtures/load_generic_route.json b/test/units/modules/network/f5/fixtures/load_generic_route.json
deleted file mode 100644
index f8299f0294..0000000000
--- a/test/units/modules/network/f5/fixtures/load_generic_route.json
+++ /dev/null
@@ -1,19 +0,0 @@
-{
- "kind": "tm:ltm:message-routing:generic:route:routestate",
- "name": "some",
- "partition": "Common",
- "fullPath": "/Common/some",
- "generation": 228,
- "selfLink": "https://localhost/mgmt/tm/ltm/message-routing/generic/route/~Common~some?ver=14.1.0.3",
- "destinationAddress": "annoying_user",
- "peerSelectionMode": "sequential",
- "sourceAddress": "99.99.99.99",
- "peers": [
- "/Common/testy"
- ],
- "peersReference": [
- {
- "link": "https://localhost/mgmt/tm/ltm/message-routing/generic/peer/~Common~testy?ver=14.1.0.3"
- }
- ]
- }
diff --git a/test/units/modules/network/f5/fixtures/load_generic_router.json b/test/units/modules/network/f5/fixtures/load_generic_router.json
deleted file mode 100644
index 45c6722244..0000000000
--- a/test/units/modules/network/f5/fixtures/load_generic_router.json
+++ /dev/null
@@ -1,22 +0,0 @@
-{
- "kind": "tm:ltm:message-routing:generic:router:routerstate",
- "name": "messagerouter",
- "partition": "Common",
- "fullPath": "/Common/messagerouter",
- "generation": 1,
- "selfLink": "https://localhost/mgmt/tm/ltm/message-routing/generic/router/~Common~messagerouter?ver=14.1.0.3",
- "ignoreClientPort": "no",
- "inheritedTrafficGroup": "true",
- "iruleScopeMessage": "no",
- "maxPayloadPendingBytes": 32768,
- "maxPendingBytes": 23768,
- "maxPendingMessages": 64,
- "maxRetries": 1,
- "mirror": "disabled",
- "mirroredMessageSweeperInterval": 1000,
- "trafficGroup": "/Common/traffic-group-1",
- "trafficGroupReference": {
- "link": "https://localhost/mgmt/tm/cm/traffic-group/~Common~traffic-group-1?ver=14.1.0.3"
- },
- "useLocalConnection": "yes"
-}
diff --git a/test/units/modules/network/f5/fixtures/load_generic_transport_config.json b/test/units/modules/network/f5/fixtures/load_generic_transport_config.json
deleted file mode 100644
index 15121910cc..0000000000
--- a/test/units/modules/network/f5/fixtures/load_generic_transport_config.json
+++ /dev/null
@@ -1,53 +0,0 @@
-{
- "kind": "tm:ltm:message-routing:generic:transport-config:transport-configstate",
- "name": "gen1",
- "partition": "Common",
- "fullPath": "/Common/gen1",
- "generation": 643,
- "selfLink": "https://localhost/mgmt/tm/ltm/message-routing/generic/transport-config/~Common~gen1?expandSubcollections=true&ver=14.1.0.3",
- "ipProtocol": "tcp",
- "sourceAddressTranslation": {
- "pool": "/Common/test_snat",
- "poolReference": {
- "link": "https://localhost/mgmt/tm/ltm/snatpool/~Common~test_snat?ver=14.1.0.3"
- },
- "type": "snat"
- },
- "sourcePort": 0,
- "rules": [
- "/Common/test"
- ],
- "rulesReference": [
- {
- "link": "https://localhost/mgmt/tm/ltm/rule/~Common~test?ver=14.1.0.3"
- }
- ],
- "profilesReference": {
- "link": "https://localhost/mgmt/tm/ltm/message-routing/generic/transport-config/~Common~gen1/profiles?ver=14.1.0.3",
- "isSubcollection": true,
- "items": [
- {
- "kind": "tm:ltm:message-routing:generic:transport-config:profiles:profilesstate",
- "name": "diametersession",
- "partition": "Common",
- "fullPath": "/Common/diametersession",
- "generation": 626,
- "selfLink": "https://localhost/mgmt/tm/ltm/message-routing/generic/transport-config/~Common~gen1/profiles/~Common~diametersession?ver=14.1.0.3",
- "nameReference": {
- "link": "https://localhost/mgmt/tm/ltm/message-routing/diameter/profile/session/~Common~diametersession?ver=14.1.0.3"
- }
- },
- {
- "kind": "tm:ltm:message-routing:generic:transport-config:profiles:profilesstate",
- "name": "tcp",
- "partition": "Common",
- "fullPath": "/Common/tcp",
- "generation": 626,
- "selfLink": "https://localhost/mgmt/tm/ltm/message-routing/generic/transport-config/~Common~gen1/profiles/~Common~tcp?ver=14.1.0.3",
- "nameReference": {
- "link": "https://localhost/mgmt/tm/ltm/profile/tcp/~Common~tcp?ver=14.1.0.3"
- }
- }
- ]
- }
-}
diff --git a/test/units/modules/network/f5/fixtures/load_gtm_datacenter_default.json b/test/units/modules/network/f5/fixtures/load_gtm_datacenter_default.json
deleted file mode 100644
index 9e1f3b8d03..0000000000
--- a/test/units/modules/network/f5/fixtures/load_gtm_datacenter_default.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
- "kind": "tm:gtm:datacenter:datacenterstate",
- "name": "asd",
- "partition": "Common",
- "fullPath": "/Common/asd",
- "generation": 278,
- "selfLink": "https://localhost/mgmt/tm/gtm/datacenter/~Common~asd?ver=12.1.2",
- "enabled": true
-}
diff --git a/test/units/modules/network/f5/fixtures/load_gtm_datacenter_disabled.json b/test/units/modules/network/f5/fixtures/load_gtm_datacenter_disabled.json
deleted file mode 100644
index 8373ac8239..0000000000
--- a/test/units/modules/network/f5/fixtures/load_gtm_datacenter_disabled.json
+++ /dev/null
@@ -1,12 +0,0 @@
-{
- "kind": "tm:gtm:datacenter:datacenterstate",
- "name": "foo",
- "partition": "Common",
- "fullPath": "/Common/foo",
- "generation": 303,
- "selfLink": "https://localhost/mgmt/tm/gtm/datacenter/~Common~foo?ver=12.1.2",
- "contact": "admin@root.local",
- "description": "This is a foo description",
- "disabled": true,
- "location": "New York"
-}
diff --git a/test/units/modules/network/f5/fixtures/load_gtm_global_settings_general_1.json b/test/units/modules/network/f5/fixtures/load_gtm_global_settings_general_1.json
deleted file mode 100644
index 6803287627..0000000000
--- a/test/units/modules/network/f5/fixtures/load_gtm_global_settings_general_1.json
+++ /dev/null
@@ -1,25 +0,0 @@
-{
- "kind": "tm:gtm:global-settings:general:generalstate",
- "selfLink": "https://localhost/mgmt/tm/gtm/global-settings/general?ver=13.1.0.4",
- "autoDiscovery": "yes",
- "autoDiscoveryInterval": 30,
- "automaticConfigurationSaveTimeout": 15,
- "cacheLdnsServers": "yes",
- "domainNameCheck": "allow-underscore",
- "drainPersistentRequests": "yes",
- "forwardStatus": "disabled",
- "gtmSetsRecursion": "no",
- "heartbeatInterval": 10,
- "monitorDisabledObjects": "no",
- "nethsmTimeout": 20,
- "sendWildcardRrs": "disabled",
- "staticPersistCidrIpv4": 32,
- "staticPersistCidrIpv6": 128,
- "synchronization": "no",
- "synchronizationGroupName": "default",
- "synchronizationTimeTolerance": 10,
- "synchronizationTimeout": 180,
- "synchronizeZoneFiles": "no",
- "synchronizeZoneFilesTimeout": 300,
- "virtualsDependOnServerState": "yes"
-}
diff --git a/test/units/modules/network/f5/fixtures/load_gtm_irules.json b/test/units/modules/network/f5/fixtures/load_gtm_irules.json
deleted file mode 100644
index 7ca9da1bf7..0000000000
--- a/test/units/modules/network/f5/fixtures/load_gtm_irules.json
+++ /dev/null
@@ -1,20 +0,0 @@
-[
- {
- "kind": "tm:gtm:rule:rulestate",
- "name": "asdf",
- "partition": "Common",
- "fullPath": "/Common/asdf",
- "generation": 92,
- "selfLink": "https://localhost/mgmt/tm/gtm/rule/~Common~asdf?ver=12.1.2",
- "apiAnonymous": "when DNS_REQUEST {\n if { [IP::addr [IP::remote_addr] equals 10.254.254.0/24] } {\n cname test.affilate.example.com\n\n } elseif { [IP::addr [IP::remote_addr] equals 10.0.0.0/8] } {\n cname test.internal.example.com\n\n }\n #everything else will be handled by the default pools in the main WIP\n}"
- },
- {
- "kind": "tm:gtm:rule:rulestate",
- "name": "foo",
- "partition": "Common",
- "fullPath": "/Common/foo",
- "generation": 93,
- "selfLink": "https://localhost/mgmt/tm/gtm/rule/~Common~foo?ver=12.1.2",
- "apiAnonymous": "when LB_SELECTED {\n # Capture IP address chosen by WIP load balancing\n set wipHost [LB::server addr]\n}\n\nwhen LB_FAILED {\n set wipHost [LB::server addr]\n}"
- }
- ]
diff --git a/test/units/modules/network/f5/fixtures/load_gtm_monitor_firepass_1.json b/test/units/modules/network/f5/fixtures/load_gtm_monitor_firepass_1.json
deleted file mode 100644
index 4b0f8f7205..0000000000
--- a/test/units/modules/network/f5/fixtures/load_gtm_monitor_firepass_1.json
+++ /dev/null
@@ -1,19 +0,0 @@
-{
- "kind": "tm:gtm:monitor:firepass:firepassstate",
- "name": "foo",
- "partition": "Common",
- "fullPath": "/Common/foo",
- "generation": 0,
- "selfLink": "https://localhost/mgmt/tm/gtm/monitor/firepass/~Common~foo?ver=13.1.0.4",
- "cipherlist": "HIGH:!ADH",
- "concurrencyLimit": 95,
- "defaultsFrom": "/Common/firepass_gtm",
- "destination": "1.1.1.1:80",
- "ignoreDownResponse": "enabled",
- "interval": 30,
- "maxLoadAverage": 12,
- "password": "secret",
- "probeTimeout": 5,
- "timeout": 90,
- "username": "gtmuser"
-}
diff --git a/test/units/modules/network/f5/fixtures/load_gtm_monitor_http_1.json b/test/units/modules/network/f5/fixtures/load_gtm_monitor_http_1.json
deleted file mode 100644
index 98151e51fe..0000000000
--- a/test/units/modules/network/f5/fixtures/load_gtm_monitor_http_1.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
- "kind": "tm:gtm:monitor:http:httpstate",
- "name": "foo",
- "partition": "Common",
- "fullPath": "/Common/foo",
- "generation": 0,
- "selfLink": "https://localhost/mgmt/tm/gtm/monitor/http/~Common~foo?ver=13.1.0.4",
- "defaultsFrom": "/Common/http",
- "description": "my description",
- "destination": "3.3.3.3:8080",
- "ignoreDownResponse": "disabled",
- "interval": 30,
- "password": "secret",
- "probeTimeout": 5,
- "recv": "the receive string",
- "reverse": "enabled",
- "send": "GET /",
- "timeout": 120,
- "transparent": "enabled",
- "username": "user1"
-}
diff --git a/test/units/modules/network/f5/fixtures/load_gtm_monitor_tcp_1.json b/test/units/modules/network/f5/fixtures/load_gtm_monitor_tcp_1.json
deleted file mode 100644
index d0d90152c1..0000000000
--- a/test/units/modules/network/f5/fixtures/load_gtm_monitor_tcp_1.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "kind": "tm:gtm:monitor:tcp:tcpstate",
- "name": "foo",
- "partition": "Common",
- "fullPath": "/Common/foo",
- "generation": 0,
- "selfLink": "https://localhost/mgmt/tm/gtm/monitor/tcp/~Common~foo?ver=13.1.0.4",
- "defaultsFrom": "/Common/tcp",
- "destination": "1.1.1.1:80",
- "ignoreDownResponse": "disabled",
- "interval": 30,
- "probeTimeout": 5,
- "recv": "the receive string",
- "reverse": "enabled",
- "send": "the send string",
- "timeout": 120,
- "transparent": "enabled"
-}
diff --git a/test/units/modules/network/f5/fixtures/load_gtm_pool_a_collection.json b/test/units/modules/network/f5/fixtures/load_gtm_pool_a_collection.json
deleted file mode 100644
index 7ed5344503..0000000000
--- a/test/units/modules/network/f5/fixtures/load_gtm_pool_a_collection.json
+++ /dev/null
@@ -1,44 +0,0 @@
-{
- "kind": "tm:gtm:pool:a:acollectionstate",
- "selfLink": "https://localhost/mgmt/tm/gtm/pool/a?expandSubcollections=true&ver=13.0.0",
- "items": [
- {
- "kind": "tm:gtm:pool:a:astate",
- "name": "foo.pool",
- "partition": "Common",
- "fullPath": "/Common/foo.pool",
- "generation": 216,
- "selfLink": "https://localhost/mgmt/tm/gtm/pool/a/~Common~foo.pool?ver=13.0.0",
- "alternateMode": "round-robin",
- "dynamicRatio": "disabled",
- "enabled": true,
- "fallbackIp": "any",
- "fallbackMode": "return-to-dns",
- "limitMaxBps": 0,
- "limitMaxBpsStatus": "disabled",
- "limitMaxConnections": 0,
- "limitMaxConnectionsStatus": "disabled",
- "limitMaxPps": 0,
- "limitMaxPpsStatus": "disabled",
- "loadBalancingMode": "round-robin",
- "manualResume": "disabled",
- "maxAnswersReturned": 1,
- "monitor": "default",
- "qosHitRatio": 5,
- "qosHops": 0,
- "qosKilobytesSecond": 3,
- "qosLcs": 30,
- "qosPacketRate": 1,
- "qosRtt": 50,
- "qosTopology": 0,
- "qosVsCapacity": 0,
- "qosVsScore": 0,
- "ttl": 30,
- "verifyMemberAvailability": "enabled",
- "membersReference": {
- "link": "https://localhost/mgmt/tm/gtm/pool/a/~Common~foo.pool/members?ver=13.0.0",
- "isSubcollection": true
- }
- }
- ]
-}
diff --git a/test/units/modules/network/f5/fixtures/load_gtm_pool_a_default.json b/test/units/modules/network/f5/fixtures/load_gtm_pool_a_default.json
deleted file mode 100644
index f90a84b213..0000000000
--- a/test/units/modules/network/f5/fixtures/load_gtm_pool_a_default.json
+++ /dev/null
@@ -1,38 +0,0 @@
-{
- "kind": "tm:gtm:pool:a:astate",
- "name": "asdf",
- "partition": "Common",
- "fullPath": "/Common/asdf",
- "generation": 94,
- "selfLink": "https://localhost/mgmt/tm/gtm/pool/a/~Common~asdf?ver=12.1.2",
- "alternateMode": "round-robin",
- "dynamicRatio": "disabled",
- "enabled": true,
- "fallbackIp": "any",
- "fallbackMode": "return-to-dns",
- "limitMaxBps": 0,
- "limitMaxBpsStatus": "disabled",
- "limitMaxConnections": 0,
- "limitMaxConnectionsStatus": "disabled",
- "limitMaxPps": 0,
- "limitMaxPpsStatus": "disabled",
- "loadBalancingMode": "round-robin",
- "manualResume": "disabled",
- "maxAnswersReturned": 1,
- "monitor": "default",
- "qosHitRatio": 5,
- "qosHops": 0,
- "qosKilobytesSecond": 3,
- "qosLcs": 30,
- "qosPacketRate": 1,
- "qosRtt": 50,
- "qosTopology": 0,
- "qosVsCapacity": 0,
- "qosVsScore": 0,
- "ttl": 30,
- "verifyMemberAvailability": "enabled",
- "membersReference": {
- "link": "https://localhost/mgmt/tm/gtm/pool/a/~Common~asdf/members?ver=12.1.2",
- "isSubcollection": true
- }
-}
diff --git a/test/units/modules/network/f5/fixtures/load_gtm_pool_a_example_stats.json b/test/units/modules/network/f5/fixtures/load_gtm_pool_a_example_stats.json
deleted file mode 100644
index 70388c9144..0000000000
--- a/test/units/modules/network/f5/fixtures/load_gtm_pool_a_example_stats.json
+++ /dev/null
@@ -1,48 +0,0 @@
-{
- "kind": "tm:gtm:pool:a:astats",
- "generation": 216,
- "selfLink": "https://localhost/mgmt/tm/gtm/pool/a/~Common~foo.pool/stats?ver=13.0.0",
- "entries": {
- "https://localhost/mgmt/tm/gtm/pool/a/~Common~foo.pool/~Common~foo.pool:A/stats": {
- "nestedStats": {
- "kind": "tm:gtm:pool:a:astats",
- "selfLink": "https://localhost/mgmt/tm/gtm/pool/a/~Common~foo.pool/~Common~foo.pool:A/stats?ver=13.0.0",
- "entries": {
- "alternate": {
- "value": 0
- },
- "dropped": {
- "value": 0
- },
- "fallback": {
- "value": 0
- },
- "tmName": {
- "description": "/Common/foo.pool"
- },
- "poolType": {
- "description": "A"
- },
- "preferred": {
- "value": 0
- },
- "returnFromDns": {
- "value": 0
- },
- "returnToDns": {
- "value": 0
- },
- "status.availabilityState": {
- "description": "offline"
- },
- "status.enabledState": {
- "description": "enabled"
- },
- "status.statusReason": {
- "description": "No enabled pool members available"
- }
- }
- }
- }
- }
-}
diff --git a/test/units/modules/network/f5/fixtures/load_gtm_pool_a_member_1.json b/test/units/modules/network/f5/fixtures/load_gtm_pool_a_member_1.json
deleted file mode 100644
index 44ae64a665..0000000000
--- a/test/units/modules/network/f5/fixtures/load_gtm_pool_a_member_1.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "kind": "tm:gtm:pool:a:members:membersstate",
- "name": "foo_gtm_server:bar",
- "partition": "Common",
- "fullPath": "/Common/foo_gtm_server:bar",
- "generation": 398,
- "selfLink": "https://localhost/mgmt/tm/gtm/pool/a/~Common~foo-pool/members/~Common~foo_gtm_server:bar?ver=13.0.0",
- "enabled": true,
- "limitMaxBps": 0,
- "limitMaxBpsStatus": "disabled",
- "limitMaxConnections": 0,
- "limitMaxConnectionsStatus": "disabled",
- "limitMaxPps": 0,
- "limitMaxPpsStatus": "disabled",
- "memberOrder": 1,
- "monitor": "default",
- "ratio": 1
-}
diff --git a/test/units/modules/network/f5/fixtures/load_gtm_pool_a_with_members_1.json b/test/units/modules/network/f5/fixtures/load_gtm_pool_a_with_members_1.json
deleted file mode 100644
index ba2ac716f0..0000000000
--- a/test/units/modules/network/f5/fixtures/load_gtm_pool_a_with_members_1.json
+++ /dev/null
@@ -1,94 +0,0 @@
-{
- "kind": "tm:gtm:pool:a:astate",
- "name": "foo",
- "partition": "Common",
- "fullPath": "/Common/foo",
- "generation": 142,
- "selfLink": "https://localhost/mgmt/tm/gtm/pool/a/~Common~foo?expandSubcollections=true&ver=12.0.0",
- "alternateMode": "round-robin",
- "dynamicRatio": "disabled",
- "enabled": true,
- "fallbackIp": "any",
- "fallbackMode": "return-to-dns",
- "limitMaxBps": 0,
- "limitMaxBpsStatus": "disabled",
- "limitMaxConnections": 0,
- "limitMaxConnectionsStatus": "disabled",
- "limitMaxPps": 0,
- "limitMaxPpsStatus": "disabled",
- "loadBalancingMode": "round-robin",
- "manualResume": "disabled",
- "maxAnswersReturned": 1,
- "monitor": "default",
- "qosHitRatio": 5,
- "qosHops": 0,
- "qosKilobytesSecond": 3,
- "qosLcs": 30,
- "qosPacketRate": 1,
- "qosRtt": 50,
- "qosTopology": 0,
- "qosVsCapacity": 0,
- "qosVsScore": 0,
- "ttl": 30,
- "verifyMemberAvailability": "enabled",
- "membersReference": {
- "link": "https://localhost/mgmt/tm/gtm/pool/a/~Common~foo/members?ver=12.0.0",
- "isSubcollection": true,
- "items": [
- {
- "kind": "tm:gtm:pool:a:members:membersstate",
- "name": "server1:vs1",
- "partition": "Common",
- "fullPath": "/Common/server1:vs1",
- "generation": 141,
- "selfLink": "https://localhost/mgmt/tm/gtm/pool/a/~Common~foo/members/~Common~server1:vs1?ver=12.0.0",
- "enabled": true,
- "limitMaxBps": 0,
- "limitMaxBpsStatus": "disabled",
- "limitMaxConnections": 0,
- "limitMaxConnectionsStatus": "disabled",
- "limitMaxPps": 0,
- "limitMaxPpsStatus": "disabled",
- "memberOrder": 0,
- "monitor": "default",
- "ratio": 1
- },
- {
- "kind": "tm:gtm:pool:a:members:membersstate",
- "name": "server1:vs2",
- "partition": "Common",
- "fullPath": "/Common/server1:vs2",
- "generation": 142,
- "selfLink": "https://localhost/mgmt/tm/gtm/pool/a/~Common~foo/members/~Common~server1:vs1?ver=12.0.0",
- "enabled": true,
- "limitMaxBps": 0,
- "limitMaxBpsStatus": "disabled",
- "limitMaxConnections": 0,
- "limitMaxConnectionsStatus": "disabled",
- "limitMaxPps": 0,
- "limitMaxPpsStatus": "disabled",
- "memberOrder": 1,
- "monitor": "/Common/tcp ",
- "ratio": 1
- },
- {
- "kind": "tm:gtm:pool:a:members:membersstate",
- "name": "server1:vs3",
- "partition": "Common",
- "fullPath": "/Common/server1:vs3",
- "generation": 141,
- "selfLink": "https://localhost/mgmt/tm/gtm/pool/a/~Common~foo/members/~Common~server1:vs3?ver=12.0.0",
- "enabled": true,
- "limitMaxBps": 0,
- "limitMaxBpsStatus": "disabled",
- "limitMaxConnections": 0,
- "limitMaxConnectionsStatus": "disabled",
- "limitMaxPps": 0,
- "limitMaxPpsStatus": "disabled",
- "memberOrder": 2,
- "monitor": "default",
- "ratio": 1
- }
- ]
- }
-}
diff --git a/test/units/modules/network/f5/fixtures/load_gtm_pool_untyped_default.json b/test/units/modules/network/f5/fixtures/load_gtm_pool_untyped_default.json
deleted file mode 100644
index c4ecb1dd13..0000000000
--- a/test/units/modules/network/f5/fixtures/load_gtm_pool_untyped_default.json
+++ /dev/null
@@ -1,39 +0,0 @@
-{
- "kind": "tm:gtm:pool:poolstate",
- "name": "asdf",
- "partition": "Common",
- "fullPath": "/Common/asdf",
- "generation": 92,
- "selfLink": "https://localhost/mgmt/tm/gtm/pool/~Common~asdf?ver=11.6.1",
- "alternateMode": "round-robin",
- "dynamicRatio": "disabled",
- "enabled": true,
- "fallbackIpv4": "any",
- "fallbackIpv6": "any6",
- "fallbackMode": "return-to-dns",
- "limitMaxBps": 0,
- "limitMaxBpsStatus": "disabled",
- "limitMaxConnections": 0,
- "limitMaxConnectionsStatus": "disabled",
- "limitMaxPps": 0,
- "limitMaxPpsStatus": "disabled",
- "loadBalancingMode": "round-robin",
- "manualResume": "disabled",
- "maxAddressReturned": 1,
- "monitor": "default",
- "qosHitRatio": 5,
- "qosHops": 0,
- "qosKilobytesSecond": 3,
- "qosLcs": 30,
- "qosPacketRate": 1,
- "qosRtt": 50,
- "qosTopology": 0,
- "qosVsCapacity": 0,
- "qosVsScore": 0,
- "ttl": 30,
- "verifyMemberAvailability": "enabled",
- "membersReference": {
- "link": "https://localhost/mgmt/tm/gtm/pool/~Common~asdf/members?ver=11.6.1",
- "isSubcollection": true
- }
-}
diff --git a/test/units/modules/network/f5/fixtures/load_gtm_server_1.json b/test/units/modules/network/f5/fixtures/load_gtm_server_1.json
deleted file mode 100644
index 4a14d9f27e..0000000000
--- a/test/units/modules/network/f5/fixtures/load_gtm_server_1.json
+++ /dev/null
@@ -1,68 +0,0 @@
-{
- "kind": "tm:gtm:server:serverstate",
- "name": "baz",
- "partition": "Common",
- "fullPath": "/Common/baz",
- "generation": 270,
- "selfLink": "https://localhost/mgmt/tm/gtm/server/~Common~baz?ver=13.0.0",
- "datacenter": "/Common/foo",
- "datacenterReference": {
- "link": "https://localhost/mgmt/tm/gtm/datacenter/~Common~foo?ver=13.0.0"
- },
- "enabled": true,
- "exposeRouteDomains": "no",
- "iqAllowPath": "yes",
- "iqAllowServiceCheck": "yes",
- "iqAllowSnmp": "yes",
- "limitCpuUsage": 0,
- "limitCpuUsageStatus": "disabled",
- "limitMaxBps": 0,
- "limitMaxBpsStatus": "disabled",
- "limitMaxConnections": 0,
- "limitMaxConnectionsStatus": "disabled",
- "limitMaxPps": 0,
- "limitMaxPpsStatus": "disabled",
- "limitMemAvail": 0,
- "limitMemAvailStatus": "disabled",
- "linkDiscovery": "disabled",
- "monitor": "/Common/bigip ",
- "proberFallback": "inherit",
- "proberPreference": "inherit",
- "product": "bigip",
- "virtualServerDiscovery": "disabled",
- "addresses": [
- {
- "name": "1.1.1.1",
- "deviceName": "bigip1",
- "translation": "10.10.10.10"
- },
- {
- "name": "2.2.2.2",
- "deviceName": "bigip2",
- "translation": "20.20.20.20"
- },
- {
- "name": "3.3.3.3",
- "deviceName": "bigip2",
- "translation": "20.20.20.20"
- },
- {
- "name": "4.4.4.4",
- "deviceName": "bigip3",
- "translation": "none"
- },
- {
- "name": "5.5.5.5",
- "deviceName": "bigip3",
- "translation": "none"
- }
- ],
- "devicesReference": {
- "link": "https://localhost/mgmt/tm/gtm/server/~Common~baz/devices?ver=13.0.0",
- "isSubcollection": true
- },
- "virtualServersReference": {
- "link": "https://localhost/mgmt/tm/gtm/server/~Common~baz/virtual-servers?ver=13.0.0",
- "isSubcollection": true
- }
-}
diff --git a/test/units/modules/network/f5/fixtures/load_gtm_server_virtual_2.json b/test/units/modules/network/f5/fixtures/load_gtm_server_virtual_2.json
deleted file mode 100644
index 336c391b1b..0000000000
--- a/test/units/modules/network/f5/fixtures/load_gtm_server_virtual_2.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "kind": "tm:gtm:server:virtual-servers:virtual-serversstate",
- "name": "vs2",
- "fullPath": "vs2",
- "generation": 129,
- "selfLink": "https://localhost/mgmt/tm/gtm/server/~Common~server1/virtual-servers/vs2?ver=13.0.0",
- "destination": "6.6.6.6:8080",
- "enabled": true,
- "limitMaxBps": 100,
- "limitMaxBpsStatus": "enabled",
- "limitMaxConnections": 300,
- "limitMaxConnectionsStatus": "enabled",
- "limitMaxPps": 200,
- "limitMaxPpsStatus": "enabled",
- "monitor": "/Common/gtp ",
- "translationAddress": "none",
- "translationPort": 0
-}
diff --git a/test/units/modules/network/f5/fixtures/load_gtm_wide_ip_with_pools.json b/test/units/modules/network/f5/fixtures/load_gtm_wide_ip_with_pools.json
deleted file mode 100644
index a7be079cdd..0000000000
--- a/test/units/modules/network/f5/fixtures/load_gtm_wide_ip_with_pools.json
+++ /dev/null
@@ -1,30 +0,0 @@
-{
- "kind": "tm:gtm:wideip:a:astate",
- "name": "foo.bar.com",
- "partition": "Common",
- "fullPath": "/Common/foo.bar.com",
- "generation": 135,
- "selfLink": "https://localhost/mgmt/tm/gtm/wideip/a/~Common~foo.bar.com?ver=13.0.0",
- "enabled": true,
- "failureRcode": "noerror",
- "failureRcodeResponse": "disabled",
- "failureRcodeTtl": 0,
- "lastResortPool": "",
- "minimalResponse": "enabled",
- "persistCidrIpv4": 32,
- "persistCidrIpv6": 128,
- "persistence": "disabled",
- "poolLbMode": "round-robin",
- "ttlPersistence": 3600,
- "pools": [
- {
- "name": "baz",
- "partition": "Common",
- "order": 0,
- "ratio": 10,
- "nameReference": {
- "link": "https://localhost/mgmt/tm/gtm/pool/a/~Common~baz?ver=13.0.0"
- }
- }
- ]
-}
diff --git a/test/units/modules/network/f5/fixtures/load_imish_output_1.json b/test/units/modules/network/f5/fixtures/load_imish_output_1.json
deleted file mode 100644
index a2b72a2a7a..0000000000
--- a/test/units/modules/network/f5/fixtures/load_imish_output_1.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "kind": "tm:util:bash:runstate",
- "command": "run",
- "utilCmdArgs": "-c 'imish -r 0 -e \"show running-config\"'",
- "commandResult": "!\nno service password-encryption\n!\nline con 0\n login\nline vty 0 39\n login\n!\nend\n\n"
-}
diff --git a/test/units/modules/network/f5/fixtures/load_ltm_dns_cache_resolver_1.json b/test/units/modules/network/f5/fixtures/load_ltm_dns_cache_resolver_1.json
deleted file mode 100644
index 5a0e9b75c4..0000000000
--- a/test/units/modules/network/f5/fixtures/load_ltm_dns_cache_resolver_1.json
+++ /dev/null
@@ -1,43 +0,0 @@
-{
- "kind": "tm:ltm:dns:cache:resolver:resolverstate",
- "name": "foo",
- "partition": "Common",
- "fullPath": "/Common/foo",
- "generation": 666,
- "selfLink": "https://localhost/mgmt/tm/ltm/dns/cache/resolver/~Common~foo?ver=13.1.0.7",
- "allowedQueryTime": 200,
- "answerDefaultZones": "no",
- "maxConcurrentQueries": 1024,
- "maxConcurrentTcp": 20,
- "maxConcurrentUdp": 8192,
- "msgCacheSize": 1048576,
- "nameserverCacheCount": 16536,
- "randomizeQueryNameCase": "yes",
- "routeDomain": "/Common/0",
- "routeDomainReference": {
- "link": "https://localhost/mgmt/tm/net/route-domain/~Common~0?ver=13.1.0.7"
- },
- "rrsetCacheSize": 10485760,
- "rrsetRotate": "none",
- "unwantedQueryReplyThreshold": 0,
- "useIpv4": "yes",
- "useIpv6": "yes",
- "useTcp": "yes",
- "useUdp": "yes",
- "forwardZones": [
- {
- "name": "foo1",
- "nameservers": [
- {
- "name": "1.1.1.1:53"
- },
- {
- "name": "2.2.2.2:53"
- }
- ]
- },
- {
- "name": "foo2"
- }
- ]
-}
diff --git a/test/units/modules/network/f5/fixtures/load_ltm_dns_nameserver_1.json b/test/units/modules/network/f5/fixtures/load_ltm_dns_nameserver_1.json
deleted file mode 100644
index e012103b00..0000000000
--- a/test/units/modules/network/f5/fixtures/load_ltm_dns_nameserver_1.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "kind": "tm:ltm:dns:nameserver:nameserverstate",
- "name": "foo",
- "partition": "Common",
- "fullPath": "/Common/foo",
- "generation": 8076,
- "selfLink": "https://localhost/mgmt/tm/ltm/dns/nameserver/~Common~foo?ver=13.1.0.7",
- "address": "127.0.0.1",
- "port": 53,
- "routeDomain": "/Common/0",
- "routeDomainReference": {
- "link": "https://localhost/mgmt/tm/net/route-domain/~Common~0?ver=13.1.0.7"
- },
- "tsigKey": "/Common/key1",
- "tsigKeyReference": {
- "link": "https://localhost/mgmt/tm/ltm/dns/tsig-key/~Common~key1?ver=13.1.0.7"
- }
-}
diff --git a/test/units/modules/network/f5/fixtures/load_ltm_dns_zone_1.json b/test/units/modules/network/f5/fixtures/load_ltm_dns_zone_1.json
deleted file mode 100644
index 686de99bc1..0000000000
--- a/test/units/modules/network/f5/fixtures/load_ltm_dns_zone_1.json
+++ /dev/null
@@ -1,31 +0,0 @@
-{
- "kind": "tm:ltm:dns:zone:zonestate",
- "name": "foo",
- "partition": "Common",
- "fullPath": "/Common/foo",
- "generation": 812,
- "selfLink": "https://localhost/mgmt/tm/ltm/dns/zone/~Common~foo?ver=13.1.0.8",
- "dnsExpressAllowNotify": [
- "1.1.1.1"
- ],
- "dnsExpressEnabled": "yes",
- "dnsExpressNotifyAction": "consume",
- "dnsExpressNotifyTsigVerify": "yes",
- "dnsExpressServer": "/Common/asd",
- "dnsExpressServerReference": {
- "link": "https://localhost/mgmt/tm/ltm/dns/nameserver/~Common~asd?ver=13.1.0.8"
- },
- "responsePolicy": "no",
- "serverTsigKey": "/Common/asd",
- "serverTsigKeyReference": {
- "link": "https://localhost/mgmt/tm/ltm/dns/tsig-key/~Common~asd?ver=13.1.0.8"
- },
- "transferClients": [
- "/Common/asd"
- ],
- "transferClientsReference": [
- {
- "link": "https://localhost/mgmt/tm/ltm/dns/nameserver/~Common~asd?ver=13.1.0.8"
- }
- ]
-}
diff --git a/test/units/modules/network/f5/fixtures/load_ltm_fastl4_profile_1.json b/test/units/modules/network/f5/fixtures/load_ltm_fastl4_profile_1.json
deleted file mode 100644
index 2667968c55..0000000000
--- a/test/units/modules/network/f5/fixtures/load_ltm_fastl4_profile_1.json
+++ /dev/null
@@ -1,56 +0,0 @@
-{
- "kind": "tm:ltm:profile:fastl4:fastl4state",
- "name": "fastL4",
- "partition": "Common",
- "fullPath": "/Common/fastL4",
- "generation": 1,
- "selfLink": "https://localhost/mgmt/tm/ltm/profile/fastl4/~Common~fastL4?ver=13.1.0.8",
- "appService": "none",
- "clientTimeout": 30,
- "defaultsFrom": "none",
- "description": "none",
- "explicitFlowMigration": "disabled",
- "hardwareSynCookie": "disabled",
- "idleTimeout": "300",
- "ipDfMode": "preserve",
- "ipTosToClient": "pass-through",
- "ipTosToServer": "pass-through",
- "ipTtlMode": "decrement",
- "ipTtlV4": 255,
- "ipTtlV6": 64,
- "keepAliveInterval": "disabled",
- "lateBinding": "disabled",
- "linkQosToClient": "pass-through",
- "linkQosToServer": "pass-through",
- "looseClose": "disabled",
- "looseInitialization": "disabled",
- "mssOverride": 0,
- "priorityToClient": "pass-through",
- "priorityToServer": "pass-through",
- "pvaAcceleration": "full",
- "pvaDynamicClientPackets": 1,
- "pvaDynamicServerPackets": 0,
- "pvaFlowAging": "enabled",
- "pvaFlowEvict": "enabled",
- "pvaOffloadDynamic": "enabled",
- "pvaOffloadState": "embryonic",
- "reassembleFragments": "disabled",
- "receiveWindowSize": 0,
- "resetOnTimeout": "enabled",
- "rttFromClient": "disabled",
- "rttFromServer": "disabled",
- "serverSack": "disabled",
- "serverTimestamp": "disabled",
- "softwareSynCookie": "disabled",
- "synCookieEnable": "enabled",
- "synCookieMss": 0,
- "synCookieWhitelist": "disabled",
- "tcpCloseTimeout": "5",
- "tcpGenerateIsn": "disabled",
- "tcpHandshakeTimeout": "5",
- "tcpStripSack": "disabled",
- "tcpTimeWaitTimeout": 0,
- "tcpTimestampMode": "preserve",
- "tcpWscaleMode": "preserve",
- "timeoutRecovery": "disconnect"
-}
diff --git a/test/units/modules/network/f5/fixtures/load_ltm_http2_profile.json b/test/units/modules/network/f5/fixtures/load_ltm_http2_profile.json
deleted file mode 100644
index 3d8c9bce3c..0000000000
--- a/test/units/modules/network/f5/fixtures/load_ltm_http2_profile.json
+++ /dev/null
@@ -1,27 +0,0 @@
-{
- "kind": "tm:ltm:profile:http2:http2state",
- "name": "test",
- "partition": "Common",
- "fullPath": "/Common/test",
- "generation": 5852,
- "selfLink": "https://localhost/mgmt/tm/ltm/profile/http2/~Common~test?ver=13.1.0.8",
- "activationModes": [
- "always"
- ],
- "appService": "none",
- "concurrentStreamsPerConnection": 10,
- "connectionIdleTimeout": 300,
- "defaultsFrom": "/Common/http2",
- "defaultsFromReference": {
- "link": "https://localhost/mgmt/tm/ltm/profile/http2/~Common~http2?ver=13.1.0.8"
- },
- "description": "this is awful documentation",
- "enforceTlsRequirements": "enabled",
- "frameSize": 2048,
- "headerTableSize": 4096,
- "includeContentLength": "disabled",
- "insertHeader": "disabled",
- "insertHeaderName": "X-HTTP2",
- "receiveWindow": 32,
- "writeSize": 16384
-}
diff --git a/test/units/modules/network/f5/fixtures/load_ltm_http_profile_1.json b/test/units/modules/network/f5/fixtures/load_ltm_http_profile_1.json
deleted file mode 100644
index 0d8f83c706..0000000000
--- a/test/units/modules/network/f5/fixtures/load_ltm_http_profile_1.json
+++ /dev/null
@@ -1,81 +0,0 @@
-{
- "kind": "tm:ltm:profile:http:httpstate",
- "name": "http",
- "partition": "Common",
- "fullPath": "/Common/http",
- "generation": 1405,
- "selfLink": "https://localhost/mgmt/tm/ltm/profile/http/~Common~http?ver=13.1.0.6",
- "acceptXff": "disabled",
- "appService": "none",
- "basicAuthRealm": "none",
- "defaultsFrom": "none",
- "description": "none",
- "encryptCookies": [],
- "enforcement": {
- "excessClientHeaders": "reject",
- "excessServerHeaders": "reject",
- "knownMethods": [
- "CONNECT",
- "DELETE",
- "GET",
- "HEAD",
- "LOCK",
- "OPTIONS",
- "POST",
- "PROPFIND",
- "PUT",
- "TRACE",
- "UNLOCK"
- ],
- "maxHeaderCount": 64,
- "maxHeaderSize": 32768,
- "maxRequests": 0,
- "oversizeClientHeaders": "reject",
- "oversizeServerHeaders": "reject",
- "pipeline": "allow",
- "truncatedRedirects": "disabled",
- "unknownMethod": "allow"
- },
- "explicitProxy": {
- "badRequestMessage": "none",
- "badResponseMessage": "none",
- "connectErrorMessage": "none",
- "defaultConnectHandling": "deny",
- "dnsErrorMessage": "none",
- "dnsResolver": "none",
- "hostNames": [],
- "ipv6": "no",
- "routeDomain": "none",
- "tunnelName": "none"
- },
- "fallbackHost": "none",
- "fallbackStatusCodes": [],
- "headerErase": "none",
- "headerInsert": "none",
- "hsts": {
- "includeSubdomains": "enabled",
- "maximumAge": 16070400,
- "mode": "disabled",
- "preload": "disabled"
- },
- "insertXforwardedFor": "disabled",
- "lwsSeparator": "none",
- "lwsWidth": 80,
- "oneconnectTransformations": "enabled",
- "proxyType": "reverse",
- "redirectRewrite": "none",
- "requestChunking": "preserve",
- "responseChunking": "selective",
- "responseHeadersPermitted": [],
- "serverAgentName": "BigIP",
- "sflow": {
- "pollInterval": 0,
- "pollIntervalGlobal": "yes",
- "samplingRate": 0,
- "samplingRateGlobal": "yes"
- },
- "viaHostName": "none",
- "viaRequest": "preserve",
- "viaResponse": "preserve",
- "xffAlternativeNames": []
-}
diff --git a/test/units/modules/network/f5/fixtures/load_ltm_irules.json b/test/units/modules/network/f5/fixtures/load_ltm_irules.json
deleted file mode 100644
index b3e026a120..0000000000
--- a/test/units/modules/network/f5/fixtures/load_ltm_irules.json
+++ /dev/null
@@ -1,179 +0,0 @@
-[
- {
- "kind": "tm:ltm:rule:rulestate",
- "name": "_sys_APM_ExchangeSupport_OA_BasicAuth",
- "partition": "Common",
- "fullPath": "/Common/_sys_APM_ExchangeSupport_OA_BasicAuth",
- "generation": 1,
- "selfLink": "https://localhost/mgmt/tm/ltm/rule/~Common~_sys_APM_ExchangeSupport_OA_BasicAuth?ver=12.1.2",
- "apiAnonymous": "nodelete nowrite \n # Global variables\n # static::POLICY_RESULT_CACHE_AUTHFAILED\n # Administrator can set this into 1, when there is a necessity to cache failed policy result.\n # This may be needed to avoid account locked caused by the Active Sync device when it uses wrong passwords.\n # One possible scenario, is that when the user changes the password in Active Directory, but missed to changed in their devices.\n # Responses\n # On denied result\n # Administrator can customize the responses to the device depends on more complex conditions when necessary.\n # In those cases, please use ACCESS::respond command.\n # The following is the syntax of ACCESS::respond\n # ACCESS::respond <status code> [ content <body> ] [ <Additional Header> <Additional Header value>* ]\n # e.g. ACCESS::respond 401 content \"Error: Denied\" WWW-Authenticate \"basic realm=\\\"f5.com\\\"\" Connection close\n when RULE_INIT {\n # Please set the following global variables for customized responses.\n set static::actsync_401_http_body \"<html><title>Authentication Failured</title><body>Error: Authentication Failure</body></html>\"\n set static::actsync_503_http_body \"<html><title>Service is not available</title><body>Error: Service is not available</body></html>\"\n set static::ACCESS_LOG_PREFIX \"01490000:7:\"\n\n # Second Virtual Server name for 401 NTLM responder\n set static::ACCESS_SECOND_VIRTUAL_NAME \"_ACCESS_401_NTLM_responder_HTTPS\"\n\n set static::POLICY_INPROGRESS \"policy_inprogress\"\n set static::POLICY_AUTHFAILED \"policy_authfailed\"\n # The request with huge content length can not be used for starting ACCESS session.\n # This kind of request will be put on hold, and this iRule will try to use another\n # request to start the session. The following value is used for Outlook Anywhere.\n set static::OA_MAGIC_CONTENT_LEN 1073741824\n\n # Similar with OutlookAnywhere case, ACCESS can not use the request which is\n # larger then following size. This becomes an issue with application that using\n # Exchange Web Service as its main protocol such as Mac OS X applications\n # (e.g. Mail app, Microsoft Entourage, etc)\n # This kind of request will be put on hold, and this iRule will try to use another\n # request to start the session.\n set static::FIRST_BIG_POST_CONTENT_LEN 640000\n\n # Set it into 1 if the backend EWS handler accepts HTTP Basic Authentication.\n set static::EWS_BKEND_BASIC_AUTH 0\n # The following variable controls the polling mechanism.\n set static::POLICY_RESULT_POLL_INTERVAL 250\n set static::POLICY_RESULT_POLL_MAXRETRYCYCLE 600\n\n # Set this global variable to 1 for caching authentication failure\n # Useful for avoiding account locked out.\n set static::POLICY_RESULT_CACHE_AUTHFAILED 0\n\n # set this global variable to set alternative timeout for particular session\n set static::POLICY_ALT_INACTIVITY_TIMEOUT 120\n\n set static::ACCESS_USERKEY_TBLNAME \"_access_userkey\"\n\n\n set static::ACCESS_DEL_COOKIE_HDR_VAL \"MRHSession=deleted; expires=Thu, 01-Jan-1970 00:00:01 GMT; path=/\"\n\n log -noname accesscontrol.local1.debug \"01490000:7: EWS_BKEND_BASIC_AUTH = $static::EWS_BKEND_BASIC_AUTH\"\n }\n when ACCESS_ACL_ALLOWED {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX [HTTP::method] [HTTP::uri] [HTTP::header Content-Length]\"\n\n # MSFT Exchange's EWS request handler always requesting NTLM even the connection has been\n # already authenticated if there is a HTTP Basic Auth in the request.\n if { [ info exists f_exchange_web_service ] && $f_exchange_web_service == 1 } {\n if { $static::EWS_BKEND_BASIC_AUTH == 0 } {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Removing HTTP Basic Authorization header\"\n HTTP::header remove Authorization\n }\n }\n }\n\n when HTTP_REQUEST {\n set http_path [ string tolower [HTTP::path] ]\n set f_clientless_mode 0\n set f_alt_inactivity_timeout 0\n set f_rpc_over_http 0\n set f_exchange_web_service 0\n set f_auto_discover 0\n set f_activesync 0\n set f_offline_address_book 0\n set f_availability_service 0\n\n # Here put appropriate pool when necessary.\n switch -glob $http_path {\n \"/rpc/rpcproxy.dll\" {\n # Supports for RPC over HTTP. (Outlook Anywhere)\n set f_rpc_over_http 1\n }\n \"/autodiscover/autodiscover.xml\" {\n # Supports for Auto Discover protocol.\n set f_auto_discover 1\n # This request does not require long inactivity timeout.\n # Don't use this for now\n set f_alt_inactivity_timeout 0\n }\n \"/microsoft-server-activesync\" {\n # Supports for ActiveSync\n set f_activesync 1\n }\n \"/oab/*\" {\n # Supports for Offline Address Book\n set f_offline_address_book 1\n # Don't use this for now\n set f_alt_inactivity_timeout 0\n }\n \"/ews/*\" {\n # Support for Exchange Web Service\n # Outlook's Availability Service borrows this protocol.\n set f_exchange_web_service 1\n }\n \"/as/*\" {\n # Support for Availability Service.\n # do nothing for now. (Untested)\n set f_availability_service 1\n }\n default {\n return\n }\n }\n\n set f_reqside_set_sess_id 0\n set http_method [HTTP::method]\n set http_hdr_host [HTTP::host]\n set http_hdr_uagent [HTTP::header User-Agent]\n set http_uri [HTTP::uri]\n set http_content_len [HTTP::header Content-Length]\n set MRHSession_cookie [HTTP::cookie value MRHSession]\n set auth_info_b64enc \"\"\n\n if { ! [ info exists src_ip ] } {\n set src_ip [IP::remote_addr]\n }\n if { ! [ info exists PROFILE_POLICY_TIMEOUT ] } {\n set PROFILE_POLICY_TIMEOUT [PROFILE::access access_policy_timeout]\n }\n if { ! [ info exists PROFILE_MAX_SESS_TIMEOUT ] } {\n set PROFILE_MAX_SESS_TIMEOUT [PROFILE::access max_session_timeout]\n }\n if { ! [ info exists PROFILE_RESTRICT_SINGLE_IP ] } {\n set PROFILE_RESTRICT_SINGLE_IP 1\n }\n\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX method: $http_method\"\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Src IP: $src_ip\"\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX User-Agent: $http_hdr_uagent\"\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX HTTP uri: $http_uri\"\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX HTTP len: $http_content_len\"\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Restrict-to-single-client-ip: $PROFILE_RESTRICT_SINGLE_IP\"\n\n # First, do we have valid MRHSession cookie.\n if { $MRHSession_cookie != \"\" } {\n if { [ACCESS::session exists -state_allow -sid $MRHSession_cookie] } {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX HTTP *VALID* MRHSession cookie: $MRHSession_cookie\"\n } else {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX HTTP *INVALID* MRHSession cookie: $MRHSession_cookie\"\n set MRHSession_cookie \"\"\n HTTP::cookie remove MRHSession\n }\n }\n\n set http_hdr_auth [HTTP::header Authorization]\n if { [ string match -nocase {basic *} $http_hdr_auth ] != 1 } {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Not basic authentication. Ignore received auth header\"\n set http_hdr_auth \"\"\n }\n\n if { $http_hdr_auth == \"\" } {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX No/Empty Auth header\"\n # clean up the cookie\n if { $MRHSession_cookie == \"\" } {\n HTTP::respond 401 content $static::actsync_401_http_body WWW-Authenticate \"Basic realm=\\\"[HTTP::header Host]\\\"\" Set-Cookie $static::ACCESS_DEL_COOKIE_HDR_VAL Connection Close\n return\n }\n # Do nothing if we have a valid MRHSession cookie.\n }\n\n set f_release_request 0\n # Optimization for clients which support cookie\n if { $MRHSession_cookie != \"\" } {\n # Default profile access setting is false\n if { $PROFILE_RESTRICT_SINGLE_IP == 0 } {\n set f_release_request 1\n }\n elseif { [ IP::addr $src_ip equals [ ACCESS::session data get -sid $MRHSession_cookie \"session.user.clientip\" ] ] } {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX source IP matched\"\n set f_release_request 1\n }\n else {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX source IP does not matched\"\n set MRHSession_cookie \"\"\n HTTP::cookie remove MRHSession\n }\n }\n\n if { $f_release_request == 0 } {\n set apm_username [string tolower [HTTP::username]]\n set apm_password [HTTP::password]\n if { $PROFILE_RESTRICT_SINGLE_IP == 0 } {\n binary scan [md5 \"$apm_password\"] H* user_hash\n }\n else {\n binary scan [md5 \"$apm_password$src_ip\"] H* user_hash\n }\n set user_key \"$apm_username.$user_hash\"\n unset user_hash\n\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX HTTP Hdr Auth: $http_hdr_auth\"\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX apm_username: $apm_username\"\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX user_key = $user_key\"\n set apm_cookie_list [ ACCESS::user getsid $user_key ]\n if { [ llength $apm_cookie_list ] != 0 } {\n set apm_cookie [ ACCESS::user getkey [ lindex $apm_cookie_list 0 ] ]\n if { $apm_cookie != \"\" } {\n HTTP::cookie insert name MRHSession value $apm_cookie\n set f_release_request 1\n }\n }\n }\n\n if { $http_content_len == $static::OA_MAGIC_CONTENT_LEN } {\n set f_oa_magic_content_len 1\n }\n\n set f_sleep_here 0\n set retry 1\n\n while { $f_release_request == 0 && $retry <= $static::POLICY_RESULT_POLL_MAXRETRYCYCLE } {\n\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Trying #$retry for $http_method $http_uri $http_content_len\"\n\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Reading $user_key from table $static::ACCESS_USERKEY_TBLNAME\"\n\n set apm_cookie [table lookup -subtable $static::ACCESS_USERKEY_TBLNAME -notouch $user_key]\n if { $apm_cookie != \"\" } {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Verifying table cookie = $apm_cookie\"\n\n # Accessing SessionDB is not that cheap. Here we are trying to check known value.\n if { $apm_cookie == \"policy_authfailed\" || $apm_cookie == \"policy_inprogress\"} {\n # Do nothing\n } elseif { ! [ ACCESS::session exists $apm_cookie ] } {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX table cookie = $apm_cookie is out-of-sync\"\n # Table value is out of sync. Ignores it.\n set apm_cookie \"\"\n }\n }\n\n switch $apm_cookie {\n \"\" {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX NO APM Cookie found\"\n\n if { [ info exists f_oa_magic_content_len ] && $f_oa_magic_content_len == 1 } {\n # Outlook Anywhere request comes in pair. The one with 1G payload is not usable\n # for creating new session since 1G content-length is intended for client to upload\n # the data when needed.\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Start to wait $static::POLICY_RESULT_POLL_INTERVAL ms for request with magic content-len\"\n set f_sleep_here 1\n } elseif { [ info exists f_exchange_web_service ] && $f_exchange_web_service == 1 && $http_content_len > $static::FIRST_BIG_POST_CONTENT_LEN } {\n # Here we are getting large EWS request, which can't be used for starting new session\n # in clientless-mode. Have it here waiting for next smaller one.\n # We are holding the request here in HTTP filter, and HTTP filter automatically\n # clamping down the TCP window when necessary.\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Start to wait $static::POLICY_RESULT_POLL_INTERVAL ms for big EWS request\"\n set f_sleep_here 1\n } else {\n set apm_cookie \"policy_inprogress\"\n set f_reqside_set_sess_id 1\n set f_release_request 1\n }\n }\n \"policy_authfailed\" {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Found $user_key with AUTH_FAILED\"\n HTTP::respond 401 content $static::actsync_401_http_body\n set f_release_request 1\n }\n \"policy_inprogress\" {\n if { [ info exists f_activesync ] && ($f_activesync == 1) } {\n # For ActiveSync requests, aggressively starts new session.\n set f_reqside_set_sess_id 1\n set f_release_request 1\n } else {\n set f_sleep_here 1\n }\n }\n default {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Using MRHSession = $apm_cookie\"\n HTTP::header insert Cookie \"MRHSession=$apm_cookie\"\n set f_release_request 1\n }\n }\n\n if { $f_reqside_set_sess_id == 1 } {\n set f_reqside_set_sess_id 0\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Setting $user_key=$apm_cookie $PROFILE_POLICY_TIMEOUT $PROFILE_POLICY_TIMEOUT\"\n set f_clientless_mode 1\n HTTP::cookie remove MRHSession\n HTTP::header insert \"clientless-mode\" 1\n HTTP::header insert \"username\" $apm_username\n HTTP::header insert \"password\" $apm_password\n table set -subtable $static::ACCESS_USERKEY_TBLNAME $user_key $apm_cookie $PROFILE_POLICY_TIMEOUT $PROFILE_POLICY_TIMEOUT\n }\n\n if { $f_sleep_here == 1 } {\n set f_sleep_here 0\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Waiting $static::POLICY_RESULT_POLL_INTERVAL ms for $http_method $http_uri\"\n after $static::POLICY_RESULT_POLL_INTERVAL\n }\n\n incr retry\n }\n\n if { ($f_release_request == 0) && ($retry >= $static::POLICY_RESULT_POLL_MAXRETRYCYCLE) } {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Policy did not finish in [expr { $static::POLICY_RESULT_POLL_MAXRETRYCYCLE * $static::POLICY_RESULT_POLL_INTERVAL } ] ms. Close connection for $http_method $http_uri\"\n\n table delete -subtable $static::ACCESS_USERKEY_TBLNAME $user_key\n ACCESS::disable\n TCP::close\n return\n }\n\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Releasing request $http_method $http_uri\"\n }\n\n when ACCESS_SESSION_STARTED {\n if { [ info exists user_key ] } {\n\n ACCESS::session data set \"session.user.uuid\" $user_key\n ACCESS::session data set \"session.user.microsoft-exchange-client\" 1\n\n if { [ info exists f_activesync ] && $f_activesync == 1 } {\n ACCESS::session data set \"session.user.microsoft-activesync\" 1\n }\n elseif { [ info exists f_auto_discover ] && $f_auto_discover == 1 } {\n ACCESS::session data set \"session.user.microsoft-autodiscover\" 1\n }\n elseif { [ info exists f_availability_service ] && $f_availability_service == 1 } {\n ACCESS::session data set \"session.user.microsoft-availabilityservice\" 1\n }\n elseif { [ info exists f_rpc_over_http ] && $f_rpc_over_http == 1 } {\n ACCESS::session data set \"session.user.microsoft-rpcoverhttp\" 1\n }\n elseif { [ info exists f_offline_address_book ] && $f_offline_address_book == 1 } {\n ACCESS::session data set \"session.user.microsoft-offlineaddressbook\" 1\n }\n elseif { [ info exists f_exchange_web_service ] && $f_exchange_web_service == 1 } {\n ACCESS::session data set \"session.user.microsoft-exchangewebservice\" 1\n }\n }\n if { [ info exists f_alt_inactivity_timeout ] && $f_alt_inactivity_timeout == 1 } {\n ACCESS::session data set \"session.inactivity_timeout\" $static::POLICY_ALT_INACTIVITY_TIMEOUT\n }\n }\n\n when ACCESS_POLICY_COMPLETED {\n if { ! [ info exists user_key ] } {\n return\n }\n\n set user_key_value \"\"\n set f_delete_session 0\n set policy_result [ACCESS::policy result]\n set sid [ ACCESS::session sid ]\n\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX ACCESS_POLICY_COMPLETED: policy_result = \\\"$policy_result\\\" user_key = \\\"$user_key\\\" sid = \\\"$sid\\\"\"\n\n set inactivity_timeout [ACCESS::session data get \"session.inactivity_timeout\"]\n set max_sess_timeout [ACCESS::session data get \"session.max_session_timeout\"]\n if { $max_sess_timeout == \"\" } {\n set max_sess_timeout $PROFILE_MAX_SESS_TIMEOUT\n }\n\n switch $policy_result {\n \"allow\" {\n # We depends on this table record self-cleanup capability in order to\n # indirectly sync with session DB.\n set user_key_value $sid\n\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Result: Allow: $user_key => $sid $inactivity_timeout $max_sess_timeout\"\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX user_key_value = $user_key_value\"\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX sid = $sid\"\n }\n \"deny\" {\n # When necessary the admin here can check appropriate session variable\n # and decide what response more appropriate then this default response.\n ACCESS::respond 401 content $static::actsync_401_http_body Set-Cookie $static::ACCESS_DEL_COOKIE_HDR_VAL Connection Close\n if { $static::POLICY_RESULT_CACHE_AUTHFAILED == 1 } {\n set user_key_value $static::POLICY_AUTHFAILED\n } else {\n set f_delete_session 1\n }\n }\n default {\n ACCESS::respond 503 content $static::actsync_503_http_body Connection Close\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Got unsupported policy result for $user_key ($sid)\"\n set f_delete_session 1\n }\n }\n if { $user_key_value != \"\" } {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Setting $user_key => $user_key_value $inactivity_timeout $max_sess_timeout in table $static::ACCESS_USERKEY_TBLNAME\"\n\n table set -subtable $static::ACCESS_USERKEY_TBLNAME $user_key $user_key_value $inactivity_timeout $max_sess_timeout\n } else {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Deleting $user_key in table $static::ACCESS_USERKEY_TBLNAME\"\n\n table delete -subtable $static::ACCESS_USERKEY_TBLNAME $user_key\n }\n\n if { $f_delete_session == 1 } {\n ACCESS::session remove\n set f_delete_session 0\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Removing the session for $user_key.\"\n }\n }\ndefinition-signature CZnUb3niz9wZPWvOmjDB0Dy4ixqjBEhIZrAVGt8VYe7+wZkhcBUFTADz3S1y5uomVwhRkGL20PLH7tfanDlpr3+IppgAGQlp98sPUl5ndEoWA4Rr90QiRGNRl/V7jWK58SOdJCQOirnutVMoeYjBWLwuprXGts08PO0WML5s0xJNOY7WPuGNeG+7Ht2pIB0vu80CgnCNGZJGZH0QR3kMVOx3yUN0ro5bAOmQ/XWel4qkj0F5DN9ufvsmKtTvb+Lc3y+5PHGbbFAQIrZ7lntZUJl/F8e/d26HE3spmZzQpPzi16qYWaMOxbvT6oedxpyhwbmJLiRNGyZmnT6kHj93FA==",
- "apiRawValues": {
- "verificationStatus": "signature-verified"
- }
- },
- {
- "kind": "tm:ltm:rule:rulestate",
- "name": "_sys_APM_ExchangeSupport_OA_NtlmAuth",
- "partition": "Common",
- "fullPath": "/Common/_sys_APM_ExchangeSupport_OA_NtlmAuth",
- "generation": 1,
- "selfLink": "https://localhost/mgmt/tm/ltm/rule/~Common~_sys_APM_ExchangeSupport_OA_NtlmAuth?ver=12.1.2",
- "apiAnonymous": "nodelete nowrite \nwhen RULE_INIT {\n set static::POLICY_INPROGRESS \"policy_inprogress\"\n set static::POLICY_FAILED \"policy_failed\"\n set static::POLICY_SUCCEED \"policy_succeed\"\n set static::POLICY_DONE_WAIT_SEC 5\n\n set static::FIRST_BIG_POST_CONTENT_LEN 640000\n set static::POLICY_RESULT_POLL_INTERVAL 100\n set static::POLICY_RESULT_POLL_MAXRETRYCYCLE 100\n set static::ACCESS_USERKEY_TBLNAME \"_access_userkey\"\n set static::ACCESS_LOG_PREFIX \"01490000:7:\"\n\n set static::USE_NTLM_AUTH 0\n set static::USE_BASIC_AUTH 1\n set static::USE_NTLM_BASIC_AUTH 2\n\n set static::URL_DEFAULT 0\n set static::URL_RPC_OVER_HTTP 1\n set static::URL_AUTODISCOVER 2\n set static::URL_ACTIVE_SYNC 3\n set static::URL_OFFLINEADDRESSBOOK 4\n set static::URL_EXCHANGEWEBSERVICE 5\n\n set static::RECVD_AUTH_NONE 0\n set static::RECVD_AUTH_NTLM 1\n set static::RECVD_AUTH_BASIC 2\n\n set static::ACCESS_DEL_COOKIE_HDR_VAL \"MRHSession=deleted; \\\n expires=Thu, 01-Jan-1970 00:00:01 GMT;\\\n path=/\"\n\n }\n\n when HTTP_REQUEST {\n set http_path [string tolower [HTTP::path]]\n set url_path $static::URL_DEFAULT\n set use_auth $static::USE_NTLM_AUTH\n set f_disable_sso 0\n\n switch -glob $http_path {\n \"/rpc/rpcproxy.dll\" {\n set url_path $static::URL_RPC_OVER_HTTP\n }\n \"/autodiscover/autodiscover.xml\" {\n set url_path $static::URL_ACTIVE_SYNC\n # Need to support both NTLM and Basic authentication for this URL\n set use_auth $static::USE_NTLM_BASIC_AUTH\n }\n \"/microsoft-server-activesync*\" {\n set url_path $static::URL_ACTIVE_SYNC\n # Use only Basic authentication for this URL\n set use_auth $static::USE_BASIC_AUTH\n set f_disable_sso 1\n }\n \"/oab*\" {\n set url_path $static::URL_OFFLINEADDRESSBOOK\n }\n \"/ews*\" {\n set url_path $static::URL_EXCHANGEWEBSERVICE\n }\n default {\n ECA::disable\n return\n }\n }\n\n if { ! [ info exists f_ntlm_auth_succeed ] } {\n set f_ntlm_auth_succeed 0\n }\n if { ! [ info exists sid_cache ] } {\n set sid_cache \"\"\n }\n if { ! [ info exists PROFILE_POLICY_TIMEOUT ] } { \n set PROFILE_POLICY_TIMEOUT [PROFILE::access access_policy_timeout]\n }\n if { ! [ info exists PROFILE_MAX_SESS_TIMEOUT ] } {\n set PROFILE_MAX_SESS_TIMEOUT [PROFILE::access max_session_timeout]\n }\n if { ! [ info exists src_ip ] } {\n set src_ip [IP::remote_addr]\n }\n if { ! [ info exists PROFILE_RESTRICT_SINGLE_IP ] } {\n set PROFILE_RESTRICT_SINGLE_IP 1\n }\n\n set http_method [HTTP::method]\n set http_hdr_host [HTTP::host]\n set http_hdr_uagent [HTTP::header User-Agent]\n set http_uri [HTTP::uri]\n set http_content_len [HTTP::header Content-Length]\n set MRHSession_cookie [HTTP::cookie value MRHSession]\n\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX method: $http_method\"\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Src IP: $src_ip\"\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX User-Agent: $http_hdr_uagent\"\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX HTTP uri: $http_uri\"\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX HTTP len: $http_content_len\"\n\n if { ! [ info exists ECA_METADATA_ARG ] } {\n # Generating argument for ECA::metadata\n # The NTLM configuration name is derived from assigned virtual name with the algorithm as follows:\n # <virtual-fullpath> ::= <folder-path>\"/\"<virtual-basename> as \"/\" is the last \"/\" char.\n # <config-fullpath> ::= <folder-path>\"/\" \"exch_ntlm\" \"_\" <virtual-basename>\n # e.g. Let us say the virtual name is \"/prod/exch/vs1\", The folder path is \"/prod/exch/\",\n # then object name will be \"/prod/exch/exch_ntlm_vs1\".\n set vs_name [virtual name]\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX virtual: $vs_name\"\n set slash_index [ string last / $vs_name ]\n if { $slash_index == -1 } {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Error: the virtual name does not contain folder information\"\n ACCESS::disable\n TCP::close\n return\n }\n set ECA_METADATA_ARG \"select_ntlm:\"\n append ECA_METADATA_ARG [ string range $vs_name 0 $slash_index ]\n append ECA_METADATA_ARG \"exch_ntlm_\"\n append ECA_METADATA_ARG [ string range $vs_name [ expr { $slash_index + 1 } ] end ]\n unset slash_index\n unset vs_name\n }\n\n if { $use_auth == $static::USE_NTLM_AUTH } {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Enable ECA: $ECA_METADATA_ARG\"\n ECA::enable\n ECA::select $ECA_METADATA_ARG\n return\n } else {\n set recvd_auth $static::RECVD_AUTH_NONE\n set http_hdr_auth [HTTP::header Authorization]\n set auth_data [split $http_hdr_auth \" \"]\n if { $http_hdr_auth != \"\" } {\n if { [ llength $auth_data ] == 2 } {\n set auth_scheme [ lindex $auth_data 0]\n if { [string equal -nocase $auth_scheme \"ntlm\" ] == 1 } {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Recv'd HTTP NTLM Authentication\"\n set recvd_auth $static::RECVD_AUTH_NTLM\n } elseif { [ string equal -nocase [ lindex $auth_data 0] \"basic\" ] == 1 } {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Recv'd HTTP Basic Authentication\"\n set recvd_auth $static::RECVD_AUTH_BASIC\n set user [string tolower [HTTP::username]]\n set password [HTTP::password]\n }\n }\n }\n if { $use_auth == $static::USE_BASIC_AUTH } {\n if { $recvd_auth == $static::RECVD_AUTH_BASIC } {\n # Defer the process until later\n } else {\n HTTP::respond 401 -version 1.1 noserver WWW-Authenticate \"Basic realm=\\\"$http_hdr_host\\\"\" \\\n Set-Cookie $static::ACCESS_DEL_COOKIE_HDR_VAL Connection Close\n return\n }\n } elseif { $use_auth == $static::USE_NTLM_BASIC_AUTH } {\n if { ($recvd_auth == $static::RECVD_AUTH_NTLM) || ($f_ntlm_auth_succeed == 1) } {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Enable ECA: $ECA_METADATA_ARG\"\n ECA::enable\n ECA::select $ECA_METADATA_ARG\n return\n } elseif { $recvd_auth == $static::RECVD_AUTH_BASIC } {\n # Defer the process until later\n } else {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Request Authorization: NTLM + Basic\"\n HTTP::respond 401 -version 1.1 noserver WWW-Authenticate \"Basic realm=\\\"$http_hdr_host\\\"\" \\\n WWW-Authenticate \"NTLM\" Set-Cookie $static::ACCESS_DEL_COOKIE_HDR_VAL Connection Close\n return\n }\n }\n\n # Disable NTLM auth\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Disable ECA\"\n ECA::disable\n # Disable KCD sso\n set f_disable_sso 1\n\n if { $MRHSession_cookie != \"\" } {\n if { [ACCESS::session exists -state_allow -sid $MRHSession_cookie] } {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX HTTP *VALID* MRHSession cookie: $MRHSession_cookie\"\n # Default profile access setting is false\n if { $PROFILE_RESTRICT_SINGLE_IP == 0 } {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Release the request\"\n return\n }\n elseif { [ IP::addr $src_ip equals [ ACCESS::session data get -sid $MRHSession_cookie \"session.user.clientip\" ] ] } {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX source IP matched. Release the request\"\n return\n }\n else {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX source IP does not matched\"\n }\n }\n else {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX HTTP *INVALID* MRHSession cookie: $MRHSession_cookie\"\n }\n\n set MRHSession_cookie \"\"\n HTTP::cookie remove MRHSession\n }\n\n set user_key {}\n if { $PROFILE_RESTRICT_SINGLE_IP == 1 } {\n append user_key $src_ip\n }\n append user_key $password\n binary scan [md5 $user_key ] H* user_key\n set user_key \"$user.$user_key\"\n\n set apm_cookie_list [ ACCESS::user getsid $user_key ]\n if { [ llength $apm_cookie_list ] != 0 } {\n set MRHSession_cookie [ ACCESS::user getkey [ lindex $apm_cookie_list 0 ] ]\n if { $MRHSession_cookie != \"\" } {\n HTTP::cookie remove MRHSession \n HTTP::cookie insert name MRHSession value $MRHSession_cookie\n return\n }\n }\n\n HTTP::cookie remove MRHSession\n HTTP::header insert \"clientless-mode\" 1\n HTTP::header insert \"username\" $user\n HTTP::header insert \"password\" $password\n return\n }\n }\n\n when ECA_REQUEST_ALLOWED {\n set f_ntlm_auth_succeed 1\n\n if { $MRHSession_cookie == \"\" } {\n # Retrieve from SID cache\n set MRHSession_cookie $sid_cache\n HTTP::cookie insert name MRHSession value $sid_cache\n }\n\n if { $MRHSession_cookie != \"\" } {\n # Destroy session ID cache. This client should not need session ID cache \n if { ($sid_cache != \"\") && ($sid_cache != $MRHSession_cookie) } {\n set sid_cache \"\"\n }\n if { [ ACCESS::session exists -state_allow $MRHSession_cookie ] } {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX HTTP *VALID* MRHSession cookie: $MRHSession_cookie\"\n # Default profile access setting is false\n if { $PROFILE_RESTRICT_SINGLE_IP == 0 } {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Release the request\"\n return\n }\n elseif { [ IP::addr $src_ip equals [ ACCESS::session data get -sid $MRHSession_cookie \"session.user.clientip\" ] ] } {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX source IP matched. Release the request\"\n return\n }\n else {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX source IP does not matched\"\n }\n } else {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX HTTP *INVALID* MRHSession cookie: $MRHSession_cookie\"\n }\n }\n\n set MRHSession \"\"\n set sid_cache \"\"\n HTTP::cookie remove MRHSession\n\n # Build user_key\n set user_key {}\n append user_key [string tolower [ECA::username]] \"@\" [ string tolower [ECA::domainname] ]\n if { $PROFILE_RESTRICT_SINGLE_IP == 0 } {\n append user_key \":\" $src_ip\n }\n append user_key \":\" [ECA::client_machine_name]\n\n set apm_cookie_list [ ACCESS::user getsid $user_key ]\n if { [ llength $apm_cookie_list ] != 0 } {\n set MRHSession_cookie [ ACCESS::user getkey [ lindex $apm_cookie_list 0 ] ]\n if { $MRHSession_cookie != \"\" } {\n set sid_cache $MRHSession_cookie\n HTTP::cookie insert name MRHSession value $MRHSession_cookie\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX APM Cookie found: $sid_cache\"\n return\n }\n }\n unset apm_cookie_list\n\n set try 1\n set start_policy_str $src_ip\n append start_policy_str [TCP::client_port]\n\n while { $try <= $static::POLICY_RESULT_POLL_MAXRETRYCYCLE } {\n\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX NO APM Cookie found\"\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Trying #$try for $http_method $http_uri $http_content_len\"\n\n if { $http_content_len > $static::FIRST_BIG_POST_CONTENT_LEN } {\n # Wait at below\n } else {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX EXEC: table set -notouch -subtable $static::ACCESS_USERKEY_TBLNAME -excl $user_key $start_policy_str $PROFILE_POLICY_TIMEOUT $PROFILE_MAX_SESS_TIMEOUT\"\n set policy_status [table set -notouch -subtable $static::ACCESS_USERKEY_TBLNAME -excl $user_key $start_policy_str $PROFILE_POLICY_TIMEOUT $PROFILE_MAX_SESS_TIMEOUT]\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX DONE: table set -notouch -subtable $static::ACCESS_USERKEY_TBLNAME -excl $user_key $start_policy_str $PROFILE_POLICY_TIMEOUT $PROFILE_MAX_SESS_TIMEOUT\"\n if { $policy_status == $start_policy_str } {\n # ACCESS Policy has not started. Start one\n HTTP::header insert \"clientless-mode\" 1\n break\n } elseif { $policy_status == $static::POLICY_SUCCEED } {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX table is out-of-sync retry\"\n table delete -subtable $static::ACCESS_USERKEY_TBLNAME $user_key\n continue\n } elseif { $policy_status == $static::POLICY_FAILED } {\n ACCESS::disable\n TCP::close\n return\n }\n # Wait at below\n }\n\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Waiting $static::POLICY_RESULT_POLL_INTERVAL ms for $http_method $http_uri\"\n # Touch the entry table\n table lookup -subtable $static::ACCESS_USERKEY_TBLNAME $user_key\n after $static::POLICY_RESULT_POLL_INTERVAL\n\n set apm_cookie_list [ ACCESS::user getsid $user_key ]\n if { [ llength $apm_cookie_list ] != 0 } {\n set MRHSession_cookie [ ACCESS::user getkey [ lindex $apm_cookie_list 0 ] ]\n if { $MRHSession_cookie != \"\" } {\n set sid_cache $MRHSession_cookie\n HTTP::cookie insert name MRHSession value $MRHSession_cookie\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX APM Cookie found: $sid_cache\"\n return\n }\n }\n\n incr try\n }\n\n if { $try > $static::POLICY_RESULT_POLL_MAXRETRYCYCLE } {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Policy did not finish in [ expr { $static::POLICY_RESULT_POLL_MAXRETRYCYCLE * $static::POLICY_RESULT_POLL_INTERVAL } ] ms. Close connection for $http_method $http_uri\"\n table delete -subtable $static::ACCESS_USERKEY_TBLNAME $user_key\n ACCESS::disable\n TCP::close\n return\n }\n\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Releasing request $http_method $http_uri\"\n\n unset try\n unset start_policy_str\n }\n\n when ECA_REQUEST_DENIED {\n set f_ntlm_auth_succeed 0\n }\n\n when HTTP_RESPONSE_RELEASE {\n if { ! [info exists user_key] } {\n return\n }\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX HTTP response: status: [HTTP::status]\"\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX HTTP response: Server: [HTTP::header Server]\"\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX HTTP response: Content-Length: [HTTP::header Content-Length]\"\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX HTTP response: WWW-Authenticate: [HTTP::header WWW-Authenticate]\"\n }\n\n when ACCESS_SESSION_STARTED {\n if { [ info exists user_key ] } {\n ACCESS::session data set \"session.user.uuid\" $user_key\n ACCESS::session data set \"session.user.microsoft-exchange-client\" 1\n }\n }\n\n when ACCESS_ACL_ALLOWED {\n if { [ info exists f_disable_sso ] && $f_disable_sso == 1 } {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Disable WEBSSO\"\n WEBSSO::disable\n }\n }\n\n when ACCESS_POLICY_COMPLETED {\n if { ! [ info exists user_key ] } {\n return\n }\n\n set user_key_value \"\"\n set f_delete_session 0\n set policy_result [ACCESS::policy result]\n set sid [ ACCESS::session sid ]\n\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX ACCESS_POLICY_COMPLETED: policy_result = \\\"$policy_result\\\" user_key = \\\"$user_key\\\" sid = \\\"$sid\\\"\"\n\n switch $policy_result {\n \"allow\" {\n set user_key_value $sid\n set sid_cache $user_key_value\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Result: Allow: $user_key\"\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX sid = $sid\"\n\n }\n \"deny\" {\n ACCESS::respond 401 content $static::actsync_401_http_body Set-Cookie $static::ACCESS_DEL_COOKIE_HDR_VAL Connection Close\n set f_delete_session 1\n }\n default {\n ACCESS::respond 503 content $static::actsync_503_http_body Connection Close\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Got unsupported policy result for $user_key ($sid)\"\n set f_delete_session 1\n }\n }\n\n if { $f_ntlm_auth_succeed == 1 } {\n if { $user_key_value != \"\" } {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Setting $user_key => $static::POLICY_SUCCEED\"\n table set -subtable $static::ACCESS_USERKEY_TBLNAME $user_key $static::POLICY_SUCCEED\n } else {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Setting $user_key => $static::POLICY_FAILED $static::POLICY_DONE_WAIT_SEC $static::POLICY_DONE_WAIT_SEC_in table $static::ACCESS_USERKEY_TBLNAME\"\n table set -subtable $static::ACCESS_USERKEY_TBLNAME $user_key $static::POLICY_FAILED $static::POLICY_DONE_WAIT_SEC $static::POLICY_DONE_WAIT_SEC\n }\n }\n\n if { $f_delete_session == 1 } {\n ACCESS::session remove\n set f_delete_session 0\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Removing the session for $user_key.\"\n }\n }\ndefinition-signature d/SlmwsO4YeDlh3eJpLqam9ytq0/EkWnAce1XTQ5bxOyla0x/VHjkr9dvoo3awaxp7lEjAenIgwGpS2jL5R1hq48WGZN2nu9LDKVjTosrq7j1MHbeKiIW8yXc3IEUtbbkhkAGNnMmfDYMD8Vg7l+iBx6B/WvRTZLr+tmppFf0BIr2Z7FWWU6c9OVl8YH1VuqqFX/lKICn2EXDhebRDRVvuXobLvbjZQxj+tqdUU2vuLzXYot/RUgClXHrg6Z2ZC6/WuAq4pp/XA2kvzWotQiY9gEceQdMC7/BxPSR8xo4VPNqkFkEPjh5hehZP0tFONTZaMaH1klVg4QbvHH5MRiBQ==",
- "apiRawValues": {
- "verificationStatus": "signature-verified"
- }
- },
- {
- "kind": "tm:ltm:rule:rulestate",
- "name": "_sys_APM_ExchangeSupport_helper",
- "partition": "Common",
- "fullPath": "/Common/_sys_APM_ExchangeSupport_helper",
- "generation": 1,
- "selfLink": "https://localhost/mgmt/tm/ltm/rule/~Common~_sys_APM_ExchangeSupport_helper?ver=12.1.2",
- "apiAnonymous": "nodelete nowrite \n # The purpose of this iRule is for help the main virtual for the timing of the HTTP request retry\n # during the SSO process for OutlookAnywhere protocol request which has a Content-Length value of 1GB.\n\n when HTTP_REQUEST {\n # Waiting for the first chunk of data.\n HTTP::collect 1\n }\n\n when HTTP_REQUEST_DATA {\n # Respond 401 and close the connection once we received the data.\n HTTP::respond 401 WWW-Authenticate NTLM Connection close\n }\ndefinition-signature fnJWcC75FIDV4savxGjyZ5sTdRTen+3mItejhseH06qn+qBXjOl/j7wYRSLDv1IcFezF8BunbDftMHXrW7QRuPuxhjMIc4vaALE2CCGkO0xcs258F+nkPeeJKoR5mTHY/E5BWpOAISinUBUSA3/nUm8blXkMwVg/Q95360jcCOoi6csgJa97OSKIF9h9OQCylh1qGBsDRHEXCR3ycw5Eb4T2QQSdBn09vr8Hgdpi/9fUER97nzJe8T/RuoG+nQ7bc8F9yzG6nFa/CQtRYDybDrcNgllCfVloXZAHZS3dCpq6FnS/FaEWfSIujmV+lXkxY23Xz9Wf6i1h/feW9fEUiQ==",
- "apiRawValues": {
- "verificationStatus": "signature-verified"
- }
- },
- {
- "kind": "tm:ltm:rule:rulestate",
- "name": "_sys_APM_ExchangeSupport_main",
- "partition": "Common",
- "fullPath": "/Common/_sys_APM_ExchangeSupport_main",
- "generation": 1,
- "selfLink": "https://localhost/mgmt/tm/ltm/rule/~Common~_sys_APM_ExchangeSupport_main?ver=12.1.2",
- "apiAnonymous": "nodelete nowrite \n # Global variables\n # static::POLICY_RESULT_CACHE_AUTHFAILED\n # Administrator can set this into 1, when there is a necessity to cache failed policy result.\n # This may be needed to avoid account locked caused by the Active Sync device when it uses wrong passwords.\n # One possible scenario, is that when the user changes the password in Active Directory, but missed to changed in their devices.\n # Responses\n # On denied result\n # Administrator can customize the responses to the device depends on more complex conditions when necessary.\n # In those cases, please use ACCESS::respond command.\n # The following is the syntax of ACCESS::respond\n # ACCESS::respond <status code> [ content <body> ] [ <Additional Header> <Additional Header value>* ]\n # e.g. ACCESS::respond 401 content \"Error: Denied\" WWW-Authenticate \"basic realm=\\\"f5.com\\\"\" Connection close\n when RULE_INIT {\n # Please set the following global variables for customized responses.\n set static::actsync_401_http_body \"<html><title>Authentication Failured</title><body>Error: Authentication Failure</body></html>\"\n set static::actsync_503_http_body \"<html><title>Service is not available</title><body>Error: Service is not available</body></html>\"\n set static::ACCESS_LOG_PREFIX \"01490000:7:\"\n\n # Second Virtual Server name for 401 NTLM responder\n set static::ACCESS_SECOND_VIRTUAL_NAME \"_ACCESS_401_NTLM_responder_HTTPS\"\n\n set static::POLICY_INPROGRESS \"policy_inprogress\"\n set static::POLICY_AUTHFAILED \"policy_authfailed\"\n # The request with huge content length can not be used for starting ACCESS session.\n # This kind of request will be put on hold, and this iRule will try to use another\n # request to start the session. The following value is used for Outlook Anywhere.\n set static::OA_MAGIC_CONTENT_LEN 1073741824\n\n # Similar with OutlookAnywhere case, ACCESS can not use the request which is\n # larger then following size. This becomes an issue with application that using\n # Exchange Web Service as its main protocol such as Mac OS X applications\n # (e.g. Mail app, Microsoft Entourage, etc)\n # This kind of request will be put on hold, and this iRule will try to use another\n # request to start the session.\n set static::FIRST_BIG_POST_CONTENT_LEN 640000\n\n # Set it into 1 if the backend EWS handler accepts HTTP Basic Authentication.\n set static::EWS_BKEND_BASIC_AUTH 0\n # Set it into 1 if the backend RPC-over-HTTP handler accepts HTTP Basic Authentication.\n set static::RPC_OVER_HTTP_BKEND_BASIC_AUTH 0\n # The following variable controls the polling mechanism.\n set static::POLICY_RESULT_POLL_INTERVAL 250\n set static::POLICY_RESULT_POLL_MAXRETRYCYCLE 600\n\n # Set this global variable to 1 for caching authentication failure\n # Useful for avoiding account locked out.\n set static::POLICY_RESULT_CACHE_AUTHFAILED 0\n\n # set this global variable to set alternative timeout for particular session\n set static::POLICY_ALT_INACTIVITY_TIMEOUT 120\n\n set static::ACCESS_USERKEY_TBLNAME \"_access_userkey\"\n\n\n set static::ACCESS_DEL_COOKIE_HDR_VAL \"MRHSession=deleted; expires=Thu, 01-Jan-1970 00:00:01 GMT; path=/\"\n\n log -noname accesscontrol.local1.debug \"01490000:7: RPC_OVER_HTTP_BKEND_BASIC_AUTH = $static::RPC_OVER_HTTP_BKEND_BASIC_AUTH\"\n log -noname accesscontrol.local1.debug \"01490000:7: EWS_BKEND_BASIC_AUTH = $static::EWS_BKEND_BASIC_AUTH\"\n }\n when ACCESS_ACL_ALLOWED {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX [HTTP::method] [HTTP::uri] [HTTP::header Content-Length]\"\n\n if { [ info exists f_rpc_over_http ] && $f_rpc_over_http == 1 } {\n if { $static::RPC_OVER_HTTP_BKEND_BASIC_AUTH == 0 } {\n if { [ info exists f_oa_magic_content_len ] && $f_oa_magic_content_len == 1 } {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Use this virtual $static::ACCESS_SECOND_VIRTUAL_NAME just once. Will be reset back after disconnection.\"\n use virtual $static::ACCESS_SECOND_VIRTUAL_NAME\n }\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Remove HTTP Auth header\"\n HTTP::header remove Authorization\n }\n }\n # MSFT Exchange's EWS request handler always requesting NTLM even the connection has been\n # already authenticated if there is a HTTP Basic Auth in the request.\n if { [ info exists f_exchange_web_service ] && $f_exchange_web_service == 1 } {\n if { $static::EWS_BKEND_BASIC_AUTH == 0 } {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Removing HTTP Basic Authorization header\"\n HTTP::header remove Authorization\n }\n }\n }\n\n when HTTP_REQUEST {\n set http_path [ string tolower [HTTP::path] ]\n set f_clientless_mode 0\n set f_alt_inactivity_timeout 0\n set f_rpc_over_http 0\n set f_exchange_web_service 0\n set f_auto_discover 0\n set f_activesync 0\n set f_offline_address_book 0\n set f_availability_service 0\n\n # Here put appropriate pool when necessary.\n switch -glob $http_path {\n \"/rpc/rpcproxy.dll\" {\n # Supports for RPC over HTTP. (Outlook Anywhere)\n set f_rpc_over_http 1\n }\n \"/autodiscover/autodiscover.xml\" {\n # Supports for Auto Discover protocol.\n set f_auto_discover 1\n # This request does not require long inactivity timeout.\n # Don't use this for now\n set f_alt_inactivity_timeout 0\n }\n \"/microsoft-server-activesync\" {\n # Supports for ActiveSync\n set f_activesync 1\n }\n \"/oab/*\" {\n # Supports for Offline Address Book\n set f_offline_address_book 1\n }\n \"/ews/*\" {\n # Support for Exchange Web Service\n # Outlook's Availability Service borrows this protocol.\n set f_exchange_web_service 1\n }\n \"/as/*\" {\n # Support for Availability Service.\n # do nothing for now. (Untested)\n set f_availability_service 1\n }\n default {\n return\n }\n }\n\n set f_reqside_set_sess_id 0\n set http_method [HTTP::method]\n set http_hdr_host [HTTP::host]\n set http_hdr_uagent [HTTP::header User-Agent]\n set src_ip [IP::remote_addr]\n set http_uri [HTTP::uri]\n set http_content_len [HTTP::header Content-Length]\n set MRHSession_cookie [HTTP::cookie value MRHSession]\n set auth_info_b64enc \"\"\n\n if { ! [ info exists PROFILE_POLICY_TIMEOUT ] } {\n set PROFILE_POLICY_TIMEOUT [PROFILE::access access_policy_timeout]\n }\n if { ! [ info exists PROFILE_MAX_SESS_TIMEOUT ] } {\n set PROFILE_MAX_SESS_TIMEOUT [PROFILE::access max_session_timeout]\n }\n if { ! [ info exists PROFILE_RESTRICT_SINGLE_IP ] } {\n set PROFILE_RESTRICT_SINGLE_IP 1\n }\n\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX method: $http_method\"\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Src IP: $src_ip\"\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX User-Agent: $http_hdr_uagent\"\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX HTTP uri: $http_uri\"\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX HTTP len: $http_content_len\"\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Restrict-to-single-client-ip: $PROFILE_RESTRICT_SINGLE_IP\"\n\n # First, do we have valid MRHSession cookie.\n if { $MRHSession_cookie != \"\" } {\n if { [ACCESS::session exists -state_allow -sid $MRHSession_cookie] } {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX HTTP *VALID* MRHSession cookie: $MRHSession_cookie\"\n } else {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX HTTP *INVALID* MRHSession cookie: $MRHSession_cookie\"\n set MRHSession_cookie \"\"\n HTTP::cookie remove MRHSession\n }\n }\n\n set http_hdr_auth [HTTP::header Authorization]\n if { [ string match -nocase {basic *} $http_hdr_auth ] != 1 } {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Not basic authentication. Ignore received auth header\"\n set http_hdr_auth \"\"\n }\n\n if { $http_hdr_auth == \"\" } {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX No/Empty Auth header\"\n # clean up the cookie\n if { $MRHSession_cookie == \"\" } {\n HTTP::respond 401 content $static::actsync_401_http_body WWW-Authenticate \"Basic realm=\\\"[HTTP::header Host]\\\"\" Set-Cookie $static::ACCESS_DEL_COOKIE_HDR_VAL Connection close\n return\n }\n # Do nothing if we have a valid MRHSession cookie.\n }\n\n set f_release_request 0\n # Optimization for clients which support cookie\n if { $MRHSession_cookie != \"\" } {\n # Default profile access setting is false\n if { $PROFILE_RESTRICT_SINGLE_IP == 0 } {\n set f_release_request 1\n }\n elseif { [ IP::addr $src_ip equals [ ACCESS::session data get -sid $MRHSession_cookie \"session.user.clientip\" ] ] } {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX source IP matched\"\n set f_release_request 1\n }\n else {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX source IP does not matched\"\n set MRHSession_cookie \"\"\n HTTP::cookie remove MRHSession\n }\n }\n\n if { $f_release_request == 0 } {\n set apm_username [ string tolower [HTTP::username]]\n set apm_password [HTTP::password]\n if { $PROFILE_RESTRICT_SINGLE_IP == 0 } {\n binary scan [md5 \"$apm_password\"] H* user_hash\n } else {\n binary scan [md5 \"$apm_password$src_ip\"] H* user_hash\n }\n\n set user_key {}\n append user_key $apm_username \".\" $user_hash\n unset user_hash\n\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX HTTP Hdr Auth: $http_hdr_auth\"\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX apm_username: $apm_username\"\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX user_key = $user_key\"\n set apm_cookie_list [ ACCESS::user getsid $user_key ]\n if { [ llength $apm_cookie_list ] != 0 } {\n set apm_cookie [ ACCESS::user getkey [ lindex $apm_cookie_list 0 ] ]\n if { $apm_cookie != \"\" } {\n HTTP::cookie insert name MRHSession value $apm_cookie\n set f_release_request 1\n }\n }\n }\n\n if { $http_content_len == $static::OA_MAGIC_CONTENT_LEN } {\n set f_oa_magic_content_len 1\n }\n\n set f_sleep_here 0\n set retry 1\n\n while { $f_release_request == 0 && $retry <= $static::POLICY_RESULT_POLL_MAXRETRYCYCLE } {\n\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Trying #$retry for $http_method $http_uri $http_content_len\"\n\n # This is also going to touch the table entry timer.\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Reading $user_key from table $static::ACCESS_USERKEY_TBLNAME\"\n\n set apm_cookie [table lookup -subtable $static::ACCESS_USERKEY_TBLNAME -notouch $user_key]\n if { $apm_cookie != \"\" } {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Verifying table cookie = $apm_cookie\"\n\n # Accessing SessionDB is not that cheap. Here we are trying to check known value.\n if { $apm_cookie == \"policy_authfailed\" || $apm_cookie == \"policy_inprogress\"} {\n # Do nothing\n } elseif { ! [ ACCESS::session exists $apm_cookie ] } {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX table cookie = $apm_cookie is out-of-sync\"\n # Table value is out of sync. Ignores it.\n set apm_cookie \"\"\n }\n }\n\n switch $apm_cookie {\n \"\" {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX NO APM Cookie found\"\n\n if { [ info exists f_oa_magic_content_len ] && $f_oa_magic_content_len == 1 } {\n # Outlook Anywhere request comes in pair. The one with 1G payload is not usable\n # for creating new session since 1G content-length is intended for client to upload\n # the data when needed.\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Start to wait $static::POLICY_RESULT_POLL_INTERVAL ms for request with magic content-len\"\n set f_sleep_here 1\n } elseif { [ info exists f_exchange_web_service ] && $f_exchange_web_service == 1 && $http_content_len > $static::FIRST_BIG_POST_CONTENT_LEN } {\n # Here we are getting large EWS request, which can't be used for starting new session\n # in clientless-mode. Have it here waiting for next smaller one.\n # We are holding the request here in HTTP filter, and HTTP filter automatically\n # clamping down the TCP window when necessary.\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Start to wait $static::POLICY_RESULT_POLL_INTERVAL ms for big EWS request\"\n set f_sleep_here 1\n } else {\n set apm_cookie \"policy_inprogress\"\n set f_reqside_set_sess_id 1\n set f_release_request 1\n }\n }\n \"policy_authfailed\" {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Found $user_key with AUTH_FAILED\"\n HTTP::respond 401 content $static::actsync_401_http_body\n set f_release_request 1\n }\n \"policy_inprogress\" {\n if { [ info exists f_activesync ] && ($f_activesync == 1) } {\n # For ActiveSync requests, aggressively starts new session.\n set f_reqside_set_sess_id 1\n set f_release_request 1\n } else {\n set f_sleep_here 1\n }\n }\n default {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Using MRHSession = $apm_cookie\"\n HTTP::header insert Cookie \"MRHSession=$apm_cookie\"\n set f_release_request 1\n }\n }\n\n if { $f_reqside_set_sess_id == 1 } {\n set f_reqside_set_sess_id 0\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Setting $user_key=$apm_cookie $PROFILE_POLICY_TIMEOUT $PROFILE_MAX_SESS_TIMEOUT\"\n set f_clientless_mode 1\n HTTP::cookie remove MRHSession\n HTTP::header insert \"clientless-mode\" 1\n HTTP::header insert \"username\" $apm_username\n HTTP::header insert \"password\" $apm_password\n table set -subtable $static::ACCESS_USERKEY_TBLNAME $user_key $apm_cookie $PROFILE_POLICY_TIMEOUT $PROFILE_MAX_SESS_TIMEOUT\n }\n\n if { $f_sleep_here == 1 } {\n set f_sleep_here 0\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Waiting $static::POLICY_RESULT_POLL_INTERVAL ms for $http_method $http_uri\"\n after $static::POLICY_RESULT_POLL_INTERVAL\n }\n\n incr retry\n }\n\n if { $f_release_request == 0 && $retry >= $static::POLICY_RESULT_POLL_MAXRETRYCYCLE } {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Policy did not finish in [expr { $static::POLICY_RESULT_POLL_MAXRETRYCYCLE * $static::POLICY_RESULT_POLL_INTERVAL } ] ms. Close connection for $http_method $http_uri\"\n\n table delete -subtable $static::ACCESS_USERKEY_TBLNAME $user_key\n ACCESS::disable\n TCP::close\n return\n }\n\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Releasing request $http_method $http_uri\"\n }\n\n when ACCESS_SESSION_STARTED {\n if { [ info exists user_key ] } {\n ACCESS::session data set \"session.user.uuid\" $user_key\n ACCESS::session data set \"session.user.microsoft-exchange-client\" 1\n\n if { [ info exists f_activesync ] && $f_activesync == 1 } {\n ACCESS::session data set \"session.user.microsoft-activesync\" 1\n }\n elseif { [ info exists f_auto_discover ] && $f_auto_discover == 1 } {\n ACCESS::session data set \"session.user.microsoft-autodiscover\" 1\n }\n elseif { [ info exists f_availability_service ] && $f_availability_service == 1 } {\n ACCESS::session data set \"session.user.microsoft-availabilityservice\" 1\n }\n elseif { [ info exists f_rpc_over_http ] && $f_rpc_over_http == 1 } {\n ACCESS::session data set \"session.user.microsoft-rpcoverhttp\" 1\n }\n elseif { [ info exists f_offline_address_book ] && $f_offline_address_book == 1 } {\n ACCESS::session data set \"session.user.microsoft-offlineaddressbook\" 1\n }\n elseif { [ info exists f_exchange_web_service ] && $f_exchange_web_service == 1 } {\n ACCESS::session data set \"session.user.microsoft-exchangewebservice\" 1\n }\n }\n if { [ info exists f_alt_inactivity_timeout ] && $f_alt_inactivity_timeout == 1 } {\n ACCESS::session data set \"session.inactivity_timeout\" $static::POLICY_ALT_INACTIVITY_TIMEOUT\n }\n }\n\n when HTTP_RESPONSE {\n if { [ info exists f_auto_discover ] && $f_auto_discover == 1 } {\n set content_len [ HTTP::header Content-Length ]\n if { $content_len > 0 } {\n HTTP::collect $content_len\n }\n }\n }\n when HTTP_RESPONSE_DATA {\n if { [ info exists f_auto_discover ] && $f_auto_discover == 1 } {\n if { [ regsub -line {<AuthPackage>Ntlm</AuthPackage>} [ HTTP::payload ] {<AuthPackage>Basic</AuthPackage>} payload ] != 0 } {\n HTTP::payload replace 0 $content_len $payload\n }\n }\n }\n when ACCESS_POLICY_COMPLETED {\n if { ! [ info exists user_key ] } {\n return\n }\n\n set user_key_value \"\"\n set f_delete_session 0\n set policy_result [ACCESS::policy result]\n set sid [ ACCESS::session sid ]\n\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX ACCESS_POLICY_COMPLETED: policy_result = \\\"$policy_result\\\" user_key = \\\"$user_key\\\" sid = \\\"$sid\\\"\"\n\n set inactivity_timeout [ACCESS::session data get \"session.inactivity_timeout\"]\n set max_sess_timeout [ACCESS::session data get \"session.max_session_timeout\"]\n if { $max_sess_timeout == \"\" } {\n set max_sess_timeout $PROFILE_MAX_SESS_TIMEOUT\n }\n\n switch $policy_result {\n \"allow\" {\n # We depends on this table record self-cleanup capability in order to\n # indirectly sync with session DB.\n set user_key_value $sid\n\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Result: Allow: $user_key => $sid $inactivity_timeout $max_sess_timeout\"\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX user_key_value = $user_key_value\"\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX sid = $sid\"\n }\n \"deny\" {\n # When necessary the admin here can check appropriate session variable\n # and decide what response more appropriate then this default response.\n ACCESS::respond 401 content $static::actsync_401_http_body Set-Cookie $static::ACCESS_DEL_COOKIE_HDR_VAL Connection close\n if { $static::POLICY_RESULT_CACHE_AUTHFAILED == 1 } {\n set user_key_value $static::POLICY_AUTHFAILED\n } else {\n set f_delete_session 1\n }\n }\n default {\n ACCESS::respond 503 content $static::actsync_503_http_body Connection close\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Got unsupported policy result for $user_key ($sid)\"\n set f_delete_session 1\n }\n }\n if { $user_key_value != \"\" } {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Setting $user_key => $user_key_value $inactivity_timeout $max_sess_timeout in table $static::ACCESS_USERKEY_TBLNAME\"\n\n table set -subtable $static::ACCESS_USERKEY_TBLNAME $user_key $user_key_value $inactivity_timeout $max_sess_timeout\n } else {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Deleting $user_key in table $static::ACCESS_USERKEY_TBLNAME\"\n\n table delete -subtable $static::ACCESS_USERKEY_TBLNAME $user_key\n }\n\n if { $f_delete_session == 1 } {\n ACCESS::session remove\n set f_delete_session 0\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Removing the session for $user_key.\"\n }\n }\ndefinition-signature feX9LM+vB6YOEdVF+EA1JtNyVkPaB7gwdW0JzaB083MXl4yPP2nZnjm+WAx3YQhsmLttq5UkPl1zHpr5H9cwJX1bu9BNMi/+n0bIqWOipDHhhSYQ+TH+a5jQUSeftISr52BSQxh0cQKZkzM3rFU/qRZn9D9Dbf0kDGiDC1KWwVosrdjp5tVHOiQXWx8zybbGPFfgBcIBE6IvOvGbh5ohebVL2ADZm0URRj2NM4ZvZ2T3C14k2rHGXnDdRsvhmf5USZ+FH1hoKtWRxqtFjkWIaqw8leenXeot1j2bdKy92/AVTC9oZj1HJN1ePuQo5v414zlUhMEtkVy/gaxvj1+vPQ==",
- "apiRawValues": {
- "verificationStatus": "signature-verified"
- }
- },
- {
- "kind": "tm:ltm:rule:rulestate",
- "name": "_sys_APM_Office365_SAML_BasicAuth",
- "partition": "Common",
- "fullPath": "/Common/_sys_APM_Office365_SAML_BasicAuth",
- "generation": 1,
- "selfLink": "https://localhost/mgmt/tm/ltm/rule/~Common~_sys_APM_Office365_SAML_BasicAuth?ver=12.1.2",
- "apiAnonymous": "nodelete nowrite \nwhen RULE_INIT {\n set static::ACCESS_LOG_ECP_PREFIX \"014d0002:7: ECP client\"\n }\n when HTTP_REQUEST {\n set http_path [string tolower [HTTP::path]]\n set http_hdr_auth [HTTP::header Authorization]\n set http_hdr_client_app [HTTP::header X-MS-Client-Application]\n set http_hdr_client_ip [HTTP::header X-MS-Forwarded-Client-IP]\n set MRHSession_cookie [HTTP::cookie value MRHSession]\n\n if { ($http_path == \"/saml/idp/profile/redirectorpost/sso\") &&\n ($http_hdr_client_app != \"\") &&\n ($http_hdr_client_app contains \"Microsoft.Exchange\") } {\n HTTP::uri \"/saml/idp/profile/ecp/sso\"\n } elseif { ($http_path != \"/saml/idp/profile/ecp/sso\") } {\n return\n }\n set f_saml_ecp_request 1\n unset http_path\n\n # If MRHSession cookie from client is present, skip further processing.\n if { $MRHSession_cookie != \"\" } {\n if { [ACCESS::session exists -state_allow -sid $MRHSession_cookie] } {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_ECP_PREFIX HTTP *VALID* MRHSession cookie: $MRHSession_cookie\"\n } else {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_ECP_PREFIX HTTP *INVALID* MRHSession cookie: $MRHSession_cookie\"\n }\n return\n }\n\n if { ($http_hdr_client_app != \"\") &&\n ($http_hdr_client_app contains \"Microsoft.Exchange\") &&\n ($http_hdr_client_ip != \"\") } {\n\t set src_ip $http_hdr_client_ip\n\t}\n unset http_hdr_client_app\n unset http_hdr_client_ip\n\n if { ! [ info exists src_ip ] } {\n set src_ip [IP::remote_addr]\n }\n\n # Only allow HTTP Basic Authentication.\n if { ($http_hdr_auth == \"\") || ([ string match -nocase {basic *} $http_hdr_auth ] != 1 ) } {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_ECP_PREFIX ECP request does not contain HTTP Basic Authorization header.\"\n unset http_hdr_auth\n return\n }\n\n set apm_username [ string tolower [HTTP::username] ]\n set apm_password [HTTP::password]\n\n binary scan [md5 \"$apm_password$src_ip\"] H* user_hash\n set user_key {}\n append user_key $apm_username \".\" $user_hash\n unset user_hash\n\n set apm_cookie_list [ ACCESS::user getsid $user_key ]\n if { [ llength $apm_cookie_list ] != 0 } {\n set apm_cookie [ ACCESS::user getkey [ lindex $apm_cookie_list 0 ] ]\n if { $apm_cookie != \"\" } {\n HTTP::cookie insert name MRHSession value $apm_cookie\n }\n }\n\n HTTP::header insert \"clientless-mode\" 1\n HTTP::header insert \"username\" $apm_username\n HTTP::header insert \"password\" $apm_password\n unset apm_username\n unset apm_password\n unset http_hdr_auth\n }\n\n when ACCESS_SESSION_STARTED {\n if { [ info exists f_saml_ecp_request ] && $f_saml_ecp_request == 1 } {\n if { [ info exists user_key ] } {\n ACCESS::session data set \"session.user.uuid\" $user_key\n }\n if { [ info exists src_ip ] } {\n ACCESS::session data set \"session.user.clientip\" $src_ip\n }\n }\n }\n\n when HTTP_RESPONSE {\n if { [ info exists f_saml_ecp_request ] && $f_saml_ecp_request == 1 } {\n unset f_saml_ecp_request\n unset apm_cookie\n }\n }\ndefinition-signature hbkbqtFWuaW9oegh6SzMveAg8WY7+tJBg32EgZs3djEixBoxjXoktrb/mcfl3FmsQXRgE6LgrZCeIvjqLdk/8/wq/4wnd4naYm2VALVoBPeETuCpWdmiyiwuvFC5G4VlYhqhYhRsx9mQhbRWm8/YvoBpvNnCCSdyx/wL+KcYQGU7Zv4woZrtruq4RiLCm6ohutAWdS2NbeIQHG37NFXT6wV6pR9EIqrkNetbXAdi6OZGuuthSXMSXMz64+CwkzpptxP3bhOsFvM/gq8FfWR8rsRJfxaHg+njkkgKSkH3TL7vhDnL3pXcHhH1/9P6qDU++YAyiXzppOlLHib33Rv0yw==",
- "apiRawValues": {
- "verificationStatus": "signature-verified"
- }
- },
- {
- "kind": "tm:ltm:rule:rulestate",
- "name": "_sys_APM_activesync",
- "partition": "Common",
- "fullPath": "/Common/_sys_APM_activesync",
- "generation": 1,
- "selfLink": "https://localhost/mgmt/tm/ltm/rule/~Common~_sys_APM_activesync?ver=12.1.2",
- "apiAnonymous": "nodelete nowrite \nwhen RULE_INIT {\n set static::actsync_401_http_body \"<html><title>Authentication Failed</title><body>Error: Authentication Failure</body></html>\"\n set static::actsync_503_http_body \"<html><title>Service is not available</title><body>Error: Service is not available</body></html>\"\n set static::ACCESS_LOG_PREFIX \"01490000:7:\"\n }\n when HTTP_REQUEST {\n set http_path [string tolower [HTTP::path]]\n set f_clientless_mode 0\n\n if { $http_path == \"/microsoft-server-activesync\" } {\n }\n elseif { $http_path == \"/autodiscover/autodiscover.xml\" } {\n set f_auto_discover 1\n }\n else return\n\n if { ! [ info exists src_ip ] } {\n set src_ip [IP::remote_addr]\n }\n if { ! [ info exists PROFILE_RESTRICT_SINGLE_IP ] } {\n set PROFILE_RESTRICT_SINGLE_IP \t 1\n }\n # Only allow HTTP Basic Authentication.\n set auth_info_b64enc \"\"\n set http_hdr_auth [HTTP::header Authorization]\n regexp -nocase {Basic (.*)} $http_hdr_auth match auth_info_b64enc\n if { $auth_info_b64enc == \"\" } {\n set http_hdr_auth \"\"\n }\n\n if { $http_hdr_auth == \"\" } {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX Empty/invalid HTTP Basic Authorization header\"\n HTTP::respond 401 content $static::actsync_401_http_body Connection close\n return\n }\n\n set MRHSession_cookie [HTTP::cookie value MRHSession]\n # Do we have valid MRHSession cookie.\n if { $MRHSession_cookie != \"\" } {\n if { [ACCESS::session exists -state_allow -sid $MRHSession_cookie] } {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX HTTP *VALID* MRHSession cookie: $MRHSession_cookie\"\n # Default profile access setting is false\n if { $PROFILE_RESTRICT_SINGLE_IP == 0 } {\n return\n }\n elseif { [ IP::addr $src_ip equals [ ACCESS::session data get -sid $MRHSession_cookie \"session.user.clientip\" ] ] } {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX source IP matched\"\n return\n }\n else {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX source IP does not matched\"\n }\n }\n else {\n log -noname accesscontrol.local1.debug \"$static::ACCESS_LOG_PREFIX HTTP *INVALID* MRHSession cookie: $MRHSession_cookie\"\n }\n set MRHSession_cookie \"\"\n HTTP::cookie remove MRHSession\n }\n\n set apm_username [ string tolower [HTTP::username] ]\n set apm_password [HTTP::password]\n\n if { $PROFILE_RESTRICT_SINGLE_IP == 0 } {\n binary scan [md5 \"$apm_password$\"] H* user_hash\n } else {\n binary scan [md5 \"$apm_password$src_ip\"] H* user_hash\n }\n set user_key {}\n append user_key $apm_username \".\" $user_hash\n unset user_hash\n\n set f_insert_clientless_mode 0\n set apm_cookie_list [ ACCESS::user getsid $user_key ]\n if { [ llength $apm_cookie_list ] != 0 } {\n set apm_cookie [ ACCESS::user getkey [ lindex $apm_cookie_list 0 ] ]\n if { $apm_cookie != \"\" } {\n HTTP::cookie insert name MRHSession value $apm_cookie\n } else {\n set f_insert_clientless_mode 1\n }\n } else {\n set f_insert_clientless_mode 1\n }\n\n if { $f_insert_clientless_mode == 1 } {\n HTTP::header insert \"clientless-mode\" 1\n HTTP::header insert \"username\" $apm_username\n HTTP::header insert \"password\" $apm_password\n }\n unset f_insert_clientless_mode\n }\n when ACCESS_SESSION_STARTED {\n if { [ info exists user_key ] } {\n ACCESS::session data set \"session.user.uuid\" $user_key\n ACCESS::session data set \"session.user.microsoft-exchange-client\" 1\n ACCESS::session data set \"session.user.activesync\" 1\n if { [ info exists f_auto_discover ] && $f_auto_discover == 1 } {\n set f_auto_discover 0\n ACCESS::session data set \"session.user.microsoft-autodiscover\" 1\n }\n }\n }\n when ACCESS_POLICY_COMPLETED {\n if { ! [ info exists user_key ] } {\n return\n }\n\n set policy_result [ACCESS::policy result]\n switch $policy_result {\n \"allow\" {\n }\n \"deny\" {\n ACCESS::respond 401 content $static::actsync_401_http_body Connection close\n ACCESS::session remove\n }\n default {\n ACCESS::respond 503 content $static::actsync_503_http_body Connection close\n ACCESS::session remove\n }\n }\n\n unset user_key\n }\ndefinition-signature jaSGZiyISQHfZu1LLt3cmS5U/vOKRUOkQZ6ZHyc0fdnKtv+VsbRUIgzQwpV1dsN+wzuFhWxEsvSzleGZSrRmlBRbO63jjeBg9jzCqj8/hfOHhPCMSP59w3/opbCnAlqt+TyCFDY1cJ6/b/SWS+irPeAt6gAl0kmw2TIBlJvxm93zTu8aWyBgQV+205oBEPjYVHjaFPGFPk5+5LnZWrBO1fC0jBqpkCT+LWxBGeVHRTC8sGup0SuhXFPfWu3oB1uTTo5SKr8ZxRUFUrLTHNj/W8RKWg2C34958TFngZNQhpxg+XGWEFJXpCkeM2fVJXN3mymRWxuanYLU26ZKXuNNxw==",
- "apiRawValues": {
- "verificationStatus": "signature-verified"
- }
- },
- {
- "kind": "tm:ltm:rule:rulestate",
- "name": "_sys_auth_krbdelegate",
- "partition": "Common",
- "fullPath": "/Common/_sys_auth_krbdelegate",
- "generation": 1,
- "selfLink": "https://localhost/mgmt/tm/ltm/rule/~Common~_sys_auth_krbdelegate?ver=12.1.2",
- "apiAnonymous": "nodelete nowrite \nwhen HTTP_REQUEST {\n set thecert \"\"\n set ckname F5KRBAUTH\n set ckpass abc123\n set authprofiles [PROFILE::list auth]\n # Search the auth profiles for the krbdelegate(7) and grab cookie info\n foreach profname $authprofiles {\n if { [PROFILE::auth $profname type] == 7 } {\n set tmpckname [PROFILE::auth $profname cookie_name]\n set tmpckpass [PROFILE::auth $profname cookie_key]\n if {[PROFILE::auth $profname cookie_name] != \"\" } {\n set ckname $tmpckname\n set ckpass $tmpckpass\n break\n }\n }\n }\n set seecookie 0\n set insertcookie 0\n # check for the cookie\n if {not [info exists tmm_auth_http_sids(krbdelegate)]} {\n set tmm_auth_sid [AUTH::start pam default_krbdelegate]\n set tmm_auth_http_sids(krbdelegate) $tmm_auth_sid\n AUTH::subscribe $tmm_auth_sid\n } else {\n set tmm_auth_sid $tmm_auth_http_sids(krbdelegate)\n }\n if { [PROFILE::exists clientssl] } {\n set certcmd \"SSL::cert 0\"\n set thecert [ eval $certcmd ]\n }\n if { $thecert == \"\" } {\n # if no cert, assume old kerb delegation\n # if there is no Authorization header and no cookie, get one.\n if { ([HTTP::header Authorization] == \"\") and\n (not [HTTP::cookie exists $ckname])} {\n HTTP::respond 401 WWW-Authenticate Negotiate\n return\n }\n }\n if {[HTTP::cookie exists $ckname]} {\n set ckval [HTTP::cookie decrypt $ckname $ckpass]\n AUTH::username_credential $tmm_auth_sid \"cookie\"\n AUTH::password_credential $tmm_auth_sid $ckval\n set seecookie 1\n } else {\n if { $thecert == \"\" } {\n # Kerberos Delegation - set username\n # Strip off the Negotiate before the base64d goodness\n AUTH::username_credential $tmm_auth_sid [lindex [HTTP::header Authorization] 1]\n }\n else {\n # Protocol Transition - set ttm_auth_sid\n AUTH::username_credential $tmm_auth_sid \"krpprottran\"\n AUTH::cert_credential $tmm_auth_sid $thecert\n }\n AUTH::password_credential $tmm_auth_sid \"xxxx\"\n }\n AUTH::authenticate $tmm_auth_sid\n\n if {not [info exists tmm_auth_http_collect_count]} {\n HTTP::collect\n set tmm_auth_http_successes 0\n set tmm_auth_http_collect_count 1\n } else {\n incr tmm_auth_http_collect_count\n }\n }\n when AUTH_RESULT {\n if {not [info exists tmm_auth_http_sids(krbdelegate)] or \\\n ($tmm_auth_http_sids(krbdelegate) != [AUTH::last_event_session_id]) or \\\n (not [info exists tmm_auth_http_collect_count])} {\n return\n }\n if {[AUTH::status] == 0} {\n incr tmm_auth_http_successes\n }\n # If multiple auth sessions are pending and\n # one failure results in termination and this is a failure\n # or enough successes have now occurred\n if {([array size tmm_auth_http_sids] > 1) and \\\n ((not [info exists tmm_auth_http_sufficient_successes] or \\\n ($tmm_auth_http_successes >= $tmm_auth_http_sufficient_successes)))} {\n # Abort the other auth sessions\n foreach {type sid} [array get tmm_auth_http_sids] {\n unset tmm_auth_http_sids($type)\n if {($type ne \"krbdelegate\") and ($sid != -1)} {\n AUTH::abort $sid\n incr tmm_auth_http_collect_count -1\n }\n }\n }\n # If this is the last outstanding auth then either\n # release or respond to this session\n incr tmm_auth_http_collect_count -1\n if {$tmm_auth_http_collect_count == 0} {\n unset tmm_auth_http_collect_count\n if { [AUTH::status] == 0 } {\n array set pamout [AUTH::response_data]\n HTTP::header replace Authorization \"Negotiate $pamout(krbdelegate:attr:SPNEGO)\"\n if {$seecookie == 0} {\n set insertcookie $pamout(krbdelegate:attr:KRB5CCNAME)\n }\n HTTP::release\n } else {\n HTTP::respond 401 WWW-Authenticate Negotiate \"Set-Cookie\" \"$ckname= ; expires=Wed Dec 31 16:00:00 1969\"\n }\n }\n }\n # When the response goes out, if we need to insert a cookie, do it.\n when HTTP_RESPONSE {\n if {$insertcookie != 0} {\n HTTP::cookie insert name $ckname value $insertcookie\n HTTP::cookie encrypt $ckname $ckpass\n }\n }\ndefinition-signature mILi/VF69pqpNg+XJ4nClBl8+zq4v9FsiBYnKjX3zLZOChRWKt5CwkwpsbCRzx5DnvHglp9uXDYrjqcAFvM5aRA2R5LAhKQSq6pVPwHdZUJluYv0t3n6af/vSyc7KYsx6gga1jLuiFZaEzmG8c+r4igxwEee874iQBjYaWhHyKYGhlhly/Ez2FE9DNRpRepz2sq/jaKzEmmMod3CCXurXVGlC/Pk8qnbNid1yC15DGosrAKW1d8lhYbVBaXVQ1ahrr/UPYnDdHB1BiWUzRSS4uOKuUyUmT/xPI14/Nwv8zdFvlu+AnnD543zH6KhdSHhJ3zCVy2HSZ5wPuN3YswcBA==",
- "apiRawValues": {
- "verificationStatus": "signature-verified"
- }
- },
- {
- "kind": "tm:ltm:rule:rulestate",
- "name": "_sys_auth_ldap",
- "partition": "Common",
- "fullPath": "/Common/_sys_auth_ldap",
- "generation": 1,
- "selfLink": "https://localhost/mgmt/tm/ltm/rule/~Common~_sys_auth_ldap?ver=12.1.2",
- "apiAnonymous": "nodelete nowrite \nwhen HTTP_REQUEST {\n if {not [info exists tmm_auth_http_sids(ldap)]} {\n set tmm_auth_sid [AUTH::start pam default_ldap]\n set tmm_auth_http_sids(ldap) $tmm_auth_sid\n if {[info exists tmm_auth_subscription]} {\n AUTH::subscribe $tmm_auth_sid\n }\n } else {\n set tmm_auth_sid $tmm_auth_http_sids(ldap)\n }\n AUTH::username_credential $tmm_auth_sid [HTTP::username]\n AUTH::password_credential $tmm_auth_sid [HTTP::password]\n AUTH::authenticate $tmm_auth_sid\n\n if {not [info exists tmm_auth_http_collect_count]} {\n HTTP::collect\n set tmm_auth_http_successes 0\n set tmm_auth_http_collect_count 1\n } else {\n incr tmm_auth_http_collect_count\n }\n }\n when AUTH_RESULT {\n if {not [info exists tmm_auth_http_sids(ldap)] or \\\n ($tmm_auth_http_sids(ldap) != [AUTH::last_event_session_id]) or \\\n (not [info exists tmm_auth_http_collect_count])} {\n return\n }\n if {[AUTH::status] == 0} {\n incr tmm_auth_http_successes\n }\n # If multiple auth sessions are pending and\n # one failure results in termination and this is a failure\n # or enough successes have now occurred\n if {([array size tmm_auth_http_sids] > 1) and \\\n ((not [info exists tmm_auth_http_sufficient_successes] or \\\n ($tmm_auth_http_successes >= $tmm_auth_http_sufficient_successes)))} {\n # Abort the other auth sessions\n foreach {type sid} [array get tmm_auth_http_sids] {\n unset tmm_auth_http_sids($type)\n if {($type ne \"ldap\") and ($sid != -1)} {\n AUTH::abort $sid\n incr tmm_auth_http_collect_count -1\n }\n }\n }\n\n # If this is the last outstanding auth then either\n # release or respond to this session\n incr tmm_auth_http_collect_count -1\n if {$tmm_auth_http_collect_count == 0} {\n unset tmm_auth_http_collect_count\n if {[AUTH::status] == 0} {\n HTTP::release\n } else {\n HTTP::respond 401\n }\n }\n }\ndefinition-signature d+BwFQlDUIY7Jf5jfpCFuEkwn/jJ+3ZjEQLQej71v7TxzQpxJps4rDaU2YxBNyM9CTAIWT3DRdLqYZAnIHqVpOIRIE/ALk0v0o79IxJIES4nUTE9UTHKM8GN13VBkihf1I8O9DmwOHgB1s0HV+A/dy5mDiyBFpbamyv6rJCASItyPp2Y7iKfcMHEFe+qgvZFA2B131QVAosIn6pFribwU5LSvArIul5pIgX1tcuI+BLPkaJy6xoN9AQcah/ufgUCOmAvkc/K5LteBkxG3ItldFNaxOtAPXDt5IDhrBuMxsvRs7P+vMbfNiGb+QSakipxML2EmwCRiacxQTZn/0DDrw==",
- "apiRawValues": {
- "verificationStatus": "signature-verified"
- }
- },
- {
- "kind": "tm:ltm:rule:rulestate",
- "name": "_sys_auth_radius",
- "partition": "Common",
- "fullPath": "/Common/_sys_auth_radius",
- "generation": 1,
- "selfLink": "https://localhost/mgmt/tm/ltm/rule/~Common~_sys_auth_radius?ver=12.1.2",
- "apiAnonymous": "nodelete nowrite \nwhen HTTP_REQUEST {\n if {not [info exists tmm_auth_http_sids(radius)]} {\n set tmm_auth_sid [AUTH::start pam default_radius]\n set tmm_auth_http_sids(radius) $tmm_auth_sid\n if {[info exists tmm_auth_subscription]} {\n AUTH::subscribe $tmm_auth_sid\n }\n } else {\n set tmm_auth_sid $tmm_auth_http_sids(radius)\n }\n AUTH::username_credential $tmm_auth_sid [HTTP::username]\n AUTH::password_credential $tmm_auth_sid [HTTP::password]\n AUTH::authenticate $tmm_auth_sid\n\n if {not [info exists tmm_auth_http_collect_count]} {\n HTTP::collect\n set tmm_auth_http_successes 0\n set tmm_auth_http_collect_count 1\n } else {\n incr tmm_auth_http_collect_count\n }\n }\n when AUTH_RESULT {\n if {not [info exists tmm_auth_http_sids(radius)] or \\\n ($tmm_auth_http_sids(radius) != [AUTH::last_event_session_id]) or \\\n (not [info exists tmm_auth_http_collect_count])} {\n return\n }\n if {[AUTH::status] == 0} {\n incr tmm_auth_http_successes\n }\n # If multiple auth sessions are pending and\n # one failure results in termination and this is a failure\n # or enough successes have now occurred\n if {([array size tmm_auth_http_sids] > 1) and \\\n ((not [info exists tmm_auth_http_sufficient_successes] or \\\n ($tmm_auth_http_successes >= $tmm_auth_http_sufficient_successes)))} {\n # Abort the other auth sessions\n foreach {type sid} [array get tmm_auth_http_sids] {\n unset tmm_auth_http_sids($type)\n if {($type ne \"radius\") and ($sid != -1)} {\n AUTH::abort $sid\n incr tmm_auth_http_collect_count -1\n }\n }\n }\n # If this is the last outstanding auth then either\n # release or respond to this session\n incr tmm_auth_http_collect_count -1\n if {$tmm_auth_http_collect_count == 0} {\n unset tmm_auth_http_collect_count\n if { [AUTH::status] == 0 } {\n HTTP::release\n } else {\n HTTP::respond 401\n }\n }\n }\ndefinition-signature m0ZhOZjHe7lvErKAbir601WnOlWEPfEh/Qc5wayIKc6B16E4IF4F+Jh8QGdYRgNOrk3Qc3Gid6zQZcCcbIzfR3NKOxfVX+tl0KfiEN1lqBQMLu3/AooE+/YTC5oCPuvV6TK/JHRLiMiexYgRx6G+AFU7xg/w/YzgvV0bjsd9OxdIUB3WO5JOUweCG6q24zhVgN+3QIIiBnuKaMeHtRSw29xVpuQqgNKVG7RaPu15loA0xp8s4fxMF0YHDYPuQuu0PLfvYTqsSP0cI3Kdbsg5JgAIAcdHlFIW3NaUJBPMGRLOAvSGibIMVhFmUfC52LNQ4iORtokInaHyYUtPQ/yHIw==",
- "apiRawValues": {
- "verificationStatus": "signature-verified"
- }
- },
- {
- "kind": "tm:ltm:rule:rulestate",
- "name": "_sys_auth_ssl_cc_ldap",
- "partition": "Common",
- "fullPath": "/Common/_sys_auth_ssl_cc_ldap",
- "generation": 1,
- "selfLink": "https://localhost/mgmt/tm/ltm/rule/~Common~_sys_auth_ssl_cc_ldap?ver=12.1.2",
- "apiAnonymous": "nodelete nowrite \nwhen CLIENT_ACCEPTED {\n set tmm_auth_ssl_cc_ldap_sid 0\n set tmm_auth_ssl_cc_ldap_done 0\n }\n when CLIENTSSL_CLIENTCERT {\n if {[SSL::cert count] == 0} {\n return\n }\n set tmm_auth_ssl_cc_ldap_done 0\n if {$tmm_auth_ssl_cc_ldap_sid == 0} {\n set tmm_auth_ssl_cc_ldap_sid [AUTH::start pam default_ssl_cc_ldap]\n if {[info exists tmm_auth_subscription]} {\n AUTH::subscribe $tmm_auth_ssl_cc_ldap_sid\n }\n }\n AUTH::cert_credential $tmm_auth_ssl_cc_ldap_sid [SSL::cert 0]\n AUTH::authenticate $tmm_auth_ssl_cc_ldap_sid\n SSL::handshake hold\n }\n when CLIENTSSL_HANDSHAKE {\n set tmm_auth_ssl_cc_ldap_done 1\n }\n when AUTH_RESULT {\n if {[info exists tmm_auth_ssl_cc_ldap_sid] and \\\n ($tmm_auth_ssl_cc_ldap_sid == [AUTH::last_event_session_id])} {\n set tmm_auth_status [AUTH::status]\n if {$tmm_auth_status == 0} {\n set tmm_auth_ssl_cc_ldap_done 1\n SSL::handshake resume\n } elseif {$tmm_auth_status != -1 || $tmm_auth_ssl_cc_ldap_done == 0} {\n reject\n }\n }\n }\ndefinition-signature O2ctQteahGXIbb4l9/vERvtwKeyl51hGNNGgccddtwme/6opsgPJu5gaiVGUXYYDkbcjFdfgDTU9oDPkLl5JmZ3VcExnlnvxLpVDuM/fKqxbgoRQZ6nl0mEceHmWxRY9AlhrODtJZxNRbQBu4OOCYS+yWioKgKkrBwQaEoIFBPSSUmeIPZHTXdNnLXwxxkY75O5Sc4sTkYQ3BvTrlu/frnwweed6qw9bWatN865CIzP3Spq0ELY0Q4bvxo+0JdLheFv2BfKUethrjEXcxiD9Ros0fnvQ83qaCHqt18xEyhakdKAf4gKZJt9UApkRn+1ZTPNJFzgQyPPYQGvU/y9JAQ==",
- "apiRawValues": {
- "verificationStatus": "signature-verified"
- }
- },
- {
- "kind": "tm:ltm:rule:rulestate",
- "name": "_sys_auth_ssl_crldp",
- "partition": "Common",
- "fullPath": "/Common/_sys_auth_ssl_crldp",
- "generation": 1,
- "selfLink": "https://localhost/mgmt/tm/ltm/rule/~Common~_sys_auth_ssl_crldp?ver=12.1.2",
- "apiAnonymous": "nodelete nowrite \nwhen CLIENT_ACCEPTED {\n set tmm_auth_ssl_crldp_sid 0\n set tmm_auth_ssl_crldp_done 0\n }\n when CLIENTSSL_CLIENTCERT {\n if {[SSL::cert count] == 0} {\n return\n }\n set tmm_auth_ssl_crldp_done 0\n if {$tmm_auth_ssl_crldp_sid == 0} {\n set tmm_auth_ssl_crldp_sid [AUTH::start pam default_ssl_crldp]\n if {[info exists tmm_auth_subscription]} {\n AUTH::subscribe $tmm_auth_ssl_crldp_sid\n }\n }\n AUTH::cert_credential $tmm_auth_ssl_crldp_sid [SSL::cert 0]\n AUTH::cert_issuer_credential $tmm_auth_ssl_crldp_sid [SSL::cert issuer 0]\n AUTH::authenticate $tmm_auth_ssl_crldp_sid\n SSL::handshake hold\n }\n when CLIENTSSL_HANDSHAKE {\n set tmm_auth_ssl_crldp_done 1\n }\n when AUTH_RESULT {\n if {[info exists tmm_auth_ssl_crldp_sid] and \\\n ($tmm_auth_ssl_crldp_sid == [AUTH::last_event_session_id])} {\n set tmm_auth_status [AUTH::status]\n if {$tmm_auth_status == 0} {\n set tmm_auth_ssl_crldp_done 1\n SSL::handshake resume\n } elseif {$tmm_auth_status != -1 || $tmm_auth_ssl_crldp_done == 0} {\n reject\n }\n }\n }\ndefinition-signature PhTy24ctbtx0d4kFIFO6+Fr9W3a/7OetZ7nlh18mpH6BB9t1dB2LNayATLZ3q4iT4wLLdyyxA+g4jdrNBeuZVpM2JOBlhwcyIcTBFLQN4H/mkWErH4Vz9ZMxVduUxHN6fIh8zDQuJJYoRVlz087/vIVvk6ygbPwS9KqTdYBa3Nn79YmIVn1NXKyVoCg/40EZ3iNklwIfKctwqGU5ELKbhwk8CGCvexDbJcwRqv8nAETC4B/nc61jpGcihpOJchJFb3buTiAKwfxSYkx90UG4EnwsyA4GqUNIfS02Dj5rYSMH403CNNBKG2AA+ZGy9by2O3bb9lq/VNGPDmsnMEff1g==",
- "apiRawValues": {
- "verificationStatus": "signature-verified"
- }
- },
- {
- "kind": "tm:ltm:rule:rulestate",
- "name": "_sys_auth_ssl_ocsp",
- "partition": "Common",
- "fullPath": "/Common/_sys_auth_ssl_ocsp",
- "generation": 1,
- "selfLink": "https://localhost/mgmt/tm/ltm/rule/~Common~_sys_auth_ssl_ocsp?ver=12.1.2",
- "apiAnonymous": "nodelete nowrite \nwhen CLIENT_ACCEPTED {\n set tmm_auth_ssl_ocsp_sid 0\n set tmm_auth_ssl_ocsp_done 0\n }\n when CLIENTSSL_CLIENTCERT {\n if {[SSL::cert count] == 0} {\n return\n }\n set tmm_auth_ssl_ocsp_done 0\n if {$tmm_auth_ssl_ocsp_sid == 0} {\n set tmm_auth_ssl_ocsp_sid [AUTH::start pam default_ssl_ocsp]\n if {[info exists tmm_auth_subscription]} {\n AUTH::subscribe $tmm_auth_ssl_ocsp_sid\n }\n }\n AUTH::cert_credential $tmm_auth_ssl_ocsp_sid [SSL::cert 0]\n AUTH::cert_issuer_credential $tmm_auth_ssl_ocsp_sid [SSL::cert issuer 0]\n AUTH::authenticate $tmm_auth_ssl_ocsp_sid\n SSL::handshake hold\n }\n when CLIENTSSL_HANDSHAKE {\n set tmm_auth_ssl_ocsp_done 1\n }\n when AUTH_RESULT {\n if {[info exists tmm_auth_ssl_ocsp_sid] and \\\n ($tmm_auth_ssl_ocsp_sid == [AUTH::last_event_session_id])} {\n set tmm_auth_status [AUTH::status]\n if {$tmm_auth_status == 0} {\n set tmm_auth_ssl_ocsp_done 1\n SSL::handshake resume\n } elseif {$tmm_auth_status != -1 || $tmm_auth_ssl_ocsp_done == 0} {\n reject\n }\n }\n }\ndefinition-signature mHRNmZiszQh85wPdt5PxM2ASLXyW47LE3CM5tS11M1lTe9ttjlWDc6yBdy5VFjC6H2O2DJ+fyrBmeMen16RVWPhUoq8YOJC9ZiuuLc6T/rW9GsopSHFPBLRjL/EPulNkuGB/DtxYvwXfXOyBuVRw+E/TYkKVi6cIrk4+e9mOnCo9biWycrRfemWwYyDCqouEaDK2huYnQ1rKyYAvIWxfd3rXXw6+jdpuvL/6RFXJjaLTJ/f1pVMHP5kuI2K/dkeojqDDgr1d1GnjIFFX2Azh5qZpaL1urPfn/M6C/7sXzew1PU0ow10MQtKKqAno5IpEpn+cPZlCs3d2Y1khtMqUug==",
- "apiRawValues": {
- "verificationStatus": "signature-verified"
- }
- },
- {
- "kind": "tm:ltm:rule:rulestate",
- "name": "_sys_auth_tacacs",
- "partition": "Common",
- "fullPath": "/Common/_sys_auth_tacacs",
- "generation": 1,
- "selfLink": "https://localhost/mgmt/tm/ltm/rule/~Common~_sys_auth_tacacs?ver=12.1.2",
- "apiAnonymous": "nodelete nowrite \nwhen HTTP_REQUEST {\n if {not [info exists tmm_auth_http_sids(tacacs)]} {\n set tmm_auth_sid [AUTH::start pam default_tacacs]\n set tmm_auth_http_sids(tacacs) $tmm_auth_sid\n if {[info exists tmm_auth_subscription]} {\n AUTH::subscribe $tmm_auth_sid\n }\n } else {\n set tmm_auth_sid $tmm_auth_http_sids(tacacs)\n }\n AUTH::username_credential $tmm_auth_sid [HTTP::username]\n AUTH::password_credential $tmm_auth_sid [HTTP::password]\n AUTH::authenticate $tmm_auth_sid\n\n if {not [info exists tmm_auth_http_collect_count]} {\n HTTP::collect\n set tmm_auth_http_successes 0\n set tmm_auth_http_collect_count 1\n } else {\n incr tmm_auth_http_collect_count\n }\n }\n when AUTH_RESULT {\n if {not [info exists tmm_auth_http_sids(tacacs)] or \\\n ($tmm_auth_http_sids(tacacs) != [AUTH::last_event_session_id]) or \\\n (not [info exists tmm_auth_http_collect_count])} {\n return\n }\n if {[AUTH::status] == 0} {\n incr tmm_auth_http_successes\n }\n # If multiple auth sessions are pending and\n # one failure results in termination and this is a failure\n # or enough successes have now occurred\n if {([array size tmm_auth_http_sids] > 1) and \\\n ((not [info exists tmm_auth_http_sufficient_successes] or \\\n ($tmm_auth_http_successes >= $tmm_auth_http_sufficient_successes)))} {\n # Abort the other auth sessions\n foreach {type sid} [array get tmm_auth_http_sids] {\n unset tmm_auth_http_sids($type)\n if {($type ne \"tacacs\") and ($sid != -1)} {\n AUTH::abort $sid\n incr tmm_auth_http_collect_count -1\n }\n }\n }\n # If this is the last outstanding auth then either\n # release or respond to this session\n incr tmm_auth_http_collect_count -1\n if {$tmm_auth_http_collect_count == 0} {\n unset tmm_auth_http_collect_count\n if { [AUTH::status] == 0 } {\n HTTP::release\n } else {\n HTTP::respond 401\n }\n }\n }\ndefinition-signature GHNO23blFC/AnIkRk9DSySYK2LiesD7h2DliAMIsVIjBk/RFL8XvZ+8WuKMVibuCiAhPWWvUu6nKsTnk9pX5/kc4yV6qRHcaaO+UaqT1/KQZsVXShCf0YCzqjRQIduJhUFFn0MUDhDmo/8ti0Upo6loKBxW3TODx5y8Jf3dTKmX2oRMfrkiMEyVtv38O7MDwJ1H5/xF2z1r2+nWGUJThZq/ILpfzcdnI7X5j/PxnAGuL1zciRIZ/0RIyMvYch0GaoXaKLVaONzDm0nHEJ+hZ7Vp8mQZiRitc8MGs1Ku9yLamxosUFAdRVnNQOLXGrlvEm94oU6XR3mq0oeqx9+dnOQ==",
- "apiRawValues": {
- "verificationStatus": "signature-verified"
- }
- },
- {
- "kind": "tm:ltm:rule:rulestate",
- "name": "_sys_https_redirect",
- "partition": "Common",
- "fullPath": "/Common/_sys_https_redirect",
- "generation": 1,
- "selfLink": "https://localhost/mgmt/tm/ltm/rule/~Common~_sys_https_redirect?ver=12.1.2",
- "apiAnonymous": "nodelete nowrite \nwhen HTTP_REQUEST {\n HTTP::redirect https://[getfield [HTTP::host] \":\" 1][HTTP::uri]\n }\ndefinition-signature mwyl4XlRKRMQc0prWs7RtpgPcNfocOKb+MaFwAnQgAuUZZyG68OaGZsOCN3poUOFdHOc6fk2XAdGRmTRiP/7BCT7thsOX5zLFzA1N1wcr57KWVzEZt3ezxVXn2Z974OmbWm7P5Lclcr7N3adrLJMWfyfPPVF1tUYn0IQPD2QNMmfbcbr1oCuO93n/5dn0s6/EacHZGG53hVibW7xQuJXdMtoQ6ArSZ4U3n4vCDTb6NLYbAj6PirVzKY2pcsWFHFUSVrphSFwERc8+0XGHUE6Cb3ihzygoZc2cQ5jk3frFY70MkDluPTShFRbHd7PlMPRezrfkVZVeUHA/iBPcYcD+w==",
- "apiRawValues": {
- "verificationStatus": "signature-verified"
- }
- },
- {
- "kind": "tm:ltm:rule:rulestate",
- "name": "foo",
- "partition": "Common",
- "fullPath": "/Common/foo",
- "generation": 94,
- "selfLink": "https://localhost/mgmt/tm/ltm/rule/~Common~foo?ver=12.1.2",
- "apiAnonymous": "when RULE_INIT {\n set static::FormBaseURL \"/sp-ofba-form\"\n set static::FormReturnURL \"/sp-ofba-completed\"\n set static::HeadAuthReq \"X-FORMS_BASED_AUTH_REQUIRED\"\n set static::HeadAuthRet \"X-FORMS_BASED_AUTH_RETURN_URL\"\n set static::HeadAuthSize \"X-FORMS_BASED_AUTH_DIALOG_SIZE\"\n set static::HeadAuthSizeVal \"800x600\"\n set static::ckname \"MRHSession_SP\"\n set static::Basic_Realm_Text \"SharePoint Authentication\"\n}\n\nwhen HTTP_REQUEST {\n set apmsessionid [HTTP::cookie value MRHSession]\n}\n\nwhen HTTP_RESPONSE {\n # Insert persistent cookie for html content type and private session\n}"
- }
-]
diff --git a/test/units/modules/network/f5/fixtures/load_ltm_monitor_http.json b/test/units/modules/network/f5/fixtures/load_ltm_monitor_http.json
deleted file mode 100644
index 79121b2b96..0000000000
--- a/test/units/modules/network/f5/fixtures/load_ltm_monitor_http.json
+++ /dev/null
@@ -1,28 +0,0 @@
-{
- "kind": "tm:ltm:monitor:http:httpstate",
- "name": "asdf",
- "partition": "Common",
- "fullPath": "/Common/asdf",
- "generation": 0,
- "selfLink": "https://localhost/mgmt/tm/ltm/monitor/http/~Common~asdf?ver=13.0.0",
- "adaptive": "disabled",
- "adaptiveDivergenceType": "relative",
- "adaptiveDivergenceValue": 25,
- "adaptiveLimit": 200,
- "adaptiveSamplingTimespan": 300,
- "defaultsFrom": "/Common/http",
- "description": "this is a description",
- "destination": "1.1.1.1:389",
- "interval": 5,
- "ipDscp": 0,
- "manualResume": "disabled",
- "password": "$M$7T$DpzEUVHt5rKkAfqrBh1PTA==",
- "recv": "hello world",
- "reverse": "enabled",
- "send": "GET /\\r\\n",
- "timeUntilUp": 0,
- "timeout": 16,
- "transparent": "disabled",
- "upInterval": 0,
- "username": "john"
-}
diff --git a/test/units/modules/network/f5/fixtures/load_ltm_monitor_https.json b/test/units/modules/network/f5/fixtures/load_ltm_monitor_https.json
deleted file mode 100644
index ff4f53f277..0000000000
--- a/test/units/modules/network/f5/fixtures/load_ltm_monitor_https.json
+++ /dev/null
@@ -1,30 +0,0 @@
-{
- "kind": "tm:ltm:monitor:https:httpsstate",
- "name": "asdf",
- "partition": "Common",
- "fullPath": "/Common/asdf",
- "generation": 0,
- "selfLink": "https://localhost/mgmt/tm/ltm/monitor/https/~Common~asdf?ver=13.0.0",
- "adaptive": "disabled",
- "adaptiveDivergenceType": "relative",
- "adaptiveDivergenceValue": 25,
- "adaptiveLimit": 200,
- "adaptiveSamplingTimespan": 300,
- "cipherlist": "DEFAULT:+SHA:+3DES:+kEDH",
- "compatibility": "enabled",
- "defaultsFrom": "/Common/https",
- "description": "this is a description",
- "destination": "1.1.1.1:389",
- "interval": 5,
- "ipDscp": 0,
- "manualResume": "disabled",
- "password": "$M$7F$+F0VTCeKM4LbGkpC/u8pwg==",
- "recv": "hello world",
- "reverse": "disabled",
- "send": "GET /\\r\\n",
- "timeUntilUp": 0,
- "timeout": 16,
- "transparent": "disabled",
- "upInterval": 0,
- "username": "john"
-}
diff --git a/test/units/modules/network/f5/fixtures/load_ltm_monitor_tcp.json b/test/units/modules/network/f5/fixtures/load_ltm_monitor_tcp.json
deleted file mode 100644
index fb9572f7e7..0000000000
--- a/test/units/modules/network/f5/fixtures/load_ltm_monitor_tcp.json
+++ /dev/null
@@ -1,25 +0,0 @@
-{
- "kind": "tm:ltm:monitor:tcp:tcpstate",
- "name": "foo",
- "partition": "Common",
- "fullPath": "/Common/foo",
- "generation": 0,
- "selfLink": "https://localhost/mgmt/tm/ltm/monitor/tcp/~Common~foo?ver=12.1.0",
- "adaptive": "disabled",
- "adaptiveDivergenceType": "relative",
- "adaptiveDivergenceValue": 25,
- "adaptiveLimit": 200,
- "adaptiveSamplingTimespan": 300,
- "defaultsFrom": "/Common/tcp",
- "destination": "10.10.10.10:80",
- "interval": 20,
- "ipDscp": 0,
- "manualResume": "disabled",
- "recv": "this is a receive string",
- "reverse": "disabled",
- "send": "this is a send string",
- "timeUntilUp": 60,
- "timeout": 30,
- "transparent": "disabled",
- "upInterval": 0
-}
diff --git a/test/units/modules/network/f5/fixtures/load_ltm_monitor_tcp_echo.json b/test/units/modules/network/f5/fixtures/load_ltm_monitor_tcp_echo.json
deleted file mode 100644
index 1a5183466a..0000000000
--- a/test/units/modules/network/f5/fixtures/load_ltm_monitor_tcp_echo.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
- "kind": "tm:ltm:monitor:tcp-echo:tcp-echostate",
- "name": "foo",
- "partition": "Common",
- "fullPath": "/Common/foo",
- "generation": 0,
- "selfLink": "https://localhost/mgmt/tm/ltm/monitor/tcp-echo/~Common~foo?ver=13.0.0",
- "adaptive": "disabled",
- "adaptiveDivergenceType": "relative",
- "adaptiveDivergenceValue": 25,
- "adaptiveLimit": 200,
- "adaptiveSamplingTimespan": 300,
- "defaultsFrom": "/Common/tcp_echo",
- "destination": "10.10.10.10",
- "interval": 20,
- "manualResume": "disabled",
- "timeUntilUp": 60,
- "timeout": 30,
- "transparent": "disabled",
- "upInterval": 0
-}
diff --git a/test/units/modules/network/f5/fixtures/load_ltm_monitor_tcp_half_open.json b/test/units/modules/network/f5/fixtures/load_ltm_monitor_tcp_half_open.json
deleted file mode 100644
index ff99c31e69..0000000000
--- a/test/units/modules/network/f5/fixtures/load_ltm_monitor_tcp_half_open.json
+++ /dev/null
@@ -1,16 +0,0 @@
-{
- "kind": "tm:ltm:monitor:tcp-half-open:tcp-half-openstate",
- "name": "foo",
- "partition": "Common",
- "fullPath": "/Common/foo",
- "generation": 0,
- "selfLink": "https://localhost/mgmt/tm/ltm/monitor/tcp-half-open/~Common~foo?ver=13.0.0",
- "defaultsFrom": "/Common/tcp_half_open",
- "destination": "10.10.10.10:80",
- "interval": 20,
- "manualResume": "disabled",
- "timeUntilUp": 60,
- "timeout": 30,
- "transparent": "disabled",
- "upInterval": 0
-}
diff --git a/test/units/modules/network/f5/fixtures/load_ltm_monitor_udp.json b/test/units/modules/network/f5/fixtures/load_ltm_monitor_udp.json
deleted file mode 100644
index 636619a259..0000000000
--- a/test/units/modules/network/f5/fixtures/load_ltm_monitor_udp.json
+++ /dev/null
@@ -1,25 +0,0 @@
-{
- "kind": "tm:ltm:monitor:udp:udpstate",
- "name": "asdf",
- "partition": "Common",
- "fullPath": "/Common/asdf",
- "generation": 0,
- "selfLink": "https://localhost/mgmt/tm/ltm/monitor/udp/~Common~asdf?ver=13.0.0",
- "adaptive": "disabled",
- "adaptiveDivergenceType": "relative",
- "adaptiveDivergenceValue": 25,
- "adaptiveLimit": 200,
- "adaptiveSamplingTimespan": 300,
- "debug": "no",
- "defaultsFrom": "/Common/udp",
- "destination": "1.1.1.1:389",
- "interval": 5,
- "manualResume": "disabled",
- "recv": "hello world",
- "reverse": "disabled",
- "send": "default send string",
- "timeUntilUp": 0,
- "timeout": 16,
- "transparent": "disabled",
- "upInterval": 0
-}
diff --git a/test/units/modules/network/f5/fixtures/load_ltm_node_1.json b/test/units/modules/network/f5/fixtures/load_ltm_node_1.json
deleted file mode 100644
index 96d25b03d1..0000000000
--- a/test/units/modules/network/f5/fixtures/load_ltm_node_1.json
+++ /dev/null
@@ -1,25 +0,0 @@
-{
- "kind": "tm:ltm:node:nodestate",
- "name": "foo",
- "partition": "Common",
- "fullPath": "/Common/foo",
- "generation": 158,
- "selfLink": "https://localhost/mgmt/tm/ltm/node/~Common~foo?ver=13.0.0",
- "address": "1.2.3.4",
- "connectionLimit": 0,
- "description": "my description of node",
- "dynamicRatio": 1,
- "ephemeral": "false",
- "fqdn": {
- "addressFamily": "ipv4",
- "autopopulate": "disabled",
- "downInterval": 5,
- "interval": "3600"
- },
- "logging": "disabled",
- "monitor": "default",
- "rateLimit": "disabled",
- "ratio": 1,
- "session": "user-enabled",
- "state": "unchecked"
-}
diff --git a/test/units/modules/network/f5/fixtures/load_ltm_node_2.json b/test/units/modules/network/f5/fixtures/load_ltm_node_2.json
deleted file mode 100644
index f23f6b5f42..0000000000
--- a/test/units/modules/network/f5/fixtures/load_ltm_node_2.json
+++ /dev/null
@@ -1,26 +0,0 @@
-{
- "kind": "tm:ltm:node:nodestate",
- "name": "fqdn-foo",
- "partition": "Common",
- "fullPath": "/Common/fqdn-foo",
- "generation": 161,
- "selfLink": "https://localhost/mgmt/tm/ltm/node/~Common~fqdn-foo?ver=13.0.0",
- "address": "any6",
- "connectionLimit": 0,
- "description": "another node but with fqdn",
- "dynamicRatio": 1,
- "ephemeral": "false",
- "fqdn": {
- "addressFamily": "ipv4",
- "autopopulate": "disabled",
- "downInterval": 5,
- "interval": "3600",
- "tmName": "google.com"
- },
- "logging": "disabled",
- "monitor": "/Common/icmp and /Common/tcp_echo ",
- "rateLimit": "disabled",
- "ratio": 1,
- "session": "user-enabled",
- "state": "fqdn-up"
-}
diff --git a/test/units/modules/network/f5/fixtures/load_ltm_node_3.json b/test/units/modules/network/f5/fixtures/load_ltm_node_3.json
deleted file mode 100644
index c6e30cf32e..0000000000
--- a/test/units/modules/network/f5/fixtures/load_ltm_node_3.json
+++ /dev/null
@@ -1,24 +0,0 @@
-{
- "kind": "tm:ltm:node:nodestate",
- "name": "mytestserver",
- "partition": "Common",
- "fullPath": "/Common/mytestserver",
- "generation": 2286,
- "selfLink": "https://localhost/mgmt/tm/ltm/node/~Common~mytestserver?ver=13.0.0",
- "address": "10.20.30.40",
- "connectionLimit": 0,
- "dynamicRatio": 1,
- "ephemeral": "false",
- "fqdn": {
- "addressFamily": "ipv4",
- "autopopulate": "disabled",
- "downInterval": 5,
- "interval": "3600"
- },
- "logging": "disabled",
- "monitor": "/Common/icmp ",
- "rateLimit": "disabled",
- "ratio": 1,
- "session": "monitor-enabled",
- "state": "down"
-}
diff --git a/test/units/modules/network/f5/fixtures/load_ltm_policy_draft_rule_http-uri_forward.json b/test/units/modules/network/f5/fixtures/load_ltm_policy_draft_rule_http-uri_forward.json
deleted file mode 100644
index 53aa0c34ec..0000000000
--- a/test/units/modules/network/f5/fixtures/load_ltm_policy_draft_rule_http-uri_forward.json
+++ /dev/null
@@ -1,60 +0,0 @@
-{
- "kind": "tm:ltm:policy:rules:rulesstate",
- "name": "foo",
- "fullPath": "foo",
- "generation": 739,
- "selfLink": "https://localhost/mgmt/tm/ltm/policy/~Common~Drafts~Bondticker-DRN/rules/foo?expandSubcollections=true&ver=13.0.0",
- "ordinal": 0,
- "actionsReference": {
- "link": "https://localhost/mgmt/tm/ltm/policy/~Common~Drafts~Bondticker-DRN/rules/foo/actions?ver=13.0.0",
- "isSubcollection": true,
- "items": [
- {
- "kind": "tm:ltm:policy:rules:actions:actionsstate",
- "name": "0",
- "fullPath": "0",
- "generation": 739,
- "selfLink": "https://localhost/mgmt/tm/ltm/policy/~Common~Drafts~Bondticker-DRN/rules/foo/actions/0?ver=13.0.0",
- "code": 0,
- "expirySecs": 0,
- "forward": true,
- "length": 0,
- "node": "1.1.1.1",
- "offset": 0,
- "port": 0,
- "request": true,
- "select": true,
- "snat": "disable",
- "status": 0,
- "timeout": 0,
- "vlan": "/Common/net1",
- "vlanId": 0
- }
- ]
- },
- "conditionsReference": {
- "link": "https://localhost/mgmt/tm/ltm/policy/~Common~Drafts~Bondticker-DRN/rules/foo/conditions?ver=13.0.0",
- "isSubcollection": true,
- "items": [
- {
- "kind": "tm:ltm:policy:rules:conditions:conditionsstate",
- "name": "0",
- "fullPath": "0",
- "generation": 739,
- "selfLink": "https://localhost/mgmt/tm/ltm/policy/~Common~Drafts~Bondticker-DRN/rules/foo/conditions/0?ver=13.0.0",
- "caseInsensitive": true,
- "external": true,
- "httpUri": true,
- "index": 0,
- "path": true,
- "present": true,
- "remote": true,
- "request": true,
- "startsWith": true,
- "values": [
- "foo"
- ]
- }
- ]
- }
-}
diff --git a/test/units/modules/network/f5/fixtures/load_ltm_pool.json b/test/units/modules/network/f5/fixtures/load_ltm_pool.json
deleted file mode 100644
index cd5be5e1af..0000000000
--- a/test/units/modules/network/f5/fixtures/load_ltm_pool.json
+++ /dev/null
@@ -1,32 +0,0 @@
-{
- "kind": "tm:ltm:pool:poolstate",
- "name": "test_pool",
- "partition": "Common",
- "fullPath": "/Common/test_pool",
- "generation": 1452,
- "selfLink": "https://localhost/mgmt/tm/ltm/pool/~Common~test_pool?ver=11.5.4",
- "allowNat": "yes",
- "allowSnat": "yes",
- "description": "test",
- "ignorePersistedWeight": "disabled",
- "ipTosToClient": "pass-through",
- "ipTosToServer": "pass-through",
- "linkQosToClient": "pass-through",
- "linkQosToServer": "pass-through",
- "loadBalancingMode": "round-robin",
- "minActiveMembers": 0,
- "minUpMembers": 0,
- "minUpMembersAction": "failover",
- "minUpMembersChecking": "disabled",
- "monitor": "min 1 of { /Common/http /Common/inband }",
- "queueDepthLimit": 0,
- "queueOnConnectionLimit": "disabled",
- "queueTimeLimit": 0,
- "reselectTries": 0,
- "serviceDownAction": "reselect",
- "slowRampTime": 10,
- "membersReference": {
- "link": "https://localhost/mgmt/tm/ltm/pool/~Common~test_pool/members?ver=11.5.4",
- "isSubcollection": true
- }
-} \ No newline at end of file
diff --git a/test/units/modules/network/f5/fixtures/load_ltm_profile_analytics_1.json b/test/units/modules/network/f5/fixtures/load_ltm_profile_analytics_1.json
deleted file mode 100644
index 3e3fa2c06e..0000000000
--- a/test/units/modules/network/f5/fixtures/load_ltm_profile_analytics_1.json
+++ /dev/null
@@ -1,52 +0,0 @@
-{
- "kind": "tm:ltm:profile:analytics:analyticsstate",
- "name": "foo",
- "partition": "Common",
- "fullPath": "/Common/foo",
- "generation": 339,
- "selfLink": "https://localhost/mgmt/tm/ltm/profile/analytics/~Common~foo?ver=13.1.1",
- "appService": "none",
- "capturedTrafficExternalLogging": "disabled",
- "capturedTrafficInternalLogging": "disabled",
- "collectGeo": "disabled",
- "collectHttpTimingMetrics": "disabled",
- "collectIp": "disabled",
- "collectMaxTpsAndThroughput": "disabled",
- "collectMethods": "enabled",
- "collectOsAndBrowser": "enabled",
- "collectPageLoadTime": "disabled",
- "collectResponseCodes": "enabled",
- "collectSubnets": "disabled",
- "collectUrl": "disabled",
- "collectUserAgent": "disabled",
- "collectUserSessions": "disabled",
- "collectedStatsExternalLogging": "disabled",
- "collectedStatsInternalLogging": "enabled",
- "countriesForStatCollection": [],
- "defaultsFrom": "/Common/analytics",
- "defaultsFromReference": {
- "link": "https://localhost/mgmt/tm/ltm/profile/analytics/~Common~analytics?ver=13.1.1"
- },
- "description": "none",
- "externalLoggingPublisher": "none",
- "ipsForStatCollection": [],
- "notificationByEmail": "disabled",
- "notificationBySnmp": "disabled",
- "notificationBySyslog": "disabled",
- "notificationEmailAddresses": [],
- "publishIruleStatistics": "disabled",
- "sampling": "enabled",
- "sessionCookieSecurity": "ssl-only",
- "sessionTimeoutMinutes": "5",
- "smtpConfig": "none",
- "subnetsForStatCollection": [],
- "urlsForStatCollection": [],
- "alertsReference": {
- "link": "https://localhost/mgmt/tm/ltm/profile/analytics/~Common~foo/alerts?ver=13.1.1",
- "isSubcollection": true
- },
- "trafficCaptureReference": {
- "link": "https://localhost/mgmt/tm/ltm/profile/analytics/~Common~foo/traffic-capture?ver=13.1.1",
- "isSubcollection": true
- }
-}
diff --git a/test/units/modules/network/f5/fixtures/load_ltm_profile_clientssl.json b/test/units/modules/network/f5/fixtures/load_ltm_profile_clientssl.json
deleted file mode 100644
index 923f6f72bb..0000000000
--- a/test/units/modules/network/f5/fixtures/load_ltm_profile_clientssl.json
+++ /dev/null
@@ -1,103 +0,0 @@
-{
- "kind": "tm:ltm:profile:client-ssl:client-sslstate",
- "name": "foo",
- "partition": "Common",
- "fullPath": "/Common/foo",
- "generation": 351,
- "selfLink": "https://localhost/mgmt/tm/ltm/profile/client-ssl/~Common~foo?ver=13.0.0",
- "alertTimeout": "indefinite",
- "allowDynamicRecordSizing": "disabled",
- "allowExpiredCrl": "disabled",
- "allowNonSsl": "disabled",
- "appService": "none",
- "authenticate": "once",
- "authenticateDepth": 9,
- "bypassOnClientCertFail": "disabled",
- "bypassOnHandshakeAlert": "disabled",
- "caFile": "none",
- "cacheSize": 262144,
- "cacheTimeout": 3600,
- "cert": "/Common/default.crt",
- "certReference": {
- "link": "https://localhost/mgmt/tm/sys/file/ssl-cert/~Common~default.crt?ver=13.0.0"
- },
- "certExtensionIncludes": [
- "basic-constraints",
- "subject-alternative-name"
- ],
- "certLifespan": 30,
- "certLookupByIpaddrPort": "disabled",
- "chain": "none",
- "cipherGroup": "none",
- "ciphers": "DEFAULT",
- "clientCertCa": "none",
- "crlFile": "none",
- "defaultsFrom": "/Common/clientssl",
- "defaultsFromReference": {
- "link": "https://localhost/mgmt/tm/ltm/profile/client-ssl/~Common~clientssl?ver=13.0.0"
- },
- "description": "none",
- "destinationIpBlacklist": "none",
- "destinationIpWhitelist": "none",
- "forwardProxyBypassDefaultAction": "intercept",
- "genericAlert": "enabled",
- "handshakeTimeout": "10",
- "hostnameBlacklist": "none",
- "hostnameWhitelist": "none",
- "inheritCertkeychain": "true",
- "key": "/Common/default.key",
- "keyReference": {
- "link": "https://localhost/mgmt/tm/sys/file/ssl-key/~Common~default.key?ver=13.0.0"
- },
- "maxActiveHandshakes": "indefinite",
- "maxAggregateRenegotiationPerMinute": "indefinite",
- "maxRenegotiationsPerMinute": 5,
- "maximumRecordSize": 16384,
- "modSslMethods": "disabled",
- "mode": "enabled",
- "notifyCertStatusToVirtualServer": "disabled",
- "ocspStapling": "disabled",
- "tmOptions": [
- "dont-insert-empty-fragments"
- ],
- "peerCertMode": "ignore",
- "peerNoRenegotiateTimeout": "10",
- "proxyCaCert": "none",
- "proxyCaKey": "none",
- "proxySsl": "disabled",
- "proxySslPassthrough": "disabled",
- "renegotiateMaxRecordDelay": "indefinite",
- "renegotiatePeriod": "indefinite",
- "renegotiateSize": "indefinite",
- "renegotiation": "enabled",
- "retainCertificate": "true",
- "secureRenegotiation": "require",
- "serverName": "none",
- "sessionMirroring": "disabled",
- "sessionTicket": "disabled",
- "sessionTicketTimeout": 0,
- "sniDefault": "false",
- "sniRequire": "false",
- "sourceIpBlacklist": "none",
- "sourceIpWhitelist": "none",
- "sslForwardProxy": "disabled",
- "sslForwardProxyBypass": "disabled",
- "sslSignHash": "any",
- "strictResume": "disabled",
- "uncleanShutdown": "enabled",
- "certKeyChain": [
- {
- "name": "default",
- "appService": "none",
- "cert": "/Common/default.crt",
- "certReference": {
- "link": "https://localhost/mgmt/tm/sys/file/ssl-cert/~Common~default.crt?ver=13.0.0"
- },
- "chain": "none",
- "key": "/Common/default.key",
- "keyReference": {
- "link": "https://localhost/mgmt/tm/sys/file/ssl-key/~Common~default.key?ver=13.0.0"
- }
- }
- ]
-}
diff --git a/test/units/modules/network/f5/fixtures/load_ltm_profile_dns_1.json b/test/units/modules/network/f5/fixtures/load_ltm_profile_dns_1.json
deleted file mode 100644
index 41736147e8..0000000000
--- a/test/units/modules/network/f5/fixtures/load_ltm_profile_dns_1.json
+++ /dev/null
@@ -1,35 +0,0 @@
-{
- "kind": "tm:ltm:profile:dns:dnsstate",
- "name": "foo",
- "partition": "Common",
- "fullPath": "/Common/foo",
- "generation": 1211,
- "selfLink": "https://localhost/mgmt/tm/ltm/profile/dns/~Common~foo?ver=13.1.0.4",
- "appService": "none",
- "avrDnsstatSampleRate": 0,
- "cache": "none",
- "defaultsFrom": "/Common/dns",
- "defaultsFromReference": {
- "link": "https://localhost/mgmt/tm/ltm/profile/dns/~Common~dns?ver=13.1.0.4"
- },
- "description": "none",
- "dnsSecurity": "none",
- "dns64": "disabled",
- "dns64AdditionalSectionRewrite": "disabled",
- "dns64Prefix": "any6",
- "enableCache": "no",
- "enableDnsExpress": "no",
- "enableDnsFirewall": "yes",
- "enableDnssec": "no",
- "enableGtm": "no",
- "enableHardwareQueryValidation": "no",
- "enableHardwareResponseCache": "no",
- "enableLogging": "no",
- "enableRapidResponse": "no",
- "logProfile": "none",
- "processRd": "yes",
- "processXfr": "yes",
- "rapidResponseLastAction": "drop",
- "unhandledQueryAction": "allow",
- "useLocalBind": "no"
-}
diff --git a/test/units/modules/network/f5/fixtures/load_ltm_profile_http_compression_1.json b/test/units/modules/network/f5/fixtures/load_ltm_profile_http_compression_1.json
deleted file mode 100644
index a9873f20a2..0000000000
--- a/test/units/modules/network/f5/fixtures/load_ltm_profile_http_compression_1.json
+++ /dev/null
@@ -1,37 +0,0 @@
-{
- "kind": "tm:ltm:profile:http-compression:http-compressionstate",
- "name": "profile1",
- "partition": "Common",
- "fullPath": "/Common/profile1",
- "generation": 132,
- "selfLink": "https://localhost/mgmt/tm/ltm/profile/http-compression/~Common~profile1?ver=13.1.0.4",
- "allowHttp_10": "disabled",
- "appService": "none",
- "browserWorkarounds": "disabled",
- "bufferSize": 4096,
- "contentTypeExclude": [],
- "contentTypeInclude": [
- "text/",
- "application/(xml|x-javascript)"
- ],
- "cpuSaver": "enabled",
- "cpuSaverHigh": 90,
- "cpuSaverLow": 75,
- "defaultsFrom": "/Common/httpcompression",
- "defaultsFromReference": {
- "link": "https://localhost/mgmt/tm/ltm/profile/http-compression/~Common~httpcompression?ver=13.1.0.4"
- },
- "description": "my profile",
- "gzipLevel": 1,
- "gzipMemoryLevel": 8192,
- "gzipWindowSize": 16384,
- "keepAcceptEncoding": "disabled",
- "methodPrefer": "gzip",
- "minSize": 1024,
- "selective": "disabled",
- "uriExclude": [],
- "uriInclude": [
- ".*"
- ],
- "varyHeader": "enabled"
-}
diff --git a/test/units/modules/network/f5/fixtures/load_ltm_profile_oneconnect_1.json b/test/units/modules/network/f5/fixtures/load_ltm_profile_oneconnect_1.json
deleted file mode 100644
index d2b05acfe4..0000000000
--- a/test/units/modules/network/f5/fixtures/load_ltm_profile_oneconnect_1.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "kind": "tm:ltm:profile:one-connect:one-connectstate",
- "name": "oneconnect",
- "partition": "Common",
- "fullPath": "/Common/oneconnect",
- "generation": 1,
- "selfLink": "https://localhost/mgmt/tm/ltm/profile/one-connect/~Common~oneconnect?ver=13.1.0.4",
- "appService": "none",
- "defaultsFrom": "none",
- "description": "none",
- "idleTimeoutOverride": "disabled",
- "limitType": "none",
- "maxAge": 86400,
- "maxReuse": 1000,
- "maxSize": 10000,
- "sharePools": "disabled",
- "sourceMask": "any"
-}
diff --git a/test/units/modules/network/f5/fixtures/load_ltm_profile_persistence_cookie_1.json b/test/units/modules/network/f5/fixtures/load_ltm_profile_persistence_cookie_1.json
deleted file mode 100644
index 771a26e919..0000000000
--- a/test/units/modules/network/f5/fixtures/load_ltm_profile_persistence_cookie_1.json
+++ /dev/null
@@ -1,27 +0,0 @@
-{
- "kind": "tm:ltm:persistence:cookie:cookiestate",
- "name": "cookie",
- "partition": "Common",
- "fullPath": "/Common/cookie",
- "generation": 1,
- "selfLink": "https://localhost/mgmt/tm/ltm/persistence/cookie/~Common~cookie?ver=13.1.0.7",
- "alwaysSend": "disabled",
- "appService": "none",
- "cookieEncryption": "disabled",
- "cookieName": "none",
- "defaultsFrom": "none",
- "description": "none",
- "encryptCookiePoolname": "disabled",
- "expiration": "0",
- "hashLength": 0,
- "hashOffset": 0,
- "httponly": "enabled",
- "matchAcrossPools": "disabled",
- "matchAcrossServices": "disabled",
- "matchAcrossVirtuals": "disabled",
- "method": "insert",
- "mirror": "disabled",
- "overrideConnectionLimit": "disabled",
- "secure": "enabled",
- "timeout": "180"
-}
diff --git a/test/units/modules/network/f5/fixtures/load_ltm_profile_persistence_src_addr_1.json b/test/units/modules/network/f5/fixtures/load_ltm_profile_persistence_src_addr_1.json
deleted file mode 100644
index 2ee6df9b33..0000000000
--- a/test/units/modules/network/f5/fixtures/load_ltm_profile_persistence_src_addr_1.json
+++ /dev/null
@@ -1,22 +0,0 @@
-{
- "kind": "tm:ltm:persistence:source-addr:source-addrstate",
- "name": "source_addr",
- "partition": "Common",
- "fullPath": "/Common/source_addr",
- "generation": 1,
- "selfLink": "https://localhost/mgmt/tm/ltm/persistence/source-addr/~Common~source_addr?ver=13.1.0.7",
- "appService": "none",
- "defaultsFrom": "none",
- "description": "none",
- "hashAlgorithm": "default",
- "mapProxies": "enabled",
- "mapProxyAddress": "none",
- "mapProxyClass": "none",
- "mask": "none",
- "matchAcrossPools": "disabled",
- "matchAcrossServices": "disabled",
- "matchAcrossVirtuals": "disabled",
- "mirror": "disabled",
- "overrideConnectionLimit": "disabled",
- "timeout": "180"
-}
diff --git a/test/units/modules/network/f5/fixtures/load_ltm_profile_serverssl_1.json b/test/units/modules/network/f5/fixtures/load_ltm_profile_serverssl_1.json
deleted file mode 100644
index 94e6019fb1..0000000000
--- a/test/units/modules/network/f5/fixtures/load_ltm_profile_serverssl_1.json
+++ /dev/null
@@ -1,73 +0,0 @@
-{
- "kind": "tm:ltm:profile:server-ssl:server-sslstate",
- "name": "asda",
- "partition": "Common",
- "fullPath": "/Common/asda",
- "generation": 160,
- "selfLink": "https://localhost/mgmt/tm/ltm/profile/server-ssl/~Common~asda?ver=13.1.0.8",
- "alertTimeout": "indefinite",
- "allowExpiredCrl": "disabled",
- "appService": "none",
- "authenticate": "once",
- "authenticateDepth": 9,
- "authenticateName": "none",
- "bypassOnClientCertFail": "disabled",
- "bypassOnHandshakeAlert": "disabled",
- "c3dCaCert": "none",
- "c3dCaKey": "none",
- "c3dCertExtensionCustomOids": [],
- "c3dCertExtensionIncludes": [
- "basic-constraints",
- "extended-key-usage",
- "key-usage",
- "subject-alternative-name"
- ],
- "c3dCertLifespan": 24,
- "caFile": "none",
- "cacheSize": 262144,
- "cacheTimeout": 3600,
- "cert": "none",
- "chain": "/Common/default.crt",
- "chainReference": {
- "link": "https://localhost/mgmt/tm/sys/file/ssl-cert/~Common~default.crt?ver=13.1.0.8"
- },
- "cipherGroup": "none",
- "ciphers": "DEFAULT",
- "crlFile": "none",
- "defaultsFrom": "/Common/serverssl",
- "defaultsFromReference": {
- "link": "https://localhost/mgmt/tm/ltm/profile/server-ssl/~Common~serverssl?ver=13.1.0.8"
- },
- "description": "none",
- "expireCertResponseControl": "drop",
- "genericAlert": "enabled",
- "handshakeTimeout": "10",
- "key": "none",
- "maxActiveHandshakes": "indefinite",
- "modSslMethods": "disabled",
- "mode": "enabled",
- "ocsp": "none",
- "tmOptions": [
- "dont-insert-empty-fragments"
- ],
- "peerCertMode": "ignore",
- "proxySsl": "disabled",
- "proxySslPassthrough": "disabled",
- "renegotiatePeriod": "indefinite",
- "renegotiateSize": "indefinite",
- "renegotiation": "enabled",
- "retainCertificate": "true",
- "secureRenegotiation": "require-strict",
- "serverName": "none",
- "sessionMirroring": "disabled",
- "sessionTicket": "disabled",
- "sniDefault": "false",
- "sniRequire": "false",
- "sslC3d": "disabled",
- "sslForwardProxy": "disabled",
- "sslForwardProxyBypass": "disabled",
- "sslSignHash": "any",
- "strictResume": "disabled",
- "uncleanShutdown": "enabled",
- "untrustedCertResponseControl": "drop"
-}
diff --git a/test/units/modules/network/f5/fixtures/load_ltm_profile_tcp_1.json b/test/units/modules/network/f5/fixtures/load_ltm_profile_tcp_1.json
deleted file mode 100644
index 03ada3cbde..0000000000
--- a/test/units/modules/network/f5/fixtures/load_ltm_profile_tcp_1.json
+++ /dev/null
@@ -1,92 +0,0 @@
-{
- "kind": "tm:ltm:profile:tcp:tcpstate",
- "name": "foo",
- "partition": "Common",
- "fullPath": "/Common/foo",
- "generation": 92,
- "selfLink": "https://localhost/mgmt/tm/ltm/profile/tcp/~Common~foo?ver=13.1.0.4",
- "abc": "enabled",
- "ackOnPush": "enabled",
- "appService": "none",
- "autoProxyBufferSize": "disabled",
- "autoReceiveWindowSize": "disabled",
- "autoSendBufferSize": "disabled",
- "closeWaitTimeout": 5,
- "cmetricsCache": "enabled",
- "cmetricsCacheTimeout": 0,
- "congestionControl": "high-speed",
- "defaultsFrom": "/Common/tcp",
- "defaultsFromReference": {
- "link": "https://localhost/mgmt/tm/ltm/profile/tcp/~Common~tcp?ver=13.1.0.4"
- },
- "deferredAccept": "disabled",
- "delayWindowControl": "disabled",
- "delayedAcks": "enabled",
- "description": "none",
- "dsack": "disabled",
- "earlyRetransmit": "enabled",
- "ecn": "enabled",
- "enhancedLossRecovery": "disabled",
- "fastOpen": "disabled",
- "fastOpenCookieExpiration": 21600,
- "finWait_2Timeout": 300,
- "finWaitTimeout": 5,
- "hardwareSynCookie": "enabled",
- "idleTimeout": 300,
- "initCwnd": 3,
- "initRwnd": 3,
- "ipDfMode": "pmtu",
- "ipTosToClient": "0",
- "ipTtlMode": "proxy",
- "ipTtlV4": 255,
- "ipTtlV6": 64,
- "keepAliveInterval": 1800,
- "limitedTransmit": "enabled",
- "linkQosToClient": "0",
- "maxRetrans": 8,
- "maxSegmentSize": 1460,
- "md5Signature": "disabled",
- "minimumRto": 1000,
- "mptcp": "disabled",
- "mptcpCsum": "disabled",
- "mptcpCsumVerify": "disabled",
- "mptcpDebug": "disabled",
- "mptcpFallback": "reset",
- "mptcpFastjoin": "disabled",
- "mptcpIdleTimeout": 300,
- "mptcpJoinMax": 5,
- "mptcpMakeafterbreak": "disabled",
- "mptcpNojoindssack": "disabled",
- "mptcpRtomax": 5,
- "mptcpRxmitmin": 1000,
- "mptcpSubflowmax": 6,
- "mptcpTimeout": 3600,
- "nagle": "disabled",
- "pktLossIgnoreBurst": 0,
- "pktLossIgnoreRate": 0,
- "proxyBufferHigh": 49152,
- "proxyBufferLow": 32768,
- "proxyMss": "enabled",
- "proxyOptions": "disabled",
- "pushFlag": "default",
- "ratePace": "disabled",
- "ratePaceMaxRate": 0,
- "receiveWindowSize": 65535,
- "resetOnTimeout": "enabled",
- "rexmtThresh": 3,
- "selectiveAcks": "enabled",
- "selectiveNack": "disabled",
- "sendBufferSize": 65535,
- "slowStart": "enabled",
- "synCookieEnable": "enabled",
- "synCookieWhitelist": "disabled",
- "synMaxRetrans": 3,
- "synRtoBase": 3000,
- "tailLossProbe": "disabled",
- "tcpOptions": "none",
- "timeWaitRecycle": "enabled",
- "timeWaitTimeout": "2000",
- "timestamps": "enabled",
- "verifiedAccept": "disabled",
- "zeroWindowTimeout": 20000
-}
diff --git a/test/units/modules/network/f5/fixtures/load_ltm_profile_udp_1.json b/test/units/modules/network/f5/fixtures/load_ltm_profile_udp_1.json
deleted file mode 100644
index a07307a0dd..0000000000
--- a/test/units/modules/network/f5/fixtures/load_ltm_profile_udp_1.json
+++ /dev/null
@@ -1,27 +0,0 @@
-{
- "kind": "tm:ltm:profile:udp:udpstate",
- "name": "foo",
- "partition": "Common",
- "fullPath": "/Common/foo",
- "generation": 107,
- "selfLink": "https://localhost/mgmt/tm/ltm/profile/udp/~Common~foo?ver=13.1.0.4",
- "allowNoPayload": "disabled",
- "appService": "none",
- "bufferMaxBytes": 655350,
- "bufferMaxPackets": 0,
- "datagramLoadBalancing": "disabled",
- "defaultsFrom": "/Common/udp",
- "defaultsFromReference": {
- "link": "https://localhost/mgmt/tm/ltm/profile/udp/~Common~udp?ver=13.1.0.4"
- },
- "description": "none",
- "idleTimeout": "60",
- "ipDfMode": "pmtu",
- "ipTosToClient": "0",
- "ipTtlMode": "proxy",
- "ipTtlV4": 255,
- "ipTtlV6": 64,
- "linkQosToClient": "0",
- "noChecksum": "disabled",
- "proxyMss": "disabled"
-}
diff --git a/test/units/modules/network/f5/fixtures/load_ltm_snat_translation_default.json b/test/units/modules/network/f5/fixtures/load_ltm_snat_translation_default.json
deleted file mode 100644
index 836866a17b..0000000000
--- a/test/units/modules/network/f5/fixtures/load_ltm_snat_translation_default.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "address": "1.1.1.1",
- "arp": "no",
- "connectionLimit": 0,
- "description": "My description",
- "ip_idle_timeout":"50",
- "kind": "tm:ltm:snat-translation:snat-translationstate",
- "name": "my-snat-translation",
- "partition": "Common",
- "state":"present",
- "enabled":"true",
- "tcp_idle_timeout":"20",
- "trafficGroup": "/Common/test",
- "udp_idle_timeout":"100"
-} \ No newline at end of file
diff --git a/test/units/modules/network/f5/fixtures/load_ltm_snatpool.json b/test/units/modules/network/f5/fixtures/load_ltm_snatpool.json
deleted file mode 100644
index fcea1dd219..0000000000
--- a/test/units/modules/network/f5/fixtures/load_ltm_snatpool.json
+++ /dev/null
@@ -1,20 +0,0 @@
-{
- "kind": "tm:ltm:snatpool:snatpoolstate",
- "name": "asdasd",
- "partition": "Common",
- "fullPath": "/Common/asdasd",
- "generation": 40,
- "selfLink": "https://localhost/mgmt/tm/ltm/snatpool/~Common~asdasd?ver=12.1.2",
- "members": [
- "/Common/1.1.1.1",
- "/Common/2.2.2.2"
- ],
- "membersReference": [
- {
- "link": "https://localhost/mgmt/tm/ltm/snat-translation/~Common~1.1.1.1?ver=12.1.2"
- },
- {
- "link": "https://localhost/mgmt/tm/ltm/snat-translation/~Common~2.2.2.2?ver=12.1.2"
- }
- ]
-}
diff --git a/test/units/modules/network/f5/fixtures/load_ltm_virtual_1.json b/test/units/modules/network/f5/fixtures/load_ltm_virtual_1.json
deleted file mode 100644
index aaf48ab87b..0000000000
--- a/test/units/modules/network/f5/fixtures/load_ltm_virtual_1.json
+++ /dev/null
@@ -1,43 +0,0 @@
-{
- "kind": "tm:ltm:virtual:virtualstate",
- "name": "my-virtual-server",
- "partition": "Common",
- "fullPath": "/Common/my-virtual-server",
- "generation": 65,
- "selfLink": "https://localhost/mgmt/tm/ltm/virtual/~Common~my-virtual-server?ver=12.1.2",
- "addressStatus": "yes",
- "autoLasthop": "default",
- "cmpEnabled": "yes",
- "connectionLimit": 0,
- "destination": "/Common/10.10.10.10:443",
- "enabled": true,
- "gtmScore": 0,
- "ipProtocol": "any",
- "mask": "255.255.255.255",
- "mirror": "disabled",
- "mobileAppTunnel": "disabled",
- "nat64": "disabled",
- "rateLimit": "disabled",
- "rateLimitDstMask": 0,
- "rateLimitMode": "object",
- "rateLimitSrcMask": 0,
- "serviceDownImmediateAction": "none",
- "source": "0.0.0.0/0",
- "sourceAddressTranslation": {
- "type": "automap"
- },
- "sourcePort": "preserve",
- "synCookieStatus": "not-activated",
- "translateAddress": "enabled",
- "translatePort": "enabled",
- "vlansDisabled": true,
- "vsIndex": 2,
- "policiesReference": {
- "link": "https://localhost/mgmt/tm/ltm/virtual/~Common~my-virtual-server/policies?ver=12.1.2",
- "isSubcollection": true
- },
- "profilesReference": {
- "link": "https://localhost/mgmt/tm/ltm/virtual/~Common~my-virtual-server/profiles?ver=12.1.2",
- "isSubcollection": true
- }
-}
diff --git a/test/units/modules/network/f5/fixtures/load_ltm_virtual_1_address.json b/test/units/modules/network/f5/fixtures/load_ltm_virtual_1_address.json
deleted file mode 100644
index 297afc9187..0000000000
--- a/test/units/modules/network/f5/fixtures/load_ltm_virtual_1_address.json
+++ /dev/null
@@ -1,25 +0,0 @@
-{
- "kind": "tm:ltm:virtual-address:virtual-addressstate",
- "name": "10.10.10.10",
- "partition": "Common",
- "fullPath": "/Common/10.10.10.10",
- "generation": 116,
- "selfLink": "https://localhost/mgmt/tm/ltm/virtual-address/~Common~10.10.10.10?ver=12.1.2",
- "address": "10.10.10.10",
- "arp": "enabled",
- "autoDelete": "true",
- "connectionLimit": 0,
- "enabled": "yes",
- "floating": "enabled",
- "icmpEcho": "enabled",
- "inheritedTrafficGroup": "false",
- "mask": "255.255.255.255",
- "routeAdvertisement": "enabled",
- "serverScope": "any",
- "spanning": "disabled",
- "trafficGroup": "/Common/traffic-group-1",
- "trafficGroupReference": {
- "link": "https://localhost/mgmt/tm/cm/traffic-group/~Common~traffic-group-1?ver=12.1.2"
- },
- "unit": 1
-}
diff --git a/test/units/modules/network/f5/fixtures/load_ltm_virtual_2.json b/test/units/modules/network/f5/fixtures/load_ltm_virtual_2.json
deleted file mode 100644
index 712b19e3d9..0000000000
--- a/test/units/modules/network/f5/fixtures/load_ltm_virtual_2.json
+++ /dev/null
@@ -1,65 +0,0 @@
-{
- "kind": "tm:ltm:virtual:virtualstate",
- "name": "my-virtual-server",
- "partition": "Common",
- "fullPath": "/Common/my-virtual-server",
- "generation": 152,
- "selfLink": "https://localhost/mgmt/tm/ltm/virtual/~Common~my-virtual-server?ver=12.1.2",
- "addressStatus": "yes",
- "autoLasthop": "default",
- "cmpEnabled": "yes",
- "connectionLimit": 0,
- "destination": "/Common/10.10.10.10:443",
- "enabled": true,
- "gtmScore": 0,
- "ipProtocol": "any",
- "mask": "255.255.255.255",
- "mirror": "disabled",
- "mobileAppTunnel": "disabled",
- "nat64": "disabled",
- "rateLimit": "disabled",
- "rateLimitDstMask": 0,
- "rateLimitMode": "object",
- "rateLimitSrcMask": 0,
- "serviceDownImmediateAction": "none",
- "source": "0.0.0.0/0",
- "sourceAddressTranslation": {
- "type": "automap"
- },
- "sourcePort": "preserve",
- "synCookieStatus": "not-activated",
- "translateAddress": "enabled",
- "translatePort": "enabled",
- "vlansDisabled": true,
- "vsIndex": 19,
- "vlans": [
- "/Common/net1"
- ],
- "vlansReference": [
- {
- "link": "https://localhost/mgmt/tm/net/vlan/~Common~net1?ver=12.1.2"
- }
- ],
- "policiesReference": {
- "link": "https://localhost/mgmt/tm/ltm/virtual/~Common~my-virtual-server/policies?ver=12.1.2",
- "isSubcollection": true
- },
- "profilesReference": {
- "link": "https://localhost/mgmt/tm/ltm/virtual/~Common~my-virtual-server/profiles?ver=12.1.2",
- "isSubcollection": true,
- "items": [
- {
- "kind": "tm:ltm:virtual:profiles:profilesstate",
- "name": "fastL4",
- "partition": "Common",
- "fullPath": "/Common/fastL4",
- "generation": 148,
- "selfLink": "https://localhost/mgmt/tm/ltm/virtual/~Common~my-virtual-server/profiles/~Common~fastL4?ver=12.1.2",
- "context": "all",
- "nameReference": {
- "link": "https://localhost/mgmt/tm/ltm/profile/fastl4/~Common~fastL4?ver=12.1.2"
- }
- }
- ]
- }
-}
diff --git a/test/units/modules/network/f5/fixtures/load_ltm_virtual_3.json b/test/units/modules/network/f5/fixtures/load_ltm_virtual_3.json
deleted file mode 100644
index e1b0c7c270..0000000000
--- a/test/units/modules/network/f5/fixtures/load_ltm_virtual_3.json
+++ /dev/null
@@ -1,115 +0,0 @@
-{
- "kind": "tm:ltm:virtual:virtualstate",
- "name": "my-virtual-server",
- "partition": "Common",
- "fullPath": "/Common/my-virtual-server",
- "generation": 340,
- "selfLink": "https://localhost/mgmt/tm/ltm/virtual/~Common~my-virtual-server?expandSubcollections=true&ver=12.0.0",
- "addressStatus": "yes",
- "autoLasthop": "default",
- "cmpEnabled": "yes",
- "connectionLimit": 0,
- "description": "Test Virtual Server",
- "destination": "/Common/10.10.10.10:443",
- "enabled": true,
- "gtmScore": 0,
- "ipProtocol": "tcp",
- "mask": "255.255.255.255",
- "mirror": "disabled",
- "mobileAppTunnel": "disabled",
- "nat64": "disabled",
- "rateLimit": "disabled",
- "rateLimitDstMask": 0,
- "rateLimitMode": "object",
- "rateLimitSrcMask": 0,
- "serviceDownImmediateAction": "none",
- "source": "0.0.0.0/0",
- "sourceAddressTranslation": {
- "type": "automap"
- },
- "sourcePort": "preserve",
- "synCookieStatus": "not-activated",
- "translateAddress": "enabled",
- "translatePort": "enabled",
- "vlansDisabled": true,
- "vsIndex": 38,
- "rules": [
- "/Common/web_logging"
- ],
- "rulesReference": [
- {
- "link": "https://localhost/mgmt/tm/ltm/rule/~Common~web_logging?ver=12.0.0"
- }
- ],
- "policiesReference": {
- "link": "https://localhost/mgmt/tm/ltm/virtual/~Common~my-virtual-server/policies?ver=12.0.0",
- "isSubcollection": true,
- "items": [
- {
- "kind": "tm:ltm:virtual:policies:policiesstate",
- "name": "policy1",
- "partition": "Common",
- "fullPath": "/Common/policy1",
- "generation": 340,
- "selfLink": "https://localhost/mgmt/tm/ltm/virtual/~Common~my-virtual-server/policies/~Common~policy1?ver=12.0.0",
- "nameReference": {
- "link": "https://localhost/mgmt/tm/ltm/policy/~Common~policy1?ver=12.0.0"
- }
- }
- ]
- },
- "profilesReference": {
- "link": "https://localhost/mgmt/tm/ltm/virtual/~Common~my-virtual-server/profiles?ver=12.0.0",
- "isSubcollection": true,
- "items": [
- {
- "kind": "tm:ltm:virtual:profiles:profilesstate",
- "name": "clientssl",
- "partition": "Common",
- "fullPath": "/Common/clientssl",
- "generation": 338,
- "selfLink": "https://localhost/mgmt/tm/ltm/virtual/~Common~my-virtual-server/profiles/~Common~clientssl?ver=12.0.0",
- "context": "clientside",
- "nameReference": {
- "link": "https://localhost/mgmt/tm/ltm/profile/client-ssl/~Common~clientssl?ver=12.0.0"
- }
- },
- {
- "kind": "tm:ltm:virtual:profiles:profilesstate",
- "name": "http",
- "partition": "Common",
- "fullPath": "/Common/http",
- "generation": 338,
- "selfLink": "https://localhost/mgmt/tm/ltm/virtual/~Common~my-virtual-server/profiles/~Common~http?ver=12.0.0",
- "context": "all",
- "nameReference": {
- "link": "https://localhost/mgmt/tm/ltm/profile/http/~Common~http?ver=12.0.0"
- }
- },
- {
- "kind": "tm:ltm:virtual:profiles:profilesstate",
- "name": "tcp",
- "partition": "Common",
- "fullPath": "/Common/tcp",
- "generation": 338,
- "selfLink": "https://localhost/mgmt/tm/ltm/virtual/~Common~my-virtual-server/profiles/~Common~tcp?ver=12.0.0",
- "context": "clientside",
- "nameReference": {
- "link": "https://localhost/mgmt/tm/ltm/profile/tcp/~Common~tcp?ver=12.0.0"
- }
- },
- {
- "kind": "tm:ltm:virtual:profiles:profilesstate",
- "name": "tcp-legacy",
- "partition": "Common",
- "fullPath": "/Common/tcp-legacy",
- "generation": 338,
- "selfLink": "https://localhost/mgmt/tm/ltm/virtual/~Common~my-virtual-server/profiles/~Common~tcp-legacy?ver=12.0.0",
- "context": "serverside",
- "nameReference": {
- "link": "https://localhost/mgmt/tm/ltm/profile/tcp/~Common~tcp-legacy?ver=12.0.0"
- }
- }
- ]
- }
-}
diff --git a/test/units/modules/network/f5/fixtures/load_ltm_virtual_address_collection_1.json b/test/units/modules/network/f5/fixtures/load_ltm_virtual_address_collection_1.json
deleted file mode 100644
index 810e659ff9..0000000000
--- a/test/units/modules/network/f5/fixtures/load_ltm_virtual_address_collection_1.json
+++ /dev/null
@@ -1,31 +0,0 @@
-{
- "kind": "tm:ltm:virtual-address:virtual-addresscollectionstate",
- "selfLink": "https://localhost/mgmt/tm/ltm/virtual-address?ver=13.1.0.4",
- "items": [
- {
- "kind": "tm:ltm:virtual-address:virtual-addressstate",
- "name": "2.3.4.5",
- "partition": "Common",
- "fullPath": "/Common/2.3.4.5",
- "generation": 1074,
- "selfLink": "https://localhost/mgmt/tm/ltm/virtual-address/~Common~2.3.4.5?ver=13.1.0.4",
- "address": "2.3.4.5",
- "arp": "enabled",
- "autoDelete": "true",
- "connectionLimit": 0,
- "enabled": "yes",
- "floating": "enabled",
- "icmpEcho": "enabled",
- "inheritedTrafficGroup": "false",
- "mask": "255.255.255.255",
- "routeAdvertisement": "disabled",
- "serverScope": "any",
- "spanning": "disabled",
- "trafficGroup": "/Common/traffic-group-1",
- "trafficGroupReference": {
- "link": "https://localhost/mgmt/tm/cm/traffic-group/~Common~traffic-group-1?ver=13.1.0.4"
- },
- "unit": 1
- }
- ]
-}
diff --git a/test/units/modules/network/f5/fixtures/load_ltm_virtual_address_default.json b/test/units/modules/network/f5/fixtures/load_ltm_virtual_address_default.json
deleted file mode 100644
index a2b87012a1..0000000000
--- a/test/units/modules/network/f5/fixtures/load_ltm_virtual_address_default.json
+++ /dev/null
@@ -1,25 +0,0 @@
-{
- "kind": "tm:ltm:virtual-address:virtual-addressstate",
- "name": "1.1.1.1",
- "partition": "Common",
- "fullPath": "/Common/1.1.1.1",
- "generation": 116,
- "selfLink": "https://localhost/mgmt/tm/ltm/virtual-address/~Common~1.1.1.1?ver=12.1.2",
- "address": "1.1.1.1",
- "arp": "enabled",
- "autoDelete": "true",
- "connectionLimit": 0,
- "enabled": "yes",
- "floating": "enabled",
- "icmpEcho": "enabled",
- "inheritedTrafficGroup": "false",
- "mask": "255.255.255.255",
- "routeAdvertisement": "disabled",
- "serverScope": "any",
- "spanning": "disabled",
- "trafficGroup": "/Common/traffic-group-1",
- "trafficGroupReference": {
- "link": "https://localhost/mgmt/tm/cm/traffic-group/~Common~traffic-group-1?ver=12.1.2"
- },
- "unit": 1
-}
diff --git a/test/units/modules/network/f5/fixtures/load_machine_resolver.json b/test/units/modules/network/f5/fixtures/load_machine_resolver.json
deleted file mode 100644
index 2422ca6db8..0000000000
--- a/test/units/modules/network/f5/fixtures/load_machine_resolver.json
+++ /dev/null
@@ -1,187 +0,0 @@
- {
- "uuid": "4dd9f559-c1b9-4e05-8d17-2345a6a3d459",
- "deviceUri": "https://10.144.74.229:443",
- "machineId": "4dd9f559-c1b9-4e05-8d17-2345a6a3d459",
- "state": "ACTIVE",
- "address": "10.144.74.229",
- "httpsPort": 443,
- "hostname": "ansible_test_lab12.lab.local",
- "version": "12.1.3",
- "product": "BIG-IP",
- "edition": "Final",
- "build": "0.0.378",
- "restFrameworkVersion": "12.1.3-0.0.378",
- "managementAddress": "10.144.74.229",
- "mcpDeviceName": "/Common/ansible_test_lab12.lab.local",
- "trustDomainGuid": "44135337-f809-480d-ab6ffa163edc9ff6",
- "properties": {
- "cm:gui:module": [
- "asmsecurity",
- "adc",
- "BigIPDevice",
- "sharedsecurity"
- ],
- "modules": [
- "Web Application Security Group",
- "Security"
- ],
- "cm-bigip-allBigIpDevices": {
- "cm:gui:module": [
- "asmsecurity",
- "adc",
- "BigIPDevice",
- "sharedsecurity"
- ],
- "shared:resolver:device-groups:discoverer": "13446925-efb3-47f4-b32c-ed705d29e878",
- "modules": [
- "Web Application Security Group",
- "Security"
- ]
- },
- "cm-asm-allDevices": {
- "cm:gui:module": [],
- "modules": []
- },
- "cm-bigip-allDevices": {
- "shared:resolver:device-groups:discoverer": "13446925-efb3-47f4-b32c-ed705d29e878",
- "cm:gui:module": [],
- "modules": []
- },
- "cm-adccore-allDevices": {
- "cm:gui:module": [],
- "modules": []
- },
- "cm-security-shared-allSharedDevices": {
- "discovered": true,
- "imported": true,
- "supportsAlpineDosDeviceConfig": true,
- "supports_14_0_Enhs": false,
- "supportsRest": true,
- "supportsAlpineDosProfileEnhs": true,
- "requiresDhcpProfileInDhcpVirtualServer": true,
- "supportsAfmSubscribers": false,
- "supportsAlpineEnhs": true,
- "supports_13_0_Enhs": false,
- "supportsFirewallRuleIdentifiers": false,
- "supportsBadgerEnhs": true,
- "supportsAlpineDosDeviceWhitelistIpProcotol": true,
- "supportsSshProfile": true,
- "supportsPortMisusePolicy": true,
- "supportsAlpineLogProfileEnhs": true,
- "supportsCascadeEnhs": true,
- "supportUdpPortList": true,
- "supports_13_1_Enhs": false,
- "supportsIncrementalDiscovery": false,
- "lastDiscoveredDateTime": "2019-02-12T13:53:06.541Z",
- "lastUserDiscoveredDateTime": "2019-02-12T13:53:06.541Z",
- "importedDateTime": "2019-02-12T13:53:24.885Z",
- "discoveryStatus": "FINISHED",
- "importStatus": "FINISHED",
- "cm:gui:module": [
- "sharedsecurity"
- ],
- "modules": [
- "Security"
- ]
- },
- "cm-adccore-allbigipDevices": {
- "discovered": true,
- "imported": true,
- "supportsRest": true,
- "requiresDhcpProfileInDhcpVirtualServer": true,
- "supportsAlpineEnhs": true,
- "supports_13_0_Enhs": false,
- "supportsFirewallRuleIdentifiers": false,
- "supportsBadgerEnhs": true,
- "restrictsPortTranslationStatelessVirtual": true,
- "supportsClassification": true,
- "supports_13_1_Enhs": false,
- "supportsIncrementalDiscovery": false,
- "supports_12_1_2_Enhs": true,
- "lastDiscoveredDateTime": "2019-02-12T13:53:03.963Z",
- "lastUserDiscoveredDateTime": "2019-02-12T13:53:03.963Z",
- "importedDateTime": "2019-02-12T13:53:18.975Z",
- "discoveryStatus": "FINISHED",
- "importStatus": "FINISHED",
- "cm:gui:module": [
- "adc"
- ],
- "modules": []
- },
- "cm-security-shared-allDevices": {
- "cm:gui:module": [],
- "modules": []
- },
- "cm-asm-allAsmDevices": {
- "discovered": true,
- "imported": true,
- "supportsHostNameEnforcementMode": false,
- "supportsRest": true,
- "supportsServerTechnologies": false,
- "supportsCpb": false,
- "supportsUrlCascadeFeatures": true,
- "supportsSessionTrackingAllLoginPagesUsernameSource": true,
- "supportsLoginEnforcementCascadeFeatures": true,
- "suppportsXmlValidationFiles": true,
- "supportsExtractions": true,
- "supportsWebSocketSecurity": true,
- "supportsWhitelistIpBlockRequestAlways": false,
- "supportsSessionTrackingSessionHijackingByDeviceId": true,
- "supportsLoginPagesHeaderOmits": false,
- "supportsBruteForceAttackPreventionsCascadeFeatures": true,
- "supportsPlainTextProfile": true,
- "supportsIncrementalDiscovery": false,
- "supportsRedirectionProtection": true,
- "supportsHeaderSignaturesOverride": false,
- "supportsIpIntelligence": true,
- "supports_13_0_Enhs": false,
- "supportsFirewallRuleIdentifiers": false,
- "supportsSessionTrackingDeviceIdThresholds": true,
- "supportsLoginEnforcement": true,
- "supportsCsrfProtection": true,
- "supportsSessionTracking": true,
- "supportsJsonProfiles": true,
- "supportsBruteForceAttackPreventions": true,
- "supportsWebScraping": true,
- "supportsLoginPagesCascadeFeatures": true,
- "supportsGwtProfiles": true,
- "supportsXmlProfiles": true,
- "supportsAsmDisallowedGeolocation": true,
- "supportsCsrfUrls": false,
- "supportsDataProtection": false,
- "supportsLoginPages": true,
- "supportsBruteForceAttackPreventionsBadgerFeatures": true,
- "supportsUrlSignaturesOverride": false,
- "signatureAutoUpdateState": true,
- "signatureFileVersion": 1.450112674E12,
- "signatureFilename": "Attack Signature Database packaged with version 12.1.3",
- "lastDiscoveredDateTime": "2019-02-12T13:53:09.188Z",
- "lastUserDiscoveredDateTime": "2019-02-12T13:53:09.188Z",
- "importedDateTime": "2019-02-12T13:53:29.730Z",
- "discoveryStatus": "FINISHED",
- "importStatus": "FINISHED",
- "cm:gui:module": [
- "asmsecurity"
- ],
- "modules": [
- "Web Application Security Group"
- ]
- }
- },
- "isClustered": false,
- "isVirtual": true,
- "isLicenseExpired": false,
- "slots": [
- {
- "volume": "HD1.1",
- "product": "BIG-IP",
- "version": "12.1.3",
- "build": "0.0.378",
- "isActive": true
- }
- ],
- "generation": 4,
- "lastUpdateMicros": 1549979318078796,
- "kind": "shared:resolver:device-groups:restdeviceresolverdevicestate",
- "selfLink": "https://localhost/mgmt/cm/system/machineid-resolver/4dd9f559-c1b9-4e05-8d17-2345a6a3d459"
- }
diff --git a/test/units/modules/network/f5/fixtures/load_net_dns_resolver_1.json b/test/units/modules/network/f5/fixtures/load_net_dns_resolver_1.json
deleted file mode 100644
index bdf3f75593..0000000000
--- a/test/units/modules/network/f5/fixtures/load_net_dns_resolver_1.json
+++ /dev/null
@@ -1,19 +0,0 @@
-{
- "kind": "tm:net:dns-resolver:dns-resolverstate",
- "name": "foo",
- "partition": "Common",
- "fullPath": "/Common/foo",
- "generation": 173,
- "selfLink": "https://localhost/mgmt/tm/net/dns-resolver/~Common~foo?ver=13.1.0.8",
- "answerDefaultZones": "no",
- "cacheSize": 5767168,
- "randomizeQueryNameCase": "yes",
- "routeDomain": "/Common/0",
- "routeDomainReference": {
- "link": "https://localhost/mgmt/tm/net/route-domain/~Common~0?ver=13.1.0.8"
- },
- "useIpv4": "no",
- "useIpv6": "yes",
- "useTcp": "yes",
- "useUdp": "yes"
-}
diff --git a/test/units/modules/network/f5/fixtures/load_net_interfaces.json b/test/units/modules/network/f5/fixtures/load_net_interfaces.json
deleted file mode 100644
index 2cc3032fc8..0000000000
--- a/test/units/modules/network/f5/fixtures/load_net_interfaces.json
+++ /dev/null
@@ -1,424 +0,0 @@
-[
- {
- "kind": "tm:net:interface:interfacestate",
- "name": "1.1",
- "fullPath": "1.1",
- "generation": 7767,
- "selfLink": "https://localhost/mgmt/tm/net/interface/1.1?ver=12.1.0",
- "bundle": "not-supported",
- "bundleSpeed": "not-supported",
- "enabled": true,
- "flowControl": "tx-rx",
- "forceGigabitFiber": "disabled",
- "forwardErrorCorrection": "not-supported",
- "ifIndex": 176,
- "lldpAdmin": "txonly",
- "lldpTlvmap": 130943,
- "macAddress": "00:23:e9:f1:e4:02",
- "mediaActive": "none",
- "mediaFixed": "auto",
- "mediaMax": "1000T-FD",
- "mediaSfp": "auto",
- "mtu": 9198,
- "preferPort": "sfp",
- "qinqEthertype": "0x8100",
- "sflow": {
- "pollInterval": 0,
- "pollIntervalGlobal": "yes"
- },
- "stp": "enabled",
- "stpAutoEdgePort": "enabled",
- "stpEdgePort": "true",
- "stpLinkType": "auto"
- },
- {
- "kind": "tm:net:interface:interfacestate",
- "name": "1.2",
- "fullPath": "1.2",
- "generation": 7770,
- "selfLink": "https://localhost/mgmt/tm/net/interface/1.2?ver=12.1.0",
- "bundle": "not-supported",
- "bundleSpeed": "not-supported",
- "enabled": true,
- "flowControl": "tx-rx",
- "forceGigabitFiber": "disabled",
- "forwardErrorCorrection": "not-supported",
- "ifIndex": 192,
- "lldpAdmin": "txonly",
- "lldpTlvmap": 130943,
- "macAddress": "00:23:e9:f1:e4:03",
- "mediaActive": "none",
- "mediaFixed": "auto",
- "mediaMax": "1000T-FD",
- "mediaSfp": "auto",
- "mtu": 9198,
- "preferPort": "sfp",
- "qinqEthertype": "0x8100",
- "sflow": {
- "pollInterval": 0,
- "pollIntervalGlobal": "yes"
- },
- "stp": "enabled",
- "stpAutoEdgePort": "enabled",
- "stpEdgePort": "true",
- "stpLinkType": "auto"
- },
- {
- "kind": "tm:net:interface:interfacestate",
- "name": "1.3",
- "fullPath": "1.3",
- "generation": 7773,
- "selfLink": "https://localhost/mgmt/tm/net/interface/1.3?ver=12.1.0",
- "bundle": "not-supported",
- "bundleSpeed": "not-supported",
- "enabled": true,
- "flowControl": "tx-rx",
- "forceGigabitFiber": "disabled",
- "forwardErrorCorrection": "not-supported",
- "ifIndex": 208,
- "lldpAdmin": "txonly",
- "lldpTlvmap": 130943,
- "macAddress": "00:23:e9:f1:e4:04",
- "mediaActive": "none",
- "mediaFixed": "auto",
- "mediaMax": "1000T-FD",
- "mediaSfp": "auto",
- "mtu": 9198,
- "preferPort": "sfp",
- "qinqEthertype": "0x8100",
- "sflow": {
- "pollInterval": 0,
- "pollIntervalGlobal": "yes"
- },
- "stp": "enabled",
- "stpAutoEdgePort": "enabled",
- "stpEdgePort": "true",
- "stpLinkType": "auto"
- },
- {
- "kind": "tm:net:interface:interfacestate",
- "name": "1.4",
- "fullPath": "1.4",
- "generation": 7776,
- "selfLink": "https://localhost/mgmt/tm/net/interface/1.4?ver=12.1.0",
- "bundle": "not-supported",
- "bundleSpeed": "not-supported",
- "enabled": true,
- "flowControl": "tx-rx",
- "forceGigabitFiber": "disabled",
- "forwardErrorCorrection": "not-supported",
- "ifIndex": 224,
- "lldpAdmin": "txonly",
- "lldpTlvmap": 130943,
- "macAddress": "00:23:e9:f1:e4:05",
- "mediaActive": "none",
- "mediaFixed": "auto",
- "mediaMax": "1000T-FD",
- "mediaSfp": "auto",
- "mtu": 9198,
- "preferPort": "sfp",
- "qinqEthertype": "0x8100",
- "sflow": {
- "pollInterval": 0,
- "pollIntervalGlobal": "yes"
- },
- "stp": "enabled",
- "stpAutoEdgePort": "enabled",
- "stpEdgePort": "true",
- "stpLinkType": "auto"
- },
- {
- "kind": "tm:net:interface:interfacestate",
- "name": "2.1",
- "fullPath": "2.1",
- "generation": 7859,
- "selfLink": "https://localhost/mgmt/tm/net/interface/2.1?ver=12.1.0",
- "bundle": "not-supported",
- "bundleSpeed": "not-supported",
- "enabled": true,
- "flowControl": "tx-rx",
- "forceGigabitFiber": "disabled",
- "forwardErrorCorrection": "not-supported",
- "ifIndex": 240,
- "lldpAdmin": "txonly",
- "lldpTlvmap": 130943,
- "macAddress": "00:23:e9:f1:e4:06",
- "mediaActive": "10000SR-FD",
- "mediaFixed": "auto",
- "mediaMax": "10000T-FD",
- "mediaSfp": "auto",
- "moduleDescription": "F5 compatible optics",
- "mtu": 9198,
- "preferPort": "sfp",
- "qinqEthertype": "0x8100",
- "serial": "ARP2LGU",
- "sflow": {
- "pollInterval": 0,
- "pollIntervalGlobal": "yes"
- },
- "stp": "enabled",
- "stpAutoEdgePort": "enabled",
- "stpEdgePort": "true",
- "stpLinkType": "auto",
- "vendor": "F5 NETWORKS INC.",
- "vendorOui": "009065",
- "vendorPartnum": "OPT-0016",
- "vendorRevision": "A0"
- },
- {
- "kind": "tm:net:interface:interfacestate",
- "name": "2.2",
- "fullPath": "2.2",
- "generation": 7746,
- "selfLink": "https://localhost/mgmt/tm/net/interface/2.2?ver=12.1.0",
- "bundle": "not-supported",
- "bundleSpeed": "not-supported",
- "enabled": true,
- "flowControl": "tx-rx",
- "forceGigabitFiber": "disabled",
- "forwardErrorCorrection": "not-supported",
- "ifIndex": 256,
- "lldpAdmin": "txonly",
- "lldpTlvmap": 130943,
- "macAddress": "00:23:e9:f1:e4:07",
- "mediaActive": "none",
- "mediaFixed": "auto",
- "mediaMax": "10000T-FD",
- "mediaSfp": "auto",
- "mtu": 9198,
- "preferPort": "sfp",
- "qinqEthertype": "0x8100",
- "sflow": {
- "pollInterval": 0,
- "pollIntervalGlobal": "yes"
- },
- "stp": "enabled",
- "stpAutoEdgePort": "enabled",
- "stpEdgePort": "true",
- "stpLinkType": "auto"
- },
- {
- "kind": "tm:net:interface:interfacestate",
- "name": "2.3",
- "fullPath": "2.3",
- "generation": 7749,
- "selfLink": "https://localhost/mgmt/tm/net/interface/2.3?ver=12.1.0",
- "bundle": "not-supported",
- "bundleSpeed": "not-supported",
- "enabled": true,
- "flowControl": "tx-rx",
- "forceGigabitFiber": "disabled",
- "forwardErrorCorrection": "not-supported",
- "ifIndex": 272,
- "lldpAdmin": "txonly",
- "lldpTlvmap": 130943,
- "macAddress": "00:23:e9:f1:e4:08",
- "mediaActive": "none",
- "mediaFixed": "auto",
- "mediaMax": "10000T-FD",
- "mediaSfp": "auto",
- "mtu": 9198,
- "preferPort": "sfp",
- "qinqEthertype": "0x8100",
- "sflow": {
- "pollInterval": 0,
- "pollIntervalGlobal": "yes"
- },
- "stp": "enabled",
- "stpAutoEdgePort": "enabled",
- "stpEdgePort": "true",
- "stpLinkType": "auto"
- },
- {
- "kind": "tm:net:interface:interfacestate",
- "name": "2.4",
- "fullPath": "2.4",
- "generation": 7752,
- "selfLink": "https://localhost/mgmt/tm/net/interface/2.4?ver=12.1.0",
- "bundle": "not-supported",
- "bundleSpeed": "not-supported",
- "enabled": true,
- "flowControl": "tx-rx",
- "forceGigabitFiber": "disabled",
- "forwardErrorCorrection": "not-supported",
- "ifIndex": 288,
- "lldpAdmin": "txonly",
- "lldpTlvmap": 130943,
- "macAddress": "00:23:e9:f1:e4:09",
- "mediaActive": "none",
- "mediaFixed": "auto",
- "mediaMax": "10000T-FD",
- "mediaSfp": "auto",
- "mtu": 9198,
- "preferPort": "sfp",
- "qinqEthertype": "0x8100",
- "sflow": {
- "pollInterval": 0,
- "pollIntervalGlobal": "yes"
- },
- "stp": "enabled",
- "stpAutoEdgePort": "enabled",
- "stpEdgePort": "true",
- "stpLinkType": "auto"
- },
- {
- "kind": "tm:net:interface:interfacestate",
- "name": "2.5",
- "fullPath": "2.5",
- "generation": 7755,
- "selfLink": "https://localhost/mgmt/tm/net/interface/2.5?ver=12.1.0",
- "bundle": "not-supported",
- "bundleSpeed": "not-supported",
- "enabled": true,
- "flowControl": "tx-rx",
- "forceGigabitFiber": "disabled",
- "forwardErrorCorrection": "not-supported",
- "ifIndex": 304,
- "lldpAdmin": "txonly",
- "lldpTlvmap": 130943,
- "macAddress": "00:23:e9:f1:e4:0a",
- "mediaActive": "none",
- "mediaFixed": "auto",
- "mediaMax": "10000T-FD",
- "mediaSfp": "auto",
- "mtu": 9198,
- "preferPort": "sfp",
- "qinqEthertype": "0x8100",
- "sflow": {
- "pollInterval": 0,
- "pollIntervalGlobal": "yes"
- },
- "stp": "enabled",
- "stpAutoEdgePort": "enabled",
- "stpEdgePort": "true",
- "stpLinkType": "auto"
- },
- {
- "kind": "tm:net:interface:interfacestate",
- "name": "2.6",
- "fullPath": "2.6",
- "generation": 7758,
- "selfLink": "https://localhost/mgmt/tm/net/interface/2.6?ver=12.1.0",
- "bundle": "not-supported",
- "bundleSpeed": "not-supported",
- "enabled": true,
- "flowControl": "tx-rx",
- "forceGigabitFiber": "disabled",
- "forwardErrorCorrection": "not-supported",
- "ifIndex": 320,
- "lldpAdmin": "txonly",
- "lldpTlvmap": 130943,
- "macAddress": "00:23:e9:f1:e4:0b",
- "mediaActive": "none",
- "mediaFixed": "auto",
- "mediaMax": "10000T-FD",
- "mediaSfp": "auto",
- "mtu": 9198,
- "preferPort": "sfp",
- "qinqEthertype": "0x8100",
- "sflow": {
- "pollInterval": 0,
- "pollIntervalGlobal": "yes"
- },
- "stp": "enabled",
- "stpAutoEdgePort": "enabled",
- "stpEdgePort": "true",
- "stpLinkType": "auto"
- },
- {
- "kind": "tm:net:interface:interfacestate",
- "name": "2.7",
- "fullPath": "2.7",
- "generation": 7761,
- "selfLink": "https://localhost/mgmt/tm/net/interface/2.7?ver=12.1.0",
- "bundle": "not-supported",
- "bundleSpeed": "not-supported",
- "enabled": true,
- "flowControl": "tx-rx",
- "forceGigabitFiber": "disabled",
- "forwardErrorCorrection": "not-supported",
- "ifIndex": 336,
- "lldpAdmin": "txonly",
- "lldpTlvmap": 130943,
- "macAddress": "00:23:e9:f1:e4:0c",
- "mediaActive": "none",
- "mediaFixed": "auto",
- "mediaMax": "10000T-FD",
- "mediaSfp": "auto",
- "mtu": 9198,
- "preferPort": "sfp",
- "qinqEthertype": "0x8100",
- "sflow": {
- "pollInterval": 0,
- "pollIntervalGlobal": "yes"
- },
- "stp": "enabled",
- "stpAutoEdgePort": "enabled",
- "stpEdgePort": "true",
- "stpLinkType": "auto"
- },
- {
- "kind": "tm:net:interface:interfacestate",
- "name": "2.8",
- "fullPath": "2.8",
- "generation": 7764,
- "selfLink": "https://localhost/mgmt/tm/net/interface/2.8?ver=12.1.0",
- "bundle": "not-supported",
- "bundleSpeed": "not-supported",
- "enabled": true,
- "flowControl": "tx-rx",
- "forceGigabitFiber": "disabled",
- "forwardErrorCorrection": "not-supported",
- "ifIndex": 352,
- "lldpAdmin": "txonly",
- "lldpTlvmap": 130943,
- "macAddress": "00:23:e9:f1:e4:0d",
- "mediaActive": "none",
- "mediaFixed": "auto",
- "mediaMax": "10000T-FD",
- "mediaSfp": "auto",
- "mtu": 9198,
- "preferPort": "sfp",
- "qinqEthertype": "0x8100",
- "sflow": {
- "pollInterval": 0,
- "pollIntervalGlobal": "yes"
- },
- "stp": "enabled",
- "stpAutoEdgePort": "enabled",
- "stpEdgePort": "true",
- "stpLinkType": "auto"
- },
- {
- "kind": "tm:net:interface:interfacestate",
- "name": "mgmt",
- "fullPath": "mgmt",
- "generation": 7651,
- "selfLink": "https://localhost/mgmt/tm/net/interface/mgmt?ver=12.1.0",
- "bundle": "not-supported",
- "bundleSpeed": "not-supported",
- "enabled": true,
- "flowControl": "tx-rx",
- "forceGigabitFiber": "disabled",
- "forwardErrorCorrection": "not-supported",
- "ifIndex": 96,
- "lldpAdmin": "txonly",
- "lldpTlvmap": 130943,
- "macAddress": "00:23:e9:f1:e4:01",
- "mediaActive": "1000T-FD",
- "mediaFixed": "auto",
- "mediaMax": "1000T-FD",
- "mediaSfp": "auto",
- "mtu": 1500,
- "preferPort": "sfp",
- "qinqEthertype": "0x8100",
- "sflow": {
- "pollInterval": 0,
- "pollIntervalGlobal": "yes"
- },
- "stp": "enabled",
- "stpAutoEdgePort": "enabled",
- "stpEdgePort": "true",
- "stpLinkType": "auto"
- }
- ]
diff --git a/test/units/modules/network/f5/fixtures/load_net_node_with_fqdn.json b/test/units/modules/network/f5/fixtures/load_net_node_with_fqdn.json
deleted file mode 100644
index 67c02568d5..0000000000
--- a/test/units/modules/network/f5/fixtures/load_net_node_with_fqdn.json
+++ /dev/null
@@ -1,25 +0,0 @@
-{
- "kind": "tm:ltm:node:nodestate",
- "name": "foo.bar.com",
- "partition": "Common",
- "fullPath": "/Common/foo.bar.com",
- "generation": 157,
- "selfLink": "https://localhost/mgmt/tm/ltm/node/~Common~foo.bar.com?ver=12.0.0",
- "address": "any6",
- "connectionLimit": 0,
- "dynamicRatio": 1,
- "ephemeral": "false",
- "fqdn": {
- "addressFamily": "ipv4",
- "autopopulate": "enabled",
- "downInterval": 5,
- "interval": "3600",
- "tmName": "foo.bar.com"
- },
- "logging": "disabled",
- "monitor": "default",
- "rateLimit": "disabled",
- "ratio": 1,
- "session": "user-enabled",
- "state": "fqdn-up-no-addr"
-}
diff --git a/test/units/modules/network/f5/fixtures/load_net_node_with_ipv4_address.json b/test/units/modules/network/f5/fixtures/load_net_node_with_ipv4_address.json
deleted file mode 100644
index 9e3be88929..0000000000
--- a/test/units/modules/network/f5/fixtures/load_net_node_with_ipv4_address.json
+++ /dev/null
@@ -1,24 +0,0 @@
-{
- "kind": "tm:ltm:node:nodestate",
- "name": "7.3.67.8",
- "partition": "Common",
- "fullPath": "/Common/7.3.67.8",
- "generation": 162,
- "selfLink": "https://localhost/mgmt/tm/ltm/node/~Common~7.3.67.8?ver=12.0.0",
- "address": "7.3.67.8",
- "connectionLimit": 0,
- "dynamicRatio": 1,
- "ephemeral": "false",
- "fqdn": {
- "addressFamily": "ipv4",
- "autopopulate": "disabled",
- "downInterval": 5,
- "interval": "3600"
- },
- "logging": "disabled",
- "monitor": "default",
- "rateLimit": "disabled",
- "ratio": 1,
- "session": "user-enabled",
- "state": "unchecked"
-}
diff --git a/test/units/modules/network/f5/fixtures/load_net_route_description.json b/test/units/modules/network/f5/fixtures/load_net_route_description.json
deleted file mode 100644
index a7c47bc8fe..0000000000
--- a/test/units/modules/network/f5/fixtures/load_net_route_description.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "kind": "tm:net:route:routestate",
- "name": "asdasd",
- "partition": "Common",
- "fullPath": "/Common/asdasd",
- "generation": 113,
- "selfLink": "https://localhost/mgmt/tm/net/route/~Common~asdasd?ver=12.1.0",
- "description": "asdasd",
- "mtu": 0,
- "network": "2.2.2.2/32",
- "pool": "/Common/adsasd",
- "poolReference": {
- "link": "https://localhost/mgmt/tm/ltm/pool/~Common~adsasd?ver=12.1.0"
- }
-} \ No newline at end of file
diff --git a/test/units/modules/network/f5/fixtures/load_net_route_domain_1.json b/test/units/modules/network/f5/fixtures/load_net_route_domain_1.json
deleted file mode 100644
index 6ff8c5dfc8..0000000000
--- a/test/units/modules/network/f5/fixtures/load_net_route_domain_1.json
+++ /dev/null
@@ -1,36 +0,0 @@
-{
- "kind": "tm:net:route-domain:route-domainstate",
- "name": "0",
- "partition": "Common",
- "fullPath": "/Common/0",
- "generation": 1,
- "selfLink": "https://localhost/mgmt/tm/net/route-domain/~Common~0?ver=13.1.0",
- "connectionLimit": 0,
- "id": 0,
- "strict": "enabled",
- "throughputCapacity": 0,
- "vlans": [
- "/Common/net1",
- "/Common/internal",
- "/Common/net2",
- "/Common/socks-tunnel",
- "/Common/http-tunnel"
- ],
- "vlansReference": [
- {
- "link": "https://localhost/mgmt/tm/net/vlan/~Common~net1?ver=13.1.0"
- },
- {
- "link": "https://localhost/mgmt/tm/net/vlan/~Common~internal?ver=13.1.0"
- },
- {
- "link": "https://localhost/mgmt/tm/net/vlan/~Common~net2?ver=13.1.0"
- },
- {
- "link": "https://localhost/mgmt/tm/net/tunnels/tunnel/~Common~socks-tunnel?ver=13.1.0"
- },
- {
- "link": "https://localhost/mgmt/tm/net/tunnels/tunnel/~Common~http-tunnel?ver=13.1.0"
- }
- ]
-}
diff --git a/test/units/modules/network/f5/fixtures/load_net_service_policy_1.json b/test/units/modules/network/f5/fixtures/load_net_service_policy_1.json
deleted file mode 100644
index a89ca59ffe..0000000000
--- a/test/units/modules/network/f5/fixtures/load_net_service_policy_1.json
+++ /dev/null
@@ -1,17 +0,0 @@
-{
- "kind": "tm:net:service-policy:service-policystate",
- "name": "baz",
- "partition": "Common",
- "fullPath": "/Common/baz",
- "generation": 581,
- "selfLink": "https://localhost/mgmt/tm/net/service-policy/~Common~baz?ver=13.1.0.4",
- "description": "my description",
- "portMisusePolicy": "/Common/bar",
- "portMisusePolicyReference": {
- "link": "https://localhost/mgmt/tm/security/firewall/port-misuse-policy/~Common~bar?ver=13.1.0.4"
- },
- "timerPolicy": "/Common/foo",
- "timerPolicyReference": {
- "link": "https://localhost/mgmt/tm/net/timer-policy/~Common~foo?ver=13.1.0.4"
- }
-}
diff --git a/test/units/modules/network/f5/fixtures/load_net_timer_policy_1.json b/test/units/modules/network/f5/fixtures/load_net_timer_policy_1.json
deleted file mode 100644
index 4b6f550a58..0000000000
--- a/test/units/modules/network/f5/fixtures/load_net_timer_policy_1.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
- "kind": "tm:net:timer-policy:timer-policystate",
- "name": "timer1",
- "partition": "Common",
- "fullPath": "/Common/timer1",
- "generation": 148,
- "selfLink": "https://localhost/mgmt/tm/net/timer-policy/~Common~timer1?ver=13.1.0.4",
- "description": "my description"
-}
diff --git a/test/units/modules/network/f5/fixtures/load_net_tunnel_1.json b/test/units/modules/network/f5/fixtures/load_net_tunnel_1.json
deleted file mode 100644
index dd0e484268..0000000000
--- a/test/units/modules/network/f5/fixtures/load_net_tunnel_1.json
+++ /dev/null
@@ -1,25 +0,0 @@
-{
- "kind": "tm:net:tunnels:tunnel:tunnelstate",
- "name": "tunnel1",
- "partition": "Common",
- "fullPath": "/Common/tunnel1",
- "generation": 3713,
- "selfLink": "https://localhost/mgmt/tm/net/tunnels/tunnel/~Common~tunnel1?ver=13.1.0.7",
- "autoLasthop": "default",
- "description": "my other tunnel",
- "idleTimeout": 300,
- "ifIndex": 736,
- "key": 0,
- "localAddress": "3.3.3.3",
- "mode": "bidirectional",
- "mtu": 1000,
- "profile": "/Common/ipip",
- "profileReference": {
- "link": "https://localhost/mgmt/tm/net/tunnels/ipip/~Common~ipip?ver=13.1.0.7"
- },
- "remoteAddress": "4.4.4.4",
- "secondaryAddress": "any6",
- "tos": "preserve",
- "transparent": "disabled",
- "usePmtu": "enabled"
-}
diff --git a/test/units/modules/network/f5/fixtures/load_ntp.json b/test/units/modules/network/f5/fixtures/load_ntp.json
deleted file mode 100644
index 3b55b4870e..0000000000
--- a/test/units/modules/network/f5/fixtures/load_ntp.json
+++ /dev/null
@@ -1,13 +0,0 @@
-{
- "kind": "tm:sys:ntp:ntpstate",
- "selfLink": "https://localhost/mgmt/tm/sys/ntp?ver=12.1.0",
- "servers": [
- "192.168.1.1",
- "192.168.1.2"
- ],
- "timezone": "America/Los_Angeles",
- "restrictReference": {
- "link": "https://localhost/mgmt/tm/sys/ntp/restrict?ver=12.1.0",
- "isSubcollection": true
- }
-} \ No newline at end of file
diff --git a/test/units/modules/network/f5/fixtures/load_regkey_license_key.json b/test/units/modules/network/f5/fixtures/load_regkey_license_key.json
deleted file mode 100644
index 8a781d1dab..0000000000
--- a/test/units/modules/network/f5/fixtures/load_regkey_license_key.json
+++ /dev/null
@@ -1,96 +0,0 @@
-{
- "description": "foo bar baz",
- "dossier": "5d54d976",
- "encryptedPrivateKey": [
- 27,
- -10,
- 12,
- 58,
- 75
- ],
- "generation": 2,
- "internalPrivateKey": "sKpXEU7",
- "kind": "cm:device:licensing:pool:regkey:licenses:item:offerings:regkeypoollicenseofferingstate",
- "lastUpdateMicros": 1513107721123304,
- "licenseState": {
- "vendor": "F5 Networks, Inc.",
- "licensedDateTime": "2017-12-12T00:00:00-08:00",
- "licensedVersion": "5.3.0",
- "evaluationStartDateTime": "2017-12-11T00:00:00-08:00",
- "evaluationEndDateTime": "2018-01-12T00:00:00-08:00",
- "licenseEndDateTime": "2018-01-12T00:00:00-08:00",
- "licenseStartDateTime": "2017-12-11T00:00:00-08:00",
- "registrationKey": "XXXX-XXXX-XXXX-XXXX-XXXX",
- "dossier": "1a44262799bc",
- "authorization": "03fc41d1e8666",
- "usage": "F5 Internal Product Development",
- "platformId": "Z100",
- "authVers": "5b",
- "serviceCheckDateTime": "2017-12-12T00:00:00-08:00",
- "serviceStatus": "As of 2017-12-12 there is no active service contract. This may inhibit your ability to upgrade your software.",
- "exclusivePlatform": [
- "Z100",
- "Z100A",
- "Z100AzureCloud",
- "Z100GoogleCloud",
- "Z100K",
- "Z100x",
- "Z100H"
- ],
- "activeModules": [
- "APM, Max, VE (2500 CCU, 10000 Access Sessions)|P961057-1761515|Anti-Virus Checks",
- "LTM, 10 Gbps, VE|T487107-2453693|, VE|DNSSEC",
- "PEM, VE|X895364-1851682"
- ],
- "optionalModules": [
- "APM, Base, VE (50 CCU / 200 AS)",
- "App Mode (TMSH Only, No Root/Bash)",
- "Concurrent Users",
- "Concurrent Users and Access Sessions, VE",
- "FIPS 140-2 Level 1, BIG-IP VE-1G to 10G",
- "IP Intelligence, 1Yr, VE",
- "IP Intelligence, 1Yr, VE-10G",
- "IP Intelligence, 3Yr, VE-10G",
- "LTM to Better Bundle Upgrade, 10Gbps",
- "PEM URL Filtering, 1Yr, HIGH PERF",
- "PEM URL Filtering, 3Yr, HIGH PERF",
- "Routing Bundle",
- "Secure Web Gateway, 1Yr, VE",
- "URL Filtering, 1Yr, VE"
- ],
- "moduleEvaluations": [
- {
- "moduleName": "IP Intelligence, 3Yr, VE|SUBSCRIPTION",
- "endDate": "soon"
- },
- {
- "moduleName": "Secure Web Gateway, 3Yr, VE|SUBSCRIPTION",
- "endDate": "soon"
- },
- {
- "moduleName": "URL Filtering, 3Yr, VE|SUBSCRIPTION",
- "endDate": "soon"
- }
- ],
- "featureFlags": [
- {
- "featureName": "gtm_rate_limit",
- "featureValue": "12345"
- }
- ],
- "generation": 0,
- "lastUpdateMicros": 0
- },
- "licenseText": "#Auth vers : BIG-IQ Product License File#",
- "message": "License XXXX-XXXX-XXXX-XXXX-XXXX ready",
- "name": "License for XXXX-XXXX-XXXX-XXXX-XXXX",
- "publicKey": [
- 48,
- 0,
- 1
- ],
- "regKey": "XXXX-XXXX-XXXX-XXXX-XXXX",
- "selfLink": "https://localhost/mgmt/cm/device/licensing/pool/regkey/licenses/452f8628-1e56-4b4d-946c-0e68f5780aa1/offerings/XXXX-XXXX-XXXX-XXXX-XXXX",
- "sortName": "Registration Key Pool Item",
- "status": "READY"
-}
diff --git a/test/units/modules/network/f5/fixtures/load_regkey_license_pool.json b/test/units/modules/network/f5/fixtures/load_regkey_license_pool.json
deleted file mode 100644
index f711817f7f..0000000000
--- a/test/units/modules/network/f5/fixtures/load_regkey_license_pool.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
- "description": "this is a description",
- "generation": 2,
- "id": "452f8628-1e56-4b4d-946c-0e68f5780aa1",
- "kind": "cm:device:licensing:pool:regkey:licenses:regkeypoollicensestate",
- "lastUpdateMicros": 1513371645532221,
- "name": "asd",
- "selfLink": "https://localhost/mgmt/cm/device/licensing/pool/regkey/licenses/452f8628-1e56-4b4d-946c-0e68f5780aa1",
- "sortName": "Registration Key Pool"
-}
diff --git a/test/units/modules/network/f5/fixtures/load_remote_user_settings.json b/test/units/modules/network/f5/fixtures/load_remote_user_settings.json
deleted file mode 100644
index 296f462f97..0000000000
--- a/test/units/modules/network/f5/fixtures/load_remote_user_settings.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
- "kind": "tm:auth:remote-user:remote-userstate",
- "selfLink": "https://localhost/mgmt/tm/auth/remote-user?ver=12.1.4",
- "defaultPartition": "all",
- "defaultPartitionReference": {
- "link": "https://localhost/mgmt/tm/auth/partition/all?ver=12.1.4"
- },
- "defaultRole": "no-access",
- "remoteConsoleAccess": "disabled"
-}
diff --git a/test/units/modules/network/f5/fixtures/load_security_address_list_1.json b/test/units/modules/network/f5/fixtures/load_security_address_list_1.json
deleted file mode 100644
index 45aca1e3cd..0000000000
--- a/test/units/modules/network/f5/fixtures/load_security_address_list_1.json
+++ /dev/null
@@ -1,53 +0,0 @@
-{
- "kind": "tm:security:firewall:address-list:address-liststate",
- "name": "bar",
- "partition": "Common",
- "fullPath": "/Common/bar",
- "generation": 135,
- "selfLink": "https://localhost/mgmt/tm/security/firewall/address-list/~Common~bar?ver=12.1.2",
- "addressLists": [
- {
- "name": "foo",
- "partition": "Common",
- "nameReference": {
- "link": "https://localhost/mgmt/tm/security/firewall/address-list/~Common~foo?ver=12.1.2"
- }
- }
- ],
- "addresses": [
- {
- "name": "1.1.1.1"
- },
- {
- "name": "2.2.2.2-3.3.3.3"
- },
- {
- "name": "5.5.5.5-6.6.6.6"
- },
- {
- "name": "2700:bc00:1f10:101::6"
- }
- ],
- "fqdns": [
- {
- "name": "google.com"
- }
- ],
- "geo": [
- {
- "name": "AF:Baghlan"
- },
- {
- "name": "AF:Helmand"
- },
- {
- "name": "BS"
- },
- {
- "name": "EU"
- },
- {
- "name": "GE:Marneulis Raioni"
- }
- ]
-}
diff --git a/test/units/modules/network/f5/fixtures/load_security_firewall_global_rules_1.json b/test/units/modules/network/f5/fixtures/load_security_firewall_global_rules_1.json
deleted file mode 100644
index 80f475eb47..0000000000
--- a/test/units/modules/network/f5/fixtures/load_security_firewall_global_rules_1.json
+++ /dev/null
@@ -1,16 +0,0 @@
-{
- "kind": "tm:security:firewall:global-rules:global-rulesstate",
- "selfLink": "https://localhost/mgmt/tm/security/firewall/global-rules?ver=13.1.0.7",
- "enforcedPolicy": "/Common/foo",
- "enforcedPolicyReference": {
- "link": "https://localhost/mgmt/tm/security/firewall/policy/~Common~foo?ver=13.1.0.7"
- },
- "servicePolicy": "/Common/bar",
- "servicePolicyReference": {
- "link": "https://localhost/mgmt/tm/net/service-policy/~Common~bar?ver=13.1.0.7"
- },
- "stagedPolicy": "/Common/baz",
- "stagedPolicyReference": {
- "link": "https://localhost/mgmt/tm/security/firewall/policy/~Common~baz?ver=13.1.0.7"
- }
-}
diff --git a/test/units/modules/network/f5/fixtures/load_security_firewall_policy_1.json b/test/units/modules/network/f5/fixtures/load_security_firewall_policy_1.json
deleted file mode 100644
index 9c24605883..0000000000
--- a/test/units/modules/network/f5/fixtures/load_security_firewall_policy_1.json
+++ /dev/null
@@ -1,51 +0,0 @@
-{
- "kind": "tm:security:firewall:policy:policystate",
- "name": "foo",
- "partition": "Common",
- "fullPath": "/Common/foo",
- "generation": 2075,
- "selfLink": "https://localhost/mgmt/tm/security/firewall/policy/~Common~foo?expandSubcollections=true&ver=13.1.0.7",
- "description": "my description",
- "rulesReference": {
- "link": "https://localhost/mgmt/tm/security/firewall/policy/~Common~foo/rules?ver=13.1.0.7",
- "isSubcollection": true,
- "items": [
- {
- "kind": "tm:security:firewall:policy:rules:rulesstate",
- "name": "rule1",
- "fullPath": "rule1",
- "generation": 2075,
- "selfLink": "https://localhost/mgmt/tm/security/firewall/policy/~Common~foo/rules/rule1?ver=13.1.0.7",
- "action": "accept",
- "ipProtocol": "any",
- "iruleSampleRate": 1,
- "log": "no",
- "status": "enabled"
- },
- {
- "kind": "tm:security:firewall:policy:rules:rulesstate",
- "name": "rule2",
- "fullPath": "rule2",
- "generation": 2075,
- "selfLink": "https://localhost/mgmt/tm/security/firewall/policy/~Common~foo/rules/rule2?ver=13.1.0.7",
- "action": "accept",
- "ipProtocol": "any",
- "iruleSampleRate": 1,
- "log": "no",
- "status": "enabled"
- },
- {
- "kind": "tm:security:firewall:policy:rules:rulesstate",
- "name": "rule3",
- "fullPath": "rule3",
- "generation": 2074,
- "selfLink": "https://localhost/mgmt/tm/security/firewall/policy/~Common~foo/rules/rule3?ver=13.1.0.7",
- "action": "accept",
- "ipProtocol": "any",
- "iruleSampleRate": 1,
- "log": "no",
- "status": "enabled"
- }
- ]
- }
-}
diff --git a/test/units/modules/network/f5/fixtures/load_security_port_list_1.json b/test/units/modules/network/f5/fixtures/load_security_port_list_1.json
deleted file mode 100644
index ec639dacf8..0000000000
--- a/test/units/modules/network/f5/fixtures/load_security_port_list_1.json
+++ /dev/null
@@ -1,41 +0,0 @@
-{
- "kind": "tm:security:firewall:port-list:port-liststate",
- "name": "foo",
- "partition": "Common",
- "fullPath": "/Common/foo",
- "generation": 119,
- "description": "this is a description",
- "selfLink": "https://localhost/mgmt/tm/security/firewall/port-list/~Common~foo?ver=12.1.0",
- "portLists": [
- {
- "name": "_sys_self_allow_tcp_defaults",
- "partition": "Common",
- "nameReference": {
- "link": "https://localhost/mgmt/tm/security/firewall/port-list/~Common~_sys_self_allow_tcp_defaults?ver=12.1.0"
- }
- }
- ],
- "ports": [
- {
- "name": "1"
- },
- {
- "name": "2"
- },
- {
- "name": "3"
- },
- {
- "name": "4"
- },
- {
- "name": "10-20"
- },
- {
- "name": "30-40"
- },
- {
- "name": "50-60"
- }
- ]
-}
diff --git a/test/units/modules/network/f5/fixtures/load_shared_system_setup_1.json b/test/units/modules/network/f5/fixtures/load_shared_system_setup_1.json
deleted file mode 100644
index 8f886e1453..0000000000
--- a/test/units/modules/network/f5/fixtures/load_shared_system_setup_1.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
- "isSystemSetup": true,
- "isAdminPasswordChanged": false,
- "isRootPasswordChanged": true,
- "generation": 7,
- "lastUpdateMicros": 1536357209120972,
- "kind": "shared:system:setup:systemsetupworkerstate",
- "selfLink": "https://localhost/mgmt/shared/system/setup"
-}
diff --git a/test/units/modules/network/f5/fixtures/load_sys_application_template_w_new_checksum.json b/test/units/modules/network/f5/fixtures/load_sys_application_template_w_new_checksum.json
deleted file mode 100644
index 57f3c3755a..0000000000
--- a/test/units/modules/network/f5/fixtures/load_sys_application_template_w_new_checksum.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
- "kind": "tm:sys:application:template:templatestate",
- "name": "good_templ",
- "partition": "Common",
- "fullPath": "/Common/good_templ",
- "generation": 410,
- "selfLink": "https://localhost/mgmt/tm/sys/application/template/~Common~good_templ?ver=13.0.0",
- "description": "My basic template",
- "ignoreVerification": "false",
- "requiresBigipVersionMin": "11.6.0",
- "requiresModules": [
- "ltm"
- ],
- "tmplChecksum": "90c46acee5ca08e300da0bcdb9130745",
- "totalSigningStatus": "checksum",
- "verificationStatus": "checksum-verified",
- "actionsReference": {
- "link": "https://localhost/mgmt/tm/sys/application/template/~Common~good_templ/actions?ver=13.0.0",
- "isSubcollection": true
- }
-}
diff --git a/test/units/modules/network/f5/fixtures/load_sys_application_template_w_old_checksum.json b/test/units/modules/network/f5/fixtures/load_sys_application_template_w_old_checksum.json
deleted file mode 100644
index da477515bf..0000000000
--- a/test/units/modules/network/f5/fixtures/load_sys_application_template_w_old_checksum.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
- "kind": "tm:sys:application:template:templatestate",
- "name": "good_templ",
- "partition": "Common",
- "fullPath": "/Common/good_templ",
- "generation": 410,
- "selfLink": "https://localhost/mgmt/tm/sys/application/template/~Common~good_templ?ver=13.0.0",
- "description": "My basic foo bar",
- "ignoreVerification": "false",
- "requiresBigipVersionMin": "12.0.0",
- "requiresModules": [
- "ltm"
- ],
- "tmplChecksum": "eee01710dbe330d380d1a4fa30eeabdb",
- "totalSigningStatus": "checksum",
- "verificationStatus": "checksum-verified",
- "actionsReference": {
- "link": "https://localhost/mgmt/tm/sys/application/template/~Common~good_templ/actions?ver=13.0.0",
- "isSubcollection": true
- }
-}
diff --git a/test/units/modules/network/f5/fixtures/load_sys_crypto_cert_validator_1.json b/test/units/modules/network/f5/fixtures/load_sys_crypto_cert_validator_1.json
deleted file mode 100644
index 59da203a5d..0000000000
--- a/test/units/modules/network/f5/fixtures/load_sys_crypto_cert_validator_1.json
+++ /dev/null
@@ -1,33 +0,0 @@
-{
- "kind": "tm:sys:crypto:cert-validator:ocsp:ocspstate",
- "name": "asd",
- "partition": "Common",
- "fullPath": "/Common/asd",
- "generation": 151,
- "selfLink": "https://localhost/mgmt/tm/sys/crypto/cert-validator/ocsp/~Common~asd?ver=13.1.0.8",
- "cacheErrorTimeout": 3600,
- "cacheTimeout": "indefinite",
- "clockSkew": 300,
- "concurrentConnectionsLimit": 500,
- "dnsResolver": "/Common/foo",
- "dnsResolverReference": {
- "link": "https://localhost/mgmt/tm/net/dns-resolver/~Common~foo?ver=13.1.0.8"
- },
- "routeDomain": "/Common/0",
- "routeDomainReference": {
- "link": "https://localhost/mgmt/tm/net/route-domain/~Common~0?ver=13.1.0.8"
- },
- "signHash": "sha256",
- "signerCert": "/Common/default.crt",
- "signerCertReference": {
- "link": "https://localhost/mgmt/tm/sys/file/ssl-cert/~Common~default.crt?ver=13.1.0.8"
- },
- "signerKey": "/Common/default.key",
- "signerKeyReference": {
- "link": "https://localhost/mgmt/tm/sys/file/ssl-key/~Common~default.key?ver=13.1.0.8"
- },
- "signerKeyPassphrase": "secret",
- "statusAge": 0,
- "strictRespCertCheck": "enabled",
- "timeout": 8
-}
diff --git a/test/units/modules/network/f5/fixtures/load_sys_file_external-monitor_1.json b/test/units/modules/network/f5/fixtures/load_sys_file_external-monitor_1.json
deleted file mode 100644
index 70dcbc23f0..0000000000
--- a/test/units/modules/network/f5/fixtures/load_sys_file_external-monitor_1.json
+++ /dev/null
@@ -1,17 +0,0 @@
-{
- "kind": "tm:sys:file:external-monitor:external-monitorstate",
- "name": "arg_example",
- "partition": "Common",
- "fullPath": "/Common/arg_example",
- "generation": 1,
- "selfLink": "https://localhost/mgmt/tm/sys/file/external-monitor/~Common~arg_example?ver=13.1.0.8",
- "checksum": "SHA1:3159:0c78e6641632e47d11802b29cfd119d2233cb80a",
- "createTime": "2018-06-16T06:49:11Z",
- "createdBy": "root",
- "lastUpdateTime": "2018-06-16T06:49:11Z",
- "mode": 33261,
- "revision": 1,
- "size": 3159,
- "systemPath": "/config/monitors/arg_example",
- "updatedBy": "root"
-}
diff --git a/test/units/modules/network/f5/fixtures/load_sys_file_ssl_cert_with_issuer_cert.json b/test/units/modules/network/f5/fixtures/load_sys_file_ssl_cert_with_issuer_cert.json
deleted file mode 100644
index bb77ca33e5..0000000000
--- a/test/units/modules/network/f5/fixtures/load_sys_file_ssl_cert_with_issuer_cert.json
+++ /dev/null
@@ -1,42 +0,0 @@
-{
- "kind": "tm:sys:file:ssl-cert:ssl-certstate",
- "name": "ocsp.example.com.crt",
- "partition": "Common",
- "fullPath": "/Common/ocsp.example.com.crt",
- "generation": 548,
- "selfLink": "https://localhost/mgmt/tm/sys/file/ssl-cert/~Common~ocsp.example.com.crt?ver=13.0.0",
- "certValidationOptions": [
- "ocsp"
- ],
- "certificateKeyCurveName": "none",
- "certificateKeySize": 4096,
- "checksum": "SHA1:2113:b84ae5ed7e236b35206b2ff61289df9547d5afa3",
- "createTime": "2017-10-25T20:56:09Z",
- "createdBy": "admin",
- "expirationDate": 1545199767,
- "expirationString": "Dec 19 06:09:27 2018 GMT",
- "isBundle": "false",
- "issuer": "CN=Alice Ltd Intermediate CA,OU=Alice Ltd Certificate Authority,O=Alice Ltd,ST=England,C=GB",
- "issuerCert": "/Common/intermediate.crt",
- "issuerCertReference": {
- "link": "https://localhost/mgmt/tm/sys/file/ssl-cert/~Common~intermediate.crt?ver=13.0.0"
- },
- "keyType": "rsa-public",
- "lastUpdateTime": "2017-10-25T20:56:09Z",
- "mode": 33188,
- "revision": 1,
- "serialNumber": "4096",
- "size": 2113,
- "sourcePath": "file:///var/config/rest/downloads/ocsp.example.com.crt",
- "subject": "CN=ocsp.example.com,OU=Alice Ltd Certificate Authority,O=Alice Ltd,ST=England,C=GB",
- "updatedBy": "admin",
- "version": 3,
- "bundleCertificatesReference": {
- "link": "https://localhost/mgmt/tm/sys/file/ssl-cert/~Common~ocsp.example.com.crt/bundle-certificates?ver=13.0.0",
- "isSubcollection": true
- },
- "certValidatorsReference": {
- "link": "https://localhost/mgmt/tm/sys/file/ssl-cert/~Common~ocsp.example.com.crt/cert-validators?ver=13.0.0",
- "isSubcollection": true
- }
-}
diff --git a/test/units/modules/network/f5/fixtures/load_sys_global_settings.json b/test/units/modules/network/f5/fixtures/load_sys_global_settings.json
deleted file mode 100644
index 191d8178a4..0000000000
--- a/test/units/modules/network/f5/fixtures/load_sys_global_settings.json
+++ /dev/null
@@ -1,24 +0,0 @@
-{
- "kind": "tm:sys:global-settings:global-settingsstate",
- "selfLink": "https://localhost/mgmt/tm/sys/global-settings?ver=13.0.0",
- "awsApiMaxConcurrency": 1,
- "consoleInactivityTimeout": 0,
- "customAddr": "none",
- "failsafeAction": "go-offline-restart-tm",
- "fileBlacklistPathPrefix": "{/shared/3dns/} {/shared/bin/} {/shared/core/} {/shared/datasync/} {/shared/em/} {/shared/GeoIP/} {/shared/images/} {/shared/lib/} {/shared/lib64/} {/shared/log/} {/shared/lost+found/} {/shared/mgmt/} {/shared/nfb/} {/shared/ssh/} {/shared/statsd/} {/shared/tmstat/} {/shared/vadc/} {/config/aaa/} {/config/big3d/} {/config/bigip/} {/config/filestore/} {/config/gtm/} {/config/httpd/} {/config/ntp.conf} {/config/rndc.key} {/config/ssh/} {/config/ssl/}",
- "fileBlacklistReadOnlyPathPrefix": "{/etc/shadow}",
- "fileLocalPathPrefix": "{/shared/} {/tmp/}",
- "fileWhitelistPathPrefix": "{/var/local/scf} {/tmp/} {/shared/} {/config/} {/usr/share/aws/}",
- "guiSecurityBanner": "enabled",
- "guiSecurityBannerText": "Welcome to the BIG-IP Configuration Utility.\n\nLog in with your username and password using the fields on the left.",
- "guiSetup": "disabled",
- "hostAddrMode": "management",
- "hostname": "bigip1",
- "lcdDisplay": "enabled",
- "ledLocator": "disabled",
- "mgmtDhcp": "enabled",
- "netReboot": "disabled",
- "passwordPrompt": "Password",
- "quietBoot": "enabled",
- "usernamePrompt": "Username"
-}
diff --git a/test/units/modules/network/f5/fixtures/load_sys_httpd.json b/test/units/modules/network/f5/fixtures/load_sys_httpd.json
deleted file mode 100644
index 38d761681b..0000000000
--- a/test/units/modules/network/f5/fixtures/load_sys_httpd.json
+++ /dev/null
@@ -1,36 +0,0 @@
-{
- "kind": "tm:sys:httpd:httpdstate",
- "selfLink": "https://localhost/mgmt/tm/sys/httpd?ver=12.1.2",
- "allow": [
- "All"
- ],
- "authName": "BIG-IP",
- "authPamDashboardTimeout": "off",
- "authPamIdleTimeout": 1200,
- "authPamValidateIp": "on",
- "fastcgiTimeout": 300,
- "fipsCipherVersion": 0,
- "hostnameLookup": "off",
- "logLevel": "warn",
- "maxClients": 10,
- "redirectHttpToHttps": "disabled",
- "requestBodyMaxTimeout": 0,
- "requestBodyMinRate": 500,
- "requestBodyTimeout": 60,
- "requestHeaderMaxTimeout": 40,
- "requestHeaderMinRate": 500,
- "requestHeaderTimeout": 20,
- "sslCertfile": "/etc/httpd/conf/ssl.crt/server.crt",
- "sslCertkeyfile": "/etc/httpd/conf/ssl.key/server.key",
- "sslCiphersuite": "ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA:ECDHE-ECDSA-AES128-SHA256:ECDHE-ECDSA-AES256-SHA384:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA:AES256-SHA:AES128-SHA256:AES256-SHA256:ECDHE-RSA-DES-CBC3-SHA:ECDHE-ECDSA-DES-CBC3-SHA:DES-CBC3-SHA",
- "sslOcspDefaultResponder": "http://127.0.0.1",
- "sslOcspEnable": "off",
- "sslOcspOverrideResponder": "off",
- "sslOcspResponderTimeout": 300,
- "sslOcspResponseMaxAge": -1,
- "sslOcspResponseTimeSkew": 300,
- "sslPort": 443,
- "sslProtocol": "all -SSLv2 -SSLv3",
- "sslVerifyClient": "no",
- "sslVerifyDepth": 10
-}
diff --git a/test/units/modules/network/f5/fixtures/load_sys_httpd_non_default.json b/test/units/modules/network/f5/fixtures/load_sys_httpd_non_default.json
deleted file mode 100644
index 05051b9c08..0000000000
--- a/test/units/modules/network/f5/fixtures/load_sys_httpd_non_default.json
+++ /dev/null
@@ -1,36 +0,0 @@
-{
- "kind": "tm:sys:httpd:httpdstate",
- "selfLink": "https://localhost/mgmt/tm/sys/httpd?ver=12.1.2",
- "allow": [
- "All"
- ],
- "authName": "BIG-IP",
- "authPamDashboardTimeout": "off",
- "authPamIdleTimeout": 1200,
- "authPamValidateIp": "on",
- "fastcgiTimeout": 300,
- "fipsCipherVersion": 0,
- "hostnameLookup": "off",
- "logLevel": "warn",
- "maxClients": 10,
- "redirectHttpToHttps": "disabled",
- "requestBodyMaxTimeout": 0,
- "requestBodyMinRate": 500,
- "requestBodyTimeout": 60,
- "requestHeaderMaxTimeout": 40,
- "requestHeaderMinRate": 500,
- "requestHeaderTimeout": 20,
- "sslCertfile": "/etc/httpd/conf/ssl.crt/server.crt",
- "sslCertkeyfile": "/etc/httpd/conf/ssl.key/server.key",
- "sslCiphersuite": "ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384",
- "sslOcspDefaultResponder": "http://127.0.0.1",
- "sslOcspEnable": "off",
- "sslOcspOverrideResponder": "off",
- "sslOcspResponderTimeout": 300,
- "sslOcspResponseMaxAge": -1,
- "sslOcspResponseTimeSkew": 300,
- "sslPort": 443,
- "sslProtocol": "all -SSLv2",
- "sslVerifyClient": "no",
- "sslVerifyDepth": 10
-}
diff --git a/test/units/modules/network/f5/fixtures/load_sys_log_config_destination_1.json b/test/units/modules/network/f5/fixtures/load_sys_log_config_destination_1.json
deleted file mode 100644
index 5288ed250c..0000000000
--- a/test/units/modules/network/f5/fixtures/load_sys_log_config_destination_1.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "kind": "tm:sys:log-config:destination:remote-syslog:remote-syslogstate",
- "name": "foo",
- "partition": "Common",
- "fullPath": "/Common/foo",
- "generation": 1767,
- "selfLink": "https://localhost/mgmt/tm/sys/log-config/destination/remote-syslog/~Common~foo?ver=13.1.0.4",
- "defaultFacility": "local0",
- "defaultSeverity": "info",
- "format": "rfc5424",
- "remoteHighSpeedLog": "/Common/pool1",
- "remoteHighSpeedLogReference": {
- "link": "https://localhost/mgmt/tm/sys/log-config/destination/remote-high-speed-log/~Common~pool1?ver=13.1.0.4"
- }
-}
diff --git a/test/units/modules/network/f5/fixtures/load_sys_log_config_publisher_1.json b/test/units/modules/network/f5/fixtures/load_sys_log_config_publisher_1.json
deleted file mode 100644
index 54dd889114..0000000000
--- a/test/units/modules/network/f5/fixtures/load_sys_log_config_publisher_1.json
+++ /dev/null
@@ -1,32 +0,0 @@
-{
- "kind": "tm:sys:log-config:publisher:publisherstate",
- "name": "foo",
- "partition": "Common",
- "fullPath": "/Common/foo",
- "generation": 5400,
- "selfLink": "https://localhost/mgmt/tm/sys/log-config/publisher/~Common~foo?ver=13.1.0.4",
- "description": "my description",
- "destinations": [
- {
- "name": "SECURITYLOGSERVERS-LOGGING",
- "partition": "Common",
- "nameReference": {
- "link": "https://localhost/mgmt/tm/sys/log-config/destination/remote-high-speed-log/~Common~SECURITYLOGSERVERS-LOGGING?ver=13.1.0.4"
- }
- },
- {
- "name": "local-db",
- "partition": "Common",
- "nameReference": {
- "link": "https://localhost/mgmt/tm/sys/log-config/destination/local-database/~Common~local-db?ver=13.1.0.4"
- }
- },
- {
- "name": "local-syslog",
- "partition": "Common",
- "nameReference": {
- "link": "https://localhost/mgmt/tm/sys/log-config/destination/local-syslog/~Common~local-syslog?ver=13.1.0.4"
- }
- }
- ]
-}
diff --git a/test/units/modules/network/f5/fixtures/load_sys_management_route_1.json b/test/units/modules/network/f5/fixtures/load_sys_management_route_1.json
deleted file mode 100644
index da3f5fcd16..0000000000
--- a/test/units/modules/network/f5/fixtures/load_sys_management_route_1.json
+++ /dev/null
@@ -1,12 +0,0 @@
-{
- "kind": "tm:sys:management-route:management-routestate",
- "name": "default",
- "partition": "Common",
- "fullPath": "/Common/default",
- "generation": 1,
- "selfLink": "https://localhost/mgmt/tm/sys/management-route/~Common~default?ver=13.1.0.4",
- "description": "configured-by-dhcp",
- "gateway": "10.0.2.2",
- "mtu": 0,
- "network": "default"
-}
diff --git a/test/units/modules/network/f5/fixtures/load_sys_provision_default.json b/test/units/modules/network/f5/fixtures/load_sys_provision_default.json
deleted file mode 100644
index 7be868a3ee..0000000000
--- a/test/units/modules/network/f5/fixtures/load_sys_provision_default.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- "level": "dedicated",
- "memory": "medium",
- "module": "urldb"
-} \ No newline at end of file
diff --git a/test/units/modules/network/f5/fixtures/load_sys_smtp_server.json b/test/units/modules/network/f5/fixtures/load_sys_smtp_server.json
deleted file mode 100644
index 9ed191eab7..0000000000
--- a/test/units/modules/network/f5/fixtures/load_sys_smtp_server.json
+++ /dev/null
@@ -1,16 +0,0 @@
-{
- "kind": "tm:sys:smtp-server:smtp-serverstate",
- "name": "foo",
- "partition": "Common",
- "fullPath": "/Common/foo",
- "generation": 54,
- "selfLink": "https://localhost/mgmt/tm/sys/smtp-server/~Common~foo?ver=13.0.0",
- "authenticationEnabled": true,
- "encryptedConnection": "ssl",
- "fromAddress": "no-reply@foo.bar",
- "localHostName": "mail-host.foo.bar",
- "passwordEncrypted": "$M$Ch$this-is-encrypted==",
- "smtpServerHostName": "mail.foo.bar",
- "smtpServerPort": 465,
- "username": "admin"
-}
diff --git a/test/units/modules/network/f5/fixtures/load_sys_snmp_communities_1.json b/test/units/modules/network/f5/fixtures/load_sys_snmp_communities_1.json
deleted file mode 100644
index f45c34651f..0000000000
--- a/test/units/modules/network/f5/fixtures/load_sys_snmp_communities_1.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
- "kind": "tm:sys:snmp:communities:communitiesstate",
- "name": "/Common/foo",
- "fullPath": "/Common/foo",
- "generation": 0,
- "selfLink": "https://localhost/mgmt/tm/sys/snmp/communities/~Common~foo?ver=13.0.0",
- "access": "ro",
- "communityName": "foo",
- "ipv6": "disabled"
-}
diff --git a/test/units/modules/network/f5/fixtures/load_sys_snmp_communities_2.json b/test/units/modules/network/f5/fixtures/load_sys_snmp_communities_2.json
deleted file mode 100644
index 32c29325e7..0000000000
--- a/test/units/modules/network/f5/fixtures/load_sys_snmp_communities_2.json
+++ /dev/null
@@ -1,12 +0,0 @@
-{
- "kind": "tm:sys:snmp:communities:communitiesstate",
- "name": "/Common/foo",
- "fullPath": "/Common/foo",
- "generation": 0,
- "selfLink": "https://localhost/mgmt/tm/sys/snmp/communities/~Common~foo?ver=13.0.0",
- "access": "rw",
- "communityName": "foo",
- "ipv6": "disabled",
- "oidSubset": ".1",
- "source": "1.1.1.1"
-}
diff --git a/test/units/modules/network/f5/fixtures/load_sys_snmp_communities_3.json b/test/units/modules/network/f5/fixtures/load_sys_snmp_communities_3.json
deleted file mode 100644
index d9a9ef121f..0000000000
--- a/test/units/modules/network/f5/fixtures/load_sys_snmp_communities_3.json
+++ /dev/null
@@ -1,12 +0,0 @@
-{
- "kind": "tm:sys:snmp:communities:communitiesstate",
- "name": "/Common/foo",
- "fullPath": "/Common/foo",
- "generation": 0,
- "selfLink": "https://localhost/mgmt/tm/sys/snmp/communities/~Common~foo?ver=13.0.0",
- "access": "ro",
- "communityName": "foo",
- "ipv6": "enabled",
- "oidSubset": ".1",
- "source": "2001:0db8:85a3:0000:0000:8a2e:0370:7334"
-}
diff --git a/test/units/modules/network/f5/fixtures/load_sys_snmp_communities_4.json b/test/units/modules/network/f5/fixtures/load_sys_snmp_communities_4.json
deleted file mode 100644
index 38bf487def..0000000000
--- a/test/units/modules/network/f5/fixtures/load_sys_snmp_communities_4.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
- "kind": "tm:sys:snmp:communities:communitiesstate",
- "name": "/Common/foo",
- "fullPath": "/Common/foo",
- "generation": 0,
- "selfLink": "https://localhost/mgmt/tm/sys/snmp/communities/~Common~foo?ver=13.0.0",
- "access": "ro",
- "communityName": "foo",
- "ipv6": "enabled"
-}
diff --git a/test/units/modules/network/f5/fixtures/load_sys_snmp_users_1.json b/test/units/modules/network/f5/fixtures/load_sys_snmp_users_1.json
deleted file mode 100644
index 4b0aac8f2a..0000000000
--- a/test/units/modules/network/f5/fixtures/load_sys_snmp_users_1.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "kind": "tm:sys:snmp:users:usersstate",
- "name": "/Common/foo",
- "fullPath": "/Common/foo",
- "generation": 0,
- "selfLink": "https://localhost/mgmt/tm/sys/snmp/users/~Common~foo?ver=13.0.0",
- "access": "ro",
- "authPasswordEncrypted": "secret",
- "authProtocol": "sha",
- "oidSubset": ".1",
- "privacyPasswordEncrypted": "secret",
- "privacyProtocol": "aes",
- "securityLevel": "auth-privacy",
- "username": "foo"
-}
diff --git a/test/units/modules/network/f5/fixtures/load_sys_software_image_1.json b/test/units/modules/network/f5/fixtures/load_sys_software_image_1.json
deleted file mode 100644
index 32a9afe075..0000000000
--- a/test/units/modules/network/f5/fixtures/load_sys_software_image_1.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "kind": "tm:sys:software:image:imagestate",
- "name": "foo.iso",
- "fullPath": "foo.iso",
- "generation": 113,
- "selfLink": "https://localhost/mgmt/tm/sys/software/image/foo.iso?ver=13.1.0.4",
- "build": "0.0.3",
- "buildDate": "Sat Jun 16 00 03 03 PDT 2018",
- "checksum": "8cdbd094195fab4b2b47ff4285577b70",
- "fileSize": "1948 MB",
- "lastModified": "Thu May 17 16:19:34 2018",
- "product": "BIG-IP",
- "verified": "yes",
- "version": "13.1.0.8"
-}
diff --git a/test/units/modules/network/f5/fixtures/load_sys_software_update.json b/test/units/modules/network/f5/fixtures/load_sys_software_update.json
deleted file mode 100644
index f1617ff2bb..0000000000
--- a/test/units/modules/network/f5/fixtures/load_sys_software_update.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
- "kind": "tm:sys:software:update:updatestate",
- "selfLink": "https://localhost/mgmt/tm/sys/software/update?ver=13.0.0",
- "autoCheck": "enabled",
- "autoPhonehome": "enabled",
- "checkStatus": "none",
- "errors": 0,
- "frequency": "weekly"
-}
diff --git a/test/units/modules/network/f5/fixtures/load_sys_syslog_1.json b/test/units/modules/network/f5/fixtures/load_sys_syslog_1.json
deleted file mode 100644
index 3e4d257637..0000000000
--- a/test/units/modules/network/f5/fixtures/load_sys_syslog_1.json
+++ /dev/null
@@ -1,24 +0,0 @@
-{
- "kind": "tm:sys:syslog:syslogstate",
- "selfLink": "https://localhost/mgmt/tm/sys/syslog?ver=13.1.0.7",
- "authPrivFrom": "notice",
- "authPrivTo": "emerg",
- "clusteredHostSlot": "enabled",
- "clusteredMessageSlot": "disabled",
- "consoleLog": "enabled",
- "cronFrom": "warning",
- "cronTo": "emerg",
- "daemonFrom": "notice",
- "daemonTo": "emerg",
- "isoDate": "disabled",
- "kernFrom": "debug",
- "kernTo": "emerg",
- "local6From": "notice",
- "local6To": "emerg",
- "mailFrom": "notice",
- "mailTo": "emerg",
- "messagesFrom": "notice",
- "messagesTo": "warning",
- "userLogFrom": "notice",
- "userLogTo": "emerg"
-}
diff --git a/test/units/modules/network/f5/fixtures/load_tg_ha_order.json b/test/units/modules/network/f5/fixtures/load_tg_ha_order.json
deleted file mode 100644
index a1ff91c851..0000000000
--- a/test/units/modules/network/f5/fixtures/load_tg_ha_order.json
+++ /dev/null
@@ -1,22 +0,0 @@
-{
- "kind": "tm:cm:traffic-group:traffic-groupstate",
- "name": "traffic-group-2",
- "partition": "Common",
- "fullPath": "/Common/traffic-group-2",
- "generation": 227,
- "selfLink": "https://localhost/mgmt/tm/cm/traffic-group/~Common~traffic-group-2?ver=12.1.4",
- "autoFailbackEnabled": "true",
- "autoFailbackTime": 60,
- "haLoadFactor": 1,
- "isFloating": "true",
- "mac": "none",
- "unitId": 1,
- "haOrder": [
- "/Common/v12-1.ansible.local"
- ],
- "haOrderReference": [
- {
- "link": "https://localhost/mgmt/tm/cm/device/~Common~v12-1.ansible.local?ver=12.1.4"
- }
- ]
-}
diff --git a/test/units/modules/network/f5/fixtures/load_tm_auth_partition.json b/test/units/modules/network/f5/fixtures/load_tm_auth_partition.json
deleted file mode 100644
index 386c30f7e2..0000000000
--- a/test/units/modules/network/f5/fixtures/load_tm_auth_partition.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
- "kind": "tm:auth:partition:partitionstate",
- "name": "foo",
- "fullPath": "foo",
- "generation": 212,
- "selfLink": "https://localhost/mgmt/tm/auth/partition/foo?ver=13.0.0",
- "defaultRouteDomain": 0,
- "description": "my description"
-}
diff --git a/test/units/modules/network/f5/fixtures/load_tm_auth_password_policy_1.json b/test/units/modules/network/f5/fixtures/load_tm_auth_password_policy_1.json
deleted file mode 100644
index 7d5aac7b61..0000000000
--- a/test/units/modules/network/f5/fixtures/load_tm_auth_password_policy_1.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "kind": "tm:auth:password-policy:password-policystate",
- "selfLink": "https://localhost/mgmt/tm/auth/password-policy?ver=13.1.0.7",
- "expirationWarning": 7,
- "maxDuration": 99999,
- "maxLoginFailures": 0,
- "minDuration": 0,
- "minimumLength": 6,
- "passwordMemory": 0,
- "policyEnforcement": "disabled",
- "requiredLowercase": 0,
- "requiredNumeric": 0,
- "requiredSpecial": 0,
- "requiredUppercase": 0
-}
diff --git a/test/units/modules/network/f5/fixtures/load_tm_auth_tacacs_1.json b/test/units/modules/network/f5/fixtures/load_tm_auth_tacacs_1.json
deleted file mode 100644
index 246226055c..0000000000
--- a/test/units/modules/network/f5/fixtures/load_tm_auth_tacacs_1.json
+++ /dev/null
@@ -1,19 +0,0 @@
-{
- "kind": "tm:auth:tacacs:tacacsstate",
- "name": "system-auth",
- "partition": "Common",
- "fullPath": "/Common/system-auth",
- "generation": 484,
- "selfLink": "https://localhost/mgmt/tm/auth/tacacs/~Common~system-auth?ver=13.1.0.1",
- "accounting": "send-to-first-server",
- "authentication": "use-first-server",
- "debug": "disabled",
- "encryption": "enabled",
- "protocol": "ftp",
- "secret": "secret",
- "servers": [
- "11.11.11.11"
- ],
- "service": "ppp",
- "timeout": 10
-}
diff --git a/test/units/modules/network/f5/fixtures/load_tm_cli_alias_1.json b/test/units/modules/network/f5/fixtures/load_tm_cli_alias_1.json
deleted file mode 100644
index bb9b0e9016..0000000000
--- a/test/units/modules/network/f5/fixtures/load_tm_cli_alias_1.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
- "kind": "tm:cli:alias:shared:sharedstate",
- "name": "bash",
- "partition": "Common",
- "fullPath": "/Common/bash",
- "generation": 1,
- "selfLink": "https://localhost/mgmt/tm/cli/alias/shared/~Common~bash?ver=13.1.0.7",
- "tmCommand": "run /util bash",
- "description": "Run the bash shell"
-}
diff --git a/test/units/modules/network/f5/fixtures/load_tm_cli_script_1.json b/test/units/modules/network/f5/fixtures/load_tm_cli_script_1.json
deleted file mode 100644
index dd1beb55ef..0000000000
--- a/test/units/modules/network/f5/fixtures/load_tm_cli_script_1.json
+++ /dev/null
@@ -1,13 +0,0 @@
-{
- "kind": "tm:cli:script:scriptstate",
- "name": "foo",
- "partition": "Common",
- "fullPath": "/Common/foo",
- "generation": 62,
- "selfLink": "https://localhost/mgmt/tm/cli/script/~Common~foo?ver=12.1.3",
- "apiAnonymous": "proc script::run {} {}\n",
- "ignoreVerification": "false",
- "scriptChecksum": "2a7a57176f8d6ef585ea3cd0db787718",
- "totalSigningStatus": "checksum",
- "verificationStatus": "checksum-verified"
-}
diff --git a/test/units/modules/network/f5/fixtures/load_tm_cm_device.json b/test/units/modules/network/f5/fixtures/load_tm_cm_device.json
deleted file mode 100644
index c99890d313..0000000000
--- a/test/units/modules/network/f5/fixtures/load_tm_cm_device.json
+++ /dev/null
@@ -1,76 +0,0 @@
-{
- "kind": "tm:cm:device:devicestate",
- "name": "bigip1",
- "partition": "Common",
- "fullPath": "/Common/bigip1",
- "generation": 65,
- "selfLink": "https://localhost/mgmt/tm/cm/device/~Common~bigip1?ver=12.1.2",
- "activeModules": [
- "APM, Max, VE (2500 CCU, 10000 Access Sessions)|P961057-1761515|Anti-Virus Checks|Base Endpoint Security Checks|Firewall Checks|Machine Certificate Checks|Network Access|Protected Workspace|Secure Virtual Keyboard|APM, Web Application|App Tunnel|Remote Desktop",
- "LTM, 10 Gbps, VE|T487107-2453693|IPV6 Gateway|Rate Shaping|Ram Cache|External Interface and Network HSM, VE|SSL, Forward Proxy, VE|DENY-VER-GBB|Application Acceleration Manager, Core|PEM, Quota Management, VE|BIG-IP, iAppsLX (Node.js)|Max Compression, VE|BIG-IP VE, Multicast Routing|Recycle, BIG-IP, VE|APM, Limited|LTM to Best Bundle Upgrade, 10Gbps|BIG-IP, iRulesLX (Node.js)|SSL, VE|Anti-Virus Checks|Base Endpoint Security Checks|Firewall Checks|Machine Certificate Checks|Network Access|Protected Workspace|Secure Virtual Keyboard|APM, Web Application|App Tunnel|Remote Desktop|SDN Services, VE|Acceleration Manager, VE|AFM, VE|APM, Base, VE GBB (500 CCU)|ASM, VE|DNS-GTM, Base, 10Gbps|DNS Licensed Objects, Unlimited|GTM Licensed Objects, Unlimited|GTM Rate, 250K|DNS Rate Fallback, 250K|DNS Rate Limit, 250K QPS|GTM Rate Fallback, 250K|CGN, BIG-IP VE, AFM ONLY|PSM, VE|Routing Bundle, VE|DNSSEC",
- "PEM, VE|X895364-1851682"
- ],
- "baseMac": "08:00:27:27:74:82",
- "build": "0.0.249",
- "cert": "/Common/dtdi.crt",
- "certReference": {
- "link": "https://localhost/mgmt/tm/cm/cert/~Common~dtdi.crt?ver=12.1.2"
- },
- "chassisId": "2d37dfa6-c0e8-4e4a-ae983c67356d",
- "chassisType": "individual",
- "configsyncIp": "10.2.2.2",
- "edition": "Final",
- "failoverState": "active",
- "haCapacity": 0,
- "hostname": "bigip1",
- "key": "/Common/dtdi.key",
- "keyReference": {
- "link": "https://localhost/mgmt/tm/cm/key/~Common~dtdi.key?ver=12.1.2"
- },
- "managementIp": "10.0.2.15",
- "marketingName": "BIG-IP Virtual Edition",
- "mirrorIp": "10.2.2.2",
- "mirrorSecondaryIp": "10.2.3.2",
- "multicastInterface": "eth0",
- "multicastIp": "224.0.0.245",
- "multicastPort": 62960,
- "optionalModules": [
- "APM, Base, VE (50 CCU / 200 Access Sessions)",
- "App Mode (TMSH Only, No Root/Bash)",
- "Concurrent Users",
- "Concurrent Users and Access Sessions, VE",
- "IPI Subscription, 1Yr, VE",
- "IPI Subscription, 1Yr, VE-10G",
- "IPI Subscription, 3Yr, VE-10G",
- "LTM to Better Bundle Upgrade, 10Gbps",
- "PEM URL Filtering, 1Yr, HIGH PERF",
- "PEM URL Filtering, 3Yr, HIGH PERF",
- "Routing Bundle",
- "SWG Subscription, 1Yr, VE",
- "URL Filtering Subscription, 1Yr, VE"
- ],
- "platformId": "Z100",
- "product": "BIG-IP",
- "selfDevice": "true",
- "timeLimitedModules": [
- "IPI Subscription, 3Yr, VE|E430735-0717882|20170429|20170511|SUBSCRIPTION",
- "SWG Subscription, 3Yr, VE|W797718-6984294|20170429|20170511|SUBSCRIPTION",
- "URL Filtering Subscription, 3Yr, VE|G132953-9613041|20170429|20170511|SUBSCRIPTION"
- ],
- "timeZone": "America/Los_Angeles",
- "version": "12.1.2",
- "unicastAddress": [
- {
- "effectiveIp": "management-ip",
- "effectivePort": 1026,
- "ip": "management-ip",
- "port": 1026
- },
- {
- "effectiveIp": "10.2.2.2",
- "effectivePort": 1026,
- "ip": "10.2.2.2",
- "port": 1026
- }
- ]
-}
diff --git a/test/units/modules/network/f5/fixtures/load_tm_cm_device_default.json b/test/units/modules/network/f5/fixtures/load_tm_cm_device_default.json
deleted file mode 100644
index 13d77f75db..0000000000
--- a/test/units/modules/network/f5/fixtures/load_tm_cm_device_default.json
+++ /dev/null
@@ -1,61 +0,0 @@
-{
- "kind": "tm:cm:device:devicestate",
- "name": "bigip1",
- "partition": "Common",
- "fullPath": "/Common/bigip1",
- "generation": 1,
- "selfLink": "https://localhost/mgmt/tm/cm/device/~Common~bigip1?ver=12.1.2",
- "activeModules": [
- "APM, Max, VE (2500 CCU, 10000 Access Sessions)|P961057-1761515|Anti-Virus Checks|Base Endpoint Security Checks|Firewall Checks|Machine Certificate Checks|Network Access|Protected Workspace|Secure Virtual Keyboard|APM, Web Application|App Tunnel|Remote Desktop",
- "LTM, 10 Gbps, VE|T487107-2453693|IPV6 Gateway|Rate Shaping|Ram Cache|External Interface and Network HSM, VE|SSL, Forward Proxy, VE|DENY-VER-GBB|Application Acceleration Manager, Core|PEM, Quota Management, VE|BIG-IP, iAppsLX (Node.js)|Max Compression, VE|BIG-IP VE, Multicast Routing|Recycle, BIG-IP, VE|APM, Limited|LTM to Best Bundle Upgrade, 10Gbps|BIG-IP, iRulesLX (Node.js)|SSL, VE|Anti-Virus Checks|Base Endpoint Security Checks|Firewall Checks|Machine Certificate Checks|Network Access|Protected Workspace|Secure Virtual Keyboard|APM, Web Application|App Tunnel|Remote Desktop|SDN Services, VE|Acceleration Manager, VE|AFM, VE|APM, Base, VE GBB (500 CCU)|ASM, VE|DNS-GTM, Base, 10Gbps|DNS Licensed Objects, Unlimited|GTM Licensed Objects, Unlimited|GTM Rate, 250K|DNS Rate Fallback, 250K|DNS Rate Limit, 250K QPS|GTM Rate Fallback, 250K|CGN, BIG-IP VE, AFM ONLY|PSM, VE|Routing Bundle, VE|DNSSEC",
- "PEM, VE|X895364-1851682"
- ],
- "baseMac": "08:00:27:27:74:82",
- "build": "0.0.249",
- "cert": "/Common/dtdi.crt",
- "certReference": {
- "link": "https://localhost/mgmt/tm/cm/cert/~Common~dtdi.crt?ver=12.1.2"
- },
- "chassisId": "42d93eba-35bb-4f01-4663fb03951a",
- "chassisType": "individual",
- "configsyncIp": "none",
- "edition": "Final",
- "failoverState": "active",
- "haCapacity": 0,
- "hostname": "bigip1",
- "key": "/Common/dtdi.key",
- "keyReference": {
- "link": "https://localhost/mgmt/tm/cm/key/~Common~dtdi.key?ver=12.1.2"
- },
- "managementIp": "10.0.2.15",
- "marketingName": "BIG-IP Virtual Edition",
- "mirrorIp": "any6",
- "mirrorSecondaryIp": "any6",
- "multicastIp": "any6",
- "multicastPort": 0,
- "optionalModules": [
- "APM, Base, VE (50 CCU / 200 Access Sessions)",
- "App Mode (TMSH Only, No Root/Bash)",
- "Concurrent Users",
- "Concurrent Users and Access Sessions, VE",
- "IPI Subscription, 1Yr, VE",
- "IPI Subscription, 1Yr, VE-10G",
- "IPI Subscription, 3Yr, VE-10G",
- "LTM to Better Bundle Upgrade, 10Gbps",
- "PEM URL Filtering, 1Yr, HIGH PERF",
- "PEM URL Filtering, 3Yr, HIGH PERF",
- "Routing Bundle",
- "SWG Subscription, 1Yr, VE",
- "URL Filtering Subscription, 1Yr, VE"
- ],
- "platformId": "Z100",
- "product": "BIG-IP",
- "selfDevice": "true",
- "timeLimitedModules": [
- "IPI Subscription, 3Yr, VE|E430735-0717882|20170502|20170511|SUBSCRIPTION",
- "SWG Subscription, 3Yr, VE|W797718-6984294|20170502|20170511|SUBSCRIPTION",
- "URL Filtering Subscription, 3Yr, VE|G132953-9613041|20170502|20170511|SUBSCRIPTION"
- ],
- "timeZone": "America/Los_Angeles",
- "version": "12.1.2"
-}
diff --git a/test/units/modules/network/f5/fixtures/load_tm_cm_device_group.json b/test/units/modules/network/f5/fixtures/load_tm_cm_device_group.json
deleted file mode 100644
index 6660234155..0000000000
--- a/test/units/modules/network/f5/fixtures/load_tm_cm_device_group.json
+++ /dev/null
@@ -1,19 +0,0 @@
-{
- "kind": "tm:cm:device-group:device-groupstate",
- "name": "device_trust_group",
- "partition": "Common",
- "fullPath": "/Common/device_trust_group",
- "generation": 1,
- "selfLink": "https://localhost/mgmt/tm/cm/device-group/~Common~device_trust_group?ver=13.0.0",
- "asmSync": "disabled",
- "autoSync": "enabled",
- "fullLoadOnSync": "false",
- "incrementalConfigSyncSizeMax": 1024,
- "networkFailover": "disabled",
- "saveOnAutoSync": "false",
- "type": "sync-only",
- "devicesReference": {
- "link": "https://localhost/mgmt/tm/cm/device-group/~Common~device_trust_group/devices?ver=13.0.0",
- "isSubcollection": true
- }
-}
diff --git a/test/units/modules/network/f5/fixtures/load_tm_cm_traffic_group_1.json b/test/units/modules/network/f5/fixtures/load_tm_cm_traffic_group_1.json
deleted file mode 100644
index dbbb190725..0000000000
--- a/test/units/modules/network/f5/fixtures/load_tm_cm_traffic_group_1.json
+++ /dev/null
@@ -1,16 +0,0 @@
-{
- "kind": "tm:cm:traffic-group:traffic-groupstate",
- "name": "traffic-group-1",
- "partition": "Common",
- "fullPath": "/Common/traffic-group-1",
- "generation": 1,
- "selfLink": "https://localhost/mgmt/tm/cm/traffic-group/~Common~traffic-group-1?ver=13.0.0",
- "autoFailbackEnabled": "false",
- "autoFailbackTime": 60,
- "failoverMethod": "ha-order",
- "haLoadFactor": 1,
- "isFloating": "true",
- "mac": "none",
- "monitor": {},
- "unitId": 1
-}
diff --git a/test/units/modules/network/f5/fixtures/load_tm_cm_traffic_group_2.json b/test/units/modules/network/f5/fixtures/load_tm_cm_traffic_group_2.json
deleted file mode 100644
index 3b93cdae9a..0000000000
--- a/test/units/modules/network/f5/fixtures/load_tm_cm_traffic_group_2.json
+++ /dev/null
@@ -1,16 +0,0 @@
-{
- "kind": "tm:cm:traffic-group:traffic-groupstate",
- "name": "asd",
- "partition": "Common",
- "fullPath": "/Common/asd",
- "generation": 176,
- "selfLink": "https://localhost/mgmt/tm/cm/traffic-group/~Common~asd?ver=13.0.0",
- "autoFailbackEnabled": "false",
- "autoFailbackTime": 60,
- "failoverMethod": "ha-order",
- "haLoadFactor": 1,
- "isFloating": "true",
- "mac": "00:00:00:00:00:02",
- "monitor": {},
- "unitId": 2
-}
diff --git a/test/units/modules/network/f5/fixtures/load_tm_net_self.json b/test/units/modules/network/f5/fixtures/load_tm_net_self.json
deleted file mode 100644
index 9bf4f23458..0000000000
--- a/test/units/modules/network/f5/fixtures/load_tm_net_self.json
+++ /dev/null
@@ -1,26 +0,0 @@
-{
- "kind": "tm:net:self:selfstate",
- "name": "net1",
- "partition": "Common",
- "fullPath": "/Common/net1",
- "generation": 7,
- "selfLink": "https://localhost/mgmt/tm/net/self/~Common~net1?ver=13.0.0",
- "address": "10.10.10.10%1/24",
- "addressSource": "from-user",
- "floating": "disabled",
- "inheritedTrafficGroup": "false",
- "trafficGroup": "/Common/traffic-group-local-only",
- "trafficGroupReference": {
- "link": "https://localhost/mgmt/tm/cm/traffic-group/~Common~traffic-group-local-only?ver=13.0.0"
- },
- "unit": 0,
- "vlan": "/Common/net1",
- "vlanReference": {
- "link": "https://localhost/mgmt/tm/net/vlan/~Common~net1?ver=13.0.0"
- },
- "allowService": [
- "tcp:80",
- "udp:53",
- "gre:0"
- ]
-}
diff --git a/test/units/modules/network/f5/fixtures/load_tm_net_trunk_1.json b/test/units/modules/network/f5/fixtures/load_tm_net_trunk_1.json
deleted file mode 100644
index af312d49f9..0000000000
--- a/test/units/modules/network/f5/fixtures/load_tm_net_trunk_1.json
+++ /dev/null
@@ -1,29 +0,0 @@
-{
- "kind": "tm:net:trunk:trunkstate",
- "name": "foo",
- "fullPath": "foo",
- "generation": 79,
- "selfLink": "https://localhost/mgmt/tm/net/trunk/foo?ver=13.1.0.4",
- "bandwidth": 10000,
- "cfgMbrCount": 1,
- "distributionHash": "dst-mac",
- "id": 0,
- "lacp": "disabled",
- "lacpMode": "active",
- "lacpTimeout": "long",
- "linkSelectPolicy": "maximum-bandwidth",
- "macAddress": "08:00:27:ea:18:52",
- "media": "10000",
- "qinqEthertype": "0x8100",
- "stp": "enabled",
- "type": "normal",
- "workingMbrCount": 1,
- "interfaces": [
- "1.3"
- ],
- "interfacesReference": [
- {
- "link": "https://localhost/mgmt/tm/net/interface/1.3?ver=13.1.0.4"
- }
- ]
-}
diff --git a/test/units/modules/network/f5/fixtures/load_tm_sys_syslog_1.json b/test/units/modules/network/f5/fixtures/load_tm_sys_syslog_1.json
deleted file mode 100644
index 47d7628207..0000000000
--- a/test/units/modules/network/f5/fixtures/load_tm_sys_syslog_1.json
+++ /dev/null
@@ -1,38 +0,0 @@
-{
- "kind": "tm:sys:syslog:syslogstate",
- "selfLink": "https://localhost/mgmt/tm/sys/syslog?ver=13.0.0",
- "authPrivFrom": "notice",
- "authPrivTo": "emerg",
- "clusteredHostSlot": "enabled",
- "clusteredMessageSlot": "disabled",
- "consoleLog": "enabled",
- "cronFrom": "warning",
- "cronTo": "emerg",
- "daemonFrom": "notice",
- "daemonTo": "emerg",
- "isoDate": "disabled",
- "kernFrom": "debug",
- "kernTo": "emerg",
- "local6From": "notice",
- "local6To": "emerg",
- "mailFrom": "notice",
- "mailTo": "emerg",
- "messagesFrom": "notice",
- "messagesTo": "warning",
- "userLogFrom": "notice",
- "userLogTo": "emerg",
- "remoteServers": [
- {
- "name": "/Common/remotesyslog1",
- "host": "10.10.10.10",
- "localIp": "none",
- "remotePort": 514
- },
- {
- "name": "/Common/remotesyslog2",
- "host": "20.20.20.20",
- "localIp": "1.1.1.1",
- "remotePort": 8000
- }
- ]
-}
diff --git a/test/units/modules/network/f5/fixtures/load_tm_sys_syslog_2.json b/test/units/modules/network/f5/fixtures/load_tm_sys_syslog_2.json
deleted file mode 100644
index d1eb8929d5..0000000000
--- a/test/units/modules/network/f5/fixtures/load_tm_sys_syslog_2.json
+++ /dev/null
@@ -1,38 +0,0 @@
-{
- "kind": "tm:sys:syslog:syslogstate",
- "selfLink": "https://localhost/mgmt/tm/sys/syslog?ver=13.0.0",
- "authPrivFrom": "notice",
- "authPrivTo": "emerg",
- "clusteredHostSlot": "enabled",
- "clusteredMessageSlot": "disabled",
- "consoleLog": "enabled",
- "cronFrom": "warning",
- "cronTo": "emerg",
- "daemonFrom": "notice",
- "daemonTo": "emerg",
- "isoDate": "disabled",
- "kernFrom": "debug",
- "kernTo": "emerg",
- "local6From": "notice",
- "local6To": "emerg",
- "mailFrom": "notice",
- "mailTo": "emerg",
- "messagesFrom": "notice",
- "messagesTo": "warning",
- "userLogFrom": "notice",
- "userLogTo": "emerg",
- "remoteServers": [
- {
- "name": "/Common/remotesyslog1",
- "host": "10.10.10.10",
- "localIp": "none",
- "remotePort": 514
- },
- {
- "name": "/Common/remotesyslog2",
- "host": "10.10.10.10",
- "localIp": "1.1.1.1",
- "remotePort": 8000
- }
- ]
-}
diff --git a/test/units/modules/network/f5/fixtures/load_tmm_log.json b/test/units/modules/network/f5/fixtures/load_tmm_log.json
deleted file mode 100644
index 5d634183b2..0000000000
--- a/test/units/modules/network/f5/fixtures/load_tmm_log.json
+++ /dev/null
@@ -1,14 +0,0 @@
-{
- "kind": "tm:sys:daemon-log-settings:tmm:tmmstate",
- "selfLink": "https://localhost/mgmt/tm/sys/daemon-log-settings/tmm?ver=12.1.3.6",
- "arpLogLevel": "warning",
- "httpCompressionLogLevel": "error",
- "httpLogLevel": "error",
- "ipLogLevel": "warning",
- "iruleLogLevel": "informational",
- "layer4LogLevel": "notice",
- "netLogLevel": "warning",
- "osLogLevel": "notice",
- "pvaLogLevel": "informational",
- "sslLogLevel": "warning"
-}
diff --git a/test/units/modules/network/f5/fixtures/load_vlan.json b/test/units/modules/network/f5/fixtures/load_vlan.json
deleted file mode 100644
index 85d7fbb228..0000000000
--- a/test/units/modules/network/f5/fixtures/load_vlan.json
+++ /dev/null
@@ -1,30 +0,0 @@
-{
- "kind": "tm:net:vlan:vlanstate",
- "name": "somevlan",
- "partition": "Common",
- "fullPath": "/Common/somevlan",
- "generation": 1,
- "selfLink": "https://localhost/mgmt/tm/net/vlan/~Common~somevlan?ver=12.1.0",
- "autoLasthop": "default",
- "cmpHash": "default",
- "dagRoundRobin": "disabled",
- "dagTunnel": "outer",
- "failsafe": "disabled",
- "failsafeAction": "failover-restart-tm",
- "failsafeTimeout": 90,
- "ifIndex": 480,
- "learning": "enable-forward",
- "mtu": 1500,
- "sflow": {
- "pollInterval": 0,
- "pollIntervalGlobal": "yes",
- "samplingRate": 0,
- "samplingRateGlobal": "yes"
- },
- "sourceChecking": "disabled",
- "tag": 4094,
- "interfacesReference": {
- "link": "https://localhost/mgmt/tm/net/vlan/~Common~somevlan/interfaces?ver=12.1.0",
- "isSubcollection": true
- }
-} \ No newline at end of file
diff --git a/test/units/modules/network/f5/fixtures/load_vlan_interfaces.json b/test/units/modules/network/f5/fixtures/load_vlan_interfaces.json
deleted file mode 100644
index 9fa16f76b2..0000000000
--- a/test/units/modules/network/f5/fixtures/load_vlan_interfaces.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "kind": "tm:net:vlan:interfaces:interfacescollectionstate",
- "selfLink": "https://localhost/mgmt/tm/net/vlan/~Common~vlan1/interfaces?ver=13.0.0",
- "items": [
- {
- "kind": "tm:net:vlan:interfaces:interfacesstate",
- "name": "1.2",
- "fullPath": "1.2",
- "generation": 105,
- "selfLink": "https://localhost/mgmt/tm/net/vlan/~Common~vlan1/interfaces/1.2?ver=13.0.0",
- "tagMode": "none",
- "tagged": true
- }
- ]
-}
diff --git a/test/units/modules/network/f5/fixtures/load_vlan_tagged_ifcs.json b/test/units/modules/network/f5/fixtures/load_vlan_tagged_ifcs.json
deleted file mode 100644
index 96b3150f78..0000000000
--- a/test/units/modules/network/f5/fixtures/load_vlan_tagged_ifcs.json
+++ /dev/null
@@ -1,12 +0,0 @@
-[
- {
- "kind": "tm:net:vlan:interfaces:interfacesstate",
- "name": "1.2",
- "fullPath": "1.2",
- "generation": 2,
- "selfLink": "https://localhost/mgmt/tm/net/vlan/~Common~internal/interfaces/1.2?ver=12.1.0",
- "tagMode": "none",
- "tagged": true
- }
-
- ] \ No newline at end of file
diff --git a/test/units/modules/network/f5/fixtures/load_vlan_untag_ifcs.json b/test/units/modules/network/f5/fixtures/load_vlan_untag_ifcs.json
deleted file mode 100644
index ebc530e74a..0000000000
--- a/test/units/modules/network/f5/fixtures/load_vlan_untag_ifcs.json
+++ /dev/null
@@ -1,11 +0,0 @@
-[
- {
- "kind": "tm:net:vlan:interfaces:interfacesstate",
- "name": "1.1",
- "fullPath": "1.1",
- "generation": 1,
- "selfLink": "https://localhost/mgmt/tm/net/vlan/~Common~internal/interfaces/1.1?ver=12.1.0",
- "tagMode": "none",
- "untagged": true
- }
- ] \ No newline at end of file
diff --git a/test/units/modules/network/f5/fixtures/pool_members_subcollection.json b/test/units/modules/network/f5/fixtures/pool_members_subcollection.json
deleted file mode 100644
index 1041f8f62c..0000000000
--- a/test/units/modules/network/f5/fixtures/pool_members_subcollection.json
+++ /dev/null
@@ -1,21 +0,0 @@
-[
- {
- "kind": "tm:ltm:pool:members:membersstate",
- "name": "1.1.1.1:80",
- "partition": "Common",
- "fullPath": "/Common/1.1.1.1:80",
- "generation": 1,
- "selfLink": "https://localhost/mgmt/tm/ltm/pool/~Common~test_pool/members/~Common~1.1.1.1:80?ver=11.5.4",
- "address": "1.1.1.1",
- "connectionLimit": 0,
- "dynamicRatio": 1,
- "inheritProfile": "enabled",
- "logging": "disabled",
- "monitor": "default",
- "priorityGroup": 0,
- "rateLimit": "disabled",
- "ratio": 1,
- "session": "user-disabled",
- "state": "up"
- }
- ]
diff --git a/test/units/modules/network/f5/fixtures/update_iapp_service_parameters_f5_http.json b/test/units/modules/network/f5/fixtures/update_iapp_service_parameters_f5_http.json
deleted file mode 100644
index cbb389364d..0000000000
--- a/test/units/modules/network/f5/fixtures/update_iapp_service_parameters_f5_http.json
+++ /dev/null
@@ -1,195 +0,0 @@
-{
- "name": "http_example",
- "partition": "Common",
- "template": "/Common/f5.http",
- "lists": [
- {
- "name": "irules__irules",
- "encrypted": "no",
- "value": [
- "/Common/lgyft"
- ]
- },
- {
- "name": "net__client_vlan",
- "encrypted": "no",
- "value": [
- "/Common/net2"
- ]
- }
- ],
- "tables": [
- {
- "columnNames": [
- "name"
- ],
- "name": "pool__hosts",
- "rows": [
- {
- "row": [
- "demo.example.com"
- ]
- }
- ]
- },
- {
- "columnNames": [
- "addr",
- "connection_limit"
- ],
- "name": "pool__members",
- "rows": [
- {
- "row": [
- "20.1.1.1",
- "0"
- ]
- },
- {
- "row": [
- "10.1.1.2",
- "0"
- ]
- }
- ]
- }
- ],
- "variables": [
- {
- "name": "afm__policy",
- "value": "/#do_not_use#"
- },
- {
- "name": "afm__dos_security_profile",
- "value": "/#do_not_use#"
- },
- {
- "name": "afm__protocol_security_profile",
- "value": "/#do_not_use#"
- },
- {
- "name": "asm__use_asm",
- "value": "/#do_not_use#"
- },
- {
- "name": "client__http_compression",
- "value": "/#do_not_use#"
- },
- {
- "name": "client__standard_caching_without_wa",
- "value": "/#do_not_use#"
- },
- {
- "name": "client__tcp_wan_opt",
- "value": "/#create_new#"
- },
- {
- "name": "monitor__monitor",
- "value": "/#create_new#"
- },
- {
- "name": "monitor__frequency",
- "value": "30"
- },
- {
- "name": "monitor__uri",
- "value": "/my/path"
- },
- {
- "name": "monitor__response",
- "value": ""
- },
- {
- "name": "net__client_mode",
- "value": "wan"
- },
- {
- "name": "net__server_mode",
- "value": "lan"
- },
- {
- "name": "net__vlan_mode",
- "value": "all"
- },
- {
- "name": "pool__addr",
- "value": "10.10.10.10"
- },
- {
- "name": "pool__http",
- "value": "/#create_new#"
- },
- {
- "name": "pool__mask",
- "value": ""
- },
- {
- "name": "pool__persist",
- "value": "/#cookie#"
- },
- {
- "name": "pool__lb_method",
- "value": "least-connections-member"
- },
- {
- "name": "pool__pool_to_use",
- "value": "/#create_new#"
- },
- {
- "name": "pool__port_secure",
- "value": "443"
- },
- {
- "name": "pool__redirect_port",
- "value": "80"
- },
- {
- "name": "pool__redirect_to_https",
- "value": "yes"
- },
- {
- "name": "pool__xff",
- "value": "yes"
- },
- {
- "name": "server__oneconnect",
- "value": "/#create_new#"
- },
- {
- "name": "server__tcp_lan_opt",
- "value": "/#create_new#"
- },
- {
- "name": "ssl__cert",
- "value": "/Common/default.crt"
- },
- {
- "name": "ssl__client_ssl_profile",
- "value": "/#create_new#"
- },
- {
- "name": "ssl__key",
- "value": "/Common/default.key"
- },
- {
- "name": "ssl__mode",
- "value": "client_ssl"
- },
- {
- "name": "ssl__use_chain_cert",
- "value": "/#do_not_use#"
- },
- {
- "name": "ssl_encryption_questions__advanced",
- "value": "yes"
- },
- {
- "name": "stats__analytics",
- "value": "/#do_not_use#"
- },
- {
- "name": "stats__request_logging",
- "value": "/#do_not_use#"
- }
- ]
-}
diff --git a/test/units/modules/network/f5/fixtures/update_vlan_description.json b/test/units/modules/network/f5/fixtures/update_vlan_description.json
deleted file mode 100644
index 99bf483343..0000000000
--- a/test/units/modules/network/f5/fixtures/update_vlan_description.json
+++ /dev/null
@@ -1,31 +0,0 @@
-{
- "kind": "tm:net:vlan:vlanstate",
- "name": "somevlan",
- "partition": "Common",
- "fullPath": "/Common/somevlan",
- "description": "changed_this",
- "generation": 1,
- "selfLink": "https://localhost/mgmt/tm/net/vlan/~Common~somevlan?ver=12.1.0",
- "autoLasthop": "default",
- "cmpHash": "default",
- "dagRoundRobin": "disabled",
- "dagTunnel": "outer",
- "failsafe": "disabled",
- "failsafeAction": "failover-restart-tm",
- "failsafeTimeout": 90,
- "ifIndex": 480,
- "learning": "enable-forward",
- "mtu": 1500,
- "sflow": {
- "pollInterval": 0,
- "pollIntervalGlobal": "yes",
- "samplingRate": 0,
- "samplingRateGlobal": "yes"
- },
- "sourceChecking": "disabled",
- "tag": 4094,
- "interfacesReference": {
- "link": "https://localhost/mgmt/tm/net/vlan/~Common~somevlan/interfaces?ver=12.1.0",
- "isSubcollection": true
- }
-} \ No newline at end of file
diff --git a/test/units/modules/network/f5/test_bigip_apm_acl.py b/test/units/modules/network/f5/test_bigip_apm_acl.py
deleted file mode 100644
index 157438c258..0000000000
--- a/test/units/modules/network/f5/test_bigip_apm_acl.py
+++ /dev/null
@@ -1,243 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2019, F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_apm_acl import ApiParameters
- from library.modules.bigip_apm_acl import ModuleParameters
- from library.modules.bigip_apm_acl import ModuleManager
- from library.modules.bigip_apm_acl import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_apm_acl import ApiParameters
- from ansible.modules.network.f5.bigip_apm_acl import ModuleParameters
- from ansible.modules.network.f5.bigip_apm_acl import ModuleManager
- from ansible.modules.network.f5.bigip_apm_acl import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- name='foo',
- acl_order=0,
- type='static',
- path_match_case=True,
- description='foobar',
- entries=[
- dict(action='allow',
- dst_port='80',
- dst_addr='192.168.1.1',
- src_port='443',
- src_addr='10.10.10.0',
- src_mask='255.255.255.128',
- protocol='tcp',
- host_name='foobar.com',
- paths='/shopfront',
- scheme='https'
- )
- ]
- )
- p = ModuleParameters(params=args)
- assert p.name == 'foo'
- assert p.acl_order == 0
- assert p.type == 'static'
- assert p.path_match_case == 'true'
- assert p.description == 'foobar'
- assert p.entries[0] == dict(action='allow',
- dstEndPort=80,
- dstStartPort=80,
- dstSubnet='192.168.1.1/32',
- srcEndPort=443,
- srcStartPort=443,
- srcSubnet='10.10.10.0/25',
- protocol=6,
- host='foobar.com',
- paths='/shopfront',
- scheme='https'
- )
-
- def test_api_parameters(self):
- args = load_fixture('load_apm_acl.json')
-
- p = ApiParameters(params=args)
- assert p.name == 'lastone'
- assert p.acl_order == 2
- assert p.type == 'static'
- assert p.path_match_case == 'false'
- assert p.description == 'foobar'
- assert p.entries[0] == dict(action='discard',
- dstEndPort=0,
- dstStartPort=0,
- dstSubnet='0.0.0.0/0',
- srcEndPort=0,
- srcStartPort=0,
- srcSubnet='0.0.0.0/0',
- protocol=1,
- scheme='any',
- log='none'
- )
-
-
-class TestManager(unittest.TestCase):
- def setUp(self):
- self.spec = ArgumentSpec()
-
- def test_create_L4_L7_ACL(self, *args):
- set_module_args(dict(
- name='foo',
- acl_order=0,
- type='static',
- path_match_case=True,
- description='my description',
- entries=[
- dict(action='allow',
- dst_port='80',
- dst_addr='192.168.1.1',
- src_port='443',
- src_addr='10.10.10.0',
- src_mask='255.255.255.128',
- protocol='tcp',
- host_name='foobar.com',
- paths='/shopfront',
- scheme='https'
- )
- ],
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- )
-
- # Override methods in the specific type of manager
- mm = ModuleManager(module=module)
- mm.exists = Mock(return_value=False)
- mm.create_on_device = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['acl_order'] == 0
- assert results['description'] == 'my description'
- assert results['type'] == 'static'
- assert results['path_match_case'] == 'yes'
- assert results['entries'] == [
- dict(action='allow',
- dst_port='80',
- dst_addr='192.168.1.1',
- src_port='443',
- src_addr='10.10.10.0',
- src_mask='255.255.255.128',
- protocol='tcp',
- host_name='foobar.com',
- paths='/shopfront',
- scheme='https'
- )]
-
- def test_update_L4_L7_ACL(self, *args):
- set_module_args(dict(
- name='lastone',
- acl_order=0,
- path_match_case='yes',
- entries=[
- dict(action='allow',
- dst_port='80',
- dst_addr='192.168.1.1',
- src_port='443',
- src_addr='10.10.10.0',
- src_mask='255.255.255.128',
- protocol='tcp',
- host_name='foobar.com',
- paths='/shopfront',
- scheme='https'
- )
- ],
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- current = ApiParameters(params=load_fixture('load_apm_acl.json'))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- )
-
- # Override methods in the specific type of manager
- mm = ModuleManager(module=module)
- mm.exists = Mock(return_value=True)
- mm.update_on_device = Mock(return_value=True)
- mm.read_current_from_device = Mock(return_value=current)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['acl_order'] == 0
- assert results['path_match_case'] == 'yes'
- assert results['entries'] == [
- dict(action='allow',
- dst_port='80',
- dst_addr='192.168.1.1',
- src_port='443',
- src_addr='10.10.10.0',
- src_mask='255.255.255.128',
- protocol='tcp',
- host_name='foobar.com',
- paths='/shopfront',
- scheme='https'
- )]
diff --git a/test/units/modules/network/f5/test_bigip_apm_network_access.py b/test/units/modules/network/f5/test_bigip_apm_network_access.py
deleted file mode 100644
index eafd99cbb7..0000000000
--- a/test/units/modules/network/f5/test_bigip_apm_network_access.py
+++ /dev/null
@@ -1,209 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2019, F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_apm_network_access import ApiParameters
- from library.modules.bigip_apm_network_access import ModuleParameters
- from library.modules.bigip_apm_network_access import ModuleManager
- from library.modules.bigip_apm_network_access import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_apm_network_access import ApiParameters
- from ansible.modules.network.f5.bigip_apm_network_access import ModuleParameters
- from ansible.modules.network.f5.bigip_apm_network_access import ModuleManager
- from ansible.modules.network.f5.bigip_apm_network_access import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- name='foo',
- ip_version='ipv4',
- split_tunnel=True,
- description='foobar',
- allow_local_subnet=True,
- allow_local_dns=True,
- snat_pool='foo_pool',
- dtls=True,
- dtls_port=4443,
- ipv4_lease_pool='ipv4lease',
- excluded_ipv4_adresses=[dict(subnet='10.10.10.1')],
- ipv4_address_space=[dict(subnet='192.168.1.0/24')],
- dns_address_space=['foobar.com'],
- excluded_dns_addresses=['bar-foo.org']
- )
-
- p = ModuleParameters(params=args)
- assert p.name == 'foo'
- assert p.ip_version == 'ipv4'
- assert p.split_tunnel == 'true'
- assert p.allow_local_subnet == 'true'
- assert p.allow_local_dns == 'true'
- assert p.snat_pool == '/Common/foo_pool'
- assert p.description == 'foobar'
- assert p.dtls == 'true'
- assert p.dtls_port == 4443
- assert p.ipv4_lease_pool == '/Common/ipv4lease'
- assert p.excluded_ipv4_adresses == [dict(subnet='10.10.10.1/32')]
- assert p.ipv4_address_space == [dict(subnet='192.168.1.0/24')]
- assert p.dns_address_space == ['foobar.com']
- assert p.excluded_dns_addresses == ['bar-foo.org']
-
- def test_api_parameters(self):
- args = load_fixture('load_apm_network_access.json')
-
- p = ApiParameters(params=args)
- assert p.name == 'test'
- assert p.ip_version == 'ipv4-ipv6'
- assert p.split_tunnel == 'true'
- assert p.allow_local_subnet == 'true'
- assert p.allow_local_dns == 'true'
- assert p.snat_pool == 'automap'
- assert p.dtls == 'false'
- assert p.dtls_port == 4433
- assert p.ipv4_lease_pool == '/Common/ipv4lease'
- assert p.excluded_ipv4_adresses == [
- dict(subnet='192.168.1.0/24'),
- dict(subnet='192.168.2.1/32')
- ]
- assert p.ipv4_address_space == [
- dict(subnet='10.10.10.1/32'),
- dict(subnet='10.11.11.0/24')
- ]
- assert p.dns_address_space == ['foo.com', 'bar.com']
- assert p.excluded_dns_addresses == ['baz.com', 'bazfoo.com']
- assert p.ipv6_address_space == [dict(subnet="2607:f0d0:1002:51::4/128")]
-
-
-class TestManager(unittest.TestCase):
- def setUp(self):
- self.spec = ArgumentSpec()
-
- def test_create_ipv4_net_access(self, *args):
- set_module_args(dict(
- name='foo',
- ip_version='ipv4',
- split_tunnel=True,
- description='foobar',
- allow_local_subnet=True,
- allow_local_dns=True,
- snat_pool='foo_pool',
- dtls=True,
- dtls_port=4443,
- ipv4_lease_pool='ipv4lease',
- excluded_ipv4_adresses=[dict(subnet='10.10.10.1')],
- ipv4_address_space=[dict(subnet='192.168.1.0/24')],
- dns_address_space=['foobar.com'],
- excluded_dns_addresses=['bar-foo.org'],
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- )
-
- # Override methods in the specific type of manager
- mm = ModuleManager(module=module)
- mm.exists = Mock(return_value=False)
- mm.create_on_device = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['ip_version'] == 'ipv4'
- assert results['split_tunnel'] == 'yes'
- assert results['allow_local_subnet'] == 'yes'
- assert results['allow_local_dns'] == 'yes'
- assert results['snat_pool'] == '/Common/foo_pool'
- assert results['description'] == 'foobar'
- assert results['dtls'] == 'yes'
- assert results['dtls_port'] == 4443
- assert results['ipv4_lease_pool'] == '/Common/ipv4lease'
- assert results['excluded_ipv4_adresses'] == [dict(subnet='10.10.10.1')]
- assert results['ipv4_address_space'] == [dict(subnet='192.168.1.0/24')]
- assert results['dns_address_space'] == ['foobar.com']
- assert results['excluded_dns_addresses'] == ['bar-foo.org']
-
- def test_update_ipv4_net_access(self, *args):
- set_module_args(dict(
- name='test',
- excluded_ipv4_adresses=[dict(subnet='10.10.10.1')],
- ipv4_address_space=[dict(subnet='192.168.1.0/24')],
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- current = ApiParameters(params=load_fixture('load_apm_network_access.json'))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- )
-
- # Override methods in the specific type of manager
- mm = ModuleManager(module=module)
- mm.exists = Mock(return_value=True)
- mm.update_on_device = Mock(return_value=True)
- mm.read_current_from_device = Mock(return_value=current)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['excluded_ipv4_adresses'] == [dict(subnet='10.10.10.1')]
- assert results['ipv4_address_space'] == [dict(subnet='192.168.1.0/24')]
diff --git a/test/units/modules/network/f5/test_bigip_apm_policy_fetch.py b/test/units/modules/network/f5/test_bigip_apm_policy_fetch.py
deleted file mode 100644
index 070b1e9b2b..0000000000
--- a/test/units/modules/network/f5/test_bigip_apm_policy_fetch.py
+++ /dev/null
@@ -1,128 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2018, F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_apm_policy_fetch import ModuleParameters
- from library.modules.bigip_apm_policy_fetch import ModuleManager
- from library.modules.bigip_apm_policy_fetch import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
- from test.units.compat.mock import patch
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_apm_policy_fetch import ModuleParameters
- from ansible.modules.network.f5.bigip_apm_policy_fetch import ModuleManager
- from ansible.modules.network.f5.bigip_apm_policy_fetch import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
- from units.compat.mock import patch
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- dest='/tmp/',
- force='yes',
- file='foo_export',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- )
- p = ModuleParameters(params=args)
- assert p.file == 'foo_export'
-
-
-class TestManager(unittest.TestCase):
- def setUp(self):
- self.spec = ArgumentSpec()
- self.patcher1 = patch('time.sleep')
- self.patcher1.start()
-
- try:
- self.p1 = patch('library.modules.bigip_apm_policy_fetch.module_provisioned')
- self.m1 = self.p1.start()
- self.m1.return_value = True
- except Exception:
- self.p1 = patch('ansible.modules.network.f5.bigip_apm_policy_fetch.module_provisioned')
- self.m1 = self.p1.start()
- self.m1.return_value = True
-
- def tearDown(self):
- self.patcher1.stop()
- self.p1.stop()
-
- def test_create(self, *args):
- set_module_args(dict(
- name='fake_policy',
- file='foo_export',
- dest='/tmp/',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- )
-
- mp = ModuleParameters(params=module.params)
- mp._item_exists = Mock(return_value=True)
- mm = ModuleManager(module=module)
- mm.version_less_than_14 = Mock(return_value=False)
- mm.want = Mock(return_value=mp)
- mm.exists = Mock(return_value=False)
- mm.create_on_device = Mock(return_value=True)
- mm.execute = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
diff --git a/test/units/modules/network/f5/test_bigip_apm_policy_import.py b/test/units/modules/network/f5/test_bigip_apm_policy_import.py
deleted file mode 100644
index 356a765cd8..0000000000
--- a/test/units/modules/network/f5/test_bigip_apm_policy_import.py
+++ /dev/null
@@ -1,127 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2018, F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_apm_policy_import import ModuleParameters
- from library.modules.bigip_apm_policy_import import ModuleManager
- from library.modules.bigip_apm_policy_import import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
- from test.units.compat.mock import patch
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_apm_policy_import import ModuleParameters
- from ansible.modules.network.f5.bigip_apm_policy_import import ModuleManager
- from ansible.modules.network.f5.bigip_apm_policy_import import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
- from units.compat.mock import patch
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- name='fake_policy',
- type='access_policy',
- source='/var/fake/fake.tar.gz'
- )
-
- p = ModuleParameters(params=args)
- assert p.name == 'fake_policy'
- assert p.source == '/var/fake/fake.tar.gz'
- assert p.type == 'access_policy'
-
-
-class TestManager(unittest.TestCase):
- def setUp(self):
- self.spec = ArgumentSpec()
- self.policy = os.path.join(fixture_path, 'fake_policy.tar.gz')
- self.patcher1 = patch('time.sleep')
- self.patcher1.start()
-
- try:
- self.p1 = patch('library.modules.bigip_apm_policy_import.module_provisioned')
- self.m1 = self.p1.start()
- self.m1.return_value = True
- except Exception:
- self.p1 = patch('ansible.modules.network.f5.bigip_apm_policy_import.module_provisioned')
- self.m1 = self.p1.start()
- self.m1.return_value = True
-
- def tearDown(self):
- self.patcher1.stop()
- self.p1.stop()
-
- def test_import_from_file(self, *args):
- set_module_args(dict(
- name='fake_policy',
- source=self.policy,
- type='access_policy',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- ),
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods to force specific logic in the module to happen
- mm = ModuleManager(module=module)
- mm.version_less_than_14 = Mock(return_value=False)
- mm.exists = Mock(return_value=False)
- mm.import_file_to_device = Mock(return_value=True)
- mm.remove_temp_file_from_device = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['name'] == 'fake_policy'
- assert results['source'] == self.policy
diff --git a/test/units/modules/network/f5/test_bigip_appsvcs_extension.py b/test/units/modules/network/f5/test_bigip_appsvcs_extension.py
deleted file mode 100644
index 4f61a23f15..0000000000
--- a/test/units/modules/network/f5/test_bigip_appsvcs_extension.py
+++ /dev/null
@@ -1,104 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2018, F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_appsvcs_extension import ModuleParameters
- from library.modules.bigip_appsvcs_extension import ModuleManager
- from library.modules.bigip_appsvcs_extension import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_appsvcs_extension import ModuleParameters
- from ansible.modules.network.f5.bigip_appsvcs_extension import ModuleManager
- from ansible.modules.network.f5.bigip_appsvcs_extension import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- content='{ "foo": "bar" }',
- force=True,
- targets=['T1', 'T2']
- )
-
- p = ModuleParameters(params=args)
- assert 'foo' in p.content
- assert p.force is True
- assert p.targets == ['T1', 'T2']
-
-
-class TestManager(unittest.TestCase):
- def setUp(self):
- self.spec = ArgumentSpec()
-
- def test_create(self, *args):
- set_module_args(dict(
- content='{ "foo": "bar" }',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- required_if=self.spec.required_if
- )
- mm = ModuleManager(module=module)
-
- # Override methods to force specific logic in the module to happen
- mm.exists = Mock(return_value=False)
- mm.upsert_on_device = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
diff --git a/test/units/modules/network/f5/test_bigip_asm_dos_application.py b/test/units/modules/network/f5/test_bigip_asm_dos_application.py
deleted file mode 100644
index bd9a99125d..0000000000
--- a/test/units/modules/network/f5/test_bigip_asm_dos_application.py
+++ /dev/null
@@ -1,279 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2019, F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_asm_dos_application import ApiParameters
- from library.modules.bigip_asm_dos_application import ModuleParameters
- from library.modules.bigip_asm_dos_application import ModuleManager
- from library.modules.bigip_asm_dos_application import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
- from test.units.compat.mock import patch
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_asm_dos_application import ApiParameters
- from ansible.modules.network.f5.bigip_asm_dos_application import ModuleParameters
- from ansible.modules.network.f5.bigip_asm_dos_application import ModuleManager
- from ansible.modules.network.f5.bigip_asm_dos_application import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
- from units.compat.mock import patch
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- profile='dos_foo',
- geolocations=dict(
- blacklist=['Argentina', 'Montenegro'],
- whitelist=['France', 'Belgium']
- ),
- heavy_urls=dict(
- auto_detect=True,
- latency_threshold=3000,
- exclude=['/exclude1.html', '/exclude2.html'],
- include=[dict(url='include1.html', threshold='auto'),
- dict(url='include2.html', threshold='2000')],
- ),
- mobile_detection=dict(
- enabled=True,
- allow_android_rooted_device=True,
- allow_any_android_package=True,
- allow_any_ios_package=True,
- allow_jailbroken_devices=True,
- allow_emulators=True,
- client_side_challenge_mode='cshui',
- ios_allowed_package_names=['foo', 'bar'],
- android_publishers=['cert1.crt', 'cert2.crt']
- ),
- rtbh_duration=180,
- rtbh_enable=True,
- scrubbing_duration=360,
- scrubbing_enable=True,
- single_page_application=True,
- trigger_irule=False,
- partition='Common'
- )
-
- p = ModuleParameters(params=args)
- assert p.profile == 'dos_foo'
- assert p.geo_whitelist == ['France', 'Belgium']
- assert p.geo_blacklist == ['Argentina', 'Montenegro']
- assert p.auto_detect == 'enabled'
- assert p.latency_threshold == 3000
- assert p.hw_url_exclude == ['/exclude1.html', '/exclude2.html']
- assert dict(name='URL/include1.html', threshold='auto', url='/include1.html') in p.hw_url_include
- assert dict(name='URL/include2.html', threshold='2000', url='/include2.html') in p.hw_url_include
- assert p.allow_android_rooted_device == 'true'
- assert p.enable_mobile_detection == 'enabled'
- assert p.allow_any_android_package == 'true'
- assert p.allow_any_ios_package == 'true'
- assert p.allow_jailbroken_devices == 'true'
- assert p.allow_emulators == 'true'
- assert p.client_side_challenge_mode == 'cshui'
- assert p.ios_allowed_package_names == ['foo', 'bar']
- assert p.android_publishers == ['/Common/cert1.crt', '/Common/cert2.crt']
- assert p.rtbh_duration == 180
- assert p.rtbh_enable == 'enabled'
- assert p.scrubbing_duration == 360
- assert p.scrubbing_enable == 'enabled'
- assert p.single_page_application == 'enabled'
- assert p.trigger_irule == 'disabled'
-
- def test_api_parameters(self):
- args = load_fixture('load_asm_dos.json')
-
- p = ApiParameters(params=args)
- assert p.geo_whitelist == ['Aland Islands']
- assert p.geo_blacklist == ['Afghanistan']
- assert p.auto_detect == 'enabled'
- assert p.latency_threshold == 1000
- assert p.hw_url_exclude == ['/exclude.html']
- assert dict(name='URL/test.htm', threshold='auto', url='/test.htm') in p.hw_url_include
- assert dict(name='URL/testy.htm', threshold='auto', url='/testy.htm') in p.hw_url_include
- assert p.allow_android_rooted_device == 'false'
- assert p.enable_mobile_detection == 'disabled'
- assert p.allow_any_android_package == 'false'
- assert p.allow_any_ios_package == 'false'
- assert p.allow_jailbroken_devices == 'true'
- assert p.allow_emulators == 'true'
- assert p.client_side_challenge_mode == 'pass'
- assert p.ios_allowed_package_names == ['foobarapp']
- assert p.android_publishers == ['/Common/ca-bundle.crt']
- assert p.rtbh_duration == 300
- assert p.rtbh_enable == 'enabled'
- assert p.scrubbing_duration == 60
- assert p.scrubbing_enable == 'enabled'
- assert p.single_page_application == 'enabled'
- assert p.trigger_irule == 'enabled'
-
-
-class TestManager(unittest.TestCase):
- def setUp(self):
- self.spec = ArgumentSpec()
- try:
- self.p1 = patch('library.modules.bigip_asm_dos_application.module_provisioned')
- self.m1 = self.p1.start()
- self.m1.return_value = True
- except Exception:
- self.p1 = patch('ansible.modules.network.f5.bigip_asm_dos_application.module_provisioned')
- self.m1 = self.p1.start()
- self.m1.return_value = True
-
- def tearDown(self):
- self.p1.stop()
-
- def test_create_asm_dos_profile(self, *args):
- set_module_args(dict(
- profile='dos_foo',
- geolocations=dict(
- blacklist=['Argentina', 'Montenegro'],
- whitelist=['France', 'Belgium']
- ),
- heavy_urls=dict(
- auto_detect=True,
- latency_threshold=3000,
- exclude=['/exclude1.html', '/exclude2.html'],
- include=[dict(url='include1.html', threshold='auto'),
- dict(url='include2.html', threshold='2000')]
- ),
- mobile_detection=dict(
- enabled=True,
- allow_android_rooted_device=True,
- allow_any_android_package=True,
- allow_any_ios_package=True,
- allow_jailbroken_devices=True,
- allow_emulators=True,
- client_side_challenge_mode='cshui',
- ios_allowed_package_names=['foo', 'bar'],
- android_publishers=['cert1.crt', 'cert2.crt']
- ),
- rtbh_duration=180,
- rtbh_enable=True,
- scrubbing_duration=360,
- scrubbing_enable=True,
- single_page_application=True,
- trigger_irule=False,
- partition='Common',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- )
-
- # Override methods in the specific type of manager
- mm = ModuleManager(module=module)
- mm.exists = Mock(return_value=False)
- mm.create_on_device = Mock(return_value=True)
- mm.version_less_than_13_1 = Mock(return_value=False)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['geolocations'] == dict(blacklist=['Argentina', 'Montenegro'], whitelist=['France', 'Belgium'])
- assert results['heavy_urls'] == dict(auto_detect='yes', latency_threshold=3000,
- exclude=['/exclude1.html', '/exclude2.html'],
- include=[dict(url='/include1.html', threshold='auto'),
- dict(url='/include2.html', threshold='2000')]
- )
- assert results['mobile_detection'] == dict(enabled='yes', allow_android_rooted_device='yes',
- allow_any_android_package='yes', allow_any_ios_package='yes',
- allow_jailbroken_devices='yes', allow_emulators='yes',
- client_side_challenge_mode='cshui',
- ios_allowed_package_names=['foo', 'bar'],
- android_publishers=['/Common/cert1.crt', '/Common/cert2.crt']
- )
- assert results['rtbh_duration'] == 180
- assert results['rtbh_enable'] == 'yes'
- assert results['scrubbing_duration'] == 360
- assert results['scrubbing_enable'] == 'yes'
- assert results['single_page_application'] == 'yes'
- assert results['trigger_irule'] == 'no'
-
- def test_update_asm_dos_profile(self, *args):
- set_module_args(dict(
- profile='test',
- heavy_urls=dict(
- latency_threshold=3000,
- exclude=['/exclude1.html', '/exclude2.html'],
- include=[dict(url='include1.html', threshold='auto'),
- dict(url='include2.html', threshold='2000')]
- ),
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- current = ApiParameters(params=load_fixture('load_asm_dos.json'))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- )
-
- # Override methods in the specific type of manager
- mm = ModuleManager(module=module)
- mm.exists = Mock(return_value=True)
- mm.update_on_device = Mock(return_value=True)
- mm.read_current_from_device = Mock(return_value=current)
- mm.version_less_than_13_1 = Mock(return_value=False)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['heavy_urls'] == dict(latency_threshold=3000, exclude=['/exclude1.html', '/exclude2.html'],
- include=[dict(url='/include1.html', threshold='auto'),
- dict(url='/include2.html', threshold='2000')]
- )
diff --git a/test/units/modules/network/f5/test_bigip_asm_policy_fetch.py b/test/units/modules/network/f5/test_bigip_asm_policy_fetch.py
deleted file mode 100644
index 2c40ffcd98..0000000000
--- a/test/units/modules/network/f5/test_bigip_asm_policy_fetch.py
+++ /dev/null
@@ -1,130 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2018, F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_asm_policy_fetch import ModuleParameters
- from library.modules.bigip_asm_policy_fetch import ModuleManager
- from library.modules.bigip_asm_policy_fetch import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
- from test.units.compat.mock import patch
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_asm_policy_fetch import ModuleParameters
- from ansible.modules.network.f5.bigip_asm_policy_fetch import ModuleManager
- from ansible.modules.network.f5.bigip_asm_policy_fetch import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
- from units.compat.mock import patch
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- inline='yes',
- compact='no',
- base64='yes',
- dest='/tmp/foo.xml',
- force='yes',
- file='foo.xml'
- )
- p = ModuleParameters(params=args)
- assert p.inline is True
- assert p.compact is False
- assert p.base64 is True
- assert p.file == 'foo.xml'
-
-
-class TestManager(unittest.TestCase):
- def setUp(self):
- self.spec = ArgumentSpec()
- self.patcher1 = patch('time.sleep')
- self.patcher1.start()
-
- try:
- self.p1 = patch('library.modules.bigip_asm_policy_fetch.module_provisioned')
- self.m1 = self.p1.start()
- self.m1.return_value = True
- except Exception:
- self.p1 = patch('ansible.modules.network.f5.bigip_asm_policy_fetch.module_provisioned')
- self.m1 = self.p1.start()
- self.m1.return_value = True
-
- def tearDown(self):
- self.patcher1.stop()
- self.p1.stop()
-
- def test_create(self, *args):
- set_module_args(dict(
- name='fake_policy',
- file='foobar.xml',
- dest='/tmp/foobar.xml',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- mutually_exclusive=self.spec.mutually_exclusive,
- )
-
- mp = ModuleParameters(params=module.params)
- mp._policy_exists = Mock(return_value=True)
- mm = ModuleManager(module=module)
- mm.want = Mock(return_value=mp)
- mm.want.binary = False
- mm.exists = Mock(return_value=False)
- mm.create_on_device = Mock(return_value=True)
- mm.execute = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
diff --git a/test/units/modules/network/f5/test_bigip_asm_policy_import.py b/test/units/modules/network/f5/test_bigip_asm_policy_import.py
deleted file mode 100644
index 5de1dcf110..0000000000
--- a/test/units/modules/network/f5/test_bigip_asm_policy_import.py
+++ /dev/null
@@ -1,125 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2018, F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_asm_policy_import import ModuleParameters
- from library.modules.bigip_asm_policy_import import ModuleManager
- from library.modules.bigip_asm_policy_import import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
- from test.units.compat.mock import patch
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_asm_policy_import import ModuleParameters
- from ansible.modules.network.f5.bigip_asm_policy_import import ModuleManager
- from ansible.modules.network.f5.bigip_asm_policy_import import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
- from units.compat.mock import patch
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- name='fake_policy',
- state='present',
- source='/var/fake/fake.xml'
- )
-
- p = ModuleParameters(params=args)
- assert p.name == 'fake_policy'
- assert p.source == '/var/fake/fake.xml'
-
-
-class TestManager(unittest.TestCase):
- def setUp(self):
- self.spec = ArgumentSpec()
- self.policy = os.path.join(fixture_path, 'fake_policy.xml')
- self.patcher1 = patch('time.sleep')
- self.patcher1.start()
-
- try:
- self.p1 = patch('library.modules.bigip_asm_policy_import.module_provisioned')
- self.m1 = self.p1.start()
- self.m1.return_value = True
- except Exception:
- self.p1 = patch('ansible.modules.network.f5.bigip_asm_policy_import.module_provisioned')
- self.m1 = self.p1.start()
- self.m1.return_value = True
-
- def tearDown(self):
- self.patcher1.stop()
- self.p1.stop()
-
- def test_import_from_file(self, *args):
- set_module_args(dict(
- name='fake_policy',
- source=self.policy,
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- mutually_exclusive=self.spec.mutually_exclusive,
- )
-
- # Override methods to force specific logic in the module to happen
- mm = ModuleManager(module=module)
- mm.exists = Mock(return_value=False)
- mm.import_file_to_device = Mock(return_value=True)
- mm.remove_temp_policy_from_device = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['name'] == 'fake_policy'
- assert results['source'] == self.policy
diff --git a/test/units/modules/network/f5/test_bigip_asm_policy_manage.py b/test/units/modules/network/f5/test_bigip_asm_policy_manage.py
deleted file mode 100644
index 6379b6600d..0000000000
--- a/test/units/modules/network/f5/test_bigip_asm_policy_manage.py
+++ /dev/null
@@ -1,519 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2018, F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_asm_policy_manage import V1Parameters
- from library.modules.bigip_asm_policy_manage import ModuleManager
- from library.modules.bigip_asm_policy_manage import V1Manager
- from library.modules.bigip_asm_policy_manage import ArgumentSpec
-
- from library.module_utils.network.f5.common import F5ModuleError
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
- from test.units.compat.mock import patch
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_asm_policy_manage import V1Parameters
- from ansible.modules.network.f5.bigip_asm_policy_manage import ModuleManager
- from ansible.modules.network.f5.bigip_asm_policy_manage import V1Manager
- from ansible.modules.network.f5.bigip_asm_policy_manage import ArgumentSpec
-
- from ansible.module_utils.network.f5.common import F5ModuleError
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
- from units.compat.mock import patch
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters_template(self):
- args = dict(
- name='fake_policy',
- state='present',
- template='LotusDomino 6.5 (http)'
- )
-
- p = V1Parameters(params=args)
- assert p.name == 'fake_policy'
- assert p.state == 'present'
- assert p.template == 'POLICY_TEMPLATE_LOTUSDOMINO_6_5_HTTP'
-
-
-class TestManager(unittest.TestCase):
- def setUp(self):
- self.spec = ArgumentSpec()
- self.policy = os.path.join(fixture_path, 'fake_policy.xml')
- self.patcher1 = patch('time.sleep')
- self.patcher1.start()
-
- try:
- self.p1 = patch('library.modules.bigip_asm_policy_manage.module_provisioned')
- self.m1 = self.p1.start()
- self.m1.return_value = True
- except Exception:
- self.p1 = patch('ansible.modules.network.f5.bigip_asm_policy_manage.module_provisioned')
- self.m1 = self.p1.start()
- self.m1.return_value = True
-
- def tearDown(self):
- self.patcher1.stop()
- self.p1.stop()
-
- def test_activate_create_from_template(self, *args):
- set_module_args(dict(
- name='fake_policy',
- template='OWA Exchange 2007 (https)',
- state='present',
- active='yes',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- current = V1Parameters(params=load_fixture('load_asm_policy_inactive.json'))
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- v1 = V1Manager(module=module)
- v1.exists = Mock(return_value=False)
- v1.import_to_device = Mock(return_value=True)
- v1.wait_for_task = Mock(side_effect=[True, True])
- v1.read_current_from_device = Mock(return_value=current)
- v1.apply_on_device = Mock(return_value=True)
- v1.create_from_template_on_device = Mock(return_value=True)
- v1._file_is_missing = Mock(return_value=False)
-
- # Override methods to force specific logic in the module to happen
- mm = ModuleManager(module=module)
- mm.version_is_less_than_13 = Mock(return_value=False)
- mm.get_manager = Mock(return_value=v1)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['name'] == 'fake_policy'
- assert results['template'] == 'OWA Exchange 2007 (https)'
- assert results['active'] is True
-
- def test_activate_create_by_name(self, *args):
- set_module_args(dict(
- name='fake_policy',
- state='present',
- active='yes',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- current = V1Parameters(params=load_fixture('load_asm_policy_inactive.json'))
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- v1 = V1Manager(module=module)
- v1.exists = Mock(return_value=False)
- v1.import_to_device = Mock(return_value=True)
- v1.wait_for_task = Mock(side_effect=[True, True])
- v1.create_on_device = Mock(return_value=True)
- v1.create_blank = Mock(return_value=True)
- v1.read_current_from_device = Mock(return_value=current)
- v1.apply_on_device = Mock(return_value=True)
- v1._file_is_missing = Mock(return_value=False)
-
- # Override methods to force specific logic in the module to happen
- mm = ModuleManager(module=module)
- mm.version_is_less_than_13 = Mock(return_value=False)
- mm.get_manager = Mock(return_value=v1)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['name'] == 'fake_policy'
- assert results['active'] is True
-
- def test_activate_policy_exists_inactive(self, *args):
- set_module_args(dict(
- name='fake_policy',
- state='present',
- active='yes',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- current = V1Parameters(params=load_fixture('load_asm_policy_inactive.json'))
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- v1 = V1Manager(module=module)
- v1.exists = Mock(return_value=True)
- v1.update_on_device = Mock(return_value=True)
- v1.wait_for_task = Mock(side_effect=[True, True])
- v1.read_current_from_device = Mock(return_value=current)
- v1.apply_on_device = Mock(return_value=True)
-
- # Override methods to force specific logic in the module to happen
- mm = ModuleManager(module=module)
- mm.version_is_less_than_13 = Mock(return_value=False)
- mm.get_manager = Mock(return_value=v1)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['active'] is True
-
- def test_activate_policy_exists_active(self, *args):
- set_module_args(dict(
- name='fake_policy',
- state='present',
- active='yes',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- current = V1Parameters(params=load_fixture('load_asm_policy_active.json'))
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods to force specific logic in the module to happen
- v1 = V1Manager(module=module)
- v1.exists = Mock(return_value=True)
- v1.read_current_from_device = Mock(return_value=current)
-
- # Override methods to force specific logic in the module to happen
- mm = ModuleManager(module=module)
- mm.version_is_less_than_13 = Mock(return_value=False)
- mm.get_manager = Mock(return_value=v1)
-
- results = mm.exec_module()
-
- assert results['changed'] is False
-
- def test_deactivate_policy_exists_active(self, *args):
- set_module_args(dict(
- name='fake_policy',
- state='present',
- active='no',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- current = V1Parameters(params=load_fixture('load_asm_policy_active.json'))
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods to force specific logic in the module to happen
- v1 = V1Manager(module=module)
- v1.exists = Mock(return_value=True)
- v1.read_current_from_device = Mock(return_value=current)
- v1.update_on_device = Mock(return_value=True)
-
- # Override methods to force specific logic in the module to happen
- mm = ModuleManager(module=module)
- mm.version_is_less_than_13 = Mock(return_value=False)
- mm.get_manager = Mock(return_value=v1)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['active'] is False
-
- def test_deactivate_policy_exists_inactive(self, *args):
- set_module_args(dict(
- name='fake_policy',
- state='present',
- active='no',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- current = V1Parameters(params=load_fixture('load_asm_policy_inactive.json'))
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods to force specific logic in the module to happen
- v1 = V1Manager(module=module)
- v1.exists = Mock(return_value=True)
- v1.read_current_from_device = Mock(return_value=current)
-
- # Override methods to force specific logic in the module to happen
- mm = ModuleManager(module=module)
- mm.version_is_less_than_13 = Mock(return_value=False)
- mm.get_manager = Mock(return_value=v1)
-
- results = mm.exec_module()
-
- assert results['changed'] is False
-
- def test_create_from_template(self, *args):
- set_module_args(dict(
- name='fake_policy',
- template='LotusDomino 6.5 (http)',
- state='present',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- current = V1Parameters(params=load_fixture('load_asm_policy_inactive.json'))
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods to force specific logic in the module to happen
- v1 = V1Manager(module=module)
- v1.exists = Mock(return_value=False)
- v1.create_from_template_on_device = Mock(return_value=True)
- v1.wait_for_task = Mock(side_effect=[True, True])
- v1.read_current_from_device = Mock(return_value=current)
- v1._file_is_missing = Mock(return_value=False)
-
- # Override methods to force specific logic in the module to happen
- mm = ModuleManager(module=module)
- mm.version_is_less_than_13 = Mock(return_value=False)
- mm.get_manager = Mock(return_value=v1)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['name'] == 'fake_policy'
- assert results['template'] == 'LotusDomino 6.5 (http)'
- assert results['active'] is False
-
- def test_create_by_name(self, *args):
- set_module_args(dict(
- name='fake_policy',
- state='present',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- current = V1Parameters(params=load_fixture('load_asm_policy_inactive.json'))
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- v1 = V1Manager(module=module)
- v1.exists = Mock(return_value=False)
- v1.import_to_device = Mock(return_value=True)
- v1.wait_for_task = Mock(side_effect=[True, True])
- v1.create_on_device = Mock(return_value=True)
- v1.create_blank = Mock(return_value=True)
- v1.read_current_from_device = Mock(return_value=current)
- v1.apply_on_device = Mock(return_value=True)
- v1._file_is_missing = Mock(return_value=False)
-
- # Override methods to force specific logic in the module to happen
- mm = ModuleManager(module=module)
- mm.version_is_less_than_13 = Mock(return_value=False)
- mm.get_manager = Mock(return_value=v1)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['name'] == 'fake_policy'
- assert results['active'] is False
-
- def test_delete_policy(self, *args):
- set_module_args(dict(
- name='fake_policy',
- state='absent',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods to force specific logic in the module to happen
- v1 = V1Manager(module=module)
- v1.exists = Mock(side_effect=[True, False])
- v1.remove_from_device = Mock(return_value=True)
-
- # Override methods to force specific logic in the module to happen
- mm = ModuleManager(module=module)
- mm.version_is_less_than_13 = Mock(return_value=False)
- mm.get_manager = Mock(return_value=v1)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
-
- def test_activate_policy_raises(self, *args):
- set_module_args(dict(
- name='fake_policy',
- state='present',
- active='yes',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- current = V1Parameters(params=load_fixture('load_asm_policy_inactive.json'))
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- msg = 'Apply policy task failed.'
- # Override methods to force specific logic in the module to happen
- v1 = V1Manager(module=module)
- v1.exists = Mock(return_value=True)
- v1.wait_for_task = Mock(return_value=False)
- v1.update_on_device = Mock(return_value=True)
- v1.read_current_from_device = Mock(return_value=current)
- v1.apply_on_device = Mock(return_value=True)
-
- # Override methods to force specific logic in the module to happen
- mm = ModuleManager(module=module)
- mm.version_is_less_than_13 = Mock(return_value=False)
- mm.get_manager = Mock(return_value=v1)
-
- with pytest.raises(F5ModuleError) as err:
- mm.exec_module()
- assert str(err.value) == msg
-
- def test_create_policy_raises(self, *args):
- set_module_args(dict(
- name='fake_policy',
- state='present',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- msg = 'Failed to create ASM policy: fake_policy'
- # Override methods to force specific logic in the module to happen
- v1 = V1Manager(module=module)
- v1.exists = Mock(return_value=False)
- v1.create_on_device = Mock(return_value=False)
- v1._file_is_missing = Mock(return_value=False)
-
- # Override methods to force specific logic in the module to happen
- mm = ModuleManager(module=module)
- mm.version_is_less_than_13 = Mock(return_value=False)
- mm.get_manager = Mock(return_value=v1)
-
- with pytest.raises(F5ModuleError) as err:
- mm.exec_module()
- assert str(err.value) == msg
-
- def test_delete_policy_raises(self, *args):
- set_module_args(dict(
- name='fake_policy',
- state='absent',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
- msg = 'Failed to delete ASM policy: fake_policy'
- # Override methods to force specific logic in the module to happen
- v1 = V1Manager(module=module)
- v1.exists = Mock(side_effect=[True, True])
- v1.remove_from_device = Mock(return_value=True)
-
- # Override methods to force specific logic in the module to happen
- mm = ModuleManager(module=module)
- mm.version_is_less_than_13 = Mock(return_value=False)
- mm.get_manager = Mock(return_value=v1)
-
- with pytest.raises(F5ModuleError) as err:
- mm.exec_module()
- assert str(err.value) == msg
diff --git a/test/units/modules/network/f5/test_bigip_asm_policy_server_technology.py b/test/units/modules/network/f5/test_bigip_asm_policy_server_technology.py
deleted file mode 100644
index 60c0530821..0000000000
--- a/test/units/modules/network/f5/test_bigip_asm_policy_server_technology.py
+++ /dev/null
@@ -1,122 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2018, F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_asm_policy_server_technology import ModuleParameters
- from library.modules.bigip_asm_policy_server_technology import ModuleManager
- from library.modules.bigip_asm_policy_server_technology import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
- from test.units.compat.mock import patch
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_asm_policy_server_technology import ModuleParameters
- from ansible.modules.network.f5.bigip_asm_policy_server_technology import ModuleManager
- from ansible.modules.network.f5.bigip_asm_policy_server_technology import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
- from units.compat.mock import patch
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- name='ASP',
- state='present',
- policy_name='fake_policy'
- )
-
- p = ModuleParameters(params=args)
- assert p.name == 'ASP'
- assert p.state == 'present'
- assert p.policy_name == 'fake_policy'
-
-
-class TestManager(unittest.TestCase):
- def setUp(self):
- self.spec = ArgumentSpec()
-
- try:
- self.p1 = patch('library.modules.bigip_asm_policy_server_technology.module_provisioned')
- self.m1 = self.p1.start()
- self.m1.return_value = True
- except Exception:
- self.p1 = patch('ansible.modules.network.f5.bigip_asm_policy_server_technology.module_provisioned')
- self.m1 = self.p1.start()
- self.m1.return_value = True
-
- def tearDown(self):
- self.p1.stop()
-
- def test_add_server_technology(self, *args):
- set_module_args(dict(
- policy_name='fake_policy',
- state='present',
- name='IIS',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- ),
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods to force specific logic in the module to happen
- mm = ModuleManager(module=module)
- mm.version_is_less_than_13 = Mock(return_value=False)
- mm.exists = Mock(return_value=False)
- mm.create_on_device = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['name'] == 'IIS'
- assert results['policy_name'] == 'fake_policy'
diff --git a/test/units/modules/network/f5/test_bigip_asm_policy_signature_set.py b/test/units/modules/network/f5/test_bigip_asm_policy_signature_set.py
deleted file mode 100644
index 7c23a5c17f..0000000000
--- a/test/units/modules/network/f5/test_bigip_asm_policy_signature_set.py
+++ /dev/null
@@ -1,151 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2018, F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_asm_policy_signature_set import ModuleParameters
- from library.modules.bigip_asm_policy_signature_set import ModuleManager
- from library.modules.bigip_asm_policy_signature_set import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
- from test.units.compat.mock import patch
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_asm_policy_signature_set import ModuleParameters
- from ansible.modules.network.f5.bigip_asm_policy_signature_set import ModuleManager
- from ansible.modules.network.f5.bigip_asm_policy_signature_set import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
- from units.compat.mock import patch
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- name='IIS and Windows Signatures',
- state='present',
- policy_name='fake_policy',
- alarm='yes',
- block='no',
- learn='yes'
- )
- try:
- self.p1 = patch('library.modules.bigip_asm_policy_signature_set.tmos_version')
- self.m1 = self.p1.start()
- self.m1.return_value = '13.1.0'
- except Exception:
- self.p1 = patch('ansible.modules.network.f5.bigip_asm_policy_signature_set.tmos_version')
- self.m1 = self.p1.start()
- self.m1.return_value = '13.1.0'
-
- p = ModuleParameters(params=args)
-
- assert p.name == 'IIS and Windows Signatures'
- assert p.state == 'present'
- assert p.policy_name == 'fake_policy'
- assert p.alarm is True
- assert p.block is False
- assert p.learn is True
-
- self.p1.stop()
-
-
-class TestManager(unittest.TestCase):
- def setUp(self):
- self.spec = ArgumentSpec()
-
- try:
- self.p1 = patch('library.modules.bigip_asm_policy_signature_set.module_provisioned')
- self.p2 = patch('library.modules.bigip_asm_policy_signature_set.tmos_version')
- self.m1 = self.p1.start()
- self.m2 = self.p2.start()
- self.m2.return_value = '13.1.0'
- self.m1.return_value = True
- except Exception:
- self.p1 = patch('ansible.modules.network.f5.bigip_asm_policy_signature_set.module_provisioned')
- self.p2 = patch('ansible.modules.network.f5.bigip_asm_policy_signature_set.tmos_version')
- self.m1 = self.p1.start()
- self.m2 = self.p2.start()
- self.m2.return_value = '13.1.0'
- self.m1.return_value = True
-
- def tearDown(self):
- self.p1.stop()
- self.p2.stop()
-
- def test_add_server_technology(self, *args):
- set_module_args(dict(
- policy_name='fake_policy',
- state='present',
- name='IIS and Windows Signatures',
- alarm='yes',
- block='no',
- learn='yes',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods to force specific logic in the module to happen
- mm = ModuleManager(module=module)
- mm.exists = Mock(return_value=False)
- mm.create_on_device = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['name'] == 'IIS and Windows Signatures'
- assert results['policy_name'] == 'fake_policy'
- assert results['alarm'] == 'yes'
- assert results['block'] == 'no'
- assert results['learn'] == 'yes'
diff --git a/test/units/modules/network/f5/test_bigip_cli_alias.py b/test/units/modules/network/f5/test_bigip_cli_alias.py
deleted file mode 100644
index 6c980cdb02..0000000000
--- a/test/units/modules/network/f5/test_bigip_cli_alias.py
+++ /dev/null
@@ -1,118 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2018, F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_cli_alias import ApiParameters
- from library.modules.bigip_cli_alias import ModuleParameters
- from library.modules.bigip_cli_alias import ModuleManager
- from library.modules.bigip_cli_alias import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_cli_alias import ApiParameters
- from ansible.modules.network.f5.bigip_cli_alias import ModuleParameters
- from ansible.modules.network.f5.bigip_cli_alias import ModuleManager
- from ansible.modules.network.f5.bigip_cli_alias import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- command='run /util bash',
- description='another description',
- scope='shared',
- )
-
- p = ModuleParameters(params=args)
- assert p.command == 'run /util bash'
- assert p.description == 'another description'
- assert p.scope == 'shared'
-
- def test_api_parameters(self):
- args = load_fixture('load_tm_cli_alias_1.json')
-
- p = ApiParameters(params=args)
- assert p.command == 'run /util bash'
- assert p.description == 'Run the bash shell'
-
-
-class TestManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
-
- def test_create_default_device_group(self, *args):
- set_module_args(
- dict(
- name="foo-group",
- command='run /util bash',
- description='another description',
- scope='shared',
- state="present",
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- )
- )
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
- mm = ModuleManager(module=module)
-
- # Override methods to force specific logic in the module to happen
- mm.create_on_device = Mock(return_value=True)
- mm.exists = Mock(return_value=False)
-
- results = mm.exec_module()
- assert results['changed'] is True
diff --git a/test/units/modules/network/f5/test_bigip_cli_script.py b/test/units/modules/network/f5/test_bigip_cli_script.py
deleted file mode 100644
index 382b0fc61e..0000000000
--- a/test/units/modules/network/f5/test_bigip_cli_script.py
+++ /dev/null
@@ -1,114 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2018, F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_cli_script import ApiParameters
- from library.modules.bigip_cli_script import ModuleParameters
- from library.modules.bigip_cli_script import ModuleManager
- from library.modules.bigip_cli_script import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_cli_script import ApiParameters
- from ansible.modules.network.f5.bigip_cli_script import ModuleParameters
- from ansible.modules.network.f5.bigip_cli_script import ModuleManager
- from ansible.modules.network.f5.bigip_cli_script import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- name='foo',
- content="my content",
- description="my description"
- )
-
- p = ModuleParameters(params=args)
- assert p.name == 'foo'
- assert p.content == 'my content'
- assert p.description == 'my description'
-
- def test_api_parameters(self):
- args = load_fixture('load_tm_cli_script_1.json')
-
- p = ApiParameters(params=args)
- assert p.name == 'foo'
- assert p.content == 'proc script::run {} {}'
-
-
-class TestManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
-
- def test_create(self, *args):
- set_module_args(dict(
- name='foo',
- content='asdasds',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods in the specific type of manager
- mm = ModuleManager(module=module)
- mm.exists = Mock(side_effect=[False, True])
- mm.create_on_device = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
diff --git a/test/units/modules/network/f5/test_bigip_command.py b/test/units/modules/network/f5/test_bigip_command.py
deleted file mode 100644
index 79b763eebc..0000000000
--- a/test/units/modules/network/f5/test_bigip_command.py
+++ /dev/null
@@ -1,299 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright (c) 2017 F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_command import Parameters
- from library.modules.bigip_command import ModuleManager
- from library.modules.bigip_command import V1Manager
- from library.modules.bigip_command import V2Manager
- from library.modules.bigip_command import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
- from test.units.compat.mock import patch
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_command import Parameters
- from ansible.modules.network.f5.bigip_command import ModuleManager
- from ansible.modules.network.f5.bigip_command import V1Manager
- from ansible.modules.network.f5.bigip_command import V2Manager
- from ansible.modules.network.f5.bigip_command import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
- from units.compat.mock import patch
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
- with open(path) as f:
- data = f.read()
- try:
- data = json.loads(data)
- except Exception:
- pass
- return data
-
-
-class TestParameters(unittest.TestCase):
-
- def test_module_parameters(self):
- args = dict(
- commands=[
- "tmsh show sys version"
- ],
- )
- p = Parameters(params=args)
- assert len(p.commands) == 1
-
-
-class TestManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
- self.patcher1 = patch('time.sleep')
- self.patcher1.start()
-
- def tearDown(self):
- self.patcher1.stop()
-
- def test_run_single_command(self, *args):
- set_module_args(dict(
- commands=[
- "tmsh show sys version"
- ],
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- m1 = V2Manager(module=module)
- m1.execute_on_device = Mock(return_value=['resp1', 'resp2'])
-
- mm = ModuleManager(module=module)
- mm._run_commands = Mock(return_value=[])
- mm.get_manager = Mock(return_value=m1)
-
- results = mm.exec_module()
-
- assert results['changed'] is False
- assert mm._run_commands.call_count == 0
- assert m1.execute_on_device.call_count == 2
-
- def test_run_single_modification_command(self, *args):
- set_module_args(dict(
- commands=[
- "tmsh create ltm virtual foo"
- ],
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- m1 = V2Manager(module=module)
- m1.execute_on_device = Mock(return_value=['resp1', 'resp2'])
-
- mm = ModuleManager(module=module)
- mm._run_commands = Mock(return_value=[])
- mm.get_manager = Mock(return_value=m1)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert mm._run_commands.call_count == 0
- assert m1.execute_on_device.call_count == 2
-
- def test_cli_command(self, *args):
- set_module_args(dict(
- commands=[
- "show sys version"
- ],
- provider=dict(
- server='localhost',
- password='password',
- user='admin',
- transport='cli'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- m1 = V1Manager(module=module)
- m1.execute_on_device = Mock(return_value=['resp1', 'resp2', 'resp3'])
-
- mm = ModuleManager(module=module)
- mm._run_commands = Mock(return_value=[])
- mm.get_manager = Mock(return_value=m1)
-
- results = mm.exec_module()
-
- assert results['changed'] is False
-
- # call count is two on CLI transport because we must first
- # determine if the remote CLI is in tmsh mode or advanced shell
- # (bash) mode.
- #
- # 1 call for the shell check
- # 1 call for the command in the "commands" list above
- #
- # Can we change this in the future by making the terminal plugin
- # find this out ahead of time?
- assert m1.execute_on_device.call_count == 3
-
- def test_command_with_commas(self, *args):
- set_module_args(dict(
- commands="""
- tmsh create /auth ldap system-auth {bind-dn uid=binduser,
- cn=users,dc=domain,dc=com bind-pw $ENCRYPTEDPW check-roles-group
- enabled search-base-dn cn=users,dc=domain,dc=com servers add {
- ldap.server.com } }
- """,
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
- m1 = V2Manager(module=module)
- m1.execute_on_device = Mock(return_value=['resp1', 'resp2'])
-
- mm = ModuleManager(module=module)
- mm.get_manager = Mock(return_value=m1)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert m1.execute_on_device.call_count == 2
-
- def test_normalizing_command_show(self, *args):
- args = dict(
- commands=[
- "show sys version"
- ],
- )
-
- result = V2Manager.normalize_commands(args['commands'])
-
- assert result[0] == 'show sys version'
-
- def test_normalizing_command_delete(self, *args):
- args = dict(
- commands=[
- "delete sys version"
- ],
- )
-
- result = V2Manager.normalize_commands(args['commands'])
-
- assert result[0] == 'delete sys version'
-
- def test_normalizing_command_modify(self, *args):
- args = dict(
- commands=[
- "modify sys version"
- ],
- )
-
- result = V2Manager.normalize_commands(args['commands'])
-
- assert result[0] == 'modify sys version'
-
- def test_normalizing_command_list(self, *args):
- args = dict(
- commands=[
- "list sys version"
- ],
- )
-
- result = V2Manager.normalize_commands(args['commands'])
-
- assert result[0] == 'list sys version'
-
- def test_normalizing_command_tmsh_show(self, *args):
- args = dict(
- commands=[
- "tmsh show sys version"
- ],
- )
-
- result = V2Manager.normalize_commands(args['commands'])
-
- assert result[0] == 'show sys version'
-
- def test_normalizing_command_tmsh_delete(self, *args):
- args = dict(
- commands=[
- "tmsh delete sys version"
- ],
- )
-
- result = V2Manager.normalize_commands(args['commands'])
-
- assert result[0] == 'delete sys version'
-
- def test_normalizing_command_tmsh_modify(self, *args):
- args = dict(
- commands=[
- "tmsh modify sys version"
- ],
- )
-
- result = V2Manager.normalize_commands(args['commands'])
-
- assert result[0] == 'modify sys version'
-
- def test_normalizing_command_tmsh_list(self, *args):
- args = dict(
- commands=[
- "tmsh list sys version"
- ],
- )
-
- result = V2Manager.normalize_commands(args['commands'])
-
- assert result[0] == 'list sys version'
diff --git a/test/units/modules/network/f5/test_bigip_config.py b/test/units/modules/network/f5/test_bigip_config.py
deleted file mode 100644
index 9c616c11ab..0000000000
--- a/test/units/modules/network/f5/test_bigip_config.py
+++ /dev/null
@@ -1,112 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright (c) 2017 F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_config import Parameters
- from library.modules.bigip_config import ModuleManager
- from library.modules.bigip_config import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_config import Parameters
- from ansible.modules.network.f5.bigip_config import ModuleManager
- from ansible.modules.network.f5.bigip_config import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- save='yes',
- reset='yes',
- merge_content='asdasd',
- verify='no',
- )
- p = Parameters(params=args)
- assert p.save == 'yes'
- assert p.reset == 'yes'
- assert p.merge_content == 'asdasd'
-
-
-class TestManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
-
- def test_run_single_command(self, *args):
- set_module_args(dict(
- save='yes',
- reset='yes',
- merge_content='asdasd',
- verify='no',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
- mm = ModuleManager(module=module)
-
- # Override methods to force specific logic in the module to happen
- mm.exit_json = Mock(return_value=True)
- mm.reset_device = Mock(return_value='reset output')
- mm.upload_to_device = Mock(return_value=True)
- mm.move_on_device = Mock(return_value=True)
- mm.merge_on_device = Mock(return_value='merge output')
- mm.remove_temporary_file = Mock(return_value=True)
- mm.save_on_device = Mock(return_value='save output')
-
- results = mm.exec_module()
-
- assert results['changed'] is True
diff --git a/test/units/modules/network/f5/test_bigip_configsync_action.py b/test/units/modules/network/f5/test_bigip_configsync_action.py
deleted file mode 100644
index 99a2401745..0000000000
--- a/test/units/modules/network/f5/test_bigip_configsync_action.py
+++ /dev/null
@@ -1,135 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright (c) 2017 F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_configsync_action import Parameters
- from library.modules.bigip_configsync_action import ModuleManager
- from library.modules.bigip_configsync_action import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
- from test.units.compat.mock import patch
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_configsync_action import Parameters
- from ansible.modules.network.f5.bigip_configsync_action import ModuleManager
- from ansible.modules.network.f5.bigip_configsync_action import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
- from units.compat.mock import patch
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- sync_device_to_group=True,
- sync_group_to_device=True,
- overwrite_config=True,
- device_group="foo"
- )
- p = Parameters(params=args)
- assert p.sync_device_to_group is True
- assert p.sync_group_to_device is True
- assert p.overwrite_config is True
- assert p.device_group == 'foo'
-
- def test_module_parameters_yes_no(self):
- args = dict(
- sync_device_to_group='yes',
- sync_group_to_device='no',
- overwrite_config='yes',
- device_group="foo"
- )
- p = Parameters(params=args)
- assert p.sync_device_to_group == 'yes'
- assert p.sync_group_to_device == 'no'
- assert p.overwrite_config == 'yes'
- assert p.device_group == 'foo'
-
-
-class TestManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
- self.patcher1 = patch('time.sleep')
- self.patcher1.start()
-
- def tearDown(self):
- self.patcher1.stop()
-
- def test_update_agent_status_traps(self, *args):
- set_module_args(dict(
- sync_device_to_group='yes',
- device_group="foo",
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- mutually_exclusive=self.spec.mutually_exclusive,
- required_one_of=self.spec.required_one_of
- )
- mm = ModuleManager(module=module)
-
- # Override methods to force specific logic in the module to happen
- mm._device_group_exists = Mock(return_value=True)
- mm._sync_to_group_required = Mock(return_value=False)
- mm.execute_on_device = Mock(return_value=True)
- mm.read_current_from_device = Mock(return_value=None)
-
- mm._get_status_from_resource = Mock()
- mm._get_status_from_resource.side_effect = [
- 'Changes Pending', 'Awaiting Initial Sync', 'In Sync'
- ]
-
- results = mm.exec_module()
-
- assert results['changed'] is True
diff --git a/test/units/modules/network/f5/test_bigip_data_group.py b/test/units/modules/network/f5/test_bigip_data_group.py
deleted file mode 100644
index fda1a71b7f..0000000000
--- a/test/units/modules/network/f5/test_bigip_data_group.py
+++ /dev/null
@@ -1,485 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_data_group import ModuleParameters
- from library.modules.bigip_data_group import ModuleManager
- from library.modules.bigip_data_group import ExternalManager
- from library.modules.bigip_data_group import InternalManager
- from library.modules.bigip_data_group import ArgumentSpec
-
- from library.module_utils.network.f5.common import F5ModuleError
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_data_group import ModuleParameters
- from ansible.modules.network.f5.bigip_data_group import ModuleManager
- from ansible.modules.network.f5.bigip_data_group import ExternalManager
- from ansible.modules.network.f5.bigip_data_group import InternalManager
- from ansible.modules.network.f5.bigip_data_group import ArgumentSpec
-
- from ansible.module_utils.network.f5.common import F5ModuleError
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- name='foo',
- type='address',
- delete_data_group_file=False,
- internal=False,
- records=[
- dict(
- key='10.10.10.10/32',
- value='bar'
- )
- ],
- separator=':=',
- state='present',
- partition='Common'
- )
-
- p = ModuleParameters(params=args)
- assert p.name == 'foo'
- assert p.type == 'ip'
- assert p.delete_data_group_file is False
- assert len(p.records) == 1
- assert 'data' in p.records[0]
- assert 'name' in p.records[0]
- assert p.records[0]['data'] == 'bar'
- assert p.records[0]['name'] == '10.10.10.10/32'
- assert p.separator == ':='
- assert p.state == 'present'
- assert p.partition == 'Common'
-
-
-class TestManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
-
- def test_create_external_datagroup_type_string(self, *args):
- set_module_args(dict(
- name='foo',
- delete_data_group_file=False,
- internal=False,
- records_src="{0}/data-group-string.txt".format(fixture_path),
- separator=':=',
- state='present',
- partition='Common',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- mutually_exclusive=self.spec.mutually_exclusive,
- )
-
- # Override methods in the specific type of manager
- mm1 = ExternalManager(module=module, params=module.params)
- mm1.exists = Mock(side_effect=[False, True])
- mm1.create_on_device = Mock(return_value=True)
-
- # Override methods to force specific logic in the module to happen
- mm0 = ModuleManager(module=module)
- mm0.get_manager = Mock(return_value=mm1)
-
- results = mm0.exec_module()
-
- assert results['changed'] is True
-
- def test_create_external_incorrect_address_data(self, *args):
- set_module_args(dict(
- name='foo',
- delete_data_group_file=False,
- internal=False,
- type='address',
- records_src="{0}/data-group-string.txt".format(fixture_path),
- separator=':=',
- state='present',
- partition='Common',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- mutually_exclusive=self.spec.mutually_exclusive,
- )
-
- # Override methods in the specific type of manager
- mm1 = ExternalManager(module=module, params=module.params)
- mm1.exists = Mock(side_effect=[False, True])
- mm1.create_on_device = Mock(return_value=True)
-
- # Override methods to force specific logic in the module to happen
- mm0 = ModuleManager(module=module)
- mm0.get_manager = Mock(return_value=mm1)
-
- with pytest.raises(F5ModuleError) as ex:
- mm0.exec_module()
-
- assert "When specifying an 'address' type, the value to the left of the separator must be an IP." == str(ex.value)
-
- def test_create_external_incorrect_integer_data(self, *args):
- set_module_args(dict(
- name='foo',
- delete_data_group_file=False,
- internal=False,
- type='integer',
- records_src="{0}/data-group-string.txt".format(fixture_path),
- separator=':=',
- state='present',
- partition='Common',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- mutually_exclusive=self.spec.mutually_exclusive,
- )
-
- # Override methods in the specific type of manager
- mm1 = ExternalManager(module=module, params=module.params)
- mm1.exists = Mock(side_effect=[False, True])
- mm1.create_on_device = Mock(return_value=True)
-
- # Override methods to force specific logic in the module to happen
- mm0 = ModuleManager(module=module)
- mm0.get_manager = Mock(return_value=mm1)
-
- with pytest.raises(F5ModuleError) as ex:
- mm0.exec_module()
-
- assert "When specifying an 'integer' type, the value to the left of the separator must be a number." == str(ex.value)
-
- def test_remove_data_group_keep_file(self, *args):
- set_module_args(dict(
- name='foo',
- delete_data_group_file=False,
- internal=False,
- state='absent',
- partition='Common',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- mutually_exclusive=self.spec.mutually_exclusive,
- )
-
- # Override methods in the specific type of manager
- mm1 = ExternalManager(module=module, params=module.params)
- mm1.exists = Mock(side_effect=[True, False])
- mm1.remove_from_device = Mock(return_value=True)
- mm1.external_file_exists = Mock(return_value=True)
-
- # Override methods to force specific logic in the module to happen
- mm0 = ModuleManager(module=module)
- mm0.get_manager = Mock(return_value=mm1)
-
- results = mm0.exec_module()
-
- assert results['changed'] is True
-
- def test_remove_data_group_remove_file(self, *args):
- set_module_args(dict(
- name='foo',
- delete_data_group_file=True,
- internal=False,
- state='absent',
- partition='Common',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- mutually_exclusive=self.spec.mutually_exclusive,
- )
-
- # Override methods in the specific type of manager
- mm1 = ExternalManager(module=module, params=module.params)
- mm1.exists = Mock(side_effect=[True, False])
- mm1.remove_from_device = Mock(return_value=True)
- mm1.external_file_exists = Mock(return_value=True)
- mm1.remove_data_group_file_from_device = Mock(return_value=True)
-
- # Override methods to force specific logic in the module to happen
- mm0 = ModuleManager(module=module)
- mm0.get_manager = Mock(return_value=mm1)
-
- results = mm0.exec_module()
-
- assert results['changed'] is True
-
- def test_create_internal_datagroup_type_string(self, *args):
- set_module_args(dict(
- name='foo',
- delete_data_group_file=False,
- internal=True,
- records_src="{0}/data-group-string.txt".format(fixture_path),
- separator=':=',
- state='present',
- partition='Common',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- mutually_exclusive=self.spec.mutually_exclusive,
- )
-
- # Override methods in the specific type of manager
- mm1 = InternalManager(module=module, params=module.params)
- mm1.exists = Mock(side_effect=[False, True])
- mm1.create_on_device = Mock(return_value=True)
-
- # Override methods to force specific logic in the module to happen
- mm0 = ModuleManager(module=module)
- mm0.get_manager = Mock(return_value=mm1)
-
- results = mm0.exec_module()
-
- assert results['changed'] is True
-
- def test_create_internal_incorrect_integer_data(self, *args):
- set_module_args(dict(
- name='foo',
- delete_data_group_file=False,
- internal=True,
- type='integer',
- records_src="{0}/data-group-string.txt".format(fixture_path),
- separator=':=',
- state='present',
- partition='Common',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- mutually_exclusive=self.spec.mutually_exclusive,
- )
-
- # Override methods in the specific type of manager
- mm1 = InternalManager(module=module, params=module.params)
- mm1.exists = Mock(side_effect=[False, True])
- mm1.create_on_device = Mock(return_value=True)
-
- # Override methods to force specific logic in the module to happen
- mm0 = ModuleManager(module=module)
- mm0.get_manager = Mock(return_value=mm1)
-
- with pytest.raises(F5ModuleError) as ex:
- mm0.exec_module()
-
- assert "When specifying an 'integer' type, the value to the left of the separator must be a number." == str(ex.value)
-
- def test_create_internal_datagroup_type_integer(self, *args):
- set_module_args(dict(
- name='foo',
- delete_data_group_file=False,
- internal=True,
- type='integer',
- records_src="{0}/data-group-integer.txt".format(fixture_path),
- separator=':=',
- state='present',
- partition='Common',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- mutually_exclusive=self.spec.mutually_exclusive,
- )
-
- # Override methods in the specific type of manager
- mm1 = InternalManager(module=module, params=module.params)
- mm1.exists = Mock(side_effect=[False, True])
- mm1.create_on_device = Mock(return_value=True)
-
- # Override methods to force specific logic in the module to happen
- mm0 = ModuleManager(module=module)
- mm0.get_manager = Mock(return_value=mm1)
-
- results = mm0.exec_module()
-
- assert results['changed'] is True
-
- def test_create_internal_datagroup_type_address(self, *args):
- set_module_args(dict(
- name='foo',
- delete_data_group_file=False,
- internal=True,
- type='address',
- records_src="{0}/data-group-address.txt".format(fixture_path),
- separator=':=',
- state='present',
- partition='Common',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- mutually_exclusive=self.spec.mutually_exclusive,
- )
-
- # Override methods in the specific type of manager
- mm1 = InternalManager(module=module, params=module.params)
- mm1.exists = Mock(side_effect=[False, True])
- mm1.create_on_device = Mock(return_value=True)
-
- # Override methods to force specific logic in the module to happen
- mm0 = ModuleManager(module=module)
- mm0.get_manager = Mock(return_value=mm1)
-
- results = mm0.exec_module()
-
- assert results['changed'] is True
-
- def test_create_internal_datagroup_type_address_list(self, *args):
- set_module_args(dict(
- name='foo',
- delete_data_group_file=False,
- internal=True,
- type='address',
- records=[
- dict(
- key='10.0.0.0/8',
- value='Network1'
- ),
- dict(
- key='172.16.0.0/12',
- value='Network2'
- ),
- dict(
- key='192.168.20.1/16',
- value='Network3'
- ),
- dict(
- key='192.168.20.1',
- value='Host1'
- ),
- dict(
- key='172.16.1.1',
- value='Host2'
- )
- ],
- separator=':=',
- state='present',
- partition='Common',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- mutually_exclusive=self.spec.mutually_exclusive,
- )
-
- # Override methods in the specific type of manager
- mm1 = InternalManager(module=module, params=module.params)
- mm1.exists = Mock(side_effect=[False, True])
- mm1.create_on_device = Mock(return_value=True)
-
- # Override methods to force specific logic in the module to happen
- mm0 = ModuleManager(module=module)
- mm0.get_manager = Mock(return_value=mm1)
-
- results = mm0.exec_module()
-
- assert results['changed'] is True
diff --git a/test/units/modules/network/f5/test_bigip_device_auth.py b/test/units/modules/network/f5/test_bigip_device_auth.py
deleted file mode 100644
index cddce38637..0000000000
--- a/test/units/modules/network/f5/test_bigip_device_auth.py
+++ /dev/null
@@ -1,131 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2018, F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_device_auth import TacacsApiParameters
- from library.modules.bigip_device_auth import TacacsModuleParameters
- from library.modules.bigip_device_auth import TacacsManager
- from library.modules.bigip_device_auth import ModuleManager
- from library.modules.bigip_device_auth import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_device_auth import TacacsApiParameters
- from ansible.modules.network.f5.bigip_device_auth import TacacsModuleParameters
- from ansible.modules.network.f5.bigip_device_auth import TacacsManager
- from ansible.modules.network.f5.bigip_device_auth import ModuleManager
- from ansible.modules.network.f5.bigip_device_auth import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- type="tacacs",
- authentication="use-all-servers",
- protocol_name="ip",
- secret="$XXXXXXXXXXXXXXXXXXXX==",
- servers=['10.10.10.10', '10.10.10.11'],
- service_name="ppp",
- use_for_auth=True,
- update_secret="on_create",
- )
- p = TacacsModuleParameters(params=args)
- assert p.type == 'tacacs'
- assert p.authentication == 'use-all-servers'
-
- def test_api_parameters(self):
- args = load_fixture('load_tm_auth_tacacs_1.json')
- p = TacacsApiParameters(params=args)
- assert p.authentication == 'use-first-server'
- assert p.protocol_name == 'ftp'
- assert p.secret == 'secret'
- assert p.servers == ['11.11.11.11']
- assert p.service_name == 'ppp'
-
-
-class TestManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
-
- def test_create(self, *args):
- set_module_args(dict(
- type="tacacs",
- authentication="use-all-servers",
- protocol_name="ip",
- secret="secret",
- servers=['10.10.10.10', '10.10.10.11'],
- service_name="ppp",
- use_for_auth=True,
- update_secret="on_create",
- state='present',
- provider=dict(
- password='admin',
- server='localhost',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods to force specific logic in the module to happen
- m1 = TacacsManager(module=module)
- m1.exists = Mock(return_value=False)
- m1.create_on_device = Mock(return_value=True)
- m1.update_auth_source_on_device = Mock(return_value=True)
-
- mm = ModuleManager(module=module)
- mm.get_manager = Mock(return_value=m1)
-
- results = mm.exec_module()
- assert results['changed'] is True
diff --git a/test/units/modules/network/f5/test_bigip_device_auth_ldap.py b/test/units/modules/network/f5/test_bigip_device_auth_ldap.py
deleted file mode 100644
index 014a2076fd..0000000000
--- a/test/units/modules/network/f5/test_bigip_device_auth_ldap.py
+++ /dev/null
@@ -1,131 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2018, F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_device_auth_ldap import ApiParameters
- from library.modules.bigip_device_auth_ldap import ModuleManager
- from library.modules.bigip_device_auth_ldap import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_device_auth_ldap import ApiParameters
- from ansible.modules.network.f5.bigip_device_auth_ldap import ModuleManager
- from ansible.modules.network.f5.bigip_device_auth_ldap import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- servers=['10.10.10.10', '10.10.10.11'],
- port=389,
- remote_directory_tree='foo',
- scope='base',
- bind_dn='bar',
- bind_password='secret',
- user_template='alice',
- check_member_attr=False,
- ssl='no',
- ssl_ca_cert='default.crt',
- ssl_client_key='default.key',
- ssl_client_cert='default1.crt',
- ssl_check_peer=True,
- login_ldap_attr='bob',
- fallback_to_local=True,
- update_password='on_create',
- )
- p = ApiParameters(params=args)
- assert p.port == 389
- assert p.servers == ['10.10.10.10', '10.10.10.11']
- assert p.remote_directory_tree == 'foo'
- assert p.scope == 'base'
- assert p.bind_dn == 'bar'
- assert p.bind_password == 'secret'
- assert p.user_template == 'alice'
- assert p.check_member_attr == 'no'
- assert p.ssl == 'no'
- assert p.ssl_ca_cert == '/Common/default.crt'
- assert p.ssl_client_key == '/Common/default.key'
- assert p.ssl_client_cert == '/Common/default1.crt'
- assert p.ssl_check_peer == 'yes'
- assert p.login_ldap_attr == 'bob'
- assert p.fallback_to_local == 'yes'
- assert p.update_password == 'on_create'
-
-
-class TestManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
-
- def test_create(self, *args):
- set_module_args(dict(
- servers=['10.10.10.10', '10.10.10.11'],
- update_password='on_create',
- state='present',
- provider=dict(
- password='admin',
- server='localhost',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods to force specific logic in the module to happen
- mm = ModuleManager(module=module)
- mm.exists = Mock(return_value=False)
- mm.create_on_device = Mock(return_value=True)
- mm.update_auth_source_on_device = Mock(return_value=True)
-
- results = mm.exec_module()
- assert results['changed'] is True
diff --git a/test/units/modules/network/f5/test_bigip_device_certificate.py b/test/units/modules/network/f5/test_bigip_device_certificate.py
deleted file mode 100644
index cb8d87dafc..0000000000
--- a/test/units/modules/network/f5/test_bigip_device_certificate.py
+++ /dev/null
@@ -1,173 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2019, F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_device_certificate import ModuleParameters
- from library.modules.bigip_device_certificate import ModuleManager
- from library.modules.bigip_device_certificate import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_device_certificate import ModuleParameters
- from ansible.modules.network.f5.bigip_device_certificate import ModuleManager
- from ansible.modules.network.f5.bigip_device_certificate import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- key_size=2048,
- cert_name='foo.crt',
- key_name='foo.key',
- days_valid=60,
- issuer=dict(
- country='US',
- state='WA',
- locality='Seattle',
- organization='F5',
- division='IT',
- common_name='foo.bar.local',
- email='admin@foo.bar.local'
- ),
- new_cert='yes'
- )
- p = ModuleParameters(params=args)
- assert p.key_size == 2048
- assert p.cert_name == 'foo.crt'
- assert p.key_name == 'foo.key'
- assert p.days_valid == 60
- assert 'CN=foo.bar.local' in p.issuer
-
-
-class TestManager(unittest.TestCase):
- def setUp(self):
- self.spec = ArgumentSpec()
-
- def test_update_expired_cert(self, *args):
- set_module_args(dict(
- days_valid=60,
- provider=dict(
- server='localhost',
- password='password',
- user='admin',
- transport='cli',
- server_port=22
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- required_if=self.spec.required_if
- )
-
- mm = ModuleManager(module=module)
- mm.expired = Mock(return_value=True)
- mm.update_certificate = Mock(return_value=True)
- mm.restart_daemon = Mock(return_value=True)
- mm.copy_files_to_trusted = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['days_valid'] == 60
-
- def test_create_new_cert(self):
- set_module_args(dict(
- key_size=2048,
- cert_name='foo.crt',
- key_name='foo.key',
- days_valid=60,
- new_cert='yes',
- issuer=dict(
- country='US',
- state='WA',
- locality='Seattle',
- organization='F5',
- division='IT',
- common_name='foo.bar.local',
- email='admin@foo.bar.local'
- ),
- provider=dict(
- server='localhost',
- password='password',
- user='admin',
- transport='cli',
- server_port=22
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- required_if=self.spec.required_if
- )
-
- mm = ModuleManager(module=module)
- mm.expired = Mock(return_value=True)
- mm.generate_cert_key = Mock(return_value=True)
- mm.restart_daemon = Mock(return_value=True)
- mm.configure_new_cert = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['days_valid'] == 60
- assert results['cert_name'] == 'foo.crt'
- assert results['key_name'] == 'foo.key'
- assert results['issuer'] == dict(
- country='US',
- state='WA',
- locality='Seattle',
- organization='F5',
- division='IT',
- common_name='foo.bar.local',
- email='admin@foo.bar.local'
- )
diff --git a/test/units/modules/network/f5/test_bigip_device_connectivity.py b/test/units/modules/network/f5/test_bigip_device_connectivity.py
deleted file mode 100644
index 178f8615f0..0000000000
--- a/test/units/modules/network/f5/test_bigip_device_connectivity.py
+++ /dev/null
@@ -1,388 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright (c) 2017 F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_device_connectivity import ApiParameters
- from library.modules.bigip_device_connectivity import ModuleParameters
- from library.modules.bigip_device_connectivity import ModuleManager
- from library.modules.bigip_device_connectivity import ArgumentSpec
-
- from library.module_utils.network.f5.common import F5ModuleError
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_device_connectivity import ApiParameters
- from ansible.modules.network.f5.bigip_device_connectivity import ModuleParameters
- from ansible.modules.network.f5.bigip_device_connectivity import ModuleManager
- from ansible.modules.network.f5.bigip_device_connectivity import ArgumentSpec
-
- from ansible.module_utils.network.f5.common import F5ModuleError
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- multicast_port='1010',
- multicast_address='10.10.10.10',
- multicast_interface='eth0',
- failover_multicast=True,
- unicast_failover=[
- dict(
- address='20.20.20.20',
- port='1234'
- )
- ],
- mirror_primary_address='1.2.3.4',
- mirror_secondary_address='5.6.7.8',
- config_sync_ip='4.3.2.1',
- state='present',
- )
- p = ModuleParameters(params=args)
- assert p.multicast_port == 1010
- assert p.multicast_address == '10.10.10.10'
- assert p.multicast_interface == 'eth0'
- assert p.failover_multicast is True
- assert p.mirror_primary_address == '1.2.3.4'
- assert p.mirror_secondary_address == '5.6.7.8'
- assert p.config_sync_ip == '4.3.2.1'
- assert len(p.unicast_failover) == 1
- assert 'effectiveIp' in p.unicast_failover[0]
- assert 'effectivePort' in p.unicast_failover[0]
- assert 'port' in p.unicast_failover[0]
- assert 'ip' in p.unicast_failover[0]
- assert p.unicast_failover[0]['effectiveIp'] == '20.20.20.20'
- assert p.unicast_failover[0]['ip'] == '20.20.20.20'
- assert p.unicast_failover[0]['port'] == 1234
- assert p.unicast_failover[0]['effectivePort'] == 1234
-
- def test_api_parameters(self):
- params = load_fixture('load_tm_cm_device.json')
- p = ApiParameters(params=params)
- assert p.multicast_port == 62960
- assert p.multicast_address == '224.0.0.245'
- assert p.multicast_interface == 'eth0'
- assert p.mirror_primary_address == '10.2.2.2'
- assert p.mirror_secondary_address == '10.2.3.2'
- assert p.config_sync_ip == '10.2.2.2'
- assert len(p.unicast_failover) == 2
- assert 'effectiveIp' in p.unicast_failover[0]
- assert 'effectivePort' in p.unicast_failover[0]
- assert 'port' in p.unicast_failover[0]
- assert 'ip' in p.unicast_failover[0]
- assert p.unicast_failover[0]['effectiveIp'] == 'management-ip'
- assert p.unicast_failover[0]['ip'] == 'management-ip'
- assert p.unicast_failover[0]['port'] == 1026
- assert p.unicast_failover[0]['effectivePort'] == 1026
-
-
-class TestManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
-
- def test_update_settings(self, *args):
- set_module_args(dict(
- config_sync_ip="10.1.30.1",
- mirror_primary_address="10.1.30.1",
- unicast_failover=[
- dict(
- address="10.1.30.1"
- )
- ],
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- # Configure the parameters that would be returned by querying the
- # remote device
- current = ApiParameters(params=load_fixture('load_tm_cm_device_default.json'))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- required_together=self.spec.required_together
- )
- mm = ModuleManager(module=module)
-
- # Override methods to force specific logic in the module to happen
- mm.update_on_device = Mock(return_value=True)
- mm.read_current_from_device = Mock(return_value=current)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['config_sync_ip'] == '10.1.30.1'
- assert results['mirror_primary_address'] == '10.1.30.1'
- assert len(results.keys()) == 4
-
- def test_set_primary_mirror_address_none(self, *args):
- set_module_args(dict(
- mirror_primary_address="none",
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- # Configure the parameters that would be returned by querying the
- # remote device
- current = ApiParameters(params=load_fixture('load_tm_cm_device.json'))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- required_together=self.spec.required_together
- )
- mm = ModuleManager(module=module)
-
- # Override methods to force specific logic in the module to happen
- mm.update_on_device = Mock(return_value=True)
- mm.read_current_from_device = Mock(return_value=current)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['mirror_primary_address'] == 'none'
- assert len(results.keys()) == 2
-
- def test_set_secondary_mirror_address_none(self, *args):
- set_module_args(dict(
- mirror_secondary_address="none",
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- # Configure the parameters that would be returned by querying the
- # remote device
- current = ApiParameters(params=load_fixture('load_tm_cm_device.json'))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- required_together=self.spec.required_together
- )
- mm = ModuleManager(module=module)
-
- # Override methods to force specific logic in the module to happen
- mm.update_on_device = Mock(return_value=True)
- mm.read_current_from_device = Mock(return_value=current)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['mirror_secondary_address'] == 'none'
- assert len(results.keys()) == 2
-
- def test_set_multicast_address_none(self, *args):
- set_module_args(dict(
- multicast_address="none",
- multicast_port=62960,
- multicast_interface="eth0",
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- # Configure the parameters that would be returned by querying the
- # remote device
- current = ApiParameters(params=load_fixture('load_tm_cm_device.json'))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- required_together=self.spec.required_together
- )
- mm = ModuleManager(module=module)
-
- # Override methods to force specific logic in the module to happen
- mm.update_on_device = Mock(return_value=True)
- mm.read_current_from_device = Mock(return_value=current)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['multicast_address'] == 'none'
- assert len(results.keys()) == 2
-
- def test_set_multicast_port_negative(self, *args):
- set_module_args(dict(
- multicast_port=-1,
- multicast_address="224.0.0.245",
- multicast_interface="eth0",
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- # Configure the parameters that would be returned by querying the
- # remote device
- current = ApiParameters(params=load_fixture('load_tm_cm_device.json'))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- required_together=self.spec.required_together
- )
- mm = ModuleManager(module=module)
-
- # Override methods to force specific logic in the module to happen
- mm.update_on_device = Mock(return_value=True)
- mm.read_current_from_device = Mock(return_value=current)
-
- with pytest.raises(F5ModuleError) as ex:
- mm.exec_module()
-
- assert 'must be between' in str(ex.value)
-
- def test_set_multicast_address(self, *args):
- set_module_args(dict(
- multicast_address="10.1.1.1",
- multicast_port=62960,
- multicast_interface="eth0",
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- # Configure the parameters that would be returned by querying the
- # remote device
- current = ApiParameters(params=load_fixture('load_tm_cm_device.json'))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- required_together=self.spec.required_together
- )
- mm = ModuleManager(module=module)
-
- # Override methods to force specific logic in the module to happen
- mm.update_on_device = Mock(return_value=True)
- mm.read_current_from_device = Mock(return_value=current)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['multicast_address'] == '10.1.1.1'
- assert len(results.keys()) == 2
-
- def test_unset_unicast_failover(self, *args):
- set_module_args(dict(
- unicast_failover="none",
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- # Configure the parameters that would be returned by querying the
- # remote device
- current = ApiParameters(params=load_fixture('load_tm_cm_device.json'))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- required_together=self.spec.required_together
- )
- mm = ModuleManager(module=module)
-
- # Override methods to force specific logic in the module to happen
- mm.update_on_device = Mock(return_value=True)
- mm.read_current_from_device = Mock(return_value=current)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['unicast_failover'] == 'none'
- assert len(results.keys()) == 2
-
- def test_unset_config_sync_ip(self, *args):
- set_module_args(dict(
- config_sync_ip="none",
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- # Configure the parameters that would be returned by querying the
- # remote device
- current = ApiParameters(params=load_fixture('load_tm_cm_device.json'))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- required_together=self.spec.required_together
- )
- mm = ModuleManager(module=module)
-
- # Override methods to force specific logic in the module to happen
- mm.update_on_device = Mock(return_value=True)
- mm.read_current_from_device = Mock(return_value=current)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['config_sync_ip'] == 'none'
- assert len(results.keys()) == 2
diff --git a/test/units/modules/network/f5/test_bigip_device_dns.py b/test/units/modules/network/f5/test_bigip_device_dns.py
deleted file mode 100644
index d0d1f182dd..0000000000
--- a/test/units/modules/network/f5/test_bigip_device_dns.py
+++ /dev/null
@@ -1,126 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright (c) 2017 F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_device_dns import Parameters
- from library.modules.bigip_device_dns import ModuleManager
- from library.modules.bigip_device_dns import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_device_dns import Parameters
- from ansible.modules.network.f5.bigip_device_dns import ModuleManager
- from ansible.modules.network.f5.bigip_device_dns import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- cache='disable',
- ip_version=4,
- name_servers=['10.10.10.10', '11.11.11.11'],
- search=['14.14.14.14', '15.15.15.15'],
- )
- p = Parameters(params=args)
- assert p.cache == 'disable'
- assert p.name_servers == ['10.10.10.10', '11.11.11.11']
- assert p.search == ['14.14.14.14', '15.15.15.15']
-
- # BIG-IP considers "ipv4" to be an empty value
- assert p.ip_version == 4
-
- def test_ipv6_parameter(self):
- args = dict(
- ip_version=6
- )
- p = Parameters(params=args)
- assert p.ip_version == 6
-
-
-class TestManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
-
- def test_update_settings(self, *args):
- set_module_args(dict(
- cache='disable',
- ip_version=4,
- name_servers=['10.10.10.10', '11.11.11.11'],
- search=['14.14.14.14', '15.15.15.15'],
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- # Configure the parameters that would be returned by querying the
- # remote device
- current = Parameters(
- dict(
- cache='enable'
- )
- )
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- required_one_of=self.spec.required_one_of
- )
- mm = ModuleManager(module=module)
-
- # Override methods to force specific logic in the module to happen
- mm.update_on_device = Mock(return_value=True)
- mm.read_current_from_device = Mock(return_value=current)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
diff --git a/test/units/modules/network/f5/test_bigip_device_group.py b/test/units/modules/network/f5/test_bigip_device_group.py
deleted file mode 100644
index fbf4be059d..0000000000
--- a/test/units/modules/network/f5/test_bigip_device_group.py
+++ /dev/null
@@ -1,186 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright (c) 2017 F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_device_group import ApiParameters
- from library.modules.bigip_device_group import ModuleParameters
- from library.modules.bigip_device_group import ModuleManager
- from library.modules.bigip_device_group import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_device_group import ApiParameters
- from ansible.modules.network.f5.bigip_device_group import ModuleParameters
- from ansible.modules.network.f5.bigip_device_group import ModuleManager
- from ansible.modules.network.f5.bigip_device_group import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- save_on_auto_sync=True,
- full_sync=False,
- description="my description",
- type="sync-failover",
- auto_sync=True
- )
-
- p = ModuleParameters(params=args)
- assert p.save_on_auto_sync is True
- assert p.full_sync is False
- assert p.description == "my description"
- assert p.type == "sync-failover"
- assert p.auto_sync is True
-
- def test_api_parameters(self):
- args = dict(
- asmSync="disabled",
- autoSync="enabled",
- fullLoadOnSync="false",
- incrementalConfigSyncSizeMax=1024,
- networkFailover="disabled",
- saveOnAutoSync="false",
- type="sync-only"
- )
-
- p = ApiParameters(params=args)
- assert p.auto_sync is True
- assert p.full_sync is False
- assert p.max_incremental_sync_size == 1024
- assert p.save_on_auto_sync is False
- assert p.type == 'sync-only'
-
-
-class TestModuleManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
-
- def test_create_default_device_group(self, *args):
- set_module_args(
- dict(
- name="foo-group",
- state="present",
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- )
- )
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
- mm = ModuleManager(module=module)
-
- # Override methods to force specific logic in the module to happen
- mm.create_on_device = Mock(return_value=True)
- mm.exists = Mock(return_value=False)
-
- results = mm.exec_module()
- assert results['changed'] is True
-
- def test_update_device_group(self, *args):
- set_module_args(
- dict(
- full_sync=True,
- name="foo-group",
- state="present",
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- )
- )
-
- current = ApiParameters(params=load_fixture('load_tm_cm_device_group.json'))
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
- mm = ModuleManager(module=module)
-
- # Override methods to force specific logic in the module to happen
- mm.update_on_device = Mock(return_value=True)
- mm.exists = Mock(return_value=True)
- mm.read_current_from_device = Mock(return_value=current)
-
- results = mm.exec_module()
- assert results['changed'] is True
-
- def test_delete_device_group(self, *args):
- set_module_args(
- dict(
- name="foo-group",
- state="absent",
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- )
- )
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
- mm = ModuleManager(module=module)
-
- # Override methods to force specific logic in the module to happen
- mm.exists = Mock(side_effect=[True, False])
- mm.remove_from_device = Mock(return_value=True)
- mm.remove_members_in_group_from_device = Mock(return_value=True)
-
- results = mm.exec_module()
- assert results['changed'] is True
diff --git a/test/units/modules/network/f5/test_bigip_device_group_member.py b/test/units/modules/network/f5/test_bigip_device_group_member.py
deleted file mode 100644
index 31e506b8c5..0000000000
--- a/test/units/modules/network/f5/test_bigip_device_group_member.py
+++ /dev/null
@@ -1,104 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright (c) 2017 F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_device_group_member import Parameters
- from library.modules.bigip_device_group_member import ModuleManager
- from library.modules.bigip_device_group_member import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_device_group_member import Parameters
- from ansible.modules.network.f5.bigip_device_group_member import ModuleManager
- from ansible.modules.network.f5.bigip_device_group_member import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- name='bigip1',
- device_group='dg1'
- )
-
- p = Parameters(params=args)
- assert p.name == 'bigip1'
- assert p.device_group == 'dg1'
-
-
-class TestManager(unittest.TestCase):
- def setUp(self):
- self.spec = ArgumentSpec()
-
- def test_create(self, *args):
- set_module_args(
- dict(
- name="bigip1",
- device_group="dg1",
- state="present",
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- )
- )
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
- mm = ModuleManager(module=module)
-
- # Override methods to force specific logic in the module to happen
- mm.create_on_device = Mock(return_value=True)
- mm.exists = Mock(return_value=False)
-
- results = mm.exec_module()
- assert results['changed'] is True
diff --git a/test/units/modules/network/f5/test_bigip_device_ha_group.py b/test/units/modules/network/f5/test_bigip_device_ha_group.py
deleted file mode 100644
index 37b50d2d0a..0000000000
--- a/test/units/modules/network/f5/test_bigip_device_ha_group.py
+++ /dev/null
@@ -1,230 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2018, F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_device_ha_group import ModuleParameters
- from library.modules.bigip_device_ha_group import ModuleManager
- from library.modules.bigip_device_ha_group import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
- from test.units.compat.mock import patch
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_device_ha_group import ModuleParameters
- from ansible.modules.network.f5.bigip_device_ha_group import ModuleManager
- from ansible.modules.network.f5.bigip_device_ha_group import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
- from units.compat.mock import patch
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters_v13(self):
- args = dict(
- name='foobar',
- description='baz',
- active_bonus=20,
- enable='yes',
- state='present',
- pools=[
- dict(
- pool_name='fakepool',
- attribute='percent-up-members',
- weight=30,
- minimum_threshold=2,
- partition='Common'
- )
- ],
- trunks=[
- dict(
- trunk_name='faketrunk',
- attribute='percent-up-members',
- weight=30,
- minimum_threshold=2
- )
- ]
- )
-
- try:
- self.p1 = patch('library.modules.bigip_device_ha_group.tmos_version')
- self.m1 = self.p1.start()
- self.m1.return_value = '13.1.0'
- except Exception:
- self.p1 = patch('ansible.modules.network.f5.bigip_device_ha_group.tmos_version')
- self.m1 = self.p1.start()
- self.m1.return_value = '13.1.0'
-
- p = ModuleParameters(params=args)
-
- assert p.name == 'foobar'
- assert p.state == 'present'
- assert p.active_bonus == 20
- assert p.enabled is True
- assert p.pools == [{'name': '/Common/fakepool', 'attribute': 'percent-up-members',
- 'weight': 30, 'minimumThreshold': 2}]
- assert p.trunks == [{'name': 'faketrunk', 'attribute': 'percent-up-members',
- 'weight': 30, 'minimumThreshold': 2}]
-
- self.p1.stop()
-
- def test_module_parameters_v12(self):
- args = dict(
- name='foobar',
- description='baz',
- active_bonus=20,
- enable='yes',
- state='present',
- pools=[
- dict(
- pool_name='fakepool',
- attribute='percent-up-members',
- weight=30,
- minimum_threshold=2,
- partition='Common'
- )
- ],
- trunks=[
- dict(
- trunk_name='faketrunk',
- attribute='percent-up-members',
- weight=20,
- minimum_threshold=1
- )
- ]
- )
-
- try:
- self.p1 = patch('library.modules.bigip_device_ha_group.tmos_version')
- self.m1 = self.p1.start()
- self.m1.return_value = '12.1.0'
- except Exception:
- self.p1 = patch('ansible.modules.network.f5.bigip_device_ha_group.tmos_version')
- self.m1 = self.p1.start()
- self.m1.return_value = '12.1.0'
-
- p = ModuleParameters(params=args)
-
- assert p.name == 'foobar'
- assert p.state == 'present'
- assert p.active_bonus == 20
- assert p.enabled is True
- assert p.pools == [{'name': '/Common/fakepool', 'attribute': 'percent-up-members',
- 'weight': 30, 'threshold': 2}]
- assert p.trunks == [{'name': 'faketrunk', 'attribute': 'percent-up-members',
- 'weight': 20, 'threshold': 1}]
-
- self.p1.stop()
-
-
-class TestManager(unittest.TestCase):
- def setUp(self):
- self.spec = ArgumentSpec()
-
- try:
- self.p1 = patch('library.modules.bigip_device_ha_group.tmos_version')
- self.m1 = self.p1.start()
- self.m1.return_value = '13.1.0'
- except Exception:
- self.p1 = patch('ansible.modules.network.f5.bigip_device_ha_group.tmos_version')
- self.m1 = self.p1.start()
- self.m1.return_value = '13.1.0'
-
- def tearDown(self):
- self.p1.stop()
-
- def test_create_ha_group(self, *args):
- set_module_args(dict(
- name='fake_group',
- state='present',
- description='baz',
- active_bonus=20,
- enable='yes',
- pools=[
- dict(
- pool_name='fakepool',
- attribute='percent-up-members',
- weight=30,
- minimum_threshold=2,
- partition='Common'
- )
- ],
- trunks=[
- dict(
- trunk_name='faketrunk',
- attribute='percent-up-members',
- weight=20,
- minimum_threshold=1
- )
- ],
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods to force specific logic in the module to happen
- mm = ModuleManager(module=module)
- mm.exists = Mock(return_value=False)
- mm.create_on_device = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['name'] == 'fake_group'
- assert results['description'] == 'baz'
- assert results['active_bonus'] == 20
- assert results['enable'] == 'yes'
- assert results['pools'] == [{'pool_name': '/Common/fakepool', 'attribute': 'percent-up-members',
- 'weight': 30, 'minimum_threshold': 2}]
- assert results['trunks'] == [{'trunk_name': 'faketrunk', 'attribute': 'percent-up-members',
- 'weight': 20, 'minimum_threshold': 1}]
diff --git a/test/units/modules/network/f5/test_bigip_device_httpd.py b/test/units/modules/network/f5/test_bigip_device_httpd.py
deleted file mode 100644
index e54d6ff2f9..0000000000
--- a/test/units/modules/network/f5/test_bigip_device_httpd.py
+++ /dev/null
@@ -1,303 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_device_httpd import Parameters
- from library.modules.bigip_device_httpd import ModuleManager
- from library.modules.bigip_device_httpd import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
- from test.units.compat.mock import patch
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_device_httpd import Parameters
- from ansible.modules.network.f5.bigip_device_httpd import ModuleManager
- from ansible.modules.network.f5.bigip_device_httpd import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
- from units.compat.mock import patch
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- auth_name='BIG-IP',
- auth_pam_idle_timeout=1200,
- auth_pam_validate_ip='on'
- )
-
- p = Parameters(params=args)
- assert p.auth_name == 'BIG-IP'
- assert p.auth_pam_idle_timeout == 1200
- assert p.auth_pam_validate_ip == 'on'
-
- def test_api_parameters(self):
- args = load_fixture('load_sys_httpd.json')
- p = Parameters(params=args)
- assert p.auth_name == 'BIG-IP'
- assert p.auth_pam_idle_timeout == 1200
-
-
-class TestModuleManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
- self.patcher1 = patch('time.sleep')
- self.patcher1.start()
-
- def tearDown(self):
- self.patcher1.stop()
-
- def test_update(self, *args):
- set_module_args(
- dict(
- auth_name='foo',
- auth_pam_idle_timeout='1000',
- auth_pam_validate_ip='off',
- auth_pam_dashboard_timeout='on',
- fast_cgi_timeout=200,
- hostname_lookup='on',
- log_level='error',
- max_clients='20',
- redirect_http_to_https='yes',
- ssl_port=8443,
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- )
- )
-
- current = Parameters(params=load_fixture('load_sys_httpd.json'))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
- mm = ModuleManager(module=module)
-
- # Override methods to force specific logic in the module to happen
- mm.update_on_device = Mock(return_value=True)
- mm.read_current_from_device = Mock(return_value=current)
-
- results = mm.exec_module()
- assert results['changed'] is True
-
- def test_update_issue_00522(self, *args):
- set_module_args(
- dict(
- ssl_cipher_suite='ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- )
- )
-
- current = Parameters(params=load_fixture('load_sys_httpd.json'))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
- mm = ModuleManager(module=module)
-
- # Override methods to force specific logic in the module to happen
- mm.update_on_device = Mock(return_value=True)
- mm.read_current_from_device = Mock(return_value=current)
-
- results = mm.exec_module()
- assert results['changed'] is True
- assert results['ssl_cipher_suite'] == 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384'
-
- def test_update_issue_00522_as_list(self, *args):
- set_module_args(
- dict(
- ssl_cipher_suite=[
- 'ECDHE-RSA-AES128-GCM-SHA256',
- 'ECDHE-RSA-AES256-GCM-SHA384'
- ],
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- )
- )
-
- current = Parameters(params=load_fixture('load_sys_httpd.json'))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
- mm = ModuleManager(module=module)
-
- # Override methods to force specific logic in the module to happen
- mm.update_on_device = Mock(return_value=True)
- mm.read_current_from_device = Mock(return_value=current)
-
- results = mm.exec_module()
- assert results['changed'] is True
- assert results['ssl_cipher_suite'] == 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384'
-
- def test_update_issue_00522_default(self, *args):
- set_module_args(
- dict(
- ssl_cipher_suite='default',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- )
- )
-
- current = Parameters(params=load_fixture('load_sys_httpd_non_default.json'))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
- mm = ModuleManager(module=module)
-
- # Override methods to force specific logic in the module to happen
- mm.update_on_device = Mock(return_value=True)
- mm.read_current_from_device = Mock(return_value=current)
-
- results = mm.exec_module()
- assert results['changed'] is True
- assert results['ssl_cipher_suite'] == 'default'
-
- def test_update_issue_00587(self, *args):
- set_module_args(
- dict(
- ssl_protocols='all -SSLv2',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- )
- )
-
- current = Parameters(params=load_fixture('load_sys_httpd.json'))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
- mm = ModuleManager(module=module)
-
- # Override methods to force specific logic in the module to happen
- mm.update_on_device = Mock(return_value=True)
- mm.read_current_from_device = Mock(return_value=current)
-
- results = mm.exec_module()
- assert results['changed'] is True
- assert results['ssl_protocols'] == 'all -SSLv2'
-
- def test_update_issue_00587_as_list(self, *args):
- set_module_args(
- dict(
- ssl_protocols=[
- 'all',
- '-SSLv2'
- ],
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- )
- )
-
- current = Parameters(params=load_fixture('load_sys_httpd.json'))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
- mm = ModuleManager(module=module)
-
- # Override methods to force specific logic in the module to happen
- mm.update_on_device = Mock(return_value=True)
- mm.read_current_from_device = Mock(return_value=current)
-
- results = mm.exec_module()
- assert results['changed'] is True
- assert results['ssl_protocols'] == 'all -SSLv2'
-
- def test_update_issue_00587_default(self, *args):
- set_module_args(
- dict(
- ssl_protocols='default',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- )
- )
-
- current = Parameters(params=load_fixture('load_sys_httpd_non_default.json'))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
- mm = ModuleManager(module=module)
-
- # Override methods to force specific logic in the module to happen
- mm.update_on_device = Mock(return_value=True)
- mm.read_current_from_device = Mock(return_value=current)
-
- results = mm.exec_module()
- assert results['changed'] is True
- assert results['ssl_protocols'] == 'default'
diff --git a/test/units/modules/network/f5/test_bigip_device_info.py b/test/units/modules/network/f5/test_bigip_device_info.py
deleted file mode 100644
index 2291c02a2a..0000000000
--- a/test/units/modules/network/f5/test_bigip_device_info.py
+++ /dev/null
@@ -1,130 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright (c) 2017 F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.six import iteritems
-
-try:
- from library.modules.bigip_device_info import Parameters
- from library.modules.bigip_device_info import VirtualAddressesFactManager
- from library.modules.bigip_device_info import ArgumentSpec
- from library.modules.bigip_device_info import ModuleManager
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
- from test.units.compat.mock import patch
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_device_info import Parameters
- from ansible.modules.network.f5.bigip_device_info import VirtualAddressesFactManager
- from ansible.modules.network.f5.bigip_device_info import ArgumentSpec
- from ansible.modules.network.f5.bigip_device_info import ModuleManager
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
- from units.compat.mock import patch
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class FakeVirtualAddress:
- def __init__(self, *args, **kwargs):
- attrs = kwargs.pop('params', {})
- for key, value in iteritems(attrs):
- setattr(self, key, value)
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- gather_subset=['virtual-servers'],
- )
- p = Parameters(params=args)
- assert p.gather_subset == ['virtual-servers']
-
-
-class TestManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
-
- try:
- self.p1 = patch('library.modules.bigip_device_info.modules_provisioned')
- self.m1 = self.p1.start()
- self.m1.return_value = ['ltm', 'gtm', 'asm']
- except Exception:
- self.p1 = patch('ansible.modules.network.f5.bigip_device_info.modules_provisioned')
- self.m1 = self.p1.start()
- self.m1.return_value = ['ltm', 'gtm', 'asm']
-
- def tearDown(self):
- self.p1.stop()
-
- def test_get_trunk_facts(self, *args):
- set_module_args(dict(
- gather_subset=['virtual-addresses'],
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- fixture1 = load_fixture('load_ltm_virtual_address_collection_1.json')
- collection = fixture1['items']
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- tm = VirtualAddressesFactManager(module=module)
- tm.read_collection_from_device = Mock(return_value=collection)
-
- # Override methods to force specific logic in the module to happen
- mm = ModuleManager(module=module)
- mm.get_manager = Mock(return_value=tm)
-
- results = mm.exec_module()
-
- assert results['queried'] is True
- assert 'virtual_addresses' in results
- assert len(results['virtual_addresses']) > 0
diff --git a/test/units/modules/network/f5/test_bigip_device_license.py b/test/units/modules/network/f5/test_bigip_device_license.py
deleted file mode 100644
index e3846862b3..0000000000
--- a/test/units/modules/network/f5/test_bigip_device_license.py
+++ /dev/null
@@ -1,120 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_device_license import ModuleParameters
- from library.modules.bigip_device_license import ModuleManager
- from library.modules.bigip_device_license import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
- from test.units.compat.mock import patch
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_device_license import ModuleParameters
- from ansible.modules.network.f5.bigip_device_license import ModuleManager
- from ansible.modules.network.f5.bigip_device_license import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
- from units.compat.mock import patch
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- license_key='xxxx-yyyy-zzzz',
- license_server='foo-license.f5.com',
- accept_eula=True
- )
-
- p = ModuleParameters(params=args)
- assert p.license_key == 'xxxx-yyyy-zzzz'
- assert p.license_server == 'foo-license.f5.com'
- assert p.accept_eula is True
-
-
-class TestModuleManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
- self.patcher1 = patch('time.sleep')
- self.patcher1.start()
-
- def tearDown(self):
- self.patcher1.stop()
-
- def test_create(self, *args):
- set_module_args(
- dict(
- license_key='xxxx-yyyy-zzzz',
- license_server='foo-license.f5.com',
- accept_eula=True,
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- )
- )
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- required_if=self.spec.required_if
- )
- mm = ModuleManager(module=module)
-
- # Override methods to force specific logic in the module to happen
- mm.exists = Mock(side_effect=[False, True])
- mm.read_dossier_from_device = Mock(return_value=True)
- mm.generate_license_from_remote = Mock(return_value=True)
- mm.upload_license_to_device = Mock(return_value=True)
- mm.upload_eula_to_device = Mock(return_value=True)
- mm.reload_license = Mock(return_value=True)
- mm._is_mcpd_ready_on_device = Mock(return_value=True)
-
- results = mm.exec_module()
- assert results['changed'] is True
diff --git a/test/units/modules/network/f5/test_bigip_device_ntp.py b/test/units/modules/network/f5/test_bigip_device_ntp.py
deleted file mode 100644
index 209af006c0..0000000000
--- a/test/units/modules/network/f5/test_bigip_device_ntp.py
+++ /dev/null
@@ -1,253 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright (c) 2017 F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_device_ntp import Parameters
- from library.modules.bigip_device_ntp import ModuleManager
- from library.modules.bigip_device_ntp import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_device_ntp import Parameters
- from ansible.modules.network.f5.bigip_device_ntp import ModuleManager
- from ansible.modules.network.f5.bigip_device_ntp import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- ntp = ['192.168.1.1', '192.168.1.2']
- args = dict(
- ntp_servers=ntp,
- timezone='Arctic/Longyearbyen'
- )
-
- p = Parameters(params=args)
- assert p.ntp_servers == ntp
- assert p.timezone == 'Arctic/Longyearbyen'
-
- def test_api_parameters(self):
- ntp = ['192.168.1.1', '192.168.1.2']
- args = dict(
- servers=ntp,
- timezone='Arctic/Longyearbyen'
- )
-
- p = Parameters(params=args)
- assert p.ntp_servers == ntp
- assert p.timezone == 'Arctic/Longyearbyen'
-
-
-class TestModuleManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
-
- def test_update_ntp_servers(self, *args):
- ntp = ['10.1.1.1', '10.1.1.2']
- set_module_args(
- dict(
- ntp_servers=ntp,
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- )
- )
-
- # Configure the parameters that would be returned by querying the
- # remote device
- current = Parameters(params=load_fixture('load_ntp.json'))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- required_one_of=self.spec.required_one_of
- )
- mm = ModuleManager(module=module)
-
- # Override methods to force specific logic in the module to happen
- mm.update_on_device = Mock(return_value=True)
- mm.read_current_from_device = Mock(return_value=current)
-
- results = mm.exec_module()
- assert results['changed'] is True
- assert results['ntp_servers'] == ntp
-
- def test_update_timezone(self, *args):
- set_module_args(
- dict(
- timezone='Arctic/Longyearbyen',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- )
- )
-
- # Configure the parameters that would be returned by querying the
- # remote device
- current = Parameters(params=load_fixture('load_ntp.json'))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- required_one_of=self.spec.required_one_of
- )
- mm = ModuleManager(module=module)
-
- # Override methods to force specific logic in the module to happen
- mm.update_on_device = Mock(return_value=True)
- mm.read_current_from_device = Mock(return_value=current)
-
- results = mm.exec_module()
- assert results['changed'] is True
- assert results['timezone'] == 'Arctic/Longyearbyen'
-
- def test_update_ntp_servers_and_timezone(self, *args):
- ntp = ['10.1.1.1', '10.1.1.2']
- set_module_args(
- dict(
- ntp_servers=ntp,
- timezone='Arctic/Longyearbyen',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- )
- )
-
- # Configure the parameters that would be returned by querying the
- # remote device
- current = Parameters(params=load_fixture('load_ntp.json'))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- required_one_of=self.spec.required_one_of
- )
- mm = ModuleManager(module=module)
-
- # Override methods to force specific logic in the module to happen
- mm.update_on_device = Mock(return_value=True)
- mm.read_current_from_device = Mock(return_value=current)
-
- results = mm.exec_module()
- assert results['changed'] is True
- assert results['ntp_servers'] == ntp
- assert results['timezone'] == 'Arctic/Longyearbyen'
-
- def test_absent_ntp_servers(self, *args):
- ntp = []
- set_module_args(
- dict(
- ntp_servers=ntp,
- timezone='America/Los_Angeles',
- state='absent',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- )
- )
-
- # Configure the parameters that would be returned by querying the
- # remote device
- current = Parameters(params=load_fixture('load_ntp.json'))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- required_one_of=self.spec.required_one_of
- )
- mm = ModuleManager(module=module)
-
- # Override methods to force specific logic in the module to happen
- mm.absent_on_device = Mock(return_value=True)
- mm.read_current_from_device = Mock(return_value=current)
-
- results = mm.exec_module()
- assert results['changed'] is True
- assert results['ntp_servers'] == ntp
- assert not hasattr(results, 'timezone')
-
- def test_absent_timezone(self, *args):
- set_module_args(
- dict(
- timezone='',
- state='absent',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- )
- )
-
- # Configure the parameters that would be returned by querying the
- # remote device
- current = Parameters(params=load_fixture('load_ntp.json'))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- required_one_of=self.spec.required_one_of
- )
- mm = ModuleManager(module=module)
-
- # Override methods to force specific logic in the module to happen
- mm.absent_on_device = Mock(return_value=True)
- mm.read_current_from_device = Mock(return_value=current)
-
- results = mm.exec_module()
- assert results['changed'] is False
diff --git a/test/units/modules/network/f5/test_bigip_device_sshd.py b/test/units/modules/network/f5/test_bigip_device_sshd.py
deleted file mode 100644
index 03ad4036ee..0000000000
--- a/test/units/modules/network/f5/test_bigip_device_sshd.py
+++ /dev/null
@@ -1,128 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright (c) 2017 F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_device_sshd import ApiParameters
- from library.modules.bigip_device_sshd import ModuleParameters
- from library.modules.bigip_device_sshd import ModuleManager
- from library.modules.bigip_device_sshd import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_device_sshd import ApiParameters
- from ansible.modules.network.f5.bigip_device_sshd import ModuleParameters
- from ansible.modules.network.f5.bigip_device_sshd import ModuleManager
- from ansible.modules.network.f5.bigip_device_sshd import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- allow=['all'],
- banner='enabled',
- banner_text='asdf',
- inactivity_timeout='100',
- log_level='debug',
- login='enabled',
- port=1010,
- )
- p = ModuleParameters(params=args)
- assert p.allow == ['all']
- assert p.banner == 'enabled'
- assert p.banner_text == 'asdf'
- assert p.inactivity_timeout == 100
- assert p.log_level == 'debug'
- assert p.login == 'enabled'
- assert p.port == 1010
-
-
-class TestManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
-
- def test_update_settings(self, *args):
- set_module_args(dict(
- allow=['all'],
- banner='enabled',
- banner_text='asdf',
- inactivity_timeout='100',
- log_level='debug',
- login='enabled',
- port=1010,
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- # Configure the parameters that would be returned by querying the
- # remote device
- current = ApiParameters(
- params=dict(
- allow=['172.27.1.1']
- )
- )
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
- mm = ModuleManager(module=module)
-
- # Override methods to force specific logic in the module to happen
- mm.update_on_device = Mock(return_value=True)
- mm.read_current_from_device = Mock(return_value=current)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['allow'] == ['all']
diff --git a/test/units/modules/network/f5/test_bigip_device_syslog.py b/test/units/modules/network/f5/test_bigip_device_syslog.py
deleted file mode 100644
index cde3babbb9..0000000000
--- a/test/units/modules/network/f5/test_bigip_device_syslog.py
+++ /dev/null
@@ -1,111 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2018, F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_device_syslog import ApiParameters
- from library.modules.bigip_device_syslog import ModuleParameters
- from library.modules.bigip_device_syslog import ModuleManager
- from library.modules.bigip_device_syslog import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_device_syslog import ApiParameters
- from ansible.modules.network.f5.bigip_device_syslog import ModuleParameters
- from ansible.modules.network.f5.bigip_device_syslog import ModuleManager
- from ansible.modules.network.f5.bigip_device_syslog import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- kern_from='err',
- kern_to='info',
- )
- p = ModuleParameters(params=args)
- assert p.kern_from == 'err'
- assert p.kern_to == 'info'
-
- def test_api_parameters(self):
- p = ApiParameters(params=load_fixture('load_sys_syslog_1.json'))
- assert p.kern_from == 'debug'
- assert p.kern_to == 'emerg'
-
-
-class TestUntypedManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
-
- def test_update(self, *args):
- set_module_args(dict(
- kern_from='emerg',
- kern_to='debug',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- current = ApiParameters(params=load_fixture('load_sys_syslog_1.json'))
-
- # Override methods to force specific logic in the module to happen
- mm = ModuleManager(module=module)
- mm.update_on_device = Mock(return_value=True)
- mm.read_current_from_device = Mock(return_value=current)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
diff --git a/test/units/modules/network/f5/test_bigip_device_traffic_group.py b/test/units/modules/network/f5/test_bigip_device_traffic_group.py
deleted file mode 100644
index 3454e1d770..0000000000
--- a/test/units/modules/network/f5/test_bigip_device_traffic_group.py
+++ /dev/null
@@ -1,167 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright (c) 2017 F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_device_traffic_group import ApiParameters
- from library.modules.bigip_device_traffic_group import ModuleParameters
- from library.modules.bigip_device_traffic_group import ModuleManager
- from library.modules.bigip_device_traffic_group import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_device_traffic_group import ApiParameters
- from ansible.modules.network.f5.bigip_device_traffic_group import ModuleParameters
- from ansible.modules.network.f5.bigip_device_traffic_group import ModuleManager
- from ansible.modules.network.f5.bigip_device_traffic_group import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters_1(self):
- args = dict(
- name='foo',
- mac_address=''
- )
-
- p = ModuleParameters(params=args)
- assert p.name == 'foo'
- assert p.mac_address == 'none'
-
- def test_module_parameters_2(self):
- args = dict(
- mac_address='00:00:00:00:00:02'
- )
-
- p = ModuleParameters(params=args)
- assert p.mac_address == '00:00:00:00:00:02'
-
- def test_module_parameters_3(self):
- args = dict(
- name='foo',
- ha_order=['bigip1'],
- ha_group='',
- auto_failback='yes',
- auto_failback_time=40
- )
-
- p = ModuleParameters(params=args)
- assert p.name == 'foo'
- assert p.ha_order == ['/Common/bigip1']
- assert p.ha_group == 'none'
- assert p.auto_failback == 'true'
- assert p.auto_failback_time == 40
-
- def test_api_parameters_1(self):
- args = load_fixture('load_tm_cm_traffic_group_1.json')
-
- p = ApiParameters(params=args)
- assert p.mac_address == 'none'
-
- def test_api_parameters_2(self):
- args = load_fixture('load_tm_cm_traffic_group_2.json')
-
- p = ApiParameters(params=args)
- assert p.mac_address == '00:00:00:00:00:02'
-
-
-class TestManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
-
- def test_create(self, *args):
- set_module_args(dict(
- name='foo',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- mm = ModuleManager(module=module)
- mm.create_on_device = Mock(return_value=True)
- mm.exists = Mock(return_value=False)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
-
- def test_modify_ha_order(self, *args):
- set_module_args(dict(
- name='traffic-group-2',
- ha_order=['v12-2.ansible.local', 'v12-1.ansible.local'],
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- )
-
- current = ApiParameters(params=load_fixture('load_tg_ha_order.json'))
-
- mm = ModuleManager(module=module)
- mm.exists = Mock(return_value=True)
- mm.read_current_from_device = Mock(return_value=current)
- mm.update_on_device = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['ha_order'] == ['/Common/v12-2.ansible.local', '/Common/v12-1.ansible.local']
diff --git a/test/units/modules/network/f5/test_bigip_device_trust.py b/test/units/modules/network/f5/test_bigip_device_trust.py
deleted file mode 100644
index 6c7f325b01..0000000000
--- a/test/units/modules/network/f5/test_bigip_device_trust.py
+++ /dev/null
@@ -1,183 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright (c) 2017 F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_device_trust import Parameters
- from library.modules.bigip_device_trust import ModuleManager
- from library.modules.bigip_device_trust import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_device_trust import Parameters
- from ansible.modules.network.f5.bigip_device_trust import ModuleManager
- from ansible.modules.network.f5.bigip_device_trust import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- peer_server='10.10.10.10',
- peer_hostname='foo.bar.baz',
- peer_user='admin',
- peer_password='secret'
- )
-
- p = Parameters(params=args)
- assert p.peer_server == '10.10.10.10'
- assert p.peer_hostname == 'foo.bar.baz'
- assert p.peer_user == 'admin'
- assert p.peer_password == 'secret'
-
- def test_module_parameters_with_peer_type(self):
- args = dict(
- peer_server='10.10.10.10',
- peer_hostname='foo.bar.baz',
- peer_user='admin',
- peer_password='secret',
- type='peer'
- )
-
- p = Parameters(params=args)
- assert p.peer_server == '10.10.10.10'
- assert p.peer_hostname == 'foo.bar.baz'
- assert p.peer_user == 'admin'
- assert p.peer_password == 'secret'
- assert p.type is True
-
- def test_module_parameters_with_subordinate_type(self):
- args = dict(
- peer_server='10.10.10.10',
- peer_hostname='foo.bar.baz',
- peer_user='admin',
- peer_password='secret',
- type='subordinate'
- )
-
- p = Parameters(params=args)
- assert p.peer_server == '10.10.10.10'
- assert p.peer_hostname == 'foo.bar.baz'
- assert p.peer_user == 'admin'
- assert p.peer_password == 'secret'
- assert p.type is False
-
- def test_hyphenated_peer_hostname(self):
- args = dict(
- peer_hostname='hn---hyphen____underscore.hmatsuda.local',
- )
-
- p = Parameters(params=args)
- assert p.peer_hostname == 'hn---hyphen____underscore.hmatsuda.local'
-
- def test_numbered_peer_hostname(self):
- args = dict(
- peer_hostname='BIG-IP_12x_ans2.example.local',
- )
-
- p = Parameters(params=args)
- assert p.peer_hostname == 'BIG-IP_12x_ans2.example.local'
-
-
-class TestManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
-
- def test_create_device_trust(self, *args):
- set_module_args(dict(
- peer_server='10.10.10.10',
- peer_hostname='foo.bar.baz',
- peer_user='admin',
- peer_password='secret',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods in the specific type of manager
- mm = ModuleManager(module=module)
- mm.exists = Mock(return_value=False)
- mm.create_on_device = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
-
- def test_create_device_trust_idempotent(self, *args):
- set_module_args(dict(
- peer_server='10.10.10.10',
- peer_hostname='foo.bar.baz',
- peer_user='admin',
- peer_password='secret',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods in the specific type of manager
- mm = ModuleManager(module=module)
- mm.exists = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is False
diff --git a/test/units/modules/network/f5/test_bigip_dns_cache_resolver.py b/test/units/modules/network/f5/test_bigip_dns_cache_resolver.py
deleted file mode 100644
index 924e2c6a92..0000000000
--- a/test/units/modules/network/f5/test_bigip_dns_cache_resolver.py
+++ /dev/null
@@ -1,113 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2018, F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_dns_cache_resolver import ApiParameters
- from library.modules.bigip_dns_cache_resolver import ModuleParameters
- from library.modules.bigip_dns_cache_resolver import ModuleManager
- from library.modules.bigip_dns_cache_resolver import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_dns_cache_resolver import ApiParameters
- from ansible.modules.network.f5.bigip_dns_cache_resolver import ModuleParameters
- from ansible.modules.network.f5.bigip_dns_cache_resolver import ModuleManager
- from ansible.modules.network.f5.bigip_dns_cache_resolver import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
-
- from units.modules.utils import set_module_args
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- name='foo',
- answer_default_zones=True,
- route_domain=10,
- )
-
- p = ModuleParameters(params=args)
- assert p.name == 'foo'
- assert p.route_domain == '/Common/10'
-
- def test_api_parameters(self):
- args = load_fixture('load_ltm_dns_cache_resolver_1.json')
-
- p = ApiParameters(params=args)
- assert p.name == 'foo'
- assert p.route_domain == '/Common/0'
-
-
-class TestManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
-
- def test_create_monitor(self, *args):
- set_module_args(dict(
- name='foo',
- route_domain=20,
- partition='Common',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods in the specific type of manager
- mm = ModuleManager(module=module)
- mm.exists = Mock(side_effect=[False, True])
- mm.create_on_device = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
diff --git a/test/units/modules/network/f5/test_bigip_dns_nameserver.py b/test/units/modules/network/f5/test_bigip_dns_nameserver.py
deleted file mode 100644
index 5d7adeb2c2..0000000000
--- a/test/units/modules/network/f5/test_bigip_dns_nameserver.py
+++ /dev/null
@@ -1,126 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2018, F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_dns_nameserver import ApiParameters
- from library.modules.bigip_dns_nameserver import ModuleParameters
- from library.modules.bigip_dns_nameserver import ModuleManager
- from library.modules.bigip_dns_nameserver import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_dns_nameserver import ApiParameters
- from ansible.modules.network.f5.bigip_dns_nameserver import ModuleParameters
- from ansible.modules.network.f5.bigip_dns_nameserver import ModuleManager
- from ansible.modules.network.f5.bigip_dns_nameserver import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- name='foo',
- address='10.10.10.10',
- service_port=80,
- route_domain=20,
- tsig_key='key1',
- partition='Common'
- )
-
- p = ModuleParameters(params=args)
- assert p.name == 'foo'
- assert p.address == '10.10.10.10'
- assert p.service_port == 80
- assert p.route_domain == '/Common/20'
- assert p.tsig_key == '/Common/key1'
-
- def test_api_parameters(self):
- args = load_fixture('load_ltm_dns_nameserver_1.json')
-
- p = ApiParameters(params=args)
- assert p.name == 'foo'
- assert p.address == '127.0.0.1'
- assert p.service_port == 53
- assert p.route_domain == '/Common/0'
- assert p.tsig_key == '/Common/key1'
-
-
-class TestManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
-
- def test_create_monitor(self, *args):
- set_module_args(dict(
- name='foo',
- address='10.10.10.10',
- service_port=80,
- route_domain=20,
- tsig_key='key1',
- partition='Common',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods in the specific type of manager
- mm = ModuleManager(module=module)
- mm.exists = Mock(side_effect=[False, True])
- mm.create_on_device = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
diff --git a/test/units/modules/network/f5/test_bigip_dns_resolver.py b/test/units/modules/network/f5/test_bigip_dns_resolver.py
deleted file mode 100644
index 568f6432e8..0000000000
--- a/test/units/modules/network/f5/test_bigip_dns_resolver.py
+++ /dev/null
@@ -1,124 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2018, F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_dns_resolver import ApiParameters
- from library.modules.bigip_dns_resolver import ModuleParameters
- from library.modules.bigip_dns_resolver import ModuleManager
- from library.modules.bigip_dns_resolver import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_dns_resolver import ApiParameters
- from ansible.modules.network.f5.bigip_dns_resolver import ModuleParameters
- from ansible.modules.network.f5.bigip_dns_resolver import ModuleManager
- from ansible.modules.network.f5.bigip_dns_resolver import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- name='foo',
- route_domain=10,
- cache_size=1234,
- answer_default_zones=True,
- randomize_query_case=False,
- use_ipv4=True,
- use_ipv6=False,
- use_udp=True,
- use_tcp=False,
- )
-
- p = ModuleParameters(params=args)
- assert p.name == 'foo'
- assert p.route_domain == '/Common/10'
- assert p.cache_size == 1234
- assert p.answer_default_zones == 'yes'
- assert p.randomize_query_case == 'no'
- assert p.use_ipv4 == 'yes'
- assert p.use_ipv6 == 'no'
- assert p.use_tcp == 'no'
- assert p.use_udp == 'yes'
-
- def test_api_parameters(self):
- args = load_fixture('load_net_dns_resolver_1.json')
- p = ApiParameters(params=args)
- assert p.name == 'foo'
-
-
-class TestManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
-
- def test_create(self, *args):
- # Configure the arguments that would be sent to the Ansible module
- set_module_args(dict(
- name='foo',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
- mm = ModuleManager(module=module)
-
- # Override methods to force specific logic in the module to happen
- mm.exists = Mock(return_value=False)
- mm.create_on_device = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
diff --git a/test/units/modules/network/f5/test_bigip_dns_zone.py b/test/units/modules/network/f5/test_bigip_dns_zone.py
deleted file mode 100644
index 38d6193ee7..0000000000
--- a/test/units/modules/network/f5/test_bigip_dns_zone.py
+++ /dev/null
@@ -1,128 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2018, F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_dns_zone import ApiParameters
- from library.modules.bigip_dns_zone import ModuleParameters
- from library.modules.bigip_dns_zone import ModuleManager
- from library.modules.bigip_dns_zone import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_dns_zone import ApiParameters
- from ansible.modules.network.f5.bigip_dns_zone import ModuleParameters
- from ansible.modules.network.f5.bigip_dns_zone import ModuleManager
- from ansible.modules.network.f5.bigip_dns_zone import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- name='foo',
- dns_express=dict(
- server='server1',
- enabled=True,
- notify_action='consume',
- allow_notify_from=['1.1.1.1'],
- verify_tsig=True,
- response_policy=False
- ),
- nameservers=[
- 'foo', 'bar', 'baz'
- ],
- tsig_server_key='key1'
- )
-
- p = ModuleParameters(params=args)
- assert p.name == 'foo'
- assert len(p.nameservers) == 3
- assert p.tsig_server_key == '/Common/key1'
- assert p.express_server == '/Common/server1'
- assert p.enabled == 'yes'
- assert p.notify_action == 'consume'
- assert len(p.allow_notify_from) == 1
- assert p.verify_tsig == 'yes'
- assert p.response_policy == 'no'
-
- def test_api_parameters(self):
- args = load_fixture('load_ltm_dns_zone_1.json')
- p = ApiParameters(params=args)
- assert p.name == 'foo'
-
-
-class TestManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
-
- def test_create(self, *args):
- # Configure the arguments that would be sent to the Ansible module
- set_module_args(dict(
- name='foo',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
- mm = ModuleManager(module=module)
-
- # Override methods to force specific logic in the module to happen
- mm.exists = Mock(return_value=False)
- mm.create_on_device = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
diff --git a/test/units/modules/network/f5/test_bigip_file_copy.py b/test/units/modules/network/f5/test_bigip_file_copy.py
deleted file mode 100644
index c52886065e..0000000000
--- a/test/units/modules/network/f5/test_bigip_file_copy.py
+++ /dev/null
@@ -1,121 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2018, F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_file_copy import ApiParameters
- from library.modules.bigip_file_copy import IFileManager
- from library.modules.bigip_file_copy import ModuleParameters
- from library.modules.bigip_file_copy import ModuleManager
- from library.modules.bigip_file_copy import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_file_copy import ApiParameters
- from ansible.modules.network.f5.bigip_file_copy import IFileManager
- from ansible.modules.network.f5.bigip_file_copy import ModuleParameters
- from ansible.modules.network.f5.bigip_file_copy import ModuleManager
- from ansible.modules.network.f5.bigip_file_copy import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- name='foo',
- source='file.txt',
- force=True
- )
-
- p = ModuleParameters(params=args)
- assert p.name == 'foo'
- assert p.source == 'file.txt'
- assert p.force is True
-
- def test_api_parameters(self):
- args = load_fixture('load_sys_file_external-monitor_1.json')
- p = ApiParameters(params=args)
- assert p.checksum == '0c78e6641632e47d11802b29cfd119d2233cb80a'
-
-
-class TestManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
-
- def test_create(self, *args):
- # Configure the arguments that would be sent to the Ansible module
- set_module_args(dict(
- name='foo',
- source='file.txt',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- required_if=self.spec.required_if
- )
-
- tm = IFileManager(module=module)
- tm.exists = Mock(return_value=False)
- tm.create_on_device = Mock(return_value=True)
- tm.upload_to_device = Mock(return_value=True)
- tm.remove_uploaded_file_from_device = Mock(return_value=True)
-
- # Override methods to force specific logic in the module to happen
- mm = ModuleManager(module=module)
- mm.get_manager = Mock(return_value=tm)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
diff --git a/test/units/modules/network/f5/test_bigip_firewall_address_list.py b/test/units/modules/network/f5/test_bigip_firewall_address_list.py
deleted file mode 100644
index 17457a240b..0000000000
--- a/test/units/modules/network/f5/test_bigip_firewall_address_list.py
+++ /dev/null
@@ -1,140 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_firewall_address_list import ApiParameters
- from library.modules.bigip_firewall_address_list import ModuleParameters
- from library.modules.bigip_firewall_address_list import ModuleManager
- from library.modules.bigip_firewall_address_list import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_firewall_address_list import ApiParameters
- from ansible.modules.network.f5.bigip_firewall_address_list import ModuleParameters
- from ansible.modules.network.f5.bigip_firewall_address_list import ModuleManager
- from ansible.modules.network.f5.bigip_firewall_address_list import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- name='foo',
- description='this is a description',
- addresses=['1.1.1.1', '2.2.2.2'],
- address_ranges=['3.3.3.3-4.4.4.4', '5.5.5.5-6.6.6.6'],
- address_lists=['/Common/foo', 'foo']
- )
-
- p = ModuleParameters(params=args)
- assert p.name == 'foo'
- assert p.description == 'this is a description'
- assert len(p.addresses) == 2
- assert len(p.address_ranges) == 2
- assert len(p.address_lists) == 2
-
- def test_api_parameters(self):
- args = load_fixture('load_security_address_list_1.json')
-
- p = ApiParameters(params=args)
- assert len(p.addresses) == 2
- assert len(p.address_ranges) == 2
- assert len(p.address_lists) == 1
- assert len(p.fqdns) == 1
- assert len(p.geo_locations) == 5
- assert sorted(p.addresses) == ['1.1.1.1', '2700:bc00:1f10:101::6']
- assert sorted(p.address_ranges) == ['2.2.2.2-3.3.3.3', '5.5.5.5-6.6.6.6']
- assert p.address_lists[0] == '/Common/foo'
-
-
-class TestManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
-
- def test_create(self, *args):
- set_module_args(dict(
- name='foo',
- description='this is a description',
- addresses=['1.1.1.1', '2.2.2.2'],
- address_ranges=['3.3.3.3-4.4.4.4', '5.5.5.5-6.6.6.6'],
- address_lists=['/Common/foo', 'foo'],
- geo_locations=[
- dict(country='US', region='Los Angeles'),
- dict(country='China'),
- dict(country='EU')
- ],
- fqdns=['google.com', 'mit.edu'],
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
- mm = ModuleManager(module=module)
-
- # Override methods to force specific logic in the module to happen
- mm.exists = Mock(return_value=False)
- mm.create_on_device = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert 'addresses' in results
- assert 'address_lists' in results
- assert 'address_ranges' in results
- assert len(results['addresses']) == 2
- assert len(results['address_ranges']) == 2
- assert len(results['address_lists']) == 2
- assert results['description'] == 'this is a description'
diff --git a/test/units/modules/network/f5/test_bigip_firewall_dos_profile.py b/test/units/modules/network/f5/test_bigip_firewall_dos_profile.py
deleted file mode 100644
index 8f0bdd6914..0000000000
--- a/test/units/modules/network/f5/test_bigip_firewall_dos_profile.py
+++ /dev/null
@@ -1,110 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2018, F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_firewall_dos_profile import ModuleParameters
- from library.modules.bigip_firewall_dos_profile import ModuleManager
- from library.modules.bigip_firewall_dos_profile import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_firewall_dos_profile import ModuleParameters
- from ansible.modules.network.f5.bigip_firewall_dos_profile import ModuleManager
- from ansible.modules.network.f5.bigip_firewall_dos_profile import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- name='foo',
- description='my description',
- threshold_sensitivity='low',
- default_whitelist='whitelist1'
- )
-
- p = ModuleParameters(params=args)
- assert p.name == 'foo'
- assert p.description == 'my description'
- assert p.threshold_sensitivity == 'low'
- assert p.default_whitelist == '/Common/whitelist1'
-
-
-class TestManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
-
- def test_create(self, *args):
- set_module_args(dict(
- name='foo',
- description='this is a description',
- threshold_sensitivity='low',
- default_whitelist='whitelist1',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
- mm = ModuleManager(module=module)
-
- # Override methods to force specific logic in the module to happen
- mm.exists = Mock(side_effect=[False, True])
- mm.create_on_device = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['description'] == 'this is a description'
diff --git a/test/units/modules/network/f5/test_bigip_firewall_dos_vector.py b/test/units/modules/network/f5/test_bigip_firewall_dos_vector.py
deleted file mode 100644
index dbcad842d6..0000000000
--- a/test/units/modules/network/f5/test_bigip_firewall_dos_vector.py
+++ /dev/null
@@ -1,110 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2018, F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_firewall_dos_vector import ModuleParameters
- from library.modules.bigip_firewall_dos_vector import ModuleManager
- from library.modules.bigip_firewall_dos_vector import ArgumentSpec
- from library.modules.bigip_firewall_dos_vector import ProtocolDnsManager
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_firewall_dos_vector import ModuleParameters
- from ansible.modules.network.f5.bigip_firewall_dos_vector import ModuleManager
- from ansible.modules.network.f5.bigip_firewall_dos_vector import ArgumentSpec
- from ansible.modules.network.f5.bigip_firewall_dos_vector import ProtocolDnsManager
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- name='foo',
- state='mitigate'
- )
-
- p = ModuleParameters(params=args)
- assert p.name == 'foo'
- assert p.state == 'mitigate'
-
-
-class TestManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
-
- def test_create_dns(self, *args):
- set_module_args(dict(
- name='aaaa',
- state='mitigate',
- profile='foo',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- m1 = ProtocolDnsManager(module=module)
- m1.read_current_from_device = Mock(return_value=[])
- m1.update_on_device = Mock(return_value=True)
-
- mm = ModuleManager(module=module)
- mm.get_manager = Mock(return_value=m1)
- mm.exists = Mock(side_effect=[False, True])
- mm.create_on_device = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
diff --git a/test/units/modules/network/f5/test_bigip_firewall_global_rules.py b/test/units/modules/network/f5/test_bigip_firewall_global_rules.py
deleted file mode 100644
index be3442a225..0000000000
--- a/test/units/modules/network/f5/test_bigip_firewall_global_rules.py
+++ /dev/null
@@ -1,115 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2018, F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_firewall_global_rules import ApiParameters
- from library.modules.bigip_firewall_global_rules import ModuleParameters
- from library.modules.bigip_firewall_global_rules import ModuleManager
- from library.modules.bigip_firewall_global_rules import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_firewall_global_rules import ApiParameters
- from ansible.modules.network.f5.bigip_firewall_global_rules import ModuleParameters
- from ansible.modules.network.f5.bigip_firewall_global_rules import ModuleManager
- from ansible.modules.network.f5.bigip_firewall_global_rules import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- enforced_policy='enforced1',
- staged_policy='staged1',
- service_policy='service1',
- )
- p = ModuleParameters(params=args)
- assert p.enforced_policy == '/Common/enforced1'
- assert p.staged_policy == '/Common/staged1'
- assert p.service_policy == '/Common/service1'
-
- def test_api_parameters(self):
- p = ApiParameters(params=load_fixture('load_security_firewall_global_rules_1.json'))
- assert p.enforced_policy == '/Common/foo'
- assert p.service_policy == '/Common/bar'
- assert p.staged_policy == '/Common/baz'
-
-
-class TestUntypedManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
-
- def test_update(self, *args):
- set_module_args(dict(
- enforced_policy='enforced1',
- staged_policy='staged1',
- service_policy='service1',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- current = ApiParameters(params=load_fixture('load_security_firewall_global_rules_1.json'))
-
- # Override methods to force specific logic in the module to happen
- mm = ModuleManager(module=module)
- mm.update_on_device = Mock(return_value=True)
- mm.read_current_from_device = Mock(return_value=current)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
diff --git a/test/units/modules/network/f5/test_bigip_firewall_log_profile.py b/test/units/modules/network/f5/test_bigip_firewall_log_profile.py
deleted file mode 100644
index 2c4743140c..0000000000
--- a/test/units/modules/network/f5/test_bigip_firewall_log_profile.py
+++ /dev/null
@@ -1,146 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2019, F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_firewall_log_profile import ApiParameters
- from library.modules.bigip_firewall_log_profile import ModuleParameters
- from library.modules.bigip_firewall_log_profile import ModuleManager
- from library.modules.bigip_firewall_log_profile import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_firewall_log_profile import ApiParameters
- from ansible.modules.network.f5.bigip_firewall_log_profile import ModuleParameters
- from ansible.modules.network.f5.bigip_firewall_log_profile import ModuleManager
- from ansible.modules.network.f5.bigip_firewall_log_profile import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- name='foo',
- description='my description',
- partition='Common',
- ip_intelligence=dict(
- log_publisher='foobar',
- rate_limit='300000',
- log_translation_fields='yes',
- log_rtbh='yes',
- log_shun='yes',
- ),
- port_misuse=dict(
- log_publisher='/Part/bazbar',
- rate_limit='indefinite',
- ),
- dos_protection=dict(
- sip_publisher='sip-pub',
- dns_publisher='/Temp/dns-pub',
- network_publisher='net-pub'
- )
- )
-
- p = ModuleParameters(params=args)
- assert p.name == 'foo'
- assert p.description == 'my description'
- assert p.ip_rate_limit == 300000
- assert p.ip_log_publisher == '/Common/foobar'
- assert p.ip_log_translation_fields == 'enabled'
- assert p.ip_log_shun is None
- assert p.ip_log_rtbh == 'enabled'
- assert p.port_log_publisher == '/Part/bazbar'
- assert p.port_rate_limit == 4294967295
- assert p.dns_publisher == '/Temp/dns-pub'
- assert p.sip_publisher == '/Common/sip-pub'
- assert p.network_publisher == '/Common/net-pub'
-
- def test_api_parameters(self):
- args = load_fixture('load_afm_log_global_network_profile.json')
-
- p = ApiParameters(params=args)
- assert p.name == 'global-network'
- assert p.description == 'Default logging profile for network events'
- assert p.ip_log_shun == 'disabled'
- assert p.ip_log_translation_fields == 'disabled'
- assert p.ip_rate_limit == 4294967295
- assert p.port_rate_limit == 4294967295
- assert p.ip_log_publisher is None
- assert p.port_log_publisher is None
-
-
-class TestManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
-
- def test_create(self, *args):
- set_module_args(dict(
- name='foo',
- description='this is a description',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
- mm = ModuleManager(module=module)
-
- # Override methods to force specific logic in the module to happen
- mm.exists = Mock(side_effect=[False, True])
- mm.create_on_device = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['description'] == 'this is a description'
diff --git a/test/units/modules/network/f5/test_bigip_firewall_log_profile_network.py b/test/units/modules/network/f5/test_bigip_firewall_log_profile_network.py
deleted file mode 100644
index a17fc05fba..0000000000
--- a/test/units/modules/network/f5/test_bigip_firewall_log_profile_network.py
+++ /dev/null
@@ -1,171 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2019, F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_firewall_log_profile_network import ApiParameters
- from library.modules.bigip_firewall_log_profile_network import ModuleParameters
- from library.modules.bigip_firewall_log_profile_network import ModuleManager
- from library.modules.bigip_firewall_log_profile_network import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_firewall_log_profile_network import ApiParameters
- from ansible.modules.network.f5.bigip_firewall_log_profile_network import ModuleParameters
- from ansible.modules.network.f5.bigip_firewall_log_profile_network import ModuleManager
- from ansible.modules.network.f5.bigip_firewall_log_profile_network import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- profile_name='foo',
- rate_limit=150000,
- log_publisher='/Common/foobar',
- log_tcp_errors=dict(
- enabled='yes',
- rate_limit=10000,
- ),
- log_tcp_events=dict(
- enabled='yes',
- rate_limit=30000,
- ),
- log_ip_errors=dict(
- enabled='yes',
- rate_limit=60000,
- ),
- log_matches_accept_rule=dict(
- enabled='yes',
- rate_limit=80000,
- ),
- log_matches_drop_rule=dict(
- enabled='no',
- rate_limit='indefinite',
- ),
- log_matches_reject_rule=dict(
- enabled='no',
- rate_limit='indefinite',
- ),
- log_format_delimiter='.',
- log_storage_format='field-list',
- log_message_fields=['vlan', 'translated_vlan', 'src_ip']
- )
-
- p = ModuleParameters(params=args)
- assert p.profile_name == 'foo'
- assert p.rate_limit == 150000
- assert p.log_publisher == '/Common/foobar'
- assert p.log_tcp_events == 'enabled'
- assert p.rate_tcp_events == 30000
- assert p.log_ip_errors == 'enabled'
- assert p.rate_ip_errors == 60000
- assert p.log_tcp_errors == 'enabled'
- assert p.rate_tcp_errors == 10000
- assert p.log_acl_match_accept == 'enabled'
- assert p.rate_acl_match_accept == 80000
- assert p.log_acl_match_drop == 'disabled'
- assert p.rate_acl_match_drop == 4294967295
- assert p.log_acl_match_reject == 'disabled'
- assert p.rate_acl_match_reject == 4294967295
- assert p.log_format_delimiter == '.'
- assert p.log_storage_format == 'field-list'
-
- def test_api_parameters(self):
- args = load_fixture('load_afm_global_network_log_network.json')
-
- p = ApiParameters(params=args)
- assert p.rate_limit == 4294967295
- assert p.log_tcp_events == 'disabled'
- assert p.rate_tcp_events == 4294967295
- assert p.log_ip_errors == 'disabled'
- assert p.rate_ip_errors == 4294967295
- assert p.log_tcp_errors == 'disabled'
- assert p.rate_tcp_errors == 4294967295
- assert p.log_acl_match_accept == 'disabled'
- assert p.rate_acl_match_accept == 4294967295
- assert p.log_acl_match_drop == 'disabled'
- assert p.rate_acl_match_drop == 4294967295
- assert p.log_acl_match_reject == 'disabled'
- assert p.rate_acl_match_reject == 4294967295
- assert p.log_format_delimiter == ','
- assert p.log_storage_format == 'none'
-
-
-class TestManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
-
- def test_create(self, *args):
- set_module_args(dict(
- profile_name='foo',
- rate_limit=150000,
- log_publisher='/Common/foobar',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
- mm = ModuleManager(module=module)
-
- # Override methods to force specific logic in the module to happen
- mm.exists = Mock(side_effect=[False, True])
- mm.create_on_device = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['rate_limit'] == 150000
- assert results['log_publisher'] == '/Common/foobar'
diff --git a/test/units/modules/network/f5/test_bigip_firewall_policy.py b/test/units/modules/network/f5/test_bigip_firewall_policy.py
deleted file mode 100644
index a5742bc81f..0000000000
--- a/test/units/modules/network/f5/test_bigip_firewall_policy.py
+++ /dev/null
@@ -1,119 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_firewall_policy import ApiParameters
- from library.modules.bigip_firewall_policy import ModuleParameters
- from library.modules.bigip_firewall_policy import ModuleManager
- from library.modules.bigip_firewall_policy import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_firewall_policy import ApiParameters
- from ansible.modules.network.f5.bigip_firewall_policy import ModuleParameters
- from ansible.modules.network.f5.bigip_firewall_policy import ModuleManager
- from ansible.modules.network.f5.bigip_firewall_policy import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- name='foo',
- description='my description',
- rules=['rule1', 'rule2', 'rule3']
- )
-
- p = ModuleParameters(params=args)
- assert p.name == 'foo'
- assert p.description == 'my description'
- assert p.rules == ['rule1', 'rule2', 'rule3']
-
- def test_api_parameters(self):
- args = load_fixture('load_security_firewall_policy_1.json')
-
- p = ApiParameters(params=args)
- assert p.name == 'foo'
- assert p.description == 'my description'
- assert p.rules == ['rule1', 'rule2', 'rule3']
-
-
-class TestManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
-
- def test_create(self, *args):
- set_module_args(dict(
- name='foo',
- description='this is a description',
- rules=['rule1', 'rule2', 'rule3'],
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
- mm = ModuleManager(module=module)
-
- # Override methods to force specific logic in the module to happen
- mm.exists = Mock(side_effect=[False, True])
- mm.create_on_device = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert 'rules' in results
- assert len(results['rules']) == 3
- assert results['description'] == 'this is a description'
diff --git a/test/units/modules/network/f5/test_bigip_firewall_port_list.py b/test/units/modules/network/f5/test_bigip_firewall_port_list.py
deleted file mode 100644
index 17547815c5..0000000000
--- a/test/units/modules/network/f5/test_bigip_firewall_port_list.py
+++ /dev/null
@@ -1,147 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_firewall_port_list import ApiParameters
- from library.modules.bigip_firewall_port_list import ModuleParameters
- from library.modules.bigip_firewall_port_list import ModuleManager
- from library.modules.bigip_firewall_port_list import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
- from test.units.compat.mock import patch
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_firewall_port_list import ApiParameters
- from ansible.modules.network.f5.bigip_firewall_port_list import ModuleParameters
- from ansible.modules.network.f5.bigip_firewall_port_list import ModuleManager
- from ansible.modules.network.f5.bigip_firewall_port_list import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
- from units.compat.mock import patch
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- name='foo',
- description='this is a description',
- ports=[1, 2, 3, 4],
- port_ranges=['10-20', '30-40', '50-60'],
- port_lists=['/Common/foo', 'foo']
- )
-
- p = ModuleParameters(params=args)
- assert p.name == 'foo'
- assert p.description == 'this is a description'
- assert len(p.ports) == 4
- assert len(p.port_ranges) == 3
- assert len(p.port_lists) == 2
-
- def test_api_parameters(self):
- args = load_fixture('load_security_port_list_1.json')
-
- p = ApiParameters(params=args)
- assert len(p.ports) == 4
- assert len(p.port_ranges) == 3
- assert len(p.port_lists) == 1
- assert sorted(p.ports) == [1, 2, 3, 4]
- assert sorted(p.port_ranges) == ['10-20', '30-40', '50-60']
- assert p.port_lists[0] == '/Common/_sys_self_allow_tcp_defaults'
-
-
-class TestManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
-
- try:
- self.p1 = patch('library.modules.bigip_firewall_port_list.module_provisioned')
- self.m1 = self.p1.start()
- self.m1.return_value = True
- except Exception:
- self.p1 = patch('ansible.modules.network.f5.bigip_firewall_port_list.module_provisioned')
- self.m1 = self.p1.start()
- self.m1.return_value = True
-
- def tearDown(self):
- self.p1.stop()
-
- def test_create(self, *args):
- set_module_args(dict(
- name='foo',
- description='this is a description',
- ports=[1, 2, 3, 4],
- port_ranges=['10-20', '30-40', '50-60'],
- port_lists=['/Common/foo', 'foo'],
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
- mm = ModuleManager(module=module)
-
- # Override methods to force specific logic in the module to happen
- mm.exists = Mock(side_effect=[False, True])
- mm.create_on_device = Mock(return_value=True)
- mm.module_provisioned = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert 'ports' in results
- assert 'port_lists' in results
- assert 'port_ranges' in results
- assert len(results['ports']) == 4
- assert len(results['port_ranges']) == 3
- assert len(results['port_lists']) == 2
- assert results['description'] == 'this is a description'
diff --git a/test/units/modules/network/f5/test_bigip_firewall_rule.py b/test/units/modules/network/f5/test_bigip_firewall_rule.py
deleted file mode 100644
index 39d45ab178..0000000000
--- a/test/units/modules/network/f5/test_bigip_firewall_rule.py
+++ /dev/null
@@ -1,156 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2018, F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_firewall_rule import ModuleParameters
- from library.modules.bigip_firewall_rule import ModuleManager
- from library.modules.bigip_firewall_rule import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_firewall_rule import ModuleParameters
- from ansible.modules.network.f5.bigip_firewall_rule import ModuleManager
- from ansible.modules.network.f5.bigip_firewall_rule import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- name='foo',
- parent_policy='policy1',
- protocol='tcp',
- source=[
- dict(address='1.2.3.4'),
- dict(address='::1'),
- dict(address_list='foo-list1'),
- dict(address_range='1.1.1.1-2.2.2.2.'),
- dict(vlan='vlan1'),
- dict(country='US'),
- dict(port='22'),
- dict(port_list='port-list1'),
- dict(port_range='80-443'),
- ],
- destination=[
- dict(address='1.2.3.4'),
- dict(address='::1'),
- dict(address_list='foo-list1'),
- dict(address_range='1.1.1.1-2.2.2.2.'),
- dict(country='US'),
- dict(port='22'),
- dict(port_list='port-list1'),
- dict(port_range='80-443'),
- ],
- irule='irule1',
- action='accept',
- logging=True,
- )
-
- p = ModuleParameters(params=args)
- assert p.irule == '/Common/irule1'
- assert p.action == 'accept'
- assert p.logging is True
-
-
-class TestManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
-
- def test_create_monitor(self, *args):
- set_module_args(dict(
- name='foo',
- parent_policy='policy1',
- protocol='tcp',
- source=[
- dict(address='1.2.3.4'),
- dict(address='::1'),
- dict(address_list='foo-list1'),
- dict(address_range='1.1.1.1-2.2.2.2.'),
- dict(vlan='vlan1'),
- dict(country='US'),
- dict(port='22'),
- dict(port_list='port-list1'),
- dict(port_range='80-443'),
- ],
- destination=[
- dict(address='1.2.3.4'),
- dict(address='::1'),
- dict(address_list='foo-list1'),
- dict(address_range='1.1.1.1-2.2.2.2.'),
- dict(country='US'),
- dict(port='22'),
- dict(port_list='port-list1'),
- dict(port_range='80-443'),
- ],
- irule='irule1',
- action='accept',
- logging='yes',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- mutually_exclusive=self.spec.mutually_exclusive,
- required_one_of=self.spec.required_one_of
- )
-
- # Override methods in the specific type of manager
- mm = ModuleManager(module=module)
- mm.exists = Mock(side_effect=[False, True])
- mm.create_on_device = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
diff --git a/test/units/modules/network/f5/test_bigip_firewall_rule_list.py b/test/units/modules/network/f5/test_bigip_firewall_rule_list.py
deleted file mode 100644
index 4c6b2d9a34..0000000000
--- a/test/units/modules/network/f5/test_bigip_firewall_rule_list.py
+++ /dev/null
@@ -1,109 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_firewall_rule_list import ModuleParameters
- from library.modules.bigip_firewall_rule_list import ModuleManager
- from library.modules.bigip_firewall_rule_list import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_firewall_rule_list import ModuleParameters
- from ansible.modules.network.f5.bigip_firewall_rule_list import ModuleManager
- from ansible.modules.network.f5.bigip_firewall_rule_list import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- name='foo',
- description='my description',
- rules=['rule1', 'rule2', 'rule3']
- )
-
- p = ModuleParameters(params=args)
- assert p.name == 'foo'
- assert p.description == 'my description'
- assert p.rules == ['rule1', 'rule2', 'rule3']
-
-
-class TestManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
-
- def test_create(self, *args):
- set_module_args(dict(
- name='foo',
- description='this is a description',
- rules=['rule1', 'rule2', 'rule3'],
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
- mm = ModuleManager(module=module)
-
- # Override methods to force specific logic in the module to happen
- mm.exists = Mock(side_effect=[False, True])
- mm.create_on_device = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert 'rules' in results
- assert len(results['rules']) == 3
- assert results['description'] == 'this is a description'
diff --git a/test/units/modules/network/f5/test_bigip_firewall_schedule.py b/test/units/modules/network/f5/test_bigip_firewall_schedule.py
deleted file mode 100644
index 35ff7ab508..0000000000
--- a/test/units/modules/network/f5/test_bigip_firewall_schedule.py
+++ /dev/null
@@ -1,128 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2019, F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_firewall_schedule import ApiParameters
- from library.modules.bigip_firewall_schedule import ModuleParameters
- from library.modules.bigip_firewall_schedule import ModuleManager
- from library.modules.bigip_firewall_schedule import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_firewall_schedule import ApiParameters
- from ansible.modules.network.f5.bigip_firewall_schedule import ModuleParameters
- from ansible.modules.network.f5.bigip_firewall_schedule import ModuleManager
- from ansible.modules.network.f5.bigip_firewall_schedule import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- name='foo',
- description='my description',
- daily_hour_end='21:00',
- daily_hour_start='11:00',
- date_valid_end='2019-03-11:15:30:00',
- date_valid_start='2019-03-01:15:30:00',
- days_of_week='all',
- )
- p = ModuleParameters(params=args)
-
- assert p.name == 'foo'
- assert p.description == 'my description'
- assert p.daily_hour_end == '21:00'
- assert p.daily_hour_start == '11:00'
- assert p.date_valid_end == '2019-03-11T15:30:00Z'
- assert p.date_valid_start == '2019-03-01T15:30:00Z'
- assert 'monday' in p.days_of_week
-
- def test_api_parameters(self):
- args = load_fixture('load_afm_schedule.json')
-
- p = ApiParameters(params=args)
- assert p.name == 'foobar'
- assert p.description == 'some description'
- assert p.daily_hour_end == '12:00'
- assert p.daily_hour_start == '6:00'
- assert p.date_valid_end == '2019-06-13T16:00:00Z'
- assert p.date_valid_start == '2019-05-31T07:00:00Z'
- assert 'sunday' in p.days_of_week
-
-
-class TestManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
-
- def test_create(self, *args):
- set_module_args(dict(
- name='foo',
- description='this is a description',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
- mm = ModuleManager(module=module)
-
- # Override methods to force specific logic in the module to happen
- mm.exists = Mock(side_effect=[False, True])
- mm.create_on_device = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['description'] == 'this is a description'
diff --git a/test/units/modules/network/f5/test_bigip_gtm_datacenter.py b/test/units/modules/network/f5/test_bigip_gtm_datacenter.py
deleted file mode 100644
index 5352c5ec15..0000000000
--- a/test/units/modules/network/f5/test_bigip_gtm_datacenter.py
+++ /dev/null
@@ -1,245 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright (c) 2017 F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_gtm_datacenter import ApiParameters
- from library.modules.bigip_gtm_datacenter import ModuleParameters
- from library.modules.bigip_gtm_datacenter import ModuleManager
- from library.modules.bigip_gtm_datacenter import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
- from test.units.compat.mock import patch
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_gtm_datacenter import ApiParameters
- from ansible.modules.network.f5.bigip_gtm_datacenter import ModuleParameters
- from ansible.modules.network.f5.bigip_gtm_datacenter import ModuleManager
- from ansible.modules.network.f5.bigip_gtm_datacenter import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
- from units.compat.mock import patch
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- state='present',
- contact='foo',
- description='bar',
- location='baz',
- name='datacenter'
- )
- p = ModuleParameters(params=args)
- assert p.state == 'present'
-
- def test_api_parameters(self):
- args = load_fixture('load_gtm_datacenter_default.json')
- p = ApiParameters(params=args)
- assert p.name == 'asd'
-
- def test_module_parameters_state_present(self):
- args = dict(
- state='present'
- )
- p = ModuleParameters(params=args)
- assert p.state == 'present'
- assert p.enabled is True
-
- def test_module_parameters_state_absent(self):
- args = dict(
- state='absent'
- )
- p = ModuleParameters(params=args)
- assert p.state == 'absent'
-
- def test_module_parameters_state_enabled(self):
- args = dict(
- state='enabled'
- )
- p = ModuleParameters(params=args)
- assert p.state == 'enabled'
- assert p.enabled is True
- assert p.disabled is None
-
- def test_module_parameters_state_disabled(self):
- args = dict(
- state='disabled'
- )
- p = ModuleParameters(params=args)
- assert p.state == 'disabled'
- assert p.enabled is None
- assert p.disabled is True
-
-
-class TestManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
-
- try:
- self.p1 = patch('library.modules.bigip_gtm_datacenter.module_provisioned')
- self.m1 = self.p1.start()
- self.m1.return_value = True
- except Exception:
- self.p1 = patch('ansible.modules.network.f5.bigip_gtm_datacenter.module_provisioned')
- self.m1 = self.p1.start()
- self.m1.return_value = True
-
- def tearDown(self):
- self.p1.stop()
-
- def test_create_datacenter(self, *args):
- set_module_args(dict(
- name='foo',
- state='present',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
- mm = ModuleManager(module=module)
-
- # Override methods to force specific logic in the module to happen
- mm.exists = Mock(side_effect=[False, True])
- mm.create_on_device = Mock(return_value=True)
- mm.module_provisioned = Mock(return_value=True)
-
- results = mm.exec_module()
- assert results['changed'] is True
- assert results['state'] == 'present'
-
- def test_create_disabled_datacenter(self, *args):
- set_module_args(dict(
- name='foo',
- state='disabled',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
-
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
- mm = ModuleManager(module=module)
-
- # Override methods to force specific logic in the module to happen
- mm.exists = Mock(side_effect=[False, True])
- mm.create_on_device = Mock(return_value=True)
- mm.module_provisioned = Mock(return_value=True)
-
- results = mm.exec_module()
- assert results['changed'] is True
- assert results['enabled'] is False
- assert results['disabled'] is True
-
- def test_create_enabled_datacenter(self, *args):
- set_module_args(dict(
- name='foo',
- state='enabled',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
-
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
- mm = ModuleManager(module=module)
-
- # Override methods to force specific logic in the module to happen
- mm.exists = Mock(side_effect=[False, True])
- mm.create_on_device = Mock(return_value=True)
- mm.module_provisioned = Mock(return_value=True)
-
- results = mm.exec_module()
- assert results['changed'] is True
- assert results['enabled'] is True
- assert results['disabled'] is False
-
- def test_idempotent_disable_datacenter(self, *args):
- set_module_args(dict(
- name='foo',
- state='disabled',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
-
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- current = ApiParameters(params=load_fixture('load_gtm_datacenter_disabled.json'))
-
- mm = ModuleManager(module=module)
-
- # Override methods to force specific logic in the module to happen
- mm.exists = Mock(return_value=True)
- mm.update_on_device = Mock(return_value=True)
- mm.read_current_from_device = Mock(return_value=current)
- mm.module_provisioned = Mock(return_value=True)
-
- results = mm.exec_module()
- assert results['changed'] is False
diff --git a/test/units/modules/network/f5/test_bigip_gtm_global.py b/test/units/modules/network/f5/test_bigip_gtm_global.py
deleted file mode 100644
index e80347e364..0000000000
--- a/test/units/modules/network/f5/test_bigip_gtm_global.py
+++ /dev/null
@@ -1,120 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_gtm_global import ApiParameters
- from library.modules.bigip_gtm_global import ModuleParameters
- from library.modules.bigip_gtm_global import ModuleManager
- from library.modules.bigip_gtm_global import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_gtm_global import ApiParameters
- from ansible.modules.network.f5.bigip_gtm_global import ModuleParameters
- from ansible.modules.network.f5.bigip_gtm_global import ModuleManager
- from ansible.modules.network.f5.bigip_gtm_global import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- synchronization=True,
- synchronization_group_name='foo',
- synchronize_zone_files=True
- )
-
- p = ModuleParameters(params=args)
- assert p.synchronization is True
- assert p.synchronization_group_name == 'foo'
- assert p.synchronize_zone_files is True
-
- def test_api_parameters(self):
- args = load_fixture('load_gtm_global_settings_general_1.json')
-
- p = ApiParameters(params=args)
- assert p.synchronization is False
- assert p.synchronization_group_name == 'default'
- assert p.synchronize_zone_files is False
-
-
-class TestManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
-
- def update(self, *args):
- set_module_args(dict(
- synchronization="yes",
- synchronization_group_name='foo',
- synchronize_zone_files="yes",
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- current = ApiParameters(params=load_fixture('load_gtm_global_settings_general_1.json'))
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods in the specific type of manager
- mm = ModuleManager(module=module)
- mm.update_on_device = Mock(return_value=True)
- mm.read_current_from_device = Mock(return_value=current)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['synchronization'] == 'yes'
- assert results['synchronization_group_name'] == 'foo'
- assert results['synchronize_zone_files'] == 'yes'
diff --git a/test/units/modules/network/f5/test_bigip_gtm_monitor_bigip.py b/test/units/modules/network/f5/test_bigip_gtm_monitor_bigip.py
deleted file mode 100644
index 08b5e838c7..0000000000
--- a/test/units/modules/network/f5/test_bigip_gtm_monitor_bigip.py
+++ /dev/null
@@ -1,179 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_gtm_monitor_bigip import ApiParameters
- from library.modules.bigip_gtm_monitor_bigip import ModuleParameters
- from library.modules.bigip_gtm_monitor_bigip import ModuleManager
- from library.modules.bigip_gtm_monitor_bigip import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
- from test.units.compat.mock import patch
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_gtm_monitor_bigip import ApiParameters
- from ansible.modules.network.f5.bigip_gtm_monitor_bigip import ModuleParameters
- from ansible.modules.network.f5.bigip_gtm_monitor_bigip import ModuleManager
- from ansible.modules.network.f5.bigip_gtm_monitor_bigip import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
- from units.compat.mock import patch
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- name='foo',
- parent='parent',
- ip='10.10.10.10',
- port=80,
- interval=20,
- timeout=30,
- aggregate_dynamic_ratios='average-members',
- partition='Common'
- )
-
- p = ModuleParameters(params=args)
- assert p.name == 'foo'
- assert p.parent == '/Common/parent'
- assert p.ip == '10.10.10.10'
- assert p.port == 80
- assert p.type == 'bigip'
- assert p.destination == '10.10.10.10:80'
- assert p.interval == 20
- assert p.timeout == 30
- assert p.aggregate_dynamic_ratios == 'average-members'
-
- def test_module_parameters_ints_as_strings(self):
- args = dict(
- name='foo',
- parent='parent',
- ip='10.10.10.10',
- port='80',
- interval='20',
- timeout='30',
- partition='Common'
- )
-
- p = ModuleParameters(params=args)
- assert p.name == 'foo'
- assert p.parent == '/Common/parent'
- assert p.ip == '10.10.10.10'
- assert p.port == 80
- assert p.type == 'bigip'
- assert p.destination == '10.10.10.10:80'
- assert p.interval == 20
- assert p.timeout == 30
-
- def test_api_parameters(self):
- args = dict(
- name='foo',
- defaultsFrom='/Common/parent',
- destination='10.10.10.10:80',
- interval=20,
- timeout=30,
- ignoreDownResponse='disabled',
- aggregateDynamicRatios='none',
- )
-
- p = ApiParameters(params=args)
- assert p.name == 'foo'
- assert p.parent == '/Common/parent'
- assert p.ip == '10.10.10.10'
- assert p.port == 80
- assert p.type == 'bigip'
- assert p.destination == '10.10.10.10:80'
- assert p.interval == 20
- assert p.timeout == 30
- assert p.aggregate_dynamic_ratios == 'none'
-
-
-class TestManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
-
- try:
- self.p1 = patch('library.modules.bigip_gtm_monitor_bigip.module_provisioned')
- self.m1 = self.p1.start()
- self.m1.return_value = True
- except Exception:
- self.p1 = patch('ansible.modules.network.f5.bigip_gtm_monitor_bigip.module_provisioned')
- self.m1 = self.p1.start()
- self.m1.return_value = True
-
- def tearDown(self):
- self.p1.stop()
-
- def test_create_monitor(self, *args):
- set_module_args(dict(
- name='foo',
- ip='10.10.10.10',
- port=80,
- interval=20,
- timeout=30,
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods in the specific type of manager
- mm = ModuleManager(module=module)
- mm.exists = Mock(side_effect=[False, True])
- mm.create_on_device = Mock(return_value=True)
- mm.module_provisioned = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
diff --git a/test/units/modules/network/f5/test_bigip_gtm_monitor_external.py b/test/units/modules/network/f5/test_bigip_gtm_monitor_external.py
deleted file mode 100644
index bc647057f6..0000000000
--- a/test/units/modules/network/f5/test_bigip_gtm_monitor_external.py
+++ /dev/null
@@ -1,135 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_gtm_monitor_external import ModuleParameters
- from library.modules.bigip_gtm_monitor_external import ModuleManager
- from library.modules.bigip_gtm_monitor_external import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
- from test.units.compat.mock import patch
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_gtm_monitor_external import ModuleParameters
- from ansible.modules.network.f5.bigip_gtm_monitor_external import ModuleManager
- from ansible.modules.network.f5.bigip_gtm_monitor_external import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
- from units.compat.mock import patch
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- name='foo',
- parent='parent',
- ip='10.10.10.10',
- port=80,
- interval=20,
- timeout=30,
- partition='Common'
- )
-
- p = ModuleParameters(params=args)
- assert p.name == 'foo'
- assert p.parent == '/Common/parent'
- assert p.ip == '10.10.10.10'
- assert p.type == 'external'
- assert p.port == 80
- assert p.destination == '10.10.10.10:80'
- assert p.interval == 20
- assert p.timeout == 30
-
-
-class TestManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
-
- try:
- self.p1 = patch('library.modules.bigip_gtm_monitor_external.module_provisioned')
- self.m1 = self.p1.start()
- self.m1.return_value = True
- except Exception:
- self.p1 = patch('ansible.modules.network.f5.bigip_gtm_monitor_external.module_provisioned')
- self.m1 = self.p1.start()
- self.m1.return_value = True
-
- def tearDown(self):
- self.p1.stop()
-
- def test_create_monitor(self, *args):
- set_module_args(dict(
- name='foo',
- parent='parent',
- ip='10.10.10.10',
- port=80,
- interval=20,
- timeout=30,
- partition='Common',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods in the specific type of manager
- mm = ModuleManager(module=module)
- mm.exists = Mock(side_effect=[False, True])
- mm.create_on_device = Mock(return_value=True)
- mm.module_provisioned = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['parent'] == '/Common/parent'
diff --git a/test/units/modules/network/f5/test_bigip_gtm_monitor_firepass.py b/test/units/modules/network/f5/test_bigip_gtm_monitor_firepass.py
deleted file mode 100644
index b0cad64b5b..0000000000
--- a/test/units/modules/network/f5/test_bigip_gtm_monitor_firepass.py
+++ /dev/null
@@ -1,156 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_gtm_monitor_firepass import ApiParameters
- from library.modules.bigip_gtm_monitor_firepass import ModuleParameters
- from library.modules.bigip_gtm_monitor_firepass import ModuleManager
- from library.modules.bigip_gtm_monitor_firepass import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
- from test.units.compat.mock import patch
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_gtm_monitor_firepass import ApiParameters
- from ansible.modules.network.f5.bigip_gtm_monitor_firepass import ModuleParameters
- from ansible.modules.network.f5.bigip_gtm_monitor_firepass import ModuleManager
- from ansible.modules.network.f5.bigip_gtm_monitor_firepass import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
- from units.compat.mock import patch
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- name='foo',
- parent='/Common/my-http',
- max_load_average='60',
- concurrency_limit='70',
- ip='1.1.1.1',
- port='80',
- interval='10',
- timeout='20',
- ignore_down_response=True,
- probe_timeout='30'
- )
-
- p = ModuleParameters(params=args)
- assert p.name == 'foo'
- assert p.parent == '/Common/my-http'
- assert p.max_load_average == 60
- assert p.concurrency_limit == 70
- assert p.destination == '1.1.1.1:80'
- assert p.ip == '1.1.1.1'
- assert p.port == 80
- assert p.interval == 10
- assert p.timeout == 20
- assert p.ignore_down_response is True
- assert p.probe_timeout == 30
-
- def test_api_parameters(self):
- args = load_fixture('load_gtm_monitor_firepass_1.json')
-
- p = ApiParameters(params=args)
- assert p.name == 'foo'
- assert p.parent == '/Common/firepass_gtm'
- assert p.max_load_average == 12
- assert p.concurrency_limit == 95
- assert p.destination == '1.1.1.1:80'
- assert p.ip == '1.1.1.1'
- assert p.port == 80
- assert p.interval == 30
- assert p.timeout == 90
- assert p.ignore_down_response is True
- assert p.probe_timeout == 5
-
-
-class TestManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
-
- try:
- self.p1 = patch('library.modules.bigip_gtm_monitor_firepass.module_provisioned')
- self.m1 = self.p1.start()
- self.m1.return_value = True
- except Exception:
- self.p1 = patch('ansible.modules.network.f5.bigip_gtm_monitor_firepass.module_provisioned')
- self.m1 = self.p1.start()
- self.m1.return_value = True
-
- def tearDown(self):
- self.p1.stop()
-
- def test_create_monitor(self, *args):
- set_module_args(dict(
- name='foo',
- ip='10.10.10.10',
- port=80,
- interval=20,
- timeout=30,
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods in the specific type of manager
- mm = ModuleManager(module=module)
- mm.exists = Mock(side_effect=[False, True])
- mm.create_on_device = Mock(return_value=True)
- mm.module_provisioned = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
diff --git a/test/units/modules/network/f5/test_bigip_gtm_monitor_http.py b/test/units/modules/network/f5/test_bigip_gtm_monitor_http.py
deleted file mode 100644
index 5e66fa31e3..0000000000
--- a/test/units/modules/network/f5/test_bigip_gtm_monitor_http.py
+++ /dev/null
@@ -1,162 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_gtm_monitor_http import ApiParameters
- from library.modules.bigip_gtm_monitor_http import ModuleParameters
- from library.modules.bigip_gtm_monitor_http import ModuleManager
- from library.modules.bigip_gtm_monitor_http import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
- from test.units.compat.mock import patch
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_gtm_monitor_http import ApiParameters
- from ansible.modules.network.f5.bigip_gtm_monitor_http import ModuleParameters
- from ansible.modules.network.f5.bigip_gtm_monitor_http import ModuleManager
- from ansible.modules.network.f5.bigip_gtm_monitor_http import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
- from units.compat.mock import patch
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- name='foo',
- parent='/Common/my-http',
- send='the send string',
- receive='the receive string',
- ip='1.1.1.1',
- port='80',
- interval='10',
- timeout='20',
- ignore_down_response=True,
- transparent=False,
- probe_timeout='30',
- reverse=True
- )
-
- p = ModuleParameters(params=args)
- assert p.name == 'foo'
- assert p.parent == '/Common/my-http'
- assert p.send == 'the send string'
- assert p.receive == 'the receive string'
- assert p.destination == '1.1.1.1:80'
- assert p.ip == '1.1.1.1'
- assert p.port == 80
- assert p.interval == 10
- assert p.timeout == 20
- assert p.ignore_down_response is True
- assert p.transparent is False
- assert p.probe_timeout == 30
- assert p.reverse is True
-
- def test_api_parameters(self):
- args = load_fixture('load_gtm_monitor_http_1.json')
-
- p = ApiParameters(params=args)
- assert p.name == 'foo'
- assert p.parent == '/Common/http'
- assert p.send == 'GET /'
- assert p.receive == 'the receive string'
- assert p.destination == '3.3.3.3:8080'
- assert p.ip == '3.3.3.3'
- assert p.port == 8080
- assert p.interval == 30
- assert p.timeout == 120
- assert p.ignore_down_response is False
- assert p.transparent is True
- assert p.probe_timeout == 5
- assert p.reverse is True
-
-
-class TestManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
-
- try:
- self.p1 = patch('library.modules.bigip_gtm_monitor_http.module_provisioned')
- self.m1 = self.p1.start()
- self.m1.return_value = True
- except Exception:
- self.p1 = patch('ansible.modules.network.f5.bigip_gtm_monitor_http.module_provisioned')
- self.m1 = self.p1.start()
- self.m1.return_value = True
-
- def tearDown(self):
- self.p1.stop()
-
- def test_create_monitor(self, *args):
- set_module_args(dict(
- name='foo',
- ip='10.10.10.10',
- port=80,
- interval=20,
- timeout=30,
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods in the specific type of manager
- mm = ModuleManager(module=module)
- mm.exists = Mock(side_effect=[False, True])
- mm.create_on_device = Mock(return_value=True)
- mm.module_provisioned = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
diff --git a/test/units/modules/network/f5/test_bigip_gtm_monitor_https.py b/test/units/modules/network/f5/test_bigip_gtm_monitor_https.py
deleted file mode 100644
index 25d7afd48d..0000000000
--- a/test/units/modules/network/f5/test_bigip_gtm_monitor_https.py
+++ /dev/null
@@ -1,170 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_gtm_monitor_https import ApiParameters
- from library.modules.bigip_gtm_monitor_https import ModuleParameters
- from library.modules.bigip_gtm_monitor_https import ModuleManager
- from library.modules.bigip_gtm_monitor_https import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
- from test.units.compat.mock import patch
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_gtm_monitor_https import ApiParameters
- from ansible.modules.network.f5.bigip_gtm_monitor_https import ModuleParameters
- from ansible.modules.network.f5.bigip_gtm_monitor_https import ModuleManager
- from ansible.modules.network.f5.bigip_gtm_monitor_https import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
- from units.compat.mock import patch
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- name='foo',
- parent='/Common/my-http',
- send='the send string',
- receive='the receive string',
- ip='1.1.1.1',
- port='80',
- interval='10',
- timeout='20',
- client_cert='default',
- client_key='default',
- target_username='user1',
- target_password='secret1',
- ignore_down_response=True,
- transparent=False,
- probe_timeout='30',
- reverse=True
- )
-
- p = ModuleParameters(params=args)
- assert p.name == 'foo'
- assert p.parent == '/Common/my-http'
- assert p.send == 'the send string'
- assert p.receive == 'the receive string'
- assert p.destination == '1.1.1.1:80'
- assert p.ip == '1.1.1.1'
- assert p.port == 80
- assert p.interval == 10
- assert p.timeout == 20
- assert p.client_cert == '/Common/default.crt'
- assert p.client_key == '/Common/default.key'
- assert p.target_username == 'user1'
- assert p.target_password == 'secret1'
- assert p.ignore_down_response is True
- assert p.transparent is False
- assert p.probe_timeout == 30
- assert p.reverse is True
-
- def test_api_parameters(self):
- args = load_fixture('load_gtm_monitor_http_1.json')
-
- p = ApiParameters(params=args)
- assert p.name == 'foo'
- assert p.parent == '/Common/http'
- assert p.send == 'GET /'
- assert p.receive == 'the receive string'
- assert p.destination == '3.3.3.3:8080'
- assert p.ip == '3.3.3.3'
- assert p.port == 8080
- assert p.interval == 30
- assert p.timeout == 120
- assert p.ignore_down_response is False
- assert p.transparent is True
- assert p.probe_timeout == 5
- assert p.reverse is True
-
-
-class TestManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
-
- try:
- self.p1 = patch('library.modules.bigip_gtm_monitor_https.module_provisioned')
- self.m1 = self.p1.start()
- self.m1.return_value = True
- except Exception:
- self.p1 = patch('ansible.modules.network.f5.bigip_gtm_monitor_https.module_provisioned')
- self.m1 = self.p1.start()
- self.m1.return_value = True
-
- def tearDown(self):
- self.p1.stop()
-
- def test_create_monitor(self, *args):
- set_module_args(dict(
- name='foo',
- ip='10.10.10.10',
- port=80,
- interval=20,
- timeout=30,
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods in the specific type of manager
- mm = ModuleManager(module=module)
- mm.exists = Mock(side_effect=[False, True])
- mm.create_on_device = Mock(return_value=True)
- mm.module_provisioned = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
diff --git a/test/units/modules/network/f5/test_bigip_gtm_monitor_tcp.py b/test/units/modules/network/f5/test_bigip_gtm_monitor_tcp.py
deleted file mode 100644
index 89d6c43185..0000000000
--- a/test/units/modules/network/f5/test_bigip_gtm_monitor_tcp.py
+++ /dev/null
@@ -1,223 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_gtm_monitor_tcp import ApiParameters
- from library.modules.bigip_gtm_monitor_tcp import ModuleParameters
- from library.modules.bigip_gtm_monitor_tcp import ModuleManager
- from library.modules.bigip_gtm_monitor_tcp import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
- from test.units.compat.mock import patch
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_gtm_monitor_tcp import ApiParameters
- from ansible.modules.network.f5.bigip_gtm_monitor_tcp import ModuleParameters
- from ansible.modules.network.f5.bigip_gtm_monitor_tcp import ModuleManager
- from ansible.modules.network.f5.bigip_gtm_monitor_tcp import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
- from units.compat.mock import patch
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- name='foo',
- parent='/Common/my-tcp',
- send='the send string',
- receive='the receive string',
- ip='1.1.1.1',
- port='80',
- interval='10',
- timeout='20',
- ignore_down_response=True,
- transparent=False,
- probe_timeout='30',
- reverse=True
- )
-
- p = ModuleParameters(params=args)
- assert p.name == 'foo'
- assert p.parent == '/Common/my-tcp'
- assert p.send == 'the send string'
- assert p.receive == 'the receive string'
- assert p.destination == '1.1.1.1:80'
- assert p.ip == '1.1.1.1'
- assert p.port == 80
- assert p.interval == 10
- assert p.timeout == 20
- assert p.ignore_down_response is True
- assert p.transparent is False
- assert p.probe_timeout == 30
- assert p.reverse is True
-
- def test_api_parameters(self):
- args = load_fixture('load_gtm_monitor_tcp_1.json')
-
- p = ApiParameters(params=args)
- assert p.name == 'foo'
- assert p.parent == '/Common/tcp'
- assert p.send == 'the send string'
- assert p.receive == 'the receive string'
- assert p.destination == '1.1.1.1:80'
- assert p.ip == '1.1.1.1'
- assert p.port == 80
- assert p.interval == 30
- assert p.timeout == 120
- assert p.ignore_down_response is False
- assert p.transparent is True
- assert p.probe_timeout == 5
- assert p.reverse is True
-
-
-class TestManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
-
- try:
- self.p1 = patch('library.modules.bigip_gtm_monitor_tcp.module_provisioned')
- self.m1 = self.p1.start()
- self.m1.return_value = True
- except Exception:
- self.p1 = patch('ansible.modules.network.f5.bigip_gtm_monitor_tcp.module_provisioned')
- self.m1 = self.p1.start()
- self.m1.return_value = True
-
- def tearDown(self):
- self.p1.stop()
-
- def test_create_monitor(self, *args):
- set_module_args(dict(
- name='foo',
- ip='10.10.10.10',
- port=80,
- interval=20,
- timeout=30,
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods in the specific type of manager
- mm = ModuleManager(module=module)
- mm.exists = Mock(side_effect=[False, True])
- mm.create_on_device = Mock(return_value=True)
- mm.module_provisioned = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
-
- def test_change_ip(self, *args):
- set_module_args(dict(
- name='foo',
- ip='10.10.10.10',
- port=80,
- interval=20,
- timeout=30,
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- current = ApiParameters(params=load_fixture('load_gtm_monitor_tcp_1.json'))
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods in the specific type of manager
- mm = ModuleManager(module=module)
- mm.exists = Mock(side_effect=[True, True])
- mm.update_on_device = Mock(return_value=True)
- mm.read_current_from_device = Mock(return_value=current)
- mm.module_provisioned = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['ip'] == '10.10.10.10'
-
- def test_change_ignore_down_response(self, *args):
- set_module_args(dict(
- name='foo',
- ignore_down_response=True,
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- current = ApiParameters(params=load_fixture('load_gtm_monitor_tcp_1.json'))
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods in the specific type of manager
- mm = ModuleManager(module=module)
- mm.exists = Mock(side_effect=[True, True])
- mm.update_on_device = Mock(return_value=True)
- mm.read_current_from_device = Mock(return_value=current)
- mm.module_provisioned = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['ignore_down_response'] is True
diff --git a/test/units/modules/network/f5/test_bigip_gtm_monitor_tcp_half_open.py b/test/units/modules/network/f5/test_bigip_gtm_monitor_tcp_half_open.py
deleted file mode 100644
index b39b9f1b1e..0000000000
--- a/test/units/modules/network/f5/test_bigip_gtm_monitor_tcp_half_open.py
+++ /dev/null
@@ -1,193 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_gtm_monitor_tcp_half_open import ApiParameters
- from library.modules.bigip_gtm_monitor_tcp_half_open import ModuleParameters
- from library.modules.bigip_gtm_monitor_tcp_half_open import ModuleManager
- from library.modules.bigip_gtm_monitor_tcp_half_open import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
- from test.units.compat.mock import patch
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_gtm_monitor_tcp_half_open import ApiParameters
- from ansible.modules.network.f5.bigip_gtm_monitor_tcp_half_open import ModuleParameters
- from ansible.modules.network.f5.bigip_gtm_monitor_tcp_half_open import ModuleManager
- from ansible.modules.network.f5.bigip_gtm_monitor_tcp_half_open import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
- from units.compat.mock import patch
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- name='foo',
- parent='parent',
- ip='10.10.10.10',
- port=80,
- interval=20,
- timeout=30,
- probe_interval=10,
- probe_timeout=20,
- probe_attempts=30,
- partition='Common'
- )
-
- p = ModuleParameters(params=args)
- assert p.name == 'foo'
- assert p.parent == '/Common/parent'
- assert p.ip == '10.10.10.10'
- assert p.port == 80
- assert p.type == 'tcp_half_open'
- assert p.destination == '10.10.10.10:80'
- assert p.interval == 20
- assert p.timeout == 30
- assert p.probe_interval == 10
- assert p.probe_timeout == 20
- assert p.probe_attempts == 30
-
- def test_module_parameters_ints_as_strings(self):
- args = dict(
- name='foo',
- parent='parent',
- ip='10.10.10.10',
- port='80',
- interval='20',
- timeout='30',
- probe_interval='10',
- probe_timeout='20',
- probe_attempts='30',
- partition='Common'
- )
-
- p = ModuleParameters(params=args)
- assert p.name == 'foo'
- assert p.parent == '/Common/parent'
- assert p.ip == '10.10.10.10'
- assert p.port == 80
- assert p.type == 'tcp_half_open'
- assert p.destination == '10.10.10.10:80'
- assert p.interval == 20
- assert p.timeout == 30
- assert p.probe_interval == 10
- assert p.probe_timeout == 20
- assert p.probe_attempts == 30
-
- def test_api_parameters(self):
- args = dict(
- name='foo',
- defaultsFrom='/Common/parent',
- destination='10.10.10.10:80',
- interval=20,
- timeout=30,
- probeInterval=10,
- probeTimeout=20,
- probeAttempts=30,
- ignoreDownResponse='disabled'
- )
-
- p = ApiParameters(params=args)
- assert p.name == 'foo'
- assert p.parent == '/Common/parent'
- assert p.ip == '10.10.10.10'
- assert p.port == 80
- assert p.type == 'tcp_half_open'
- assert p.destination == '10.10.10.10:80'
- assert p.interval == 20
- assert p.timeout == 30
- assert p.probe_interval == 10
- assert p.probe_timeout == 20
- assert p.probe_attempts == 30
-
-
-class TestManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
-
- try:
- self.p1 = patch('library.modules.bigip_gtm_monitor_tcp_half_open.module_provisioned')
- self.m1 = self.p1.start()
- self.m1.return_value = True
- except Exception:
- self.p1 = patch('ansible.modules.network.f5.bigip_gtm_monitor_tcp_half_open.module_provisioned')
- self.m1 = self.p1.start()
- self.m1.return_value = True
-
- def tearDown(self):
- self.p1.stop()
-
- def test_create_monitor(self, *args):
- set_module_args(dict(
- name='foo',
- ip='10.10.10.10',
- port=80,
- interval=20,
- timeout=30,
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods in the specific type of manager
- mm = ModuleManager(module=module)
- mm.exists = Mock(side_effect=[False, True])
- mm.create_on_device = Mock(return_value=True)
- mm.module_provisioned = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
diff --git a/test/units/modules/network/f5/test_bigip_gtm_pool.py b/test/units/modules/network/f5/test_bigip_gtm_pool.py
deleted file mode 100644
index 4f01b0ee9f..0000000000
--- a/test/units/modules/network/f5/test_bigip_gtm_pool.py
+++ /dev/null
@@ -1,385 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright (c) 2017 F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_gtm_pool import ApiParameters
- from library.modules.bigip_gtm_pool import ModuleParameters
- from library.modules.bigip_gtm_pool import ModuleManager
- from library.modules.bigip_gtm_pool import ArgumentSpec
- from library.modules.bigip_gtm_pool import UntypedManager
- from library.modules.bigip_gtm_pool import TypedManager
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
- from test.units.compat.mock import patch
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_gtm_pool import ApiParameters
- from ansible.modules.network.f5.bigip_gtm_pool import ModuleParameters
- from ansible.modules.network.f5.bigip_gtm_pool import ModuleManager
- from ansible.modules.network.f5.bigip_gtm_pool import ArgumentSpec
- from ansible.modules.network.f5.bigip_gtm_pool import UntypedManager
- from ansible.modules.network.f5.bigip_gtm_pool import TypedManager
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
- from units.compat.mock import patch
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- name='foo',
- preferred_lb_method='topology',
- alternate_lb_method='ratio',
- fallback_lb_method='fewest-hops',
- fallback_ip='10.10.10.10',
- type='a'
- )
- p = ModuleParameters(params=args)
- assert p.name == 'foo'
- assert p.preferred_lb_method == 'topology'
- assert p.alternate_lb_method == 'ratio'
- assert p.fallback_lb_method == 'fewest-hops'
- assert p.fallback_ip == '10.10.10.10'
- assert p.type == 'a'
-
- def test_module_parameters_members(self):
- args = dict(
- partition='Common',
- members=[
- dict(
- server='foo',
- virtual_server='bar'
- )
- ]
- )
- p = ModuleParameters(params=args)
- assert len(p.members) == 1
- assert p.members[0] == '/Common/foo:bar'
-
- def test_api_parameters(self):
- args = dict(
- name='foo',
- loadBalancingMode='topology',
- alternateMode='ratio',
- fallbackMode='fewest-hops',
- fallbackIp='10.10.10.10'
- )
- p = ApiParameters(params=args)
- assert p.name == 'foo'
- assert p.preferred_lb_method == 'topology'
- assert p.alternate_lb_method == 'ratio'
- assert p.fallback_lb_method == 'fewest-hops'
- assert p.fallback_ip == '10.10.10.10'
-
- def test_api_parameters_members(self):
- args = load_fixture('load_gtm_pool_a_with_members_1.json')
- p = ApiParameters(params=args)
- assert len(p.members) == 3
- assert p.members[0] == '/Common/server1:vs1'
- assert p.members[1] == '/Common/server1:vs2'
- assert p.members[2] == '/Common/server1:vs3'
-
-
-class TestUntypedManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
-
- try:
- self.p1 = patch('library.modules.bigip_gtm_pool.module_provisioned')
- self.m1 = self.p1.start()
- self.m1.return_value = True
- except Exception:
- self.p1 = patch('ansible.modules.network.f5.bigip_gtm_pool.module_provisioned')
- self.m1 = self.p1.start()
- self.m1.return_value = True
-
- def tearDown(self):
- self.p1.stop()
-
- def test_create_pool(self, *args):
- set_module_args(dict(
- name='foo',
- preferred_lb_method='round-robin',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- required_if=self.spec.required_if
- )
-
- # Override methods in the specific type of manager
- tm = UntypedManager(module=module)
- tm.exists = Mock(side_effect=[False, True])
- tm.create_on_device = Mock(return_value=True)
- tm.version_is_less_than_12 = Mock(return_value=True)
-
- # Override methods to force specific logic in the module to happen
- mm = ModuleManager(module=module)
- mm.version_is_less_than_12 = Mock(return_value=True)
- mm.get_manager = Mock(return_value=tm)
- mm.gtm_provisioned = Mock(return_value=True)
- mm.module_provisioned = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['preferred_lb_method'] == 'round-robin'
-
- def test_update_pool(self, *args):
- set_module_args(dict(
- name='foo',
- preferred_lb_method='topology',
- alternate_lb_method='drop-packet',
- fallback_lb_method='cpu',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- required_if=self.spec.required_if
- )
-
- current = ApiParameters(params=load_fixture('load_gtm_pool_untyped_default.json'))
-
- # Override methods in the specific type of manager
- tm = UntypedManager(module=module)
- tm.exists = Mock(side_effect=[True, True])
- tm.update_on_device = Mock(return_value=True)
- tm.version_is_less_than_12 = Mock(return_value=True)
- tm.read_current_from_device = Mock(return_value=current)
-
- # Override methods to force specific logic in the module to happen
- mm = ModuleManager(module=module)
- mm.version_is_less_than_12 = Mock(return_value=True)
- mm.get_manager = Mock(return_value=tm)
- mm.gtm_provisioned = Mock(return_value=True)
- mm.module_provisioned = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['preferred_lb_method'] == 'topology'
- assert results['alternate_lb_method'] == 'drop-packet'
- assert results['fallback_lb_method'] == 'cpu'
-
- def test_delete_pool(self, *args):
- set_module_args(dict(
- name='foo',
- state='absent',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- required_if=self.spec.required_if
- )
-
- # Override methods in the specific type of manager
- tm = UntypedManager(module=module)
- tm.exists = Mock(side_effect=[True, False])
- tm.version_is_less_than_12 = Mock(return_value=True)
- tm.remove_from_device = Mock(return_value=True)
-
- # Override methods to force specific logic in the module to happen
- mm = ModuleManager(module=module)
- mm.version_is_less_than_12 = Mock(return_value=True)
- mm.get_manager = Mock(return_value=tm)
- mm.gtm_provisioned = Mock(return_value=True)
- mm.module_provisioned = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
-
-
-class TestTypedManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
-
- try:
- self.p1 = patch('library.modules.bigip_gtm_pool.module_provisioned')
- self.m1 = self.p1.start()
- self.m1.return_value = True
- except Exception:
- self.p1 = patch('ansible.modules.network.f5.bigip_gtm_pool.module_provisioned')
- self.m1 = self.p1.start()
- self.m1.return_value = True
-
- def tearDown(self):
- self.p1.stop()
-
- def test_create_pool(self, *args):
- set_module_args(dict(
- name='foo',
- preferred_lb_method='round-robin',
- type='a',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- required_if=self.spec.required_if
- )
-
- # Override methods in the specific type of manager
- tm = TypedManager(module=module)
- tm.exists = Mock(side_effect=[False, True])
- tm.create_on_device = Mock(return_value=True)
- tm.version_is_less_than_12 = Mock(return_value=False)
-
- # Override methods to force specific logic in the module to happen
- mm = ModuleManager(module=module)
- mm.version_is_less_than_12 = Mock(return_value=False)
- mm.get_manager = Mock(return_value=tm)
- mm.gtm_provisioned = Mock(return_value=True)
- mm.module_provisioned = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['preferred_lb_method'] == 'round-robin'
-
- def test_update_pool(self, *args):
- set_module_args(dict(
- name='foo',
- preferred_lb_method='topology',
- alternate_lb_method='drop-packet',
- fallback_lb_method='cpu',
- type='a',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- required_if=self.spec.required_if
- )
-
- current = ApiParameters(params=load_fixture('load_gtm_pool_a_default.json'))
-
- # Override methods in the specific type of manager
- tm = TypedManager(module=module)
- tm.exists = Mock(side_effect=[True, True])
- tm.update_on_device = Mock(return_value=True)
- tm.version_is_less_than_12 = Mock(return_value=False)
- tm.read_current_from_device = Mock(return_value=current)
-
- # Override methods to force specific logic in the module to happen
- mm = ModuleManager(module=module)
- mm.version_is_less_than_12 = Mock(return_value=False)
- mm.get_manager = Mock(return_value=tm)
- mm.gtm_provisioned = Mock(return_value=True)
- mm.module_provisioned = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['preferred_lb_method'] == 'topology'
- assert results['alternate_lb_method'] == 'drop-packet'
- assert results['fallback_lb_method'] == 'cpu'
-
- def test_delete_pool(self, *args):
- set_module_args(dict(
- name='foo',
- type='a',
- state='absent',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- required_if=self.spec.required_if
- )
-
- # Override methods in the specific type of manager
- tm = TypedManager(module=module)
- tm.exists = Mock(side_effect=[True, False])
- tm.version_is_less_than_12 = Mock(return_value=False)
- tm.remove_from_device = Mock(return_value=True)
-
- # Override methods to force specific logic in the module to happen
- mm = ModuleManager(module=module)
- mm.version_is_less_than_12 = Mock(return_value=False)
- mm.get_manager = Mock(return_value=tm)
- mm.gtm_provisioned = Mock(return_value=True)
- mm.module_provisioned = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
diff --git a/test/units/modules/network/f5/test_bigip_gtm_pool_member.py b/test/units/modules/network/f5/test_bigip_gtm_pool_member.py
deleted file mode 100644
index d0cc9819b9..0000000000
--- a/test/units/modules/network/f5/test_bigip_gtm_pool_member.py
+++ /dev/null
@@ -1,219 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_gtm_pool_member import ApiParameters
- from library.modules.bigip_gtm_pool_member import ModuleParameters
- from library.modules.bigip_gtm_pool_member import ModuleManager
- from library.modules.bigip_gtm_pool_member import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
- from test.units.compat.mock import patch
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_gtm_pool_member import ApiParameters
- from ansible.modules.network.f5.bigip_gtm_pool_member import ModuleParameters
- from ansible.modules.network.f5.bigip_gtm_pool_member import ModuleManager
- from ansible.modules.network.f5.bigip_gtm_pool_member import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
- from units.compat.mock import patch
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- pool='pool1',
- server_name='server1',
- virtual_server='vs1',
- type='a',
- state='enabled',
- limits=dict(
- bits_enabled=True,
- packets_enabled=True,
- connections_enabled=True,
- bits_limit=100,
- packets_limit=200,
- connections_limit=300
- ),
- description='foo description',
- ratio=10,
- monitor='tcp',
- member_order=2
- )
-
- p = ModuleParameters(params=args)
- assert p.pool == 'pool1'
- assert p.server_name == 'server1'
- assert p.virtual_server == 'vs1'
- assert p.type == 'a'
- assert p.state == 'enabled'
- assert p.bits_enabled == 'enabled'
- assert p.packets_enabled == 'enabled'
- assert p.connections_enabled == 'enabled'
- assert p.bits_limit == 100
- assert p.packets_limit == 200
- assert p.connections_limit == 300
-
- def test_api_parameters(self):
- args = load_fixture('load_gtm_pool_a_member_1.json')
-
- p = ApiParameters(params=args)
- assert p.ratio == 1
- assert p.monitor == 'default'
- assert p.member_order == 1
- assert p.packets_enabled == 'disabled'
- assert p.packets_limit == 0
- assert p.bits_enabled == 'disabled'
- assert p.bits_limit == 0
- assert p.connections_enabled == 'disabled'
- assert p.connections_limit == 0
-
-
-class TestManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
-
- try:
- self.p1 = patch('library.modules.bigip_gtm_pool_member.module_provisioned')
- self.m1 = self.p1.start()
- self.m1.return_value = True
- except Exception:
- self.p1 = patch('ansible.modules.network.f5.bigip_gtm_pool_member.module_provisioned')
- self.m1 = self.p1.start()
- self.m1.return_value = True
-
- def tearDown(self):
- self.p1.stop()
-
- def test_create_monitor(self, *args):
- set_module_args(dict(
- pool='pool1',
- server_name='server1',
- virtual_server='vs1',
- type='a',
- state='enabled',
- limits=dict(
- bits_enabled='yes',
- packets_enabled='yes',
- connections_enabled='yes',
- bits_limit=100,
- packets_limit=200,
- connections_limit=300
- ),
- description='foo description',
- ratio=10,
- monitor='tcp',
- member_order=2,
- partition='Common',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- mutually_exclusive=self.spec.mutually_exclusive,
- required_one_of=self.spec.required_one_of,
- required_together=self.spec.required_together,
- )
-
- # Override methods in the specific type of manager
- mm = ModuleManager(module=module)
- mm.exists = Mock(side_effect=[False, True])
- mm.create_on_device = Mock(return_value=True)
- mm.module_provisioned = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
-
- def test_create_aggregate_pool_members(self, *args):
- set_module_args(dict(
- pool='fake_pool',
- type='a',
- aggregate=[
- dict(
- server_name='my-name1',
- virtual_server='some-vs2',
- state='present',
- partition='Common',
-
- ),
- dict(
- server_name='my-name1',
- virtual_server='some-vs1',
- state='present',
- partition='Common'
- )
- ],
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- mutually_exclusive=self.spec.mutually_exclusive,
- required_one_of=self.spec.required_one_of,
- required_together=self.spec.required_together,
- )
-
- mm = ModuleManager(module=module)
- mm.create_on_device = Mock(return_value=True)
- mm.exists = Mock(return_value=False)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
diff --git a/test/units/modules/network/f5/test_bigip_gtm_server.py b/test/units/modules/network/f5/test_bigip_gtm_server.py
deleted file mode 100644
index d9dee9c03b..0000000000
--- a/test/units/modules/network/f5/test_bigip_gtm_server.py
+++ /dev/null
@@ -1,341 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright (c) 2017 F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_gtm_server import ApiParameters
- from library.modules.bigip_gtm_server import ModuleParameters
- from library.modules.bigip_gtm_server import ModuleManager
- from library.modules.bigip_gtm_server import V1Manager
- from library.modules.bigip_gtm_server import V2Manager
- from library.modules.bigip_gtm_server import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
- from test.units.compat.mock import patch
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_gtm_server import ApiParameters
- from ansible.modules.network.f5.bigip_gtm_server import ModuleParameters
- from ansible.modules.network.f5.bigip_gtm_server import ModuleManager
- from ansible.modules.network.f5.bigip_gtm_server import V1Manager
- from ansible.modules.network.f5.bigip_gtm_server import V2Manager
- from ansible.modules.network.f5.bigip_gtm_server import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
- from units.compat.mock import patch
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- name='GTM_Server',
- datacenter='New York',
- partition='Common',
- server_type='bigip',
- link_discovery='disabled',
- virtual_server_discovery='disabled',
- devices=[
- dict(
- name='server_1',
- address='1.1.1.1'
- ),
- dict(
- name='server_2',
- address='2.2.2.1',
- translation='192.168.2.1'
- ),
- dict(
- name='server_2',
- address='2.2.2.2'
- ),
- dict(
- name='server_3',
- addresses=[
- dict(
- address='3.3.3.1'
- ),
- dict(
- address='3.3.3.2'
- )
- ]
- ),
- dict(
- name='server_4',
- addresses=[
- dict(
- address='4.4.4.1',
- translation='192.168.14.1'
- ),
- dict(
- address='4.4.4.2'
- )
- ]
- )
- ]
- )
-
- p = ModuleParameters(params=args)
- assert p.name == 'GTM_Server'
- assert p.datacenter == '/Common/New York'
- assert p.server_type == 'bigip'
- assert p.link_discovery == 'disabled'
- assert p.virtual_server_discovery == 'disabled'
-
- def test_api_parameters(self):
- args = load_fixture('load_gtm_server_1.json')
-
- p = ApiParameters(params=args)
- assert p.name == 'baz'
- assert p.datacenter == '/Common/foo'
- assert p.server_type == 'bigip'
- assert p.link_discovery == 'disabled'
- assert p.virtual_server_discovery == 'disabled'
-
-
-class TestV1Manager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
-
- try:
- self.p1 = patch('library.modules.bigip_gtm_server.module_provisioned')
- self.m1 = self.p1.start()
- self.m1.return_value = True
- except Exception:
- self.p1 = patch('ansible.modules.network.f5.bigip_gtm_server.module_provisioned')
- self.m1 = self.p1.start()
- self.m1.return_value = True
-
- try:
- self.p2 = patch('library.modules.bigip_gtm_server.tmos_version')
- self.m2 = self.p2.start()
- self.m2.return_value = '13.0.0'
- except Exception:
- self.p2 = patch('ansible.modules.network.f5.bigip_gtm_server.tmos_version')
- self.m2 = self.p2.start()
- self.m2.return_value = '13.0.0'
-
- def tearDown(self):
- self.p1.stop()
- self.p2.stop()
-
- def test_create(self, *args):
- set_module_args(dict(
- name='GTM_Server',
- datacenter='/Common/New York',
- server_type='bigip',
- link_discovery='disabled',
- virtual_server_discovery='disabled',
- devices=[
- dict(
- name='server_1',
- address='1.1.1.1'
- ),
- dict(
- name='server_2',
- address='2.2.2.1',
- translation='192.168.2.1'
- ),
- dict(
- name='server_2',
- address='2.2.2.2'
- ),
- dict(
- name='server_3',
- addresses=[
- dict(
- address='3.3.3.1'
- ),
- dict(
- address='3.3.3.2'
- )
- ]
- ),
- dict(
- name='server_4',
- addresses=[
- dict(
- address='4.4.4.1',
- translation='192.168.14.1'
- ),
- dict(
- address='4.4.4.2'
- )
- ]
- )
- ],
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- m1 = V1Manager(module=module, params=module.params)
- m1.exists = Mock(side_effect=[False, True])
- m1.create_on_device = Mock(return_value=True)
- m1.client = Mock()
- m1.client.api.tmos_version = '12.0.0'
-
- # Override methods in the specific type of manager
- mm = ModuleManager(module=module)
- mm.get_manager = Mock(return_value=m1)
- mm.version_is_less_than = Mock(return_value=True)
- mm.gtm_provisioned = Mock(return_value=True)
- mm.module_provisioned = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['server_type'] == 'bigip'
-
-
-class TestV2Manager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
-
- try:
- self.p1 = patch('library.modules.bigip_gtm_server.module_provisioned')
- self.m1 = self.p1.start()
- self.m1.return_value = True
- except Exception:
- self.p1 = patch('ansible.modules.network.f5.bigip_gtm_server.module_provisioned')
- self.m1 = self.p1.start()
- self.m1.return_value = True
-
- try:
- self.p2 = patch('library.modules.bigip_gtm_server.tmos_version')
- self.m2 = self.p2.start()
- self.m2.return_value = '13.0.0'
- except Exception:
- self.p2 = patch('ansible.modules.network.f5.bigip_gtm_server.tmos_version')
- self.m2 = self.p2.start()
- self.m2.return_value = '13.0.0'
-
- def tearDown(self):
- self.p1.stop()
- self.p2.stop()
-
- def test_create(self, *args):
- set_module_args(dict(
- name='GTM_Server',
- datacenter='/Common/New York',
- server_type='bigip',
- link_discovery='disabled',
- virtual_server_discovery='disabled',
- devices=[
- dict(
- name='server_1',
- address='1.1.1.1'
- ),
- dict(
- name='server_2',
- address='2.2.2.1',
- translation='192.168.2.1'
- ),
- dict(
- name='server_2',
- address='2.2.2.2'
- ),
- dict(
- name='server_3',
- addresses=[
- dict(
- address='3.3.3.1'
- ),
- dict(
- address='3.3.3.2'
- )
- ]
- ),
- dict(
- name='server_4',
- addresses=[
- dict(
- address='4.4.4.1',
- translation='192.168.14.1'
- ),
- dict(
- address='4.4.4.2'
- )
- ]
- )
- ],
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- m1 = V2Manager(module=module)
- m1.exists = Mock(side_effect=[False, True])
- m1.create_on_device = Mock(return_value=True)
- m1.client = Mock()
- m1.client.api.tmos_version = '13.1.0'
-
- # Override methods in the specific type of manager
- mm = ModuleManager(module=module)
- mm.get_manager = Mock(return_value=m1)
- mm.version_is_less_than = Mock(return_value=False)
- mm.gtm_provisioned = Mock(return_value=True)
- mm.module_provisioned = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['server_type'] == 'bigip'
diff --git a/test/units/modules/network/f5/test_bigip_gtm_topology_record.py b/test/units/modules/network/f5/test_bigip_gtm_topology_record.py
deleted file mode 100644
index 68f5199ca9..0000000000
--- a/test/units/modules/network/f5/test_bigip_gtm_topology_record.py
+++ /dev/null
@@ -1,132 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2018, F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_gtm_topology_record import ApiParameters
- from library.modules.bigip_gtm_topology_record import ModuleParameters
- from library.modules.bigip_gtm_topology_record import ModuleManager
- from library.modules.bigip_gtm_topology_record import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_gtm_topology_record import ApiParameters
- from ansible.modules.network.f5.bigip_gtm_topology_record import ModuleParameters
- from ansible.modules.network.f5.bigip_gtm_topology_record import ModuleManager
- from ansible.modules.network.f5.bigip_gtm_topology_record import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- source=dict(
- subnet='192.168.1.0/24',
- negate=True
- ),
- destination=dict(
- region='Foobar',
- ),
- weight=10
- )
-
- p = ModuleParameters(params=args)
- assert p.name == 'ldns: not subnet 192.168.1.0/24 server: region /Common/Foobar'
- assert p.weight == 10
-
- def test_api_parameters(self):
- args = dict(
- source=dict(
- subnet='192.168.1.0/24',
- negate=True
- ),
- destination=dict(
- region='Foobar',
- ),
- score=10
- )
-
- p = ApiParameters(params=args)
- assert p.weight == 10
-
-
-class TestManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
-
- def test_create_topology_record(self, *args):
- set_module_args(dict(
- source=dict(
- subnet='192.168.1.0/24',
- negate=True
- ),
- destination=dict(
- region='Foobar',
- ),
- weight=10,
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods in the specific type of manager
- mm = ModuleManager(module=module)
- mm.exists = Mock(side_effect=[False, True])
- mm.create_on_device = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
diff --git a/test/units/modules/network/f5/test_bigip_gtm_topology_region.py b/test/units/modules/network/f5/test_bigip_gtm_topology_region.py
deleted file mode 100644
index 629604db84..0000000000
--- a/test/units/modules/network/f5/test_bigip_gtm_topology_region.py
+++ /dev/null
@@ -1,144 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2018, F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_gtm_topology_region import ApiParameters
- from library.modules.bigip_gtm_topology_region import ModuleParameters
- from library.modules.bigip_gtm_topology_region import ModuleManager
- from library.modules.bigip_gtm_topology_region import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_gtm_topology_region import ApiParameters
- from ansible.modules.network.f5.bigip_gtm_topology_region import ModuleParameters
- from ansible.modules.network.f5.bigip_gtm_topology_region import ModuleManager
- from ansible.modules.network.f5.bigip_gtm_topology_region import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- name='foobar',
- region_members=[
- dict(
- country='Poland',
- negate=True
- ),
- dict(
- datacenter='bazcenter'
- )
- ],
- partition='Common'
- )
-
- p = ModuleParameters(params=args)
- assert p.name == 'foobar'
- assert p.partition == 'Common'
- assert p.region_members == ['not country PL', 'datacenter /Common/bazcenter']
-
- def test_api_parameters(self):
- args = dict(
- name='foobar',
- region_members=[
- dict(
- name='not country PL'
- ),
- dict(
- name='datacenter /Common/bazcenter'
- )
- ],
- partition='Common'
- )
-
- p = ApiParameters(params=args)
- assert p.name == 'foobar'
- assert p.partition == 'Common'
- assert p.region_members == ['not country PL', 'datacenter /Common/bazcenter']
-
-
-class TestManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
-
- def test_create_topology_region(self, *args):
- set_module_args(dict(
- name='foobar',
- region_members=[
- dict(
- country='Poland',
- negate=True
- ),
- dict(
- datacenter='bazcenter'
- )
- ],
- partition='Common',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- )
- )
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods in the specific type of manager
- mm = ModuleManager(module=module)
- mm.exists = Mock(return_value=False)
- mm.create_on_device = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
diff --git a/test/units/modules/network/f5/test_bigip_gtm_virtual_server.py b/test/units/modules/network/f5/test_bigip_gtm_virtual_server.py
deleted file mode 100644
index b911a1ad38..0000000000
--- a/test/units/modules/network/f5/test_bigip_gtm_virtual_server.py
+++ /dev/null
@@ -1,178 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_gtm_virtual_server import ApiParameters
- from library.modules.bigip_gtm_virtual_server import ModuleParameters
- from library.modules.bigip_gtm_virtual_server import ModuleManager
- from library.modules.bigip_gtm_virtual_server import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
- from test.units.compat.mock import patch
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_gtm_virtual_server import ApiParameters
- from ansible.modules.network.f5.bigip_gtm_virtual_server import ModuleParameters
- from ansible.modules.network.f5.bigip_gtm_virtual_server import ModuleManager
- from ansible.modules.network.f5.bigip_gtm_virtual_server import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
- from units.compat.mock import patch
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- name='foo',
- server_name='server1',
- address='1.1.1.1',
- port=22,
- translation_address='2.2.2.2',
- translation_port=443,
- availability_requirements=dict(
- type='at_least',
- at_least=2,
- ),
- monitors=['http', 'tcp', 'gtp'],
- virtual_server_dependencies=[
- dict(
- server='server2',
- virtual_server='vs2'
- )
- ],
- link='link1',
- limits=dict(
- bits_enabled=True,
- packets_enabled=True,
- connections_enabled=True,
- bits_limit=100,
- packets_limit=200,
- connections_limit=300
- ),
- state='present'
- )
-
- p = ModuleParameters(params=args)
- assert p.name == 'foo'
- assert p.server_name == 'server1'
- assert p.address == '1.1.1.1'
- assert p.port == 22
- assert p.translation_address == '2.2.2.2'
- assert p.translation_port == 443
- assert p.availability_requirement_type == 'at_least'
- assert p.at_least == 2
- assert p.monitors == 'min 2 of { /Common/http /Common/tcp /Common/gtp }'
- assert len(p.virtual_server_dependencies) == 1
- assert p.link == '/Common/link1'
- assert p.bits_enabled == 'enabled'
- assert p.bits_limit == 100
- assert p.packets_enabled == 'enabled'
- assert p.packets_limit == 200
- assert p.connections_enabled == 'enabled'
- assert p.connections_limit == 300
-
- def test_api_parameters(self):
- args = load_fixture('load_gtm_server_virtual_2.json')
-
- p = ApiParameters(params=args)
- assert p.name == 'vs2'
- assert p.address == '6.6.6.6'
- assert p.port == 8080
- assert p.translation_address == 'none'
- assert p.translation_port == 0
- assert p.availability_requirement_type == 'all'
- assert p.monitors == '/Common/gtp'
- assert p.bits_enabled == 'enabled'
- assert p.bits_limit == 100
- assert p.packets_enabled == 'enabled'
- assert p.packets_limit == 200
- assert p.connections_enabled == 'enabled'
- assert p.connections_limit == 300
-
-
-class TestManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
-
- try:
- self.p1 = patch('library.modules.bigip_gtm_virtual_server.module_provisioned')
- self.m1 = self.p1.start()
- self.m1.return_value = True
- except Exception:
- self.p1 = patch('ansible.modules.network.f5.bigip_gtm_virtual_server.module_provisioned')
- self.m1 = self.p1.start()
- self.m1.return_value = True
-
- def tearDown(self):
- self.p1.stop()
-
- def test_create_datacenter(self, *args):
- set_module_args(dict(
- server_name='foo',
- name='vs1',
- address='1.1.1.1',
- state='present',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
- mm = ModuleManager(module=module)
-
- # Override methods to force specific logic in the module to happen
- mm.exists = Mock(side_effect=[False, True])
- mm.create_on_device = Mock(return_value=True)
-
- results = mm.exec_module()
- assert results['changed'] is True
diff --git a/test/units/modules/network/f5/test_bigip_gtm_wide_ip.py b/test/units/modules/network/f5/test_bigip_gtm_wide_ip.py
deleted file mode 100644
index 020a46262d..0000000000
--- a/test/units/modules/network/f5/test_bigip_gtm_wide_ip.py
+++ /dev/null
@@ -1,351 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright (c) 2017 F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_gtm_wide_ip import ApiParameters
- from library.modules.bigip_gtm_wide_ip import ModuleParameters
- from library.modules.bigip_gtm_wide_ip import ModuleManager
- from library.modules.bigip_gtm_wide_ip import ArgumentSpec
- from library.modules.bigip_gtm_wide_ip import UntypedManager
- from library.modules.bigip_gtm_wide_ip import TypedManager
-
- from library.module_utils.network.f5.common import F5ModuleError
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
- from test.units.compat.mock import patch
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_gtm_wide_ip import ApiParameters
- from ansible.modules.network.f5.bigip_gtm_wide_ip import ModuleParameters
- from ansible.modules.network.f5.bigip_gtm_wide_ip import ModuleManager
- from ansible.modules.network.f5.bigip_gtm_wide_ip import ArgumentSpec
- from ansible.modules.network.f5.bigip_gtm_wide_ip import UntypedManager
- from ansible.modules.network.f5.bigip_gtm_wide_ip import TypedManager
-
- from ansible.module_utils.network.f5.common import F5ModuleError
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
- from units.compat.mock import patch
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- name='foo.baz.bar',
- pool_lb_method='round-robin',
- )
- p = ModuleParameters(params=args)
- assert p.name == 'foo.baz.bar'
- assert p.pool_lb_method == 'round-robin'
-
- def test_module_pools(self):
- args = dict(
- pools=[
- dict(
- name='foo',
- ratio='100'
- )
- ]
- )
- p = ModuleParameters(params=args)
- assert len(p.pools) == 1
-
- def test_api_parameters(self):
- args = dict(
- name='foo.baz.bar',
- poolLbMode='round-robin'
- )
- p = ApiParameters(params=args)
- assert p.name == 'foo.baz.bar'
- assert p.pool_lb_method == 'round-robin'
-
- def test_api_pools(self):
- args = load_fixture('load_gtm_wide_ip_with_pools.json')
- p = ApiParameters(params=args)
- assert len(p.pools) == 1
- assert 'name' in p.pools[0]
- assert 'ratio' in p.pools[0]
- assert p.pools[0]['name'] == '/Common/baz'
- assert p.pools[0]['ratio'] == 10
-
- def test_module_not_fqdn_name(self):
- args = dict(
- name='foo',
- lb_method='round-robin'
- )
- with pytest.raises(F5ModuleError) as excinfo:
- p = ModuleParameters(params=args)
- assert p.name == 'foo'
- assert 'The provided name must be a valid FQDN' in str(excinfo.value)
-
-
-class TestUntypedManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
- try:
- self.p1 = patch('library.modules.bigip_gtm_wide_ip.module_provisioned')
- self.m1 = self.p1.start()
- self.m1.return_value = True
- except Exception:
- self.p1 = patch('ansible.modules.network.f5.bigip_gtm_wide_ip.module_provisioned')
- self.m1 = self.p1.start()
- self.m1.return_value = True
-
- def tearDown(self):
- self.p1.stop()
-
- def test_create_wideip(self, *args):
- set_module_args(dict(
- name='foo.baz.bar',
- lb_method='round-robin',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods in the specific type of manager
- tm = UntypedManager(module=module, params=module.params)
- tm.exists = Mock(return_value=False)
- tm.create_on_device = Mock(return_value=True)
- tm.version_is_less_than_12 = Mock(return_value=True)
-
- # Override methods to force specific logic in the module to happen
- mm = ModuleManager(module=module)
- mm.version_is_less_than_12 = Mock(return_value=True)
- mm.get_manager = Mock(return_value=tm)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['name'] == 'foo.baz.bar'
- assert results['state'] == 'present'
- assert results['lb_method'] == 'round-robin'
-
-
-class TestTypedManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
- try:
- self.p1 = patch('library.modules.bigip_gtm_wide_ip.module_provisioned')
- self.m1 = self.p1.start()
- self.m1.return_value = True
- except Exception:
- self.p1 = patch('ansible.modules.network.f5.bigip_gtm_wide_ip.module_provisioned')
- self.m1 = self.p1.start()
- self.m1.return_value = True
-
- def tearDown(self):
- self.p1.stop()
-
- def test_create_wideip(self, *args):
- set_module_args(dict(
- name='foo.baz.bar',
- lb_method='round-robin',
- type='a',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods in the specific type of manager
- tm = TypedManager(module=module, params=module.params)
- tm.exists = Mock(return_value=False)
- tm.create_on_device = Mock(return_value=True)
- tm.version_is_less_than_12 = Mock(return_value=False)
-
- # Override methods to force specific logic in the module to happen
- mm = ModuleManager(module=module)
- mm.version_is_less_than_12 = Mock(return_value=False)
- mm.get_manager = Mock(return_value=tm)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['name'] == 'foo.baz.bar'
- assert results['state'] == 'present'
- assert results['lb_method'] == 'round-robin'
-
- def test_create_wideip_with_pool(self, *args):
- set_module_args(dict(
- name='foo.baz.bar',
- lb_method='round-robin',
- type='a',
- pools=[
- dict(
- name='foo',
- ratio=10
- )
- ],
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods in the specific type of manager
- tm = TypedManager(module=module, params=module.params)
- tm.exists = Mock(return_value=False)
- tm.create_on_device = Mock(return_value=True)
- tm.version_is_less_than_12 = Mock(return_value=False)
-
- # Override methods to force specific logic in the module to happen
- mm = ModuleManager(module=module)
- mm.version_is_less_than_12 = Mock(return_value=False)
- mm.get_manager = Mock(return_value=tm)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['name'] == 'foo.baz.bar'
- assert results['state'] == 'present'
- assert results['lb_method'] == 'round-robin'
-
- def test_create_wideip_with_pool_idempotent(self, *args):
- set_module_args(dict(
- name='foo.bar.com',
- lb_method='round-robin',
- type='a',
- pools=[
- dict(
- name='baz',
- ratio=10
- )
- ],
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- current = ApiParameters(params=load_fixture('load_gtm_wide_ip_with_pools.json'))
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods in the specific type of manager
- tm = TypedManager(module=module, params=module.params)
- tm.exists = Mock(return_value=True)
- tm.read_current_from_device = Mock(return_value=current)
- tm.version_is_less_than_12 = Mock(return_value=False)
-
- # Override methods to force specific logic in the module to happen
- mm = ModuleManager(module=module)
- mm.version_is_less_than_12 = Mock(return_value=False)
- mm.get_manager = Mock(return_value=tm)
-
- results = mm.exec_module()
-
- assert results['changed'] is False
-
- def test_update_wideip_with_pool(self, *args):
- set_module_args(dict(
- name='foo.bar.com',
- lb_method='round-robin',
- type='a',
- pools=[
- dict(
- name='baz',
- ratio=10
- ),
- dict(
- name='alec',
- ratio=100
- )
- ],
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- current = ApiParameters(params=load_fixture('load_gtm_wide_ip_with_pools.json'))
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods in the specific type of manager
- tm = TypedManager(module=module, params=module.params)
- tm.exists = Mock(return_value=True)
- tm.read_current_from_device = Mock(return_value=current)
- tm.update_on_device = Mock(return_value=True)
- tm.version_is_less_than_12 = Mock(return_value=False)
-
- # Override methods to force specific logic in the module to happen
- mm = ModuleManager(module=module)
- mm.version_is_less_than_12 = Mock(return_value=False)
- mm.get_manager = Mock(return_value=tm)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert 'pools' in results
diff --git a/test/units/modules/network/f5/test_bigip_hostname.py b/test/units/modules/network/f5/test_bigip_hostname.py
deleted file mode 100644
index c625e73884..0000000000
--- a/test/units/modules/network/f5/test_bigip_hostname.py
+++ /dev/null
@@ -1,109 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright (c) 2017 F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_hostname import ApiParameters
- from library.modules.bigip_hostname import ModuleParameters
- from library.modules.bigip_hostname import ModuleManager
- from library.modules.bigip_hostname import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_hostname import ApiParameters
- from ansible.modules.network.f5.bigip_hostname import ModuleParameters
- from ansible.modules.network.f5.bigip_hostname import ModuleManager
- from ansible.modules.network.f5.bigip_hostname import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- hostname='foo.internal.com'
- )
- p = ModuleParameters(params=args)
- assert p.hostname == 'foo.internal.com'
-
-
-class TestManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
-
- def test_update_hostname(self, *args):
- set_module_args(dict(
- hostname='foo2.internal.com',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- # Configure the parameters that would be returned by querying the
- # remote device
- current = ApiParameters(
- params=dict(
- hostname='foo.internal.com'
- )
- )
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods to force specific logic in the module to happen
- mm = ModuleManager(module=module)
- mm.update_on_device = Mock(return_value=True)
- mm.read_current_from_device = Mock(return_value=current)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['hostname'] == 'foo2.internal.com'
diff --git a/test/units/modules/network/f5/test_bigip_iapp_service.py b/test/units/modules/network/f5/test_bigip_iapp_service.py
deleted file mode 100644
index 4b46c7a981..0000000000
--- a/test/units/modules/network/f5/test_bigip_iapp_service.py
+++ /dev/null
@@ -1,376 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright (c) 2017 F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_iapp_service import Parameters
- from library.modules.bigip_iapp_service import ApiParameters
- from library.modules.bigip_iapp_service import ModuleParameters
- from library.modules.bigip_iapp_service import ModuleManager
- from library.modules.bigip_iapp_service import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_iapp_service import Parameters
- from ansible.modules.network.f5.bigip_iapp_service import ApiParameters
- from ansible.modules.network.f5.bigip_iapp_service import ModuleParameters
- from ansible.modules.network.f5.bigip_iapp_service import ModuleManager
- from ansible.modules.network.f5.bigip_iapp_service import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
-
- def test_module_parameters_keys(self):
- args = load_fixture('create_iapp_service_parameters_f5_http.json')
- p = ModuleParameters(params=args)
-
- # Assert the top-level keys
- assert p.name == 'http_example'
- assert p.partition == 'Common'
- assert p.template == '/Common/f5.http'
- assert p.device_group is None
- assert p.inheritedTrafficGroup == 'true'
- assert p.inheritedDevicegroup == 'true'
- assert p.traffic_group == '/Common/traffic-group-local-only'
-
- def test_module_parameters_lists(self):
- args = load_fixture('create_iapp_service_parameters_f5_http.json')
- p = ModuleParameters(params=args)
-
- assert 'lists' in p._values
-
- assert p.lists[0]['name'] == 'irules__irules'
- assert p.lists[0]['encrypted'] == 'no'
- assert len(p.lists[0]['value']) == 1
- assert p.lists[0]['value'][0] == '/Common/lgyft'
-
- assert p.lists[1]['name'] == 'net__client_vlan'
- assert p.lists[1]['encrypted'] == 'no'
- assert len(p.lists[1]['value']) == 1
- assert p.lists[1]['value'][0] == '/Common/net2'
-
- def test_module_parameters_tables(self):
- args = load_fixture('create_iapp_service_parameters_f5_http.json')
- p = ModuleParameters(params=args)
-
- assert 'tables' in p._values
-
- assert 'columnNames' in p.tables[0]
- assert len(p.tables[0]['columnNames']) == 1
- assert p.tables[0]['columnNames'][0] == 'name'
-
- assert 'name' in p.tables[0]
- assert p.tables[0]['name'] == 'pool__hosts'
-
- assert 'rows' in p.tables[0]
- assert len(p.tables[0]['rows']) == 1
- assert 'row' in p.tables[0]['rows'][0]
- assert len(p.tables[0]['rows'][0]['row']) == 1
- assert p.tables[0]['rows'][0]['row'][0] == 'demo.example.com'
-
- assert len(p.tables[1]['rows']) == 2
- assert 'row' in p.tables[0]['rows'][0]
- assert len(p.tables[1]['rows'][0]['row']) == 2
- assert p.tables[1]['rows'][0]['row'][0] == '10.1.1.1'
- assert p.tables[1]['rows'][0]['row'][1] == '0'
- assert p.tables[1]['rows'][1]['row'][0] == '10.1.1.2'
- assert p.tables[1]['rows'][1]['row'][1] == '0'
-
- def test_module_parameters_variables(self):
- args = load_fixture('create_iapp_service_parameters_f5_http.json')
- p = ModuleParameters(params=args)
-
- assert 'variables' in p._values
- assert len(p.variables) == 34
-
- # Assert one configuration value
- assert 'name' in p.variables[0]
- assert 'value' in p.variables[0]
- assert p.variables[0]['name'] == 'afm__dos_security_profile'
- assert p.variables[0]['value'] == '/#do_not_use#'
-
- # Assert a second configuration value
- assert 'name' in p.variables[1]
- assert 'value' in p.variables[1]
- assert p.variables[1]['name'] == 'afm__policy'
- assert p.variables[1]['value'] == '/#do_not_use#'
-
- def test_module_strict_updates_from_top_level(self):
- # Assumes the user did not provide any parameters
-
- args = dict(
- strict_updates=True
- )
- p = ModuleParameters(params=args)
- assert p.strict_updates == 'enabled'
-
- args = dict(
- strict_updates=False
- )
- p = ModuleParameters(params=args)
- assert p.strict_updates == 'disabled'
-
- def test_module_strict_updates_override_from_top_level(self):
- args = dict(
- strict_updates=True,
- parameters=dict(
- strictUpdates='disabled'
- )
- )
- p = ModuleParameters(params=args)
- assert p.strict_updates == 'enabled'
-
- args = dict(
- strict_updates=False,
- parameters=dict(
- strictUpdates='enabled'
- )
- )
- p = ModuleParameters(params=args)
- assert p.strict_updates == 'disabled'
-
- def test_module_strict_updates_only_parameters(self):
- args = dict(
- parameters=dict(
- strictUpdates='disabled'
- )
- )
- p = ModuleParameters(params=args)
- assert p.strict_updates == 'disabled'
-
- args = dict(
- parameters=dict(
- strictUpdates='enabled'
- )
- )
- p = ModuleParameters(params=args)
- assert p.strict_updates == 'enabled'
-
- def test_api_strict_updates_from_top_level(self):
- args = dict(
- strictUpdates='enabled'
- )
- p = ApiParameters(params=args)
- assert p.strict_updates == 'enabled'
-
- args = dict(
- strictUpdates='disabled'
- )
- p = ApiParameters(params=args)
- assert p.strict_updates == 'disabled'
-
- def test_api_parameters_variables(self):
- args = dict(
- variables=[
- dict(
- name="client__http_compression",
- encrypted="no",
- value="/#create_new#"
- )
- ]
- )
- p = ApiParameters(params=args)
- assert p.variables[0]['name'] == 'client__http_compression'
-
- def test_api_parameters_tables(self):
- args = dict(
- tables=[
- {
- "name": "pool__members",
- "columnNames": [
- "addr",
- "port",
- "connection_limit"
- ],
- "rows": [
- {
- "row": [
- "12.12.12.12",
- "80",
- "0"
- ]
- },
- {
- "row": [
- "13.13.13.13",
- "443",
- 10
- ]
- }
- ]
- }
- ]
- )
- p = ApiParameters(params=args)
- assert p.tables[0]['name'] == 'pool__members'
- assert p.tables[0]['columnNames'] == ['addr', 'port', 'connection_limit']
- assert len(p.tables[0]['rows']) == 2
- assert 'row' in p.tables[0]['rows'][0]
- assert 'row' in p.tables[0]['rows'][1]
- assert p.tables[0]['rows'][0]['row'] == ['12.12.12.12', '80', '0']
- assert p.tables[0]['rows'][1]['row'] == ['13.13.13.13', '443', '10']
-
- def test_api_parameters_device_group(self):
- args = dict(
- deviceGroup='none'
- )
- p = ApiParameters(params=args)
- assert p.device_group is None
-
- def test_api_parameters_inherited_traffic_group(self):
- args = dict(
- inheritedTrafficGroup='true'
- )
- p = ApiParameters(params=args)
- assert p.inheritedTrafficGroup == 'true'
-
- def test_api_parameters_inherited_devicegroup(self):
- args = dict(
- inheritedDevicegroup='true'
- )
- p = ApiParameters(params=args)
- assert p.inheritedDevicegroup == 'true'
-
- def test_api_parameters_traffic_group(self):
- args = dict(
- trafficGroup='/Common/traffic-group-local-only'
- )
- p = ApiParameters(params=args)
- assert p.traffic_group == '/Common/traffic-group-local-only'
-
- def test_module_template_same_partition(self):
- args = dict(
- template='foo',
- partition='bar'
- )
- p = ModuleParameters(params=args)
- assert p.template == '/bar/foo'
-
- def test_module_template_same_partition_full_path(self):
- args = dict(
- template='/bar/foo',
- partition='bar'
- )
- p = ModuleParameters(params=args)
- assert p.template == '/bar/foo'
-
- def test_module_template_different_partition_full_path(self):
- args = dict(
- template='/Common/foo',
- partition='bar'
- )
- p = ModuleParameters(params=args)
- assert p.template == '/Common/foo'
-
-
-class TestManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
-
- def test_create_service(self, *args):
- parameters = load_fixture('create_iapp_service_parameters_f5_http.json')
- set_module_args(dict(
- name='foo',
- template='f5.http',
- parameters=parameters,
- state='present',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
- mm = ModuleManager(module=module)
-
- # Override methods to force specific logic in the module to happen
- mm.exists = Mock(return_value=False)
- mm.create_on_device = Mock(return_value=True)
- mm.template_exists = Mock(return_value=True)
-
- results = mm.exec_module()
- assert results['changed'] is True
-
- def test_update_agent_status_traps(self, *args):
- parameters = load_fixture('update_iapp_service_parameters_f5_http.json')
- set_module_args(dict(
- name='foo',
- template='f5.http',
- parameters=parameters,
- state='present',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- # Configure the parameters that would be returned by querying the
- # remote device
- parameters = load_fixture('create_iapp_service_parameters_f5_http.json')
- current = Parameters(parameters)
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
- mm = ModuleManager(module=module)
-
- # Override methods to force specific logic in the module to happen
- mm.exists = Mock(return_value=True)
- mm.update_on_device = Mock(return_value=True)
- mm.read_current_from_device = Mock(return_value=current)
-
- results = mm.exec_module()
- assert results['changed'] is True
diff --git a/test/units/modules/network/f5/test_bigip_iapp_template.py b/test/units/modules/network/f5/test_bigip_iapp_template.py
deleted file mode 100644
index cf86e41224..0000000000
--- a/test/units/modules/network/f5/test_bigip_iapp_template.py
+++ /dev/null
@@ -1,202 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright (c) 2017 F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_iapp_template import Parameters
- from library.modules.bigip_iapp_template import ModuleManager
- from library.modules.bigip_iapp_template import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_iapp_template import Parameters
- from ansible.modules.network.f5.bigip_iapp_template import ArgumentSpec
- from ansible.modules.network.f5.bigip_iapp_template import ModuleManager
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- iapp = load_fixture('create_iapp_template.iapp')
- args = dict(
- content=iapp
- )
- p = Parameters(params=args)
- assert p.name == 'foo.iapp'
-
- def test_module_parameters_custom_name(self):
- iapp = load_fixture('create_iapp_template.iapp')
- args = dict(
- content=iapp,
- name='foobar'
- )
- p = Parameters(params=args)
- assert p.name == 'foobar'
- assert 'sys application template /Common/foobar' in p.content
-
- def test_module_parameters_custom_partition(self):
- iapp = load_fixture('create_iapp_template.iapp')
- args = dict(
- content=iapp,
- partition='foobar'
- )
- p = Parameters(params=args)
- assert p.name == 'foo.iapp'
- assert 'sys application template /foobar/foo.iapp' in p.content
-
-
-class TestManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
-
- def test_create_iapp_template(self, *args):
- # Configure the arguments that would be sent to the Ansible module
- set_module_args(dict(
- content=load_fixture('basic-iapp.tmpl'),
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
- mm = ModuleManager(module=module)
-
- # Override methods to force specific logic in the module to happen
- mm.exists = Mock(side_effect=[False, True])
- mm.create_on_device = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
-
- def test_update_iapp_template(self, *args):
- # Configure the arguments that would be sent to the Ansible module
- set_module_args(dict(
- content=load_fixture('basic-iapp.tmpl'),
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- current1 = Parameters(params=load_fixture('load_sys_application_template_w_new_checksum.json'))
- current2 = Parameters(params=load_fixture('load_sys_application_template_w_old_checksum.json'))
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
- mm = ModuleManager(module=module)
-
- # Override methods to force specific logic in the module to happen
- mm.exists = Mock(side_effect=[True, True])
- mm.create_on_device = Mock(return_value=True)
- mm.read_current_from_device = Mock(return_value=current1)
- mm.template_in_use = Mock(return_value=False)
- mm._get_temporary_template = Mock(return_value=current2)
- mm._remove_iapp_checksum = Mock(return_value=None)
- mm._generate_template_checksum_on_device = Mock(return_value=None)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
-
- def test_delete_iapp_template(self, *args):
- set_module_args(dict(
- content=load_fixture('basic-iapp.tmpl'),
- state='absent',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
- mm = ModuleManager(module=module)
-
- # Override methods to force specific logic in the module to happen
- mm.exists = Mock(side_effect=[True, False])
- mm.remove_from_device = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
-
- def test_delete_iapp_template_idempotent(self, *args):
- set_module_args(dict(
- content=load_fixture('basic-iapp.tmpl'),
- state='absent',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
- mm = ModuleManager(module=module)
-
- # Override methods to force specific logic in the module to happen
- mm.exists = Mock(side_effect=[False, False])
-
- results = mm.exec_module()
-
- assert results['changed'] is False
diff --git a/test/units/modules/network/f5/test_bigip_ike_peer.py b/test/units/modules/network/f5/test_bigip_ike_peer.py
deleted file mode 100644
index 4edc5e6298..0000000000
--- a/test/units/modules/network/f5/test_bigip_ike_peer.py
+++ /dev/null
@@ -1,111 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2018, F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_ike_peer import ApiParameters
- from library.modules.bigip_ike_peer import ModuleParameters
- from library.modules.bigip_ike_peer import ModuleManager
- from library.modules.bigip_ike_peer import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_ike_peer import ApiParameters
- from ansible.modules.network.f5.bigip_ike_peer import ModuleParameters
- from ansible.modules.network.f5.bigip_ike_peer import ModuleManager
- from ansible.modules.network.f5.bigip_ike_peer import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- name='ike1',
- )
- p = ModuleParameters(params=args)
- assert p.name == 'ike1'
-
- def test_api_parameters(self):
- args = dict(
- name='ike1',
- )
- p = ApiParameters(params=args)
- assert p.name == 'ike1'
-
-
-class TestUntypedManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
-
- def test_create(self, *args):
- set_module_args(dict(
- name='ike1',
- version=['v1'],
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- required_if=self.spec.required_if,
- required_together=self.spec.required_together
- )
-
- # Override methods to force specific logic in the module to happen
- mm = ModuleManager(module=module)
- mm.create_on_device = Mock(return_value=True)
- mm.exists = Mock(return_value=False)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
diff --git a/test/units/modules/network/f5/test_bigip_imish_config.py b/test/units/modules/network/f5/test_bigip_imish_config.py
deleted file mode 100644
index 92197fb037..0000000000
--- a/test/units/modules/network/f5/test_bigip_imish_config.py
+++ /dev/null
@@ -1,104 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2018, F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_imish_config import ModuleManager
- from library.modules.bigip_imish_config import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_imish_config import ModuleManager
- from ansible.modules.network.f5.bigip_imish_config import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
-
- def test_create(self, *args):
- set_module_args(dict(
- lines=[
- 'bgp graceful-restart restart-time 120',
- 'redistribute kernel route-map rhi',
- 'neighbor 10.10.10.11 remote-as 65000',
- 'neighbor 10.10.10.11 fall-over bfd',
- 'neighbor 10.10.10.11 remote-as 65000',
- 'neighbor 10.10.10.11 fall-over bfd'
- ],
- parents='router bgp 64664',
- before='bfd slow-timer 2000',
- match='exact',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- current = load_fixture('load_imish_output_1.json')
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- mutually_exclusive=self.spec.mutually_exclusive,
- required_if=self.spec.required_if,
- add_file_common_args=self.spec.add_file_common_args
- )
-
- # Override methods in the specific type of manager
- mm = ModuleManager(module=module)
- mm.read_current_from_device = Mock(return_value=current['commandResult'])
- mm.upload_file_to_device = Mock(return_value=True)
- mm.load_config_on_device = Mock(return_value=True)
- mm.remove_uploaded_file_from_device = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
diff --git a/test/units/modules/network/f5/test_bigip_ipsec_policy.py b/test/units/modules/network/f5/test_bigip_ipsec_policy.py
deleted file mode 100644
index 4fc769f082..0000000000
--- a/test/units/modules/network/f5/test_bigip_ipsec_policy.py
+++ /dev/null
@@ -1,109 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2018, F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_ipsec_policy import ApiParameters
- from library.modules.bigip_ipsec_policy import ModuleParameters
- from library.modules.bigip_ipsec_policy import ModuleManager
- from library.modules.bigip_ipsec_policy import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_ipsec_policy import ApiParameters
- from ansible.modules.network.f5.bigip_ipsec_policy import ModuleParameters
- from ansible.modules.network.f5.bigip_ipsec_policy import ModuleManager
- from ansible.modules.network.f5.bigip_ipsec_policy import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- name='ipsec1',
- )
- p = ModuleParameters(params=args)
- assert p.name == 'ipsec1'
-
- def test_api_parameters(self):
- args = dict(
- name='ipsec1',
- )
- p = ApiParameters(params=args)
- assert p.name == 'ipsec1'
-
-
-class TestUntypedManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
-
- def test_create(self, *args):
- set_module_args(dict(
- name='ipsec1',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- required_if=self.spec.required_if
- )
-
- # Override methods to force specific logic in the module to happen
- mm = ModuleManager(module=module)
- mm.create_on_device = Mock(return_value=True)
- mm.exists = Mock(return_value=False)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
diff --git a/test/units/modules/network/f5/test_bigip_irule.py b/test/units/modules/network/f5/test_bigip_irule.py
deleted file mode 100644
index 3e80c3f8ac..0000000000
--- a/test/units/modules/network/f5/test_bigip_irule.py
+++ /dev/null
@@ -1,266 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright (c) 2017 F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils.six import PY3
-
-try:
- from library.modules.bigip_irule import Parameters
- from library.modules.bigip_irule import ModuleManager
- from library.modules.bigip_irule import ArgumentSpec
- from library.modules.bigip_irule import GtmManager
- from library.modules.bigip_irule import LtmManager
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
- from test.units.compat.mock import patch
- from test.units.compat.mock import mock_open
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_irule import Parameters
- from ansible.modules.network.f5.bigip_irule import ModuleManager
- from ansible.modules.network.f5.bigip_irule import ArgumentSpec
- from ansible.modules.network.f5.bigip_irule import GtmManager
- from ansible.modules.network.f5.bigip_irule import LtmManager
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
- from units.compat.mock import patch
- from units.compat.mock import mock_open
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class BigIpObj(object):
- def __init__(self, **kwargs):
- self.__dict__.update(kwargs)
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters_ltm(self):
- content = load_fixture('create_ltm_irule.tcl')
- args = dict(
- content=content,
- module='ltm',
- name='foo',
- state='present'
- )
- p = Parameters(params=args)
- assert p.content == content
-
- def test_module_parameters_gtm(self):
- content = load_fixture('create_gtm_irule.tcl')
- args = dict(
- content=content,
- module='gtm',
- name='foo',
- state='present'
- )
- p = Parameters(params=args)
- assert p.content == content
-
- def test_api_parameters_ltm(self):
- content = load_fixture('create_ltm_irule.tcl')
- args = dict(
- apiAnonymous=content
- )
- p = Parameters(params=args)
- assert p.content == content
-
- def test_return_api_params(self):
- content = load_fixture('create_ltm_irule.tcl')
- args = dict(
- content=content,
- module='ltm',
- name='foo',
- state='present'
- )
- p = Parameters(params=args)
- params = p.api_params()
-
- assert 'apiAnonymous' in params
-
-
-class TestManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
- self.ltm_irules = []
- self.gtm_irules = []
-
- members = load_fixture('load_ltm_irules.json')
- for item in members:
- self.ltm_irules.append(BigIpObj(**item))
-
- members = load_fixture('load_gtm_irules.json')
- for item in members:
- self.gtm_irules.append(BigIpObj(**item))
-
- def test_create_ltm_irule(self, *args):
- set_module_args(dict(
- name='foo',
- module='ltm',
- content='this is my content',
- partition='Common',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- mutually_exclusive=self.spec.mutually_exclusive,
- )
-
- # Override methods in the specific type of manager
- tm = LtmManager(module=module, params=module.params)
- tm.exists = Mock(side_effect=[False, True])
- tm.create_on_device = Mock(return_value=True)
-
- # Override methods to force specific logic in the module to happen
- mm = ModuleManager(module=module)
- mm.get_manager = Mock(return_value=tm)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['content'] == 'this is my content'
-
- def test_create_gtm_irule(self, *args):
- set_module_args(dict(
- name='foo',
- module='gtm',
- content='this is my content',
- partition='Common',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- mutually_exclusive=self.spec.mutually_exclusive,
- )
-
- # Override methods in the specific type of manager
- tm = GtmManager(module=module, params=module.params)
- tm.exists = Mock(side_effect=[False, True])
- tm.create_on_device = Mock(return_value=True)
-
- # Override methods to force specific logic in the module to happen
- mm = ModuleManager(module=module)
- mm.get_manager = Mock(return_value=tm)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['content'] == 'this is my content'
-
- def test_create_gtm_irule_src(self, *args):
- set_module_args(dict(
- name='foo',
- module='gtm',
- src='{0}/create_ltm_irule.tcl'.format(fixture_path),
- partition='Common',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- mutually_exclusive=self.spec.mutually_exclusive,
- )
-
- if PY3:
- builtins_name = 'builtins'
- else:
- builtins_name = '__builtin__'
-
- with patch(builtins_name + '.open', mock_open(read_data='this is my content'), create=True):
- # Override methods in the specific type of manager
- tm = GtmManager(module=module, params=module.params)
- tm.exists = Mock(side_effect=[False, True])
- tm.create_on_device = Mock(return_value=True)
-
- # Override methods to force specific logic in the module to happen
- mm = ModuleManager(module=module)
- mm.get_manager = Mock(return_value=tm)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['content'] == 'this is my content'
- assert results['module'] == 'gtm'
- assert results['src'] == '{0}/create_ltm_irule.tcl'.format(fixture_path)
- assert len(results.keys()) == 4
-
- def test_module_mutual_exclusion(self, *args):
- set_module_args(dict(
- content='foo',
- module='ltm',
- name='foo',
- state='present',
- src='/path/to/irules/foo.tcl',
- partition='Common',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- with patch('ansible.module_utils.basic.AnsibleModule.fail_json', unsafe=True) as mo:
- AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- mutually_exclusive=self.spec.mutually_exclusive,
- )
- mo.assert_called_once()
diff --git a/test/units/modules/network/f5/test_bigip_log_destination.py b/test/units/modules/network/f5/test_bigip_log_destination.py
deleted file mode 100644
index 5a02fde620..0000000000
--- a/test/units/modules/network/f5/test_bigip_log_destination.py
+++ /dev/null
@@ -1,131 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_log_destination import V1ApiParameters
- from library.modules.bigip_log_destination import V1ModuleParameters
- from library.modules.bigip_log_destination import ModuleManager
- from library.modules.bigip_log_destination import V1Manager
- from library.modules.bigip_log_destination import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_log_destination import V1ApiParameters
- from ansible.modules.network.f5.bigip_log_destination import V1ModuleParameters
- from ansible.modules.network.f5.bigip_log_destination import ModuleManager
- from ansible.modules.network.f5.bigip_log_destination import V1Manager
- from ansible.modules.network.f5.bigip_log_destination import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestV1Parameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- name='foo',
- syslog_settings=dict(
- forward_to='pool1',
- syslog_format='rfc5424'
- ),
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- )
- p = V1ModuleParameters(params=args)
- assert p.name == 'foo'
- assert p.forward_to == '/Common/pool1'
- assert p.syslog_format == 'rfc5424'
-
- def test_api_parameters(self):
- args = load_fixture('load_sys_log_config_destination_1.json')
- p = V1ApiParameters(params=args)
- assert p.name == 'foo'
- assert p.syslog_format == 'rfc5424'
- assert p.forward_to == '/Common/pool1'
-
-
-class TestV1Manager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
-
- def test_create_policy(self, *args):
- set_module_args(dict(
- name="foo",
- type='remote-syslog',
- syslog_settings=dict(
- forward_to='pool1',
- ),
- state='present',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- mutually_exclusive=self.spec.mutually_exclusive
- )
-
- # Override methods in the specific type of manager
- tm = V1Manager(module=module, params=module.params)
- tm.exists = Mock(return_value=False)
- tm.create_on_device = Mock(return_value=True)
-
- # Override methods to force specific logic in the module to happen
- mm = ModuleManager(module=module)
- mm.get_manager = Mock(return_value=tm)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
diff --git a/test/units/modules/network/f5/test_bigip_log_publisher.py b/test/units/modules/network/f5/test_bigip_log_publisher.py
deleted file mode 100644
index c45e31b79d..0000000000
--- a/test/units/modules/network/f5/test_bigip_log_publisher.py
+++ /dev/null
@@ -1,132 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_log_publisher import ApiParameters
- from library.modules.bigip_log_publisher import ModuleParameters
- from library.modules.bigip_log_publisher import ModuleManager
- from library.modules.bigip_log_publisher import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_log_publisher import ApiParameters
- from ansible.modules.network.f5.bigip_log_publisher import ModuleParameters
- from ansible.modules.network.f5.bigip_log_publisher import ModuleManager
- from ansible.modules.network.f5.bigip_log_publisher import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- name='foo',
- description='my desc',
- destinations=[
- 'dest1',
- 'dest2'
- ],
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- )
- p = ModuleParameters(params=args)
- assert p.name == 'foo'
- assert p.description == 'my desc'
- assert p.destinations == ['/Common/dest1', '/Common/dest2']
-
- def test_api_parameters(self):
- args = load_fixture('load_sys_log_config_publisher_1.json')
- p = ApiParameters(params=args)
- assert p.name == 'foo'
- assert p.description == 'my description'
- assert p.destinations == [
- '/Common/SECURITYLOGSERVERS-LOGGING',
- '/Common/local-db',
- '/Common/local-syslog',
- ]
-
-
-class TestManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
-
- def test_create_policy(self, *args):
- set_module_args(dict(
- name="foo",
- description='foo description',
- destinations=[
- 'dest1',
- 'dest2'
- ],
- state='present',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods to force specific logic in the module to happen
- mm = ModuleManager(module=module)
- mm.exists = Mock(return_value=False)
- mm.create_on_device = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['description'] == 'foo description'
- assert results['destinations'] == ['/Common/dest1', '/Common/dest2']
diff --git a/test/units/modules/network/f5/test_bigip_lx_package.py b/test/units/modules/network/f5/test_bigip_lx_package.py
deleted file mode 100644
index d98c8014bb..0000000000
--- a/test/units/modules/network/f5/test_bigip_lx_package.py
+++ /dev/null
@@ -1,123 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright (c) 2017 F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_lx_package import Parameters
- from library.modules.bigip_lx_package import ModuleManager
- from library.modules.bigip_lx_package import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
- from test.units.compat.mock import patch
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_lx_package import Parameters
- from ansible.modules.network.f5.bigip_lx_package import ArgumentSpec
- from ansible.modules.network.f5.bigip_lx_package import ModuleManager
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
- from units.compat.mock import patch
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- package='MyApp-0.1.0-0001.noarch.rpm',
- state='present'
- )
- p = Parameters(params=args)
- assert p.package == 'MyApp-0.1.0-0001.noarch.rpm'
-
-
-class TestManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
- self.patcher1 = patch('time.sleep')
- self.patcher1.start()
-
- try:
- self.p1 = patch('library.modules.bigip_lx_package.tmos_version')
- self.m1 = self.p1.start()
- self.m1.return_value = '12.1.3'
- except Exception:
- self.p1 = patch('ansible.modules.network.f5.bigip_lx_package.tmos_version')
- self.m1 = self.p1.start()
- self.m1.return_value = '12.1.3'
-
- def tearDown(self):
- self.patcher1.stop()
-
- def test_create_iapp_template(self, *args):
- package_name = os.path.join(fixture_path, 'MyApp-0.1.0-0001.noarch.rpm')
- # Configure the arguments that would be sent to the Ansible module
- set_module_args(dict(
- package=package_name,
- state='present',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- required_if=self.spec.required_if
- )
- mm = ModuleManager(module=module)
-
- # Override methods to force specific logic in the module to happen
- mm.exists = Mock(side_effect=[False, True])
- mm.create_on_device = Mock(return_value=True)
- mm.upload_to_device = Mock(return_value=True)
- mm.enable_iapplx_on_device = Mock(return_value=True)
- mm.remove_package_file_from_device = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
diff --git a/test/units/modules/network/f5/test_bigip_management_route.py b/test/units/modules/network/f5/test_bigip_management_route.py
deleted file mode 100644
index a3d6501710..0000000000
--- a/test/units/modules/network/f5/test_bigip_management_route.py
+++ /dev/null
@@ -1,124 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_management_route import ApiParameters
- from library.modules.bigip_management_route import ModuleParameters
- from library.modules.bigip_management_route import ModuleManager
- from library.modules.bigip_management_route import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_management_route import ApiParameters
- from ansible.modules.network.f5.bigip_management_route import ModuleParameters
- from ansible.modules.network.f5.bigip_management_route import ModuleManager
- from ansible.modules.network.f5.bigip_management_route import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- name='foo',
- gateway='1.1.1.1',
- network='default',
- description='my description'
- )
-
- p = ModuleParameters(params=args)
- assert p.name == 'foo'
- assert p.gateway == '1.1.1.1'
- assert p.network == 'default'
- assert p.description == 'my description'
-
- def test_api_parameters(self):
- args = load_fixture('load_sys_management_route_1.json')
-
- p = ApiParameters(params=args)
- assert p.name == 'default'
- assert p.gateway == '10.0.2.2'
- assert p.network == 'default'
- assert p.description == 'configured-by-dhcp'
-
-
-class TestManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
-
- def test_create_monitor(self, *args):
- set_module_args(dict(
- name='foo',
- gateway='1.1.1.1',
- network='default',
- description='my description',
- partition='Common',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods in the specific type of manager
- mm = ModuleManager(module=module)
- mm.exists = Mock(side_effect=[False, True])
- mm.create_on_device = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['gateway'] == '1.1.1.1'
- assert results['network'] == 'default'
- assert results['description'] == 'my description'
diff --git a/test/units/modules/network/f5/test_bigip_message_routing_peer.py b/test/units/modules/network/f5/test_bigip_message_routing_peer.py
deleted file mode 100644
index 9c67fdbb9a..0000000000
--- a/test/units/modules/network/f5/test_bigip_message_routing_peer.py
+++ /dev/null
@@ -1,194 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2019, F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_message_routing_peer import ApiParameters
- from library.modules.bigip_message_routing_peer import ModuleParameters
- from library.modules.bigip_message_routing_peer import ModuleManager
- from library.modules.bigip_message_routing_peer import GenericModuleManager
- from library.modules.bigip_message_routing_peer import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_message_routing_peer import ApiParameters
- from ansible.modules.network.f5.bigip_message_routing_peer import ModuleParameters
- from ansible.modules.network.f5.bigip_message_routing_peer import ModuleManager
- from ansible.modules.network.f5.bigip_message_routing_peer import GenericModuleManager
- from ansible.modules.network.f5.bigip_message_routing_peer import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- name='foo',
- partition='foobar',
- description='my description',
- auto_init='yes',
- auto_init_interval=1234,
- connection_mode='per-peer',
- number_of_connections=20,
- pool='/Common/example',
- ratio=10,
- transport_config='/Common/virtual'
- )
-
- p = ModuleParameters(params=args)
- assert p.name == 'foo'
- assert p.partition == 'foobar'
- assert p.description == 'my description'
- assert p.auto_init == 'enabled'
- assert p.auto_init_interval == 1234
- assert p.connection_mode == 'per-peer'
- assert p.number_of_connections == 20
- assert p.pool == '/Common/example'
- assert p.ratio == 10
- assert p.transport_config == '/Common/virtual'
-
- def test_api_parameters(self):
- args = load_fixture('load_generic_peer.json')
-
- p = ApiParameters(params=args)
- assert p.name == 'test'
- assert p.partition == 'Common'
- assert p.description == 'foobar'
- assert p.auto_init == 'disabled'
- assert p.auto_init_interval == 5000
- assert p.connection_mode == 'per-peer'
- assert p.number_of_connections == 1
- assert p.pool == '/Common/example'
- assert p.ratio == 1
- assert p.transport_config == '/Common/test_tranport'
-
-
-class TestManager(unittest.TestCase):
- def setUp(self):
- self.spec = ArgumentSpec()
-
- def test_create_generic_peer(self, *args):
- set_module_args(dict(
- name='foo',
- partition='foobar',
- description='my description',
- auto_init='yes',
- auto_init_interval=1234,
- connection_mode='per-peer',
- number_of_connections=20,
- pool='/Common/example',
- ratio=10,
- transport_config='/Common/virtual',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- required_if=self.spec.required_if
- )
-
- # Override methods in the specific type of manager
- gm = GenericModuleManager(module=module)
- gm.exists = Mock(return_value=False)
- gm.create_on_device = Mock(return_value=True)
-
- mm = ModuleManager(module=module)
- mm.version_less_than_14 = Mock(return_value=False)
- mm.get_manager = Mock(return_value=gm)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['auto_init'] == 'yes'
- assert results['description'] == 'my description'
- assert results['auto_init_interval'] == 1234
- assert results['connection_mode'] == 'per-peer'
- assert results['number_of_connections'] == 20
- assert results['pool'] == '/Common/example'
- assert results['ratio'] == 10
- assert results['transport_config'] == '/Common/virtual'
-
- def test_update_generic_peer(self, *args):
- set_module_args(dict(
- name='test',
- auto_init_interval=3000,
- ratio=120,
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- current = ApiParameters(params=load_fixture('load_generic_peer.json'))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- required_if=self.spec.required_if
- )
-
- # Override methods in the specific type of manager
- gm = GenericModuleManager(module=module)
- gm.exists = Mock(return_value=True)
- gm.update_on_device = Mock(return_value=True)
- gm.read_current_from_device = Mock(return_value=current)
-
- mm = ModuleManager(module=module)
- mm.version_less_than_14 = Mock(return_value=False)
- mm.get_manager = Mock(return_value=gm)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['auto_init_interval'] == 3000
- assert results['ratio'] == 120
diff --git a/test/units/modules/network/f5/test_bigip_message_routing_protocol.py b/test/units/modules/network/f5/test_bigip_message_routing_protocol.py
deleted file mode 100644
index 0a59d5e9de..0000000000
--- a/test/units/modules/network/f5/test_bigip_message_routing_protocol.py
+++ /dev/null
@@ -1,179 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2019, F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_message_routing_protocol import ApiParameters
- from library.modules.bigip_message_routing_protocol import ModuleParameters
- from library.modules.bigip_message_routing_protocol import ModuleManager
- from library.modules.bigip_message_routing_protocol import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_message_routing_protocol import ApiParameters
- from ansible.modules.network.f5.bigip_message_routing_protocol import ModuleParameters
- from ansible.modules.network.f5.bigip_message_routing_protocol import ModuleManager
- from ansible.modules.network.f5.bigip_message_routing_protocol import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- name='foo',
- partition='foobar',
- description='my description',
- parent='barfoo',
- disable_parser=True,
- max_egress_buffer=10000,
- max_msg_size=2000,
- msg_terminator='%%%%',
- no_response=False,
- )
-
- p = ModuleParameters(params=args)
- assert p.name == 'foo'
- assert p.partition == 'foobar'
- assert p.description == 'my description'
- assert p.parent == '/foobar/barfoo'
- assert p.disable_parser == 'yes'
- assert p.max_egress_buffer == 10000
- assert p.max_msg_size == 2000
- assert p.msg_terminator == '%%%%'
- assert p.no_response == 'no'
-
- def test_api_parameters(self):
- args = load_fixture('load_generic_parser.json')
-
- p = ApiParameters(params=args)
- assert p.name == 'foobar'
- assert p.partition == 'Common'
- assert p.parent == '/Common/genericmsg'
- assert p.disable_parser == 'no'
- assert p.max_egress_buffer == 32768
- assert p.max_msg_size == 32768
- assert p.no_response == 'no'
-
-
-class TestManager(unittest.TestCase):
- def setUp(self):
- self.spec = ArgumentSpec()
-
- def test_create_generic_protocol(self, *args):
- set_module_args(dict(
- name='foo',
- partition='foobar',
- description='my description',
- parent='barfoo',
- disable_parser=True,
- max_egress_buffer=10000,
- max_msg_size=2000,
- msg_terminator='%%%%',
- no_response=False,
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods in the specific type of manager
- mm = ModuleManager(module=module)
- mm.exists = Mock(return_value=False)
- mm.create_on_device = Mock(return_value=True)
- mm.version_less_than_14 = Mock(return_value=False)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['description'] == 'my description'
- assert results['parent'] == '/foobar/barfoo'
- assert results['disable_parser'] == 'yes'
- assert results['max_egress_buffer'] == 10000
- assert results['max_msg_size'] == 2000
- assert results['msg_terminator'] == '%%%%'
- assert results['no_response'] == 'no'
-
- def test_update_generic_protocol(self, *args):
- set_module_args(dict(
- name='foobar',
- disable_parser=True,
- max_egress_buffer=10000,
- max_msg_size=2000,
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- current = ApiParameters(params=load_fixture('load_generic_parser.json'))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods in the specific type of manager
- mm = ModuleManager(module=module)
- mm.exists = Mock(return_value=True)
- mm.update_on_device = Mock(return_value=True)
- mm.read_current_from_device = Mock(return_value=current)
- mm.version_less_than_14 = Mock(return_value=False)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['disable_parser'] == 'yes'
- assert results['max_egress_buffer'] == 10000
- assert results['max_msg_size'] == 2000
diff --git a/test/units/modules/network/f5/test_bigip_message_routing_route.py b/test/units/modules/network/f5/test_bigip_message_routing_route.py
deleted file mode 100644
index db68ae1edf..0000000000
--- a/test/units/modules/network/f5/test_bigip_message_routing_route.py
+++ /dev/null
@@ -1,178 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2019, F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_message_routing_route import ApiParameters
- from library.modules.bigip_message_routing_route import ModuleParameters
- from library.modules.bigip_message_routing_route import ModuleManager
- from library.modules.bigip_message_routing_route import GenericModuleManager
- from library.modules.bigip_message_routing_route import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_message_routing_route import ApiParameters
- from ansible.modules.network.f5.bigip_message_routing_route import ModuleParameters
- from ansible.modules.network.f5.bigip_message_routing_route import ModuleManager
- from ansible.modules.network.f5.bigip_message_routing_route import GenericModuleManager
- from ansible.modules.network.f5.bigip_message_routing_route import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- name='foo',
- partition='foobar',
- description='my description',
- dst_address='some_destination',
- src_address='some_address',
- peer_selection_mode='ratio',
- peers=['/Common/example']
- )
-
- p = ModuleParameters(params=args)
- assert p.name == 'foo'
- assert p.partition == 'foobar'
- assert p.description == 'my description'
- assert p.dst_address == 'some_destination'
- assert p.src_address == 'some_address'
- assert p.peer_selection_mode == 'ratio'
- assert p.peers == ['/Common/example']
-
- def test_api_parameters(self):
- args = load_fixture('load_generic_route.json')
-
- p = ApiParameters(params=args)
- assert p.name == 'some'
- assert p.partition == 'Common'
- assert p.dst_address == 'annoying_user'
- assert p.src_address == '99.99.99.99'
- assert p.peer_selection_mode == 'sequential'
- assert p.peers == ['/Common/testy']
-
-
-class TestManager(unittest.TestCase):
- def setUp(self):
- self.spec = ArgumentSpec()
-
- def test_create_generic_route(self, *args):
- set_module_args(dict(
- name='some',
- partition='foobar',
- description='my description',
- dst_address='some_destination',
- src_address='some_address',
- peer_selection_mode='ratio',
- peers=['/Common/example'],
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods in the specific type of manager
- gm = GenericModuleManager(module=module)
- gm.exists = Mock(return_value=False)
- gm.create_on_device = Mock(return_value=True)
-
- mm = ModuleManager(module=module)
- mm.version_less_than_14 = Mock(return_value=False)
- mm.get_manager = Mock(return_value=gm)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['description'] == 'my description'
- assert results['dst_address'] == 'some_destination'
- assert results['src_address'] == 'some_address'
- assert results['peer_selection_mode'] == 'ratio'
- assert results['peers'] == ['/Common/example']
-
- def test_update_generic_peer(self, *args):
- set_module_args(dict(
- name='some',
- dst_address="blackhole",
- peer_selection_mode='ratio',
- peers=['/Common/example'],
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- current = ApiParameters(params=load_fixture('load_generic_route.json'))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods in the specific type of manager
- gm = GenericModuleManager(module=module)
- gm.exists = Mock(return_value=True)
- gm.update_on_device = Mock(return_value=True)
- gm.read_current_from_device = Mock(return_value=current)
-
- mm = ModuleManager(module=module)
- mm.version_less_than_14 = Mock(return_value=False)
- mm.get_manager = Mock(return_value=gm)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['dst_address'] == 'blackhole'
- assert results['peer_selection_mode'] == 'ratio'
- assert results['peers'] == ['/Common/example']
diff --git a/test/units/modules/network/f5/test_bigip_message_routing_router.py b/test/units/modules/network/f5/test_bigip_message_routing_router.py
deleted file mode 100644
index 6bd5525a26..0000000000
--- a/test/units/modules/network/f5/test_bigip_message_routing_router.py
+++ /dev/null
@@ -1,206 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2019, F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_message_routing_router import ApiParameters
- from library.modules.bigip_message_routing_router import ModuleParameters
- from library.modules.bigip_message_routing_router import GenericModuleManager
- from library.modules.bigip_message_routing_router import ModuleManager
- from library.modules.bigip_message_routing_router import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_message_routing_router import ApiParameters
- from ansible.modules.network.f5.bigip_message_routing_router import ModuleParameters
- from ansible.modules.network.f5.bigip_message_routing_router import ModuleManager
- from ansible.modules.network.f5.bigip_message_routing_router import GenericModuleManager
- from ansible.modules.network.f5.bigip_message_routing_router import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- name='foo',
- partition='foobar',
- description='my description',
- ignore_client_port='no',
- inherited_traffic_group='yes',
- use_local_connection='no',
- max_pending_bytes=20000,
- max_pending_messages=300,
- max_retries=32,
- mirror='yes',
- mirrored_msg_sweeper_interval=3000,
- routes=['test1', 'test2'],
- traffic_group='footraffic',
- )
- p = ModuleParameters(params=args)
- assert p.name == 'foo'
- assert p.partition == 'foobar'
- assert p.description == 'my description'
- assert p.ignore_client_port == 'no'
- assert p.inherited_traffic_group == 'true'
- assert p.use_local_connection == 'no'
- assert p.max_pending_bytes == 20000
- assert p.max_pending_messages == 300
- assert p.max_retries == 32
- assert p.mirror == 'enabled'
- assert p.mirrored_msg_sweeper_interval == 3000
- assert p.routes == ['/foobar/test1', '/foobar/test2']
- assert p.traffic_group == '/Common/footraffic'
-
- def test_api_parameters(self):
- args = load_fixture('load_generic_router.json')
-
- p = ApiParameters(params=args)
- assert p.name == 'messagerouter'
- assert p.partition == 'Common'
- assert p.ignore_client_port == 'no'
- assert p.inherited_traffic_group == 'true'
- assert p.use_local_connection == 'yes'
- assert p.max_pending_bytes == 23768
- assert p.max_pending_messages == 64
- assert p.max_retries == 1
- assert p.mirror == 'disabled'
- assert p.mirrored_msg_sweeper_interval == 1000
- assert p.traffic_group == '/Common/traffic-group-1'
-
-
-class TestManager(unittest.TestCase):
- def setUp(self):
- self.spec = ArgumentSpec()
-
- def test_create_generic_router(self, *args):
- set_module_args(dict(
- name='foo',
- partition='foobar',
- description='my description',
- ignore_client_port='no',
- inherited_traffic_group='yes',
- use_local_connection='no',
- max_pending_bytes=20000,
- max_pending_messages=300,
- max_retries=32,
- mirror='yes',
- mirrored_msg_sweeper_interval=3000,
- routes=['test1', 'test2'],
- traffic_group='footraffic',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods in the specific type of manager
- gm = GenericModuleManager(module=module)
- gm.exists = Mock(return_value=False)
- gm.create_on_device = Mock(return_value=True)
-
- mm = ModuleManager(module=module)
- mm.version_less_than_14 = Mock(return_value=False)
- mm.get_manager = Mock(return_value=gm)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['description'] == 'my description'
- assert results['ignore_client_port'] == 'no'
- assert results['inherited_traffic_group'] == 'yes'
- assert results['use_local_connection'] == 'no'
- assert results['max_pending_bytes'] == 20000
- assert results['max_pending_messages'] == 300
- assert results['max_retries'] == 32
- assert results['mirror'] == 'yes'
- assert results['mirrored_msg_sweeper_interval'] == 3000
- assert results['traffic_group'] == '/Common/footraffic'
- assert results['routes'] == ['/foobar/test1', '/foobar/test2']
-
- def test_update_generic_router(self, *args):
- set_module_args(dict(
- name='messagerouter',
- use_local_connection='no',
- mirror='yes',
- routes=['/Common/example'],
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- current = ApiParameters(params=load_fixture('load_generic_router.json'))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods in the specific type of manager
- gm = GenericModuleManager(module=module)
- gm.exists = Mock(return_value=True)
- gm.update_on_device = Mock(return_value=True)
- gm.read_current_from_device = Mock(return_value=current)
-
- mm = ModuleManager(module=module)
- mm.version_less_than_14 = Mock(return_value=False)
- mm.get_manager = Mock(return_value=gm)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['use_local_connection'] == 'no'
- assert results['mirror'] == 'yes'
- assert results['routes'] == ['/Common/example']
diff --git a/test/units/modules/network/f5/test_bigip_message_routing_transport_config.py b/test/units/modules/network/f5/test_bigip_message_routing_transport_config.py
deleted file mode 100644
index d532005d7e..0000000000
--- a/test/units/modules/network/f5/test_bigip_message_routing_transport_config.py
+++ /dev/null
@@ -1,183 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2019, F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_message_routing_transport_config import ApiParameters
- from library.modules.bigip_message_routing_transport_config import ModuleParameters
- from library.modules.bigip_message_routing_transport_config import ModuleManager
- from library.modules.bigip_message_routing_transport_config import GenericModuleManager
- from library.modules.bigip_message_routing_transport_config import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_message_routing_transport_config import ApiParameters
- from ansible.modules.network.f5.bigip_message_routing_transport_config import ModuleParameters
- from ansible.modules.network.f5.bigip_message_routing_transport_config import ModuleManager
- from ansible.modules.network.f5.bigip_message_routing_transport_config import GenericModuleManager
- from ansible.modules.network.f5.bigip_message_routing_transport_config import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- name='foo',
- partition='foobar',
- description='my description',
- profiles=['genericmsg', 'foo_udp'],
- src_addr_translation=dict(
- type='snat',
- pool='some_pool1'
- ),
- src_port=1023,
- rules=['rule1', 'rule2'],
- )
- p = ModuleParameters(params=args)
- assert p.name == 'foo'
- assert p.partition == 'foobar'
- assert p.description == 'my description'
- assert p.profiles == ['/foobar/genericmsg', '/foobar/foo_udp']
- assert p.snat_type == 'snat'
- assert p.snat_pool == '/foobar/some_pool1'
- assert p.src_port == 1023
- assert p.rules == ['/foobar/rule1', '/foobar/rule2']
-
- def test_api_parameters(self):
- args = load_fixture('load_generic_transport_config.json')
-
- p = ApiParameters(params=args)
- assert p.name == 'gen1'
- assert p.partition == 'Common'
- assert p.profiles == ['/Common/diametersession', '/Common/tcp']
- assert p.snat_type == 'snat'
- assert p.src_port == 0
- assert p.snat_pool == '/Common/test_snat'
- assert p.rules == ['/Common/test']
-
-
-class TestManager(unittest.TestCase):
- def setUp(self):
- self.spec = ArgumentSpec()
-
- def test_create_generic_transport(self, *args):
- set_module_args(dict(
- name='foo',
- partition='foobar',
- description='my description',
- profiles=['genericmsg', 'foo_udp'],
- src_addr_translation=dict(
- type='snat',
- pool='some_pool1'
- ),
- src_port=1023,
- rules=['rule1', 'rule2'],
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods in the specific type of manager
- gm = GenericModuleManager(module=module)
- gm.exists = Mock(return_value=False)
- gm.create_on_device = Mock(return_value=True)
-
- mm = ModuleManager(module=module)
- mm.version_less_than_14 = Mock(return_value=False)
- mm.get_manager = Mock(return_value=gm)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['description'] == 'my description'
- assert results['src_addr_translation'] == dict(type='snat', pool='/foobar/some_pool1')
- assert results['src_port'] == 1023
- assert results['rules'] == ['/foobar/rule1', '/foobar/rule2']
- assert results['profiles'] == ['/foobar/genericmsg', '/foobar/foo_udp']
-
- def test_update_generic_transport(self, *args):
- set_module_args(dict(
- name='gen1',
- src_port=1024,
- rules=['/Common/barfoo'],
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- current = ApiParameters(params=load_fixture('load_generic_transport_config.json'))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- )
-
- # Override methods in the specific type of manager
- gm = GenericModuleManager(module=module)
- gm.exists = Mock(return_value=True)
- gm.update_on_device = Mock(return_value=True)
- gm.read_current_from_device = Mock(return_value=current)
-
- mm = ModuleManager(module=module)
- mm.version_less_than_14 = Mock(return_value=False)
- mm.get_manager = Mock(return_value=gm)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['src_port'] == 1024
- assert results['rules'] == ['/Common/barfoo']
diff --git a/test/units/modules/network/f5/test_bigip_monitor_dns.py b/test/units/modules/network/f5/test_bigip_monitor_dns.py
deleted file mode 100644
index ad473e5540..0000000000
--- a/test/units/modules/network/f5/test_bigip_monitor_dns.py
+++ /dev/null
@@ -1,157 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_monitor_dns import ApiParameters
- from library.modules.bigip_monitor_dns import ModuleParameters
- from library.modules.bigip_monitor_dns import ModuleManager
- from library.modules.bigip_monitor_dns import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_monitor_dns import ApiParameters
- from ansible.modules.network.f5.bigip_monitor_dns import ModuleParameters
- from ansible.modules.network.f5.bigip_monitor_dns import ModuleManager
- from ansible.modules.network.f5.bigip_monitor_dns import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- parent='/Common/dns',
- interval=10,
- time_until_up=0,
- timeout=30,
- )
-
- p = ModuleParameters(params=args)
- assert p.parent == '/Common/dns'
- assert p.interval == 10
- assert p.time_until_up == 0
- assert p.timeout == 30
-
- def test_api_parameters(self):
- args = dict(
- defaultsFrom='/Common/dns',
- interval=10,
- timeUntilUp=0,
- timeout=30,
- )
-
- p = ApiParameters(params=args)
- assert p.parent == '/Common/dns'
- assert p.interval == 10
- assert p.time_until_up == 0
- assert p.timeout == 30
-
-
-class TestManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
-
- def test_create(self, *args):
- set_module_args(dict(
- name='foo',
- parent='/Common/dns',
- query_name='foo',
- interval=20,
- timeout=30,
- time_until_up=60,
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods in the specific type of manager
- mm = ModuleManager(module=module)
- mm.exists = Mock(side_effect=[False, True])
- mm.create_on_device = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
-
- def test_create_with_description(self, *args):
- set_module_args(dict(
- name='foo',
- parent='/Common/dns',
- query_name='foo',
- interval=20,
- timeout=30,
- time_until_up=60,
- description='Important Description',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods in the specific type of manager
- mm = ModuleManager(module=module)
- mm.exists = Mock(side_effect=[False, True])
- mm.create_on_device = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
diff --git a/test/units/modules/network/f5/test_bigip_monitor_external.py b/test/units/modules/network/f5/test_bigip_monitor_external.py
deleted file mode 100644
index 3f29036321..0000000000
--- a/test/units/modules/network/f5/test_bigip_monitor_external.py
+++ /dev/null
@@ -1,120 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_monitor_external import ModuleParameters
- from library.modules.bigip_monitor_external import ModuleManager
- from library.modules.bigip_monitor_external import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_monitor_external import ModuleParameters
- from ansible.modules.network.f5.bigip_monitor_external import ModuleManager
- from ansible.modules.network.f5.bigip_monitor_external import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- name='foo',
- parent='parent',
- ip='10.10.10.10',
- port=80,
- interval=20,
- timeout=30,
- partition='Common'
- )
-
- p = ModuleParameters(params=args)
- assert p.name == 'foo'
- assert p.parent == '/Common/parent'
- assert p.ip == '10.10.10.10'
- assert p.type == 'external'
- assert p.port == 80
- assert p.destination == '10.10.10.10:80'
- assert p.interval == 20
- assert p.timeout == 30
-
-
-class TestManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
-
- def test_create_monitor(self, *args):
- set_module_args(dict(
- name='foo',
- parent='parent',
- ip='10.10.10.10',
- port=80,
- interval=20,
- timeout=30,
- partition='Common',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods in the specific type of manager
- mm = ModuleManager(module=module)
- mm.exists = Mock(side_effect=[False, True])
- mm.create_on_device = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['parent'] == '/Common/parent'
diff --git a/test/units/modules/network/f5/test_bigip_monitor_gateway_icmp.py b/test/units/modules/network/f5/test_bigip_monitor_gateway_icmp.py
deleted file mode 100644
index f327bfc80f..0000000000
--- a/test/units/modules/network/f5/test_bigip_monitor_gateway_icmp.py
+++ /dev/null
@@ -1,155 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_monitor_gateway_icmp import ApiParameters
- from library.modules.bigip_monitor_gateway_icmp import ModuleParameters
- from library.modules.bigip_monitor_gateway_icmp import ModuleManager
- from library.modules.bigip_monitor_gateway_icmp import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_monitor_gateway_icmp import ApiParameters
- from ansible.modules.network.f5.bigip_monitor_gateway_icmp import ModuleParameters
- from ansible.modules.network.f5.bigip_monitor_gateway_icmp import ModuleManager
- from ansible.modules.network.f5.bigip_monitor_gateway_icmp import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- parent='/Common/gateway-icmp',
- interval=10,
- time_until_up=0,
- timeout=30,
- )
-
- p = ModuleParameters(params=args)
- assert p.parent == '/Common/gateway-icmp'
- assert p.interval == 10
- assert p.time_until_up == 0
- assert p.timeout == 30
-
- def test_api_parameters(self):
- args = dict(
- defaultsFrom='/Common/gateway-icmp',
- interval=10,
- timeUntilUp=0,
- timeout=30,
- )
-
- p = ApiParameters(params=args)
- assert p.parent == '/Common/gateway-icmp'
- assert p.interval == 10
- assert p.time_until_up == 0
- assert p.timeout == 30
-
-
-class TestManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
-
- def test_create(self, *args):
- set_module_args(dict(
- name='foo',
- parent='/Common/gateway-icmp',
- interval=20,
- timeout=30,
- time_until_up=60,
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods in the specific type of manager
- mm = ModuleManager(module=module)
- mm.exists = Mock(side_effect=[False, True])
- mm.create_on_device = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
-
- def test_create_with_description(self, *args):
- set_module_args(dict(
- name='foo',
- parent='/Common/gateway-icmp',
- interval=20,
- timeout=30,
- time_until_up=60,
- description='Important Description',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods in the specific type of manager
- mm = ModuleManager(module=module)
- mm.exists = Mock(side_effect=[False, True])
- mm.create_on_device = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
diff --git a/test/units/modules/network/f5/test_bigip_monitor_http.py b/test/units/modules/network/f5/test_bigip_monitor_http.py
deleted file mode 100644
index 0c9a66005c..0000000000
--- a/test/units/modules/network/f5/test_bigip_monitor_http.py
+++ /dev/null
@@ -1,452 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright (c) 2017 F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_monitor_http import Parameters
- from library.modules.bigip_monitor_http import ModuleManager
- from library.modules.bigip_monitor_http import ArgumentSpec
-
- from library.module_utils.network.f5.common import F5ModuleError
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_monitor_http import Parameters
- from ansible.modules.network.f5.bigip_monitor_http import ModuleManager
- from ansible.modules.network.f5.bigip_monitor_http import ArgumentSpec
-
- from ansible.module_utils.network.f5.common import F5ModuleError
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- name='foo',
- parent='parent',
- send='this is a send string',
- receive='this is a receive string',
- ip='10.10.10.10',
- port=80,
- interval=20,
- timeout=30,
- time_until_up=60,
- partition='Common'
- )
-
- p = Parameters(params=args)
- assert p.name == 'foo'
- assert p.parent == '/Common/parent'
- assert p.send == 'this is a send string'
- assert p.receive == 'this is a receive string'
- assert p.ip == '10.10.10.10'
- assert p.type == 'http'
- assert p.port == 80
- assert p.destination == '10.10.10.10:80'
- assert p.interval == 20
- assert p.timeout == 30
- assert p.time_until_up == 60
-
- def test_module_parameters_ints_as_strings(self):
- args = dict(
- name='foo',
- parent='parent',
- send='this is a send string',
- receive='this is a receive string',
- ip='10.10.10.10',
- port='80',
- interval='20',
- timeout='30',
- time_until_up='60',
- partition='Common'
- )
-
- p = Parameters(params=args)
- assert p.name == 'foo'
- assert p.parent == '/Common/parent'
- assert p.send == 'this is a send string'
- assert p.receive == 'this is a receive string'
- assert p.ip == '10.10.10.10'
- assert p.type == 'http'
- assert p.port == 80
- assert p.destination == '10.10.10.10:80'
- assert p.interval == 20
- assert p.timeout == 30
- assert p.time_until_up == 60
-
- def test_api_parameters(self):
- args = dict(
- name='foo',
- defaultsFrom='/Common/parent',
- send='this is a send string',
- recv='this is a receive string',
- destination='10.10.10.10:80',
- interval=20,
- timeout=30,
- timeUntilUp=60
- )
-
- p = Parameters(params=args)
- assert p.name == 'foo'
- assert p.parent == '/Common/parent'
- assert p.send == 'this is a send string'
- assert p.receive == 'this is a receive string'
- assert p.ip == '10.10.10.10'
- assert p.type == 'http'
- assert p.port == 80
- assert p.destination == '10.10.10.10:80'
- assert p.interval == 20
- assert p.timeout == 30
- assert p.time_until_up == 60
-
-
-class TestManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
-
- def test_create_monitor(self, *args):
- set_module_args(dict(
- name='foo',
- parent='parent',
- send='this is a send string',
- receive='this is a receive string',
- ip='10.10.10.10',
- port=80,
- interval=20,
- timeout=30,
- time_until_up=60,
- partition='Common',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods in the specific type of manager
- mm = ModuleManager(module=module)
- mm.exists = Mock(side_effect=[False, True])
- mm.create_on_device = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['parent'] == '/Common/parent'
-
- def test_create_monitor_idempotent(self, *args):
- set_module_args(dict(
- name='asdf',
- parent='http',
- send='GET /\\r\\n',
- receive='hello world',
- ip='1.1.1.1',
- port=389,
- interval=5,
- timeout=16,
- time_until_up=0,
- partition='Common',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- current = Parameters(params=load_fixture('load_ltm_monitor_http.json'))
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods in the specific type of manager
- mm = ModuleManager(module=module)
- mm.exists = Mock(return_value=True)
- mm.read_current_from_device = Mock(return_value=current)
-
- results = mm.exec_module()
-
- assert results['changed'] is False
-
- def test_update_port(self, *args):
- set_module_args(dict(
- name='asdf',
- port=800,
- partition='Common',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- current = Parameters(params=load_fixture('load_ltm_monitor_http.json'))
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods in the specific type of manager
- mm = ModuleManager(module=module)
- mm.exists = Mock(return_value=True)
- mm.read_current_from_device = Mock(return_value=current)
- mm.update_on_device = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['port'] == 800
-
- def test_update_interval(self, *args):
- set_module_args(dict(
- name='foo',
- interval=10,
- partition='Common',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- current = Parameters(params=load_fixture('load_ltm_monitor_http.json'))
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods in the specific type of manager
- mm = ModuleManager(module=module)
- mm.exists = Mock(return_value=True)
- mm.read_current_from_device = Mock(return_value=current)
- mm.update_on_device = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['interval'] == 10
-
- def test_update_interval_larger_than_existing_timeout(self, *args):
- set_module_args(dict(
- name='asdf',
- interval=30,
- partition='Common',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- current = Parameters(params=load_fixture('load_ltm_monitor_http.json'))
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods in the specific type of manager
- mm = ModuleManager(module=module)
- mm.exists = Mock(return_value=True)
- mm.read_current_from_device = Mock(return_value=current)
- mm.update_on_device = Mock(return_value=True)
-
- with pytest.raises(F5ModuleError) as ex:
- mm.exec_module()
-
- assert "must be less than" in str(ex.value)
-
- def test_update_interval_larger_than_new_timeout(self, *args):
- set_module_args(dict(
- name='asdf',
- interval=10,
- timeout=5,
- partition='Common',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- current = Parameters(params=load_fixture('load_ltm_monitor_http.json'))
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods in the specific type of manager
- mm = ModuleManager(module=module)
- mm.exists = Mock(return_value=True)
- mm.read_current_from_device = Mock(return_value=current)
- mm.update_on_device = Mock(return_value=True)
-
- with pytest.raises(F5ModuleError) as ex:
- mm.exec_module()
-
- assert "must be less than" in str(ex.value)
-
- def test_update_send(self, *args):
- set_module_args(dict(
- name='asdf',
- send='this is another send string',
- partition='Common',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- current = Parameters(params=load_fixture('load_ltm_monitor_http.json'))
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods in the specific type of manager
- mm = ModuleManager(module=module)
- mm.exists = Mock(return_value=True)
- mm.read_current_from_device = Mock(return_value=current)
- mm.update_on_device = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['send'] == 'this is another send string'
-
- def test_update_receive(self, *args):
- set_module_args(dict(
- name='asdf',
- receive='this is another receive string',
- partition='Common',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- current = Parameters(params=load_fixture('load_ltm_monitor_http.json'))
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods in the specific type of manager
- mm = ModuleManager(module=module)
- mm.exists = Mock(return_value=True)
- mm.read_current_from_device = Mock(return_value=current)
- mm.update_on_device = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['receive'] == 'this is another receive string'
-
- def test_update_timeout(self, *args):
- set_module_args(dict(
- name='asdf',
- timeout=300,
- partition='Common',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- current = Parameters(params=load_fixture('load_ltm_monitor_http.json'))
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods in the specific type of manager
- mm = ModuleManager(module=module)
- mm.exists = Mock(return_value=True)
- mm.read_current_from_device = Mock(return_value=current)
- mm.update_on_device = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['timeout'] == 300
-
- def test_update_time_until_up(self, *args):
- set_module_args(dict(
- name='asdf',
- time_until_up=300,
- partition='Common',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- current = Parameters(params=load_fixture('load_ltm_monitor_http.json'))
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods in the specific type of manager
- mm = ModuleManager(module=module)
- mm.exists = Mock(return_value=True)
- mm.read_current_from_device = Mock(return_value=current)
- mm.update_on_device = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['time_until_up'] == 300
diff --git a/test/units/modules/network/f5/test_bigip_monitor_https.py b/test/units/modules/network/f5/test_bigip_monitor_https.py
deleted file mode 100644
index 214bec50f5..0000000000
--- a/test/units/modules/network/f5/test_bigip_monitor_https.py
+++ /dev/null
@@ -1,452 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright (c) 2017 F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_monitor_https import Parameters
- from library.modules.bigip_monitor_https import ModuleManager
- from library.modules.bigip_monitor_https import ArgumentSpec
-
- from library.module_utils.network.f5.common import F5ModuleError
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_monitor_https import Parameters
- from ansible.modules.network.f5.bigip_monitor_https import ModuleManager
- from ansible.modules.network.f5.bigip_monitor_https import ArgumentSpec
-
- from ansible.module_utils.network.f5.common import F5ModuleError
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- name='foo',
- parent='parent',
- send='this is a send string',
- receive='this is a receive string',
- ip='10.10.10.10',
- port=80,
- interval=20,
- timeout=30,
- time_until_up=60,
- partition='Common'
- )
-
- p = Parameters(params=args)
- assert p.name == 'foo'
- assert p.parent == '/Common/parent'
- assert p.send == 'this is a send string'
- assert p.receive == 'this is a receive string'
- assert p.ip == '10.10.10.10'
- assert p.type == 'https'
- assert p.port == 80
- assert p.destination == '10.10.10.10:80'
- assert p.interval == 20
- assert p.timeout == 30
- assert p.time_until_up == 60
-
- def test_module_parameters_ints_as_strings(self):
- args = dict(
- name='foo',
- parent='parent',
- send='this is a send string',
- receive='this is a receive string',
- ip='10.10.10.10',
- port='80',
- interval='20',
- timeout='30',
- time_until_up='60',
- partition='Common'
- )
-
- p = Parameters(params=args)
- assert p.name == 'foo'
- assert p.parent == '/Common/parent'
- assert p.send == 'this is a send string'
- assert p.receive == 'this is a receive string'
- assert p.ip == '10.10.10.10'
- assert p.type == 'https'
- assert p.port == 80
- assert p.destination == '10.10.10.10:80'
- assert p.interval == 20
- assert p.timeout == 30
- assert p.time_until_up == 60
-
- def test_api_parameters(self):
- args = dict(
- name='foo',
- defaultsFrom='/Common/parent',
- send='this is a send string',
- recv='this is a receive string',
- destination='10.10.10.10:80',
- interval=20,
- timeout=30,
- timeUntilUp=60
- )
-
- p = Parameters(params=args)
- assert p.name == 'foo'
- assert p.parent == '/Common/parent'
- assert p.send == 'this is a send string'
- assert p.receive == 'this is a receive string'
- assert p.ip == '10.10.10.10'
- assert p.type == 'https'
- assert p.port == 80
- assert p.destination == '10.10.10.10:80'
- assert p.interval == 20
- assert p.timeout == 30
- assert p.time_until_up == 60
-
-
-class TestManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
-
- def test_create_monitor(self, *args):
- set_module_args(dict(
- name='foo',
- parent='parent',
- send='this is a send string',
- receive='this is a receive string',
- ip='10.10.10.10',
- port=80,
- interval=20,
- timeout=30,
- time_until_up=60,
- partition='Common',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods in the specific type of manager
- mm = ModuleManager(module=module)
- mm.exists = Mock(side_effect=[False, True])
- mm.create_on_device = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['parent'] == '/Common/parent'
-
- def test_create_monitor_idempotent(self, *args):
- set_module_args(dict(
- name='asdf',
- parent='https',
- send='GET /\\r\\n',
- receive='hello world',
- ip='1.1.1.1',
- port=389,
- interval=5,
- timeout=16,
- time_until_up=0,
- partition='Common',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- current = Parameters(params=load_fixture('load_ltm_monitor_https.json'))
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods in the specific type of manager
- mm = ModuleManager(module=module)
- mm.exists = Mock(return_value=True)
- mm.read_current_from_device = Mock(return_value=current)
-
- results = mm.exec_module()
-
- assert results['changed'] is False
-
- def test_update_port(self, *args):
- set_module_args(dict(
- name='asdf',
- port=800,
- partition='Common',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- current = Parameters(params=load_fixture('load_ltm_monitor_https.json'))
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods in the specific type of manager
- mm = ModuleManager(module=module)
- mm.exists = Mock(return_value=True)
- mm.read_current_from_device = Mock(return_value=current)
- mm.update_on_device = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['port'] == 800
-
- def test_update_interval(self, *args):
- set_module_args(dict(
- name='foo',
- interval=10,
- partition='Common',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- current = Parameters(params=load_fixture('load_ltm_monitor_https.json'))
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods in the specific type of manager
- mm = ModuleManager(module=module)
- mm.exists = Mock(return_value=True)
- mm.read_current_from_device = Mock(return_value=current)
- mm.update_on_device = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['interval'] == 10
-
- def test_update_interval_larger_than_existing_timeout(self, *args):
- set_module_args(dict(
- name='asdf',
- interval=30,
- partition='Common',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- current = Parameters(params=load_fixture('load_ltm_monitor_https.json'))
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods in the specific type of manager
- mm = ModuleManager(module=module)
- mm.exists = Mock(return_value=True)
- mm.read_current_from_device = Mock(return_value=current)
- mm.update_on_device = Mock(return_value=True)
-
- with pytest.raises(F5ModuleError) as ex:
- mm.exec_module()
-
- assert "must be less than" in str(ex.value)
-
- def test_update_interval_larger_than_new_timeout(self, *args):
- set_module_args(dict(
- name='asdf',
- interval=10,
- timeout=5,
- partition='Common',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- current = Parameters(params=load_fixture('load_ltm_monitor_https.json'))
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods in the specific type of manager
- mm = ModuleManager(module=module)
- mm.exists = Mock(return_value=True)
- mm.read_current_from_device = Mock(return_value=current)
- mm.update_on_device = Mock(return_value=True)
-
- with pytest.raises(F5ModuleError) as ex:
- mm.exec_module()
-
- assert "must be less than" in str(ex.value)
-
- def test_update_send(self, *args):
- set_module_args(dict(
- name='asdf',
- send='this is another send string',
- partition='Common',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- current = Parameters(params=load_fixture('load_ltm_monitor_https.json'))
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods in the specific type of manager
- mm = ModuleManager(module=module)
- mm.exists = Mock(return_value=True)
- mm.read_current_from_device = Mock(return_value=current)
- mm.update_on_device = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['send'] == 'this is another send string'
-
- def test_update_receive(self, *args):
- set_module_args(dict(
- name='asdf',
- receive='this is another receive string',
- partition='Common',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- current = Parameters(params=load_fixture('load_ltm_monitor_https.json'))
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods in the specific type of manager
- mm = ModuleManager(module=module)
- mm.exists = Mock(return_value=True)
- mm.read_current_from_device = Mock(return_value=current)
- mm.update_on_device = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['receive'] == 'this is another receive string'
-
- def test_update_timeout(self, *args):
- set_module_args(dict(
- name='asdf',
- timeout=300,
- partition='Common',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- current = Parameters(params=load_fixture('load_ltm_monitor_https.json'))
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods in the specific type of manager
- mm = ModuleManager(module=module)
- mm.exists = Mock(return_value=True)
- mm.read_current_from_device = Mock(return_value=current)
- mm.update_on_device = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['timeout'] == 300
-
- def test_update_time_until_up(self, *args):
- set_module_args(dict(
- name='asdf',
- time_until_up=300,
- partition='Common',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- current = Parameters(params=load_fixture('load_ltm_monitor_https.json'))
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods in the specific type of manager
- mm = ModuleManager(module=module)
- mm.exists = Mock(return_value=True)
- mm.read_current_from_device = Mock(return_value=current)
- mm.update_on_device = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['time_until_up'] == 300
diff --git a/test/units/modules/network/f5/test_bigip_monitor_ldap.py b/test/units/modules/network/f5/test_bigip_monitor_ldap.py
deleted file mode 100644
index a81fd34d96..0000000000
--- a/test/units/modules/network/f5/test_bigip_monitor_ldap.py
+++ /dev/null
@@ -1,110 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2018, F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_monitor_ldap import ApiParameters
- from library.modules.bigip_monitor_ldap import ModuleManager
- from library.modules.bigip_monitor_ldap import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_monitor_ldap import ApiParameters
- from ansible.modules.network.f5.bigip_monitor_ldap import ModuleManager
- from ansible.modules.network.f5.bigip_monitor_ldap import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- parent='/Common/ldap',
- interval=10,
- time_until_up=0,
- timeout=30,
- )
-
- p = ApiParameters(params=args)
- assert p.parent == '/Common/ldap'
- assert p.interval == 10
- assert p.time_until_up == 0
- assert p.timeout == 30
-
-
-class TestManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
-
- def test_create(self, *args):
- set_module_args(dict(
- name='foo',
- parent='/Common/ldap',
- interval=20,
- timeout=30,
- time_until_up=60,
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods in the specific type of manager
- mm = ModuleManager(module=module)
- mm.exists = Mock(side_effect=[False, True])
- mm.create_on_device = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
diff --git a/test/units/modules/network/f5/test_bigip_monitor_snmp_dca.py b/test/units/modules/network/f5/test_bigip_monitor_snmp_dca.py
deleted file mode 100644
index 8c45bddbb7..0000000000
--- a/test/units/modules/network/f5/test_bigip_monitor_snmp_dca.py
+++ /dev/null
@@ -1,175 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright (c) 2017 F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_monitor_snmp_dca import Parameters
- from library.modules.bigip_monitor_snmp_dca import ModuleManager
- from library.modules.bigip_monitor_snmp_dca import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_monitor_snmp_dca import Parameters
- from ansible.modules.network.f5.bigip_monitor_snmp_dca import ModuleManager
- from ansible.modules.network.f5.bigip_monitor_snmp_dca import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- agent_type='UCD',
- community='public',
- cpu_coefficient='1.5',
- cpu_threshold='80',
- parent='/Common/snmp_dca',
- disk_coefficient='2.0',
- disk_threshold='90',
- interval=10,
- memory_coefficient='1.0',
- memory_threshold='70',
- time_until_up=0,
- timeout=30,
- version='v1'
- )
-
- p = Parameters(params=args)
- assert p.agent_type == 'UCD'
- assert p.community == 'public'
- assert p.cpu_coefficient == 1.5
- assert p.cpu_threshold == 80
- assert p.parent == '/Common/snmp_dca'
- assert p.disk_coefficient == 2.0
- assert p.disk_threshold == 90
- assert p.interval == 10
- assert p.memory_coefficient == 1.0
- assert p.memory_threshold == 70
- assert p.time_until_up == 0
- assert p.timeout == 30
- assert p.version == 'v1'
-
- def test_api_parameters(self):
- args = dict(
- agentType='UCD',
- community='public',
- cpuCoefficient='1.5',
- cpuThreshold='80',
- defaultsFrom='/Common/snmp_dca',
- diskCoefficient='2.0',
- diskThreshold='90',
- interval=10,
- memoryCoefficient='1.0',
- memoryThreshold='70',
- timeUntilUp=0,
- timeout=30,
- apiRawValues={
- "userDefined asdasd": "{ foo }",
- "userDefined bar": "tim rupp",
- "user-defined baz-": "nia",
- "userDefined userDefined": "23234"
- },
- version='v1'
- )
-
- p = Parameters(params=args)
- assert p.agent_type == 'UCD'
- assert p.community == 'public'
- assert p.cpu_coefficient == 1.5
- assert p.cpu_threshold == 80
- assert p.parent == '/Common/snmp_dca'
- assert p.disk_coefficient == 2.0
- assert p.disk_threshold == 90
- assert p.interval == 10
- assert p.memory_coefficient == 1.0
- assert p.memory_threshold == 70
- assert p.time_until_up == 0
- assert p.timeout == 30
- assert p.version == 'v1'
-
-
-class TestManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
-
- def test_create(self, *args):
- set_module_args(dict(
- name='foo',
- agent_type='UCD',
- community='public',
- cpu_coefficient='1.5',
- cpu_threshold='80',
- parent='/Common/snmp_dca',
- disk_coefficient='2.0',
- disk_threshold='90',
- memory_coefficient='1.0',
- memory_threshold='70',
- version='v1',
- interval=20,
- timeout=30,
- time_until_up=60,
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods in the specific type of manager
- mm = ModuleManager(module=module)
- mm.exists = Mock(side_effect=[False, True])
- mm.create_on_device = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
diff --git a/test/units/modules/network/f5/test_bigip_monitor_tcp.py b/test/units/modules/network/f5/test_bigip_monitor_tcp.py
deleted file mode 100644
index de64d3ef42..0000000000
--- a/test/units/modules/network/f5/test_bigip_monitor_tcp.py
+++ /dev/null
@@ -1,454 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright (c) 2017 F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_monitor_tcp import Parameters
- from library.modules.bigip_monitor_tcp import ModuleManager
- from library.modules.bigip_monitor_tcp import ArgumentSpec
-
- from library.module_utils.network.f5.common import F5ModuleError
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_monitor_tcp import Parameters
- from ansible.modules.network.f5.bigip_monitor_tcp import ModuleManager
- from ansible.modules.network.f5.bigip_monitor_tcp import ArgumentSpec
-
- from ansible.module_utils.network.f5.common import F5ModuleError
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- name='foo',
- parent='parent',
- send='this is a send string',
- receive='this is a receive string',
- ip='10.10.10.10',
- type='TTYPE_TCP',
- port=80,
- interval=20,
- timeout=30,
- time_until_up=60,
- partition='Common'
- )
-
- p = Parameters(params=args)
- assert p.name == 'foo'
- assert p.parent == '/Common/parent'
- assert p.send == 'this is a send string'
- assert p.receive == 'this is a receive string'
- assert p.ip == '10.10.10.10'
- assert p.type == 'tcp'
- assert p.port == 80
- assert p.destination == '10.10.10.10:80'
- assert p.interval == 20
- assert p.timeout == 30
- assert p.time_until_up == 60
-
- def test_module_parameters_ints_as_strings(self):
- args = dict(
- name='foo',
- parent='parent',
- send='this is a send string',
- receive='this is a receive string',
- ip='10.10.10.10',
- type='TTYPE_TCP',
- port='80',
- interval='20',
- timeout='30',
- time_until_up='60',
- partition='Common'
- )
-
- p = Parameters(params=args)
- assert p.name == 'foo'
- assert p.parent == '/Common/parent'
- assert p.send == 'this is a send string'
- assert p.receive == 'this is a receive string'
- assert p.ip == '10.10.10.10'
- assert p.type == 'tcp'
- assert p.port == 80
- assert p.destination == '10.10.10.10:80'
- assert p.interval == 20
- assert p.timeout == 30
- assert p.time_until_up == 60
-
- def test_api_parameters(self):
- args = dict(
- name='foo',
- defaultsFrom='/Common/parent',
- send='this is a send string',
- recv='this is a receive string',
- destination='10.10.10.10:80',
- interval=20,
- timeout=30,
- timeUntilUp=60
- )
-
- p = Parameters(params=args)
- assert p.name == 'foo'
- assert p.parent == '/Common/parent'
- assert p.send == 'this is a send string'
- assert p.receive == 'this is a receive string'
- assert p.ip == '10.10.10.10'
- assert p.type == 'tcp'
- assert p.port == 80
- assert p.destination == '10.10.10.10:80'
- assert p.interval == 20
- assert p.timeout == 30
- assert p.time_until_up == 60
-
-
-class TestManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
-
- def test_create_monitor(self, *args):
- set_module_args(dict(
- name='foo',
- parent='parent',
- send='this is a send string',
- receive='this is a receive string',
- ip='10.10.10.10',
- port=80,
- interval=20,
- timeout=30,
- time_until_up=60,
- partition='Common',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods to force specific logic in the module to happen
- mm = ModuleManager(module=module)
- mm.exists = Mock(side_effect=[False, True])
- mm.create_on_device = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['parent'] == '/Common/parent'
-
- def test_create_monitor_idempotent(self, *args):
- set_module_args(dict(
- name='foo',
- parent='tcp',
- send='this is a send string',
- receive='this is a receive string',
- ip='10.10.10.10',
- port=80,
- interval=20,
- timeout=30,
- time_until_up=60,
- partition='Common',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- current = Parameters(params=load_fixture('load_ltm_monitor_tcp.json'))
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods in the specific type of manager
- mm = ModuleManager(module=module)
- mm.exists = Mock(return_value=True)
- mm.read_current_from_device = Mock(return_value=current)
-
- results = mm.exec_module()
-
- assert results['changed'] is False
-
- def test_update_port(self, *args):
- set_module_args(dict(
- name='foo',
- port=800,
- partition='Common',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- current = Parameters(params=load_fixture('load_ltm_monitor_tcp.json'))
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods in the specific type of manager
- mm = ModuleManager(module=module)
- mm.exists = Mock(return_value=True)
- mm.read_current_from_device = Mock(return_value=current)
- mm.update_on_device = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['port'] == 800
-
- def test_update_interval(self, *args):
- set_module_args(dict(
- name='foo',
- interval=10,
- partition='Common',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- current = Parameters(params=load_fixture('load_ltm_monitor_tcp.json'))
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods in the specific type of manager
- mm = ModuleManager(module=module)
- mm.exists = Mock(return_value=True)
- mm.read_current_from_device = Mock(return_value=current)
- mm.update_on_device = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['interval'] == 10
-
- def test_update_interval_larger_than_existing_timeout(self, *args):
- set_module_args(dict(
- name='foo',
- interval=30,
- partition='Common',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- current = Parameters(params=load_fixture('load_ltm_monitor_tcp.json'))
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods in the specific type of manager
- mm = ModuleManager(module=module)
- mm.exists = Mock(return_value=True)
- mm.read_current_from_device = Mock(return_value=current)
- mm.update_on_device = Mock(return_value=True)
-
- with pytest.raises(F5ModuleError) as ex:
- mm.exec_module()
-
- assert "must be less than" in str(ex.value)
-
- def test_update_interval_larger_than_new_timeout(self, *args):
- set_module_args(dict(
- name='foo',
- interval=10,
- timeout=5,
- partition='Common',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- current = Parameters(params=load_fixture('load_ltm_monitor_tcp.json'))
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods in the specific type of manager
- mm = ModuleManager(module=module)
- mm.exists = Mock(return_value=True)
- mm.read_current_from_device = Mock(return_value=current)
- mm.update_on_device = Mock(return_value=True)
-
- with pytest.raises(F5ModuleError) as ex:
- mm.exec_module()
-
- assert "must be less than" in str(ex.value)
-
- def test_update_send(self, *args):
- set_module_args(dict(
- name='foo',
- send='this is another send string',
- partition='Common',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- current = Parameters(params=load_fixture('load_ltm_monitor_tcp.json'))
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods in the specific type of manager
- mm = ModuleManager(module=module)
- mm.exists = Mock(return_value=True)
- mm.read_current_from_device = Mock(return_value=current)
- mm.update_on_device = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['send'] == 'this is another send string'
-
- def test_update_receive(self, *args):
- set_module_args(dict(
- name='foo',
- receive='this is another receive string',
- partition='Common',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- current = Parameters(params=load_fixture('load_ltm_monitor_tcp.json'))
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods in the specific type of manager
- mm = ModuleManager(module=module)
- mm.exists = Mock(return_value=True)
- mm.read_current_from_device = Mock(return_value=current)
- mm.update_on_device = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['receive'] == 'this is another receive string'
-
- def test_update_timeout(self, *args):
- set_module_args(dict(
- name='foo',
- timeout=300,
- partition='Common',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- current = Parameters(params=load_fixture('load_ltm_monitor_tcp.json'))
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods in the specific type of manager
- mm = ModuleManager(module=module)
- mm.exists = Mock(return_value=True)
- mm.read_current_from_device = Mock(return_value=current)
- mm.update_on_device = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['timeout'] == 300
-
- def test_update_time_until_up(self, *args):
- set_module_args(dict(
- name='foo',
- time_until_up=300,
- partition='Common',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- current = Parameters(params=load_fixture('load_ltm_monitor_tcp.json'))
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods in the specific type of manager
- mm = ModuleManager(module=module)
- mm.exists = Mock(return_value=True)
- mm.read_current_from_device = Mock(return_value=current)
- mm.update_on_device = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['time_until_up'] == 300
diff --git a/test/units/modules/network/f5/test_bigip_monitor_tcp_echo.py b/test/units/modules/network/f5/test_bigip_monitor_tcp_echo.py
deleted file mode 100644
index a33a1c495b..0000000000
--- a/test/units/modules/network/f5/test_bigip_monitor_tcp_echo.py
+++ /dev/null
@@ -1,331 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright (c) 2017 F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_monitor_tcp_echo import Parameters
- from library.modules.bigip_monitor_tcp_echo import ModuleManager
- from library.modules.bigip_monitor_tcp_echo import ArgumentSpec
-
- from library.module_utils.network.f5.common import F5ModuleError
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_monitor_tcp_echo import Parameters
- from ansible.modules.network.f5.bigip_monitor_tcp_echo import ModuleManager
- from ansible.modules.network.f5.bigip_monitor_tcp_echo import ArgumentSpec
-
- from ansible.module_utils.network.f5.common import F5ModuleError
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- name='foo',
- parent='parent',
- ip='10.10.10.10',
- interval=20,
- timeout=30,
- time_until_up=60,
- partition='Common'
- )
-
- p = Parameters(params=args)
- assert p.name == 'foo'
- assert p.parent == '/Common/parent'
- assert p.ip == '10.10.10.10'
- assert p.type == 'tcp_echo'
- assert p.destination == '10.10.10.10'
- assert p.interval == 20
- assert p.timeout == 30
- assert p.time_until_up == 60
-
- def test_module_parameters_ints_as_strings(self):
- args = dict(
- name='foo',
- parent='parent',
- ip='10.10.10.10',
- interval='20',
- timeout='30',
- time_until_up='60',
- partition='Common'
- )
-
- p = Parameters(params=args)
- assert p.name == 'foo'
- assert p.parent == '/Common/parent'
- assert p.ip == '10.10.10.10'
- assert p.type == 'tcp_echo'
- assert p.destination == '10.10.10.10'
- assert p.interval == 20
- assert p.timeout == 30
- assert p.time_until_up == 60
-
- def test_api_parameters(self):
- args = dict(
- name='foo',
- defaultsFrom='/Common/parent',
- destination='10.10.10.10',
- interval=20,
- timeout=30,
- timeUntilUp=60
- )
-
- p = Parameters(params=args)
- assert p.name == 'foo'
- assert p.parent == '/Common/parent'
- assert p.ip == '10.10.10.10'
- assert p.type == 'tcp_echo'
- assert p.destination == '10.10.10.10'
- assert p.interval == 20
- assert p.timeout == 30
- assert p.time_until_up == 60
-
-
-class TestManagerEcho(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
-
- def test_create_monitor(self, *args):
- set_module_args(dict(
- name='foo',
- ip='10.10.10.10',
- interval=20,
- timeout=30,
- time_until_up=60,
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods in the specific type of manager
- mm = ModuleManager(module=module)
- mm.exists = Mock(side_effect=[False, True])
- mm.create_on_device = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
-
- def test_create_monitor_idempotent(self, *args):
- set_module_args(dict(
- name='foo',
- ip='10.10.10.10',
- interval=20,
- timeout=30,
- time_until_up=60,
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- current = Parameters(params=load_fixture('load_ltm_monitor_tcp_echo.json'))
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods in the specific type of manager
- mm = ModuleManager(module=module)
- mm.exists = Mock(return_value=True)
- mm.read_current_from_device = Mock(return_value=current)
-
- results = mm.exec_module()
-
- assert results['changed'] is False
-
- def test_update_interval(self, *args):
- set_module_args(dict(
- name='foo',
- interval=10,
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- current = Parameters(params=load_fixture('load_ltm_monitor_tcp_echo.json'))
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods in the specific type of manager
- mm = ModuleManager(module=module)
- mm.exists = Mock(return_value=True)
- mm.read_current_from_device = Mock(return_value=current)
- mm.update_on_device = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['interval'] == 10
-
- def test_update_interval_larger_than_existing_timeout(self, *args):
- set_module_args(dict(
- name='foo',
- interval=30,
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- current = Parameters(params=load_fixture('load_ltm_monitor_tcp_echo.json'))
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods in the specific type of manager
- mm = ModuleManager(module=module)
- mm.exists = Mock(return_value=True)
- mm.read_current_from_device = Mock(return_value=current)
- mm.update_on_device = Mock(return_value=True)
-
- with pytest.raises(F5ModuleError) as ex:
- mm.exec_module()
-
- assert "must be less than" in str(ex.value)
-
- def test_update_interval_larger_than_new_timeout(self, *args):
- set_module_args(dict(
- name='foo',
- interval=10,
- timeout=5,
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- current = Parameters(params=load_fixture('load_ltm_monitor_tcp_echo.json'))
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods in the specific type of manager
- mm = ModuleManager(module=module)
- mm.exists = Mock(return_value=True)
- mm.read_current_from_device = Mock(return_value=current)
- mm.update_on_device = Mock(return_value=True)
-
- with pytest.raises(F5ModuleError) as ex:
- mm.exec_module()
-
- assert "must be less than" in str(ex.value)
-
- def test_update_timeout(self, *args):
- set_module_args(dict(
- name='foo',
- timeout=300,
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- current = Parameters(params=load_fixture('load_ltm_monitor_tcp_echo.json'))
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods in the specific type of manager
- mm = ModuleManager(module=module)
- mm.exists = Mock(return_value=True)
- mm.read_current_from_device = Mock(return_value=current)
- mm.update_on_device = Mock(return_value=True)
-
- results = mm.exec_module()
- assert results['changed'] is True
- assert results['timeout'] == 300
-
- def test_update_time_until_up(self, *args):
- set_module_args(dict(
- name='foo',
- time_until_up=300,
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- current = Parameters(params=load_fixture('load_ltm_monitor_tcp_echo.json'))
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods in the specific type of manager
- mm = ModuleManager(module=module)
- mm.exists = Mock(return_value=True)
- mm.read_current_from_device = Mock(return_value=current)
- mm.update_on_device = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['time_until_up'] == 300
diff --git a/test/units/modules/network/f5/test_bigip_monitor_tcp_half_open.py b/test/units/modules/network/f5/test_bigip_monitor_tcp_half_open.py
deleted file mode 100644
index b009ddbca5..0000000000
--- a/test/units/modules/network/f5/test_bigip_monitor_tcp_half_open.py
+++ /dev/null
@@ -1,338 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright (c) 2017 F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_monitor_tcp_half_open import Parameters
- from library.modules.bigip_monitor_tcp_half_open import ModuleManager
- from library.modules.bigip_monitor_tcp_half_open import ArgumentSpec
-
- from library.module_utils.network.f5.common import F5ModuleError
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_monitor_tcp_half_open import Parameters
- from ansible.modules.network.f5.bigip_monitor_tcp_half_open import ModuleManager
- from ansible.modules.network.f5.bigip_monitor_tcp_half_open import ArgumentSpec
-
- from ansible.module_utils.network.f5.common import F5ModuleError
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- name='foo',
- parent='parent',
- ip='10.10.10.10',
- port=80,
- interval=20,
- timeout=30,
- time_until_up=60,
- partition='Common'
- )
-
- p = Parameters(params=args)
- assert p.name == 'foo'
- assert p.parent == '/Common/parent'
- assert p.ip == '10.10.10.10'
- assert p.port == 80
- assert p.type == 'tcp_half_open'
- assert p.destination == '10.10.10.10:80'
- assert p.interval == 20
- assert p.timeout == 30
- assert p.time_until_up == 60
-
- def test_module_parameters_ints_as_strings(self):
- args = dict(
- name='foo',
- parent='parent',
- ip='10.10.10.10',
- port=80,
- interval='20',
- timeout='30',
- time_until_up='60',
- partition='Common'
- )
-
- p = Parameters(params=args)
- assert p.name == 'foo'
- assert p.parent == '/Common/parent'
- assert p.ip == '10.10.10.10'
- assert p.port == 80
- assert p.type == 'tcp_half_open'
- assert p.destination == '10.10.10.10:80'
- assert p.interval == 20
- assert p.timeout == 30
- assert p.time_until_up == 60
-
- def test_api_parameters(self):
- args = dict(
- name='foo',
- defaultsFrom='/Common/parent',
- destination='10.10.10.10:80',
- interval=20,
- timeout=30,
- timeUntilUp=60
- )
-
- p = Parameters(params=args)
- assert p.name == 'foo'
- assert p.parent == '/Common/parent'
- assert p.ip == '10.10.10.10'
- assert p.port == 80
- assert p.type == 'tcp_half_open'
- assert p.destination == '10.10.10.10:80'
- assert p.interval == 20
- assert p.timeout == 30
- assert p.time_until_up == 60
-
-
-class TestManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
-
- def test_create_monitor(self, *args):
- set_module_args(dict(
- name='foo',
- ip='10.10.10.10',
- port=80,
- interval=20,
- timeout=30,
- time_until_up=60,
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods in the specific type of manager
- mm = ModuleManager(module=module)
- mm.exists = Mock(side_effect=[False, True])
- mm.create_on_device = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
-
- def test_create_monitor_idempotent(self, *args):
- set_module_args(dict(
- name='foo',
- ip='10.10.10.10',
- port=80,
- interval=20,
- timeout=30,
- time_until_up=60,
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- current = Parameters(params=load_fixture('load_ltm_monitor_tcp_half_open.json'))
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods in the specific type of manager
- mm = ModuleManager(module=module)
- mm.exists = Mock(return_value=True)
- mm.read_current_from_device = Mock(return_value=current)
-
- results = mm.exec_module()
-
- assert results['changed'] is False
-
- def test_update_interval(self, *args):
- set_module_args(dict(
- name='foo',
- interval=10,
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- current = Parameters(params=load_fixture('load_ltm_monitor_tcp_half_open.json'))
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods in the specific type of manager
- mm = ModuleManager(module=module)
- mm.exists = Mock(return_value=True)
- mm.read_current_from_device = Mock(return_value=current)
- mm.update_on_device = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['interval'] == 10
-
- def test_update_interval_larger_than_existing_timeout(self, *args):
- set_module_args(dict(
- name='foo',
- interval=30,
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- current = Parameters(params=load_fixture('load_ltm_monitor_tcp_half_open.json'))
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods in the specific type of manager
- mm = ModuleManager(module=module)
- mm.exists = Mock(return_value=True)
- mm.read_current_from_device = Mock(return_value=current)
- mm.update_on_device = Mock(return_value=True)
-
- with pytest.raises(F5ModuleError) as ex:
- mm.exec_module()
-
- assert "must be less than" in str(ex.value)
-
- def test_update_interval_larger_than_new_timeout(self, *args):
- set_module_args(dict(
- name='foo',
- interval=10,
- timeout=5,
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- current = Parameters(params=load_fixture('load_ltm_monitor_tcp_half_open.json'))
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods in the specific type of manager
- mm = ModuleManager(module=module)
- mm.exists = Mock(return_value=True)
- mm.read_current_from_device = Mock(return_value=current)
- mm.update_on_device = Mock(return_value=True)
-
- with pytest.raises(F5ModuleError) as ex:
- mm.exec_module()
-
- assert "must be less than" in str(ex.value)
-
- def test_update_timeout(self, *args):
- set_module_args(dict(
- name='foo',
- timeout=300,
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- current = Parameters(params=load_fixture('load_ltm_monitor_tcp_half_open.json'))
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods in the specific type of manager
- mm = ModuleManager(module=module)
- mm.exists = Mock(return_value=True)
- mm.read_current_from_device = Mock(return_value=current)
- mm.update_on_device = Mock(return_value=True)
-
- results = mm.exec_module()
- assert results['changed'] is True
- assert results['timeout'] == 300
-
- def test_update_time_until_up(self, *args):
- set_module_args(dict(
- name='foo',
- time_until_up=300,
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- current = Parameters(params=load_fixture('load_ltm_monitor_tcp_half_open.json'))
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods in the specific type of manager
- mm = ModuleManager(module=module)
- mm.exists = Mock(return_value=True)
- mm.read_current_from_device = Mock(return_value=current)
- mm.update_on_device = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['time_until_up'] == 300
diff --git a/test/units/modules/network/f5/test_bigip_monitor_udp.py b/test/units/modules/network/f5/test_bigip_monitor_udp.py
deleted file mode 100644
index 71eb245f37..0000000000
--- a/test/units/modules/network/f5/test_bigip_monitor_udp.py
+++ /dev/null
@@ -1,452 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_monitor_udp import Parameters
- from library.modules.bigip_monitor_udp import ModuleManager
- from library.modules.bigip_monitor_udp import ArgumentSpec
-
- from library.module_utils.network.f5.common import F5ModuleError
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_monitor_udp import Parameters
- from ansible.modules.network.f5.bigip_monitor_udp import ModuleManager
- from ansible.modules.network.f5.bigip_monitor_udp import ArgumentSpec
-
- from ansible.module_utils.network.f5.common import F5ModuleError
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- name='foo',
- parent='parent',
- send='this is a send string',
- receive='this is a receive string',
- ip='10.10.10.10',
- port=80,
- interval=20,
- timeout=30,
- time_until_up=60,
- partition='Common'
- )
-
- p = Parameters(params=args)
- assert p.name == 'foo'
- assert p.parent == '/Common/parent'
- assert p.send == 'this is a send string'
- assert p.receive == 'this is a receive string'
- assert p.ip == '10.10.10.10'
- assert p.type == 'udp'
- assert p.port == 80
- assert p.destination == '10.10.10.10:80'
- assert p.interval == 20
- assert p.timeout == 30
- assert p.time_until_up == 60
-
- def test_module_parameters_ints_as_strings(self):
- args = dict(
- name='foo',
- parent='parent',
- send='this is a send string',
- receive='this is a receive string',
- ip='10.10.10.10',
- port='80',
- interval='20',
- timeout='30',
- time_until_up='60',
- partition='Common'
- )
-
- p = Parameters(params=args)
- assert p.name == 'foo'
- assert p.parent == '/Common/parent'
- assert p.send == 'this is a send string'
- assert p.receive == 'this is a receive string'
- assert p.ip == '10.10.10.10'
- assert p.type == 'udp'
- assert p.port == 80
- assert p.destination == '10.10.10.10:80'
- assert p.interval == 20
- assert p.timeout == 30
- assert p.time_until_up == 60
-
- def test_api_parameters(self):
- args = dict(
- name='foo',
- defaultsFrom='/Common/parent',
- send='this is a send string',
- recv='this is a receive string',
- destination='10.10.10.10:80',
- interval=20,
- timeout=30,
- timeUntilUp=60
- )
-
- p = Parameters(params=args)
- assert p.name == 'foo'
- assert p.parent == '/Common/parent'
- assert p.send == 'this is a send string'
- assert p.receive == 'this is a receive string'
- assert p.ip == '10.10.10.10'
- assert p.type == 'udp'
- assert p.port == 80
- assert p.destination == '10.10.10.10:80'
- assert p.interval == 20
- assert p.timeout == 30
- assert p.time_until_up == 60
-
-
-class TestManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
-
- def test_create_monitor(self, *args):
- set_module_args(dict(
- name='foo',
- parent='parent',
- send='this is a send string',
- receive='this is a receive string',
- ip='10.10.10.10',
- port=80,
- interval=20,
- timeout=30,
- time_until_up=60,
- partition='Common',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods in the specific type of manager
- mm = ModuleManager(module=module)
- mm.exists = Mock(side_effect=[False, True])
- mm.create_on_device = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['parent'] == '/Common/parent'
-
- def test_create_monitor_idempotent(self, *args):
- set_module_args(dict(
- name='asdf',
- parent='udp',
- send='default send string',
- receive='hello world',
- ip='1.1.1.1',
- port=389,
- interval=5,
- timeout=16,
- time_until_up=0,
- partition='Common',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- current = Parameters(params=load_fixture('load_ltm_monitor_udp.json'))
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods in the specific type of manager
- mm = ModuleManager(module=module)
- mm.exists = Mock(return_value=True)
- mm.read_current_from_device = Mock(return_value=current)
-
- results = mm.exec_module()
-
- assert results['changed'] is False
-
- def test_update_port(self, *args):
- set_module_args(dict(
- name='asdf',
- port=800,
- partition='Common',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- current = Parameters(params=load_fixture('load_ltm_monitor_udp.json'))
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods in the specific type of manager
- mm = ModuleManager(module=module)
- mm.exists = Mock(return_value=True)
- mm.read_current_from_device = Mock(return_value=current)
- mm.update_on_device = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['port'] == 800
-
- def test_update_interval(self, *args):
- set_module_args(dict(
- name='foo',
- interval=10,
- partition='Common',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- current = Parameters(params=load_fixture('load_ltm_monitor_udp.json'))
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods in the specific type of manager
- mm = ModuleManager(module=module)
- mm.exists = Mock(return_value=True)
- mm.read_current_from_device = Mock(return_value=current)
- mm.update_on_device = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['interval'] == 10
-
- def test_update_interval_larger_than_existing_timeout(self, *args):
- set_module_args(dict(
- name='asdf',
- interval=30,
- partition='Common',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- current = Parameters(params=load_fixture('load_ltm_monitor_udp.json'))
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods in the specific type of manager
- mm = ModuleManager(module=module)
- mm.exists = Mock(return_value=True)
- mm.read_current_from_device = Mock(return_value=current)
- mm.update_on_device = Mock(return_value=True)
-
- with pytest.raises(F5ModuleError) as ex:
- mm.exec_module()
-
- assert "must be less than" in str(ex.value)
-
- def test_update_interval_larger_than_new_timeout(self, *args):
- set_module_args(dict(
- name='asdf',
- interval=10,
- timeout=5,
- partition='Common',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- current = Parameters(params=load_fixture('load_ltm_monitor_udp.json'))
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods in the specific type of manager
- mm = ModuleManager(module=module)
- mm.exists = Mock(return_value=True)
- mm.read_current_from_device = Mock(return_value=current)
- mm.update_on_device = Mock(return_value=True)
-
- with pytest.raises(F5ModuleError) as ex:
- mm.exec_module()
-
- assert "must be less than" in str(ex.value)
-
- def test_update_send(self, *args):
- set_module_args(dict(
- name='asdf',
- send='this is another send string',
- partition='Common',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- current = Parameters(params=load_fixture('load_ltm_monitor_udp.json'))
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods in the specific type of manager
- mm = ModuleManager(module=module)
- mm.exists = Mock(return_value=True)
- mm.read_current_from_device = Mock(return_value=current)
- mm.update_on_device = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['send'] == 'this is another send string'
-
- def test_update_receive(self, *args):
- set_module_args(dict(
- name='asdf',
- receive='this is another receive string',
- partition='Common',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- current = Parameters(params=load_fixture('load_ltm_monitor_udp.json'))
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods in the specific type of manager
- mm = ModuleManager(module=module)
- mm.exists = Mock(return_value=True)
- mm.read_current_from_device = Mock(return_value=current)
- mm.update_on_device = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['receive'] == 'this is another receive string'
-
- def test_update_timeout(self, *args):
- set_module_args(dict(
- name='asdf',
- timeout=300,
- partition='Common',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- current = Parameters(params=load_fixture('load_ltm_monitor_udp.json'))
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods in the specific type of manager
- mm = ModuleManager(module=module)
- mm.exists = Mock(return_value=True)
- mm.read_current_from_device = Mock(return_value=current)
- mm.update_on_device = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['timeout'] == 300
-
- def test_update_time_until_up(self, *args):
- set_module_args(dict(
- name='asdf',
- time_until_up=300,
- partition='Common',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- current = Parameters(params=load_fixture('load_ltm_monitor_udp.json'))
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods in the specific type of manager
- mm = ModuleManager(module=module)
- mm.exists = Mock(return_value=True)
- mm.read_current_from_device = Mock(return_value=current)
- mm.update_on_device = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['time_until_up'] == 300
diff --git a/test/units/modules/network/f5/test_bigip_node.py b/test/units/modules/network/f5/test_bigip_node.py
deleted file mode 100644
index 4592471e8f..0000000000
--- a/test/units/modules/network/f5/test_bigip_node.py
+++ /dev/null
@@ -1,250 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright (c) 2017 F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_node import Parameters
- from library.modules.bigip_node import ApiParameters
- from library.modules.bigip_node import ModuleManager
- from library.modules.bigip_node import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_node import Parameters
- from ansible.modules.network.f5.bigip_node import ApiParameters
- from ansible.modules.network.f5.bigip_node import ModuleManager
- from ansible.modules.network.f5.bigip_node import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- host='10.20.30.40',
- name='10.20.30.40'
- )
-
- p = Parameters(params=args)
- assert p.host == '10.20.30.40'
- assert p.name == '10.20.30.40'
-
- def test_api_parameters(self):
- args = load_fixture('load_ltm_node_1.json')
-
- p = Parameters(params=args)
- assert p.address == '1.2.3.4'
-
-
-class TestManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
-
- def test_create_node(self, *args):
- set_module_args(dict(
- host='10.20.30.40',
- name='mytestserver',
- monitors=[
- '/Common/icmp'
- ],
- partition='Common',
- state='present',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- mutually_exclusive=self.spec.mutually_exclusive
- )
- mm = ModuleManager(module=module)
-
- # Override methods to force specific logic in the module to happen
- mm.exists = Mock(side_effect=[False, True])
- mm.create_on_device = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
-
- def test_create_node_idempotent(self, *args):
- set_module_args(dict(
- host='10.20.30.40',
- name='mytestserver',
- monitors=[
- '/Common/icmp'
- ],
- partition='Common',
- state='present',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- current = ApiParameters(params=load_fixture('load_ltm_node_3.json'))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- mutually_exclusive=self.spec.mutually_exclusive
- )
- mm = ModuleManager(module=module)
-
- # Override methods to force specific logic in the module to happen
- mm.exists = Mock(side_effect=[True, True])
- mm.read_current_from_device = Mock(return_value=current)
-
- results = mm.exec_module()
-
- assert results['changed'] is False
-
- def test_create_node_fqdn(self, *args):
- set_module_args(dict(
- fqdn='foo.bar',
- name='mytestserver',
- monitors=[
- '/Common/icmp'
- ],
- partition='Common',
- state='present',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- mutually_exclusive=self.spec.mutually_exclusive
- )
- mm = ModuleManager(module=module)
-
- # Override methods to force specific logic in the module to happen
- mm.exists = Mock(side_effect=[False, True])
- mm.create_on_device = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
-
- def test_update_node_fqdn_up_interval(self, *args):
- set_module_args(dict(
- fqdn='foo.bar',
- fqdn_up_interval=100,
- name='mytestserver',
- monitors=[
- '/Common/icmp'
- ],
- partition='Common',
- state='present',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- current = ApiParameters(params=load_fixture('load_ltm_node_2.json'))
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- mutually_exclusive=self.spec.mutually_exclusive
- )
- mm = ModuleManager(module=module)
-
- # Override methods to force specific logic in the module to happen
- mm.exists = Mock(side_effect=[True, True])
- mm.update_on_device = Mock(return_value=True)
- mm.read_current_from_device = Mock(return_value=current)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
-
- def test_update_node_fqdn_up_interval_idempotent(self, *args):
- set_module_args(dict(
- fqdn='google.com',
- fqdn_up_interval=3600,
- name='fqdn-foo',
- monitors=[
- 'icmp',
- 'tcp_echo'
- ],
- partition='Common',
- state='present',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- current = ApiParameters(params=load_fixture('load_ltm_node_2.json'))
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- mutually_exclusive=self.spec.mutually_exclusive
- )
- mm = ModuleManager(module=module)
-
- # Override methods to force specific logic in the module to happen
- mm.exists = Mock(side_effect=[True, True])
- mm.update_on_device = Mock(return_value=True)
- mm.read_current_from_device = Mock(return_value=current)
-
- results = mm.exec_module()
-
- assert results['changed'] is not True
diff --git a/test/units/modules/network/f5/test_bigip_partition.py b/test/units/modules/network/f5/test_bigip_partition.py
deleted file mode 100644
index b12f87ae1e..0000000000
--- a/test/units/modules/network/f5/test_bigip_partition.py
+++ /dev/null
@@ -1,214 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright (c) 2017 F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_partition import ApiParameters
- from library.modules.bigip_partition import ModuleParameters
- from library.modules.bigip_partition import ModuleManager
- from library.modules.bigip_partition import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_partition import ApiParameters
- from ansible.modules.network.f5.bigip_partition import ModuleParameters
- from ansible.modules.network.f5.bigip_partition import ModuleManager
- from ansible.modules.network.f5.bigip_partition import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- name='foo',
- description='my description',
- route_domain=0
- )
-
- p = ModuleParameters(params=args)
- assert p.name == 'foo'
- assert p.description == 'my description'
- assert p.route_domain == 0
-
- def test_module_parameters_string_domain(self):
- args = dict(
- name='foo',
- route_domain='0'
- )
-
- p = ModuleParameters(params=args)
- assert p.name == 'foo'
- assert p.route_domain == 0
-
- def test_api_parameters(self):
- args = dict(
- name='foo',
- description='my description',
- defaultRouteDomain=1
- )
-
- p = ApiParameters(params=args)
- assert p.name == 'foo'
- assert p.description == 'my description'
- assert p.route_domain == 1
-
-
-class TestManagerEcho(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
-
- def test_create_partition(self, *args):
- set_module_args(dict(
- name='foo',
- description='my description',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods in the specific type of manager
- mm = ModuleManager(module=module)
- mm.exists = Mock(side_effect=[False, True])
- mm.create_on_device = Mock(return_value=True)
- mm.update_folder_on_device = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
-
- def test_create_partition_idempotent(self, *args):
- set_module_args(dict(
- name='foo',
- description='my description',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- current = ApiParameters(params=load_fixture('load_tm_auth_partition.json'))
- current.update({'folder_description': 'my description'})
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods in the specific type of manager
- mm = ModuleManager(module=module)
- mm.exists = Mock(return_value=True)
- mm.read_current_from_device = Mock(return_value=current)
-
- results = mm.exec_module()
-
- assert results['changed'] is False
-
- def test_update_description(self, *args):
- set_module_args(dict(
- name='foo',
- description='another description',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- current = ApiParameters(params=load_fixture('load_tm_auth_partition.json'))
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods in the specific type of manager
- mm = ModuleManager(module=module)
- mm.exists = Mock(return_value=True)
- mm.read_current_from_device = Mock(return_value=current)
- mm.update_on_device = Mock(return_value=True)
- mm.update_folder_on_device = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['description'] == 'another description'
-
- def test_update_route_domain(self, *args):
- set_module_args(dict(
- name='foo',
- route_domain=1,
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- current = ApiParameters(params=load_fixture('load_tm_auth_partition.json'))
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods in the specific type of manager
- mm = ModuleManager(module=module)
- mm.exists = Mock(return_value=True)
- mm.read_current_from_device = Mock(return_value=current)
- mm.update_on_device = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['route_domain'] == 1
diff --git a/test/units/modules/network/f5/test_bigip_password_policy.py b/test/units/modules/network/f5/test_bigip_password_policy.py
deleted file mode 100644
index bf7ff8b935..0000000000
--- a/test/units/modules/network/f5/test_bigip_password_policy.py
+++ /dev/null
@@ -1,152 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2018, F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_password_policy import ApiParameters
- from library.modules.bigip_password_policy import ModuleParameters
- from library.modules.bigip_password_policy import ModuleManager
- from library.modules.bigip_password_policy import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
- from test.units.compat.mock import patch
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_password_policy import ApiParameters
- from ansible.modules.network.f5.bigip_password_policy import ModuleParameters
- from ansible.modules.network.f5.bigip_password_policy import ModuleManager
- from ansible.modules.network.f5.bigip_password_policy import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
- from units.compat.mock import patch
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- expiration_warning=7,
- max_duration=99999,
- max_login_failures=0,
- min_duration=0,
- min_length=6,
- password_memory=0,
- policy_enforcement=False,
- required_lowercase=0,
- required_numeric=0,
- required_special=0,
- required_uppercase=0,
- )
-
- p = ModuleParameters(params=args)
- assert p.expiration_warning == 7
- assert p.max_duration == 99999
- assert p.max_login_failures == 0
- assert p.min_duration == 0
- assert p.password_memory == 0
- assert p.policy_enforcement == 'no'
- assert p.required_lowercase == 0
- assert p.required_numeric == 0
- assert p.required_special == 0
- assert p.required_uppercase == 0
-
- def test_api_parameters(self):
- args = load_fixture('load_tm_auth_password_policy_1.json')
-
- p = ApiParameters(params=args)
- assert p.expiration_warning == 7
- assert p.max_duration == 99999
- assert p.max_login_failures == 0
- assert p.min_duration == 0
- assert p.password_memory == 0
- assert p.policy_enforcement == 'no'
- assert p.required_lowercase == 0
- assert p.required_numeric == 0
- assert p.required_special == 0
- assert p.required_uppercase == 0
-
-
-@patch('ansible.module_utils.f5_utils.AnsibleF5Client._get_mgmt_root',
- return_value=True)
-class TestManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
-
- def test_create_partition(self, *args):
- set_module_args(dict(
- expiration_warning=7,
- max_duration=9999,
- max_login_failures=0,
- min_duration=0,
- min_length=6,
- password_memory=0,
- policy_enforcement='no',
- required_lowercase=0,
- required_numeric=0,
- required_special=0,
- required_uppercase=0,
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- current = ApiParameters(params=load_fixture('load_tm_auth_password_policy_1.json'))
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods in the specific type of manager
- mm = ModuleManager(module=module)
- mm.exists = Mock(side_effect=[False, True])
- mm.update_on_device = Mock(return_value=True)
- mm.read_current_from_device = Mock(return_value=current)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
diff --git a/test/units/modules/network/f5/test_bigip_policy.py b/test/units/modules/network/f5/test_bigip_policy.py
deleted file mode 100644
index e59b2facf9..0000000000
--- a/test/units/modules/network/f5/test_bigip_policy.py
+++ /dev/null
@@ -1,158 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright (c) 2017 F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_policy import Parameters
- from library.modules.bigip_policy import ModuleManager
- from library.modules.bigip_policy import SimpleManager
- from library.modules.bigip_policy import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_policy import Parameters
- from ansible.modules.network.f5.bigip_policy import ModuleManager
- from ansible.modules.network.f5.bigip_policy import SimpleManager
- from ansible.modules.network.f5.bigip_policy import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters_none_strategy(self):
- args = dict(
- name='foo',
- description='asdf asdf asdf',
- )
- p = Parameters(params=args)
- assert p.name == 'foo'
- assert p.description == 'asdf asdf asdf'
- assert p.strategy is None
-
- def test_module_parameters_with_strategy_no_partition(self):
- args = dict(
- name='foo',
- description='asdf asdf asdf',
- strategy='foo',
- partition='Common'
- )
- p = Parameters(params=args)
- assert p.name == 'foo'
- assert p.description == 'asdf asdf asdf'
- assert p.strategy == '/Common/foo'
-
- def test_module_parameters_with_strategy_partition(self):
- args = dict(
- name='foo',
- description='asdf asdf asdf',
- strategy='/Common/foo',
- partition='Common'
- )
- p = Parameters(params=args)
- assert p.name == 'foo'
- assert p.description == 'asdf asdf asdf'
- assert p.strategy == '/Common/foo'
-
- def test_module_parameters_with_strategy_different_partition(self):
- args = dict(
- name='foo',
- description='asdf asdf asdf',
- strategy='/Foo/bar',
- partition='Common'
- )
- p = Parameters(params=args)
- assert p.name == 'foo'
- assert p.description == 'asdf asdf asdf'
- assert p.strategy == '/Foo/bar'
-
- def test_api_parameters(self):
- args = dict(
- name='foo',
- description='asdf asdf asdf',
- strategy='/Common/asdf'
- )
- p = Parameters(params=args)
- assert p.name == 'foo'
- assert p.description == 'asdf asdf asdf'
- assert p.strategy == '/Common/asdf'
-
-
-class TestSimpleTrafficPolicyManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
-
- def test_create_policy(self, *args):
- set_module_args(dict(
- name="Policy-Foo",
- state='present',
- strategy='best',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods in the specific type of manager
- tm = SimpleManager(module=module, params=module.params)
- tm.exists = Mock(return_value=False)
- tm.create_on_device = Mock(return_value=True)
-
- # Override methods to force specific logic in the module to happen
- mm = ModuleManager(module=module)
- mm.version_is_less_than_12 = Mock(return_value=True)
- mm.get_manager = Mock(return_value=tm)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
diff --git a/test/units/modules/network/f5/test_bigip_policy_rule.py b/test/units/modules/network/f5/test_bigip_policy_rule.py
deleted file mode 100644
index 70ef8dc235..0000000000
--- a/test/units/modules/network/f5/test_bigip_policy_rule.py
+++ /dev/null
@@ -1,198 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright (c) 2017 F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_policy_rule import ModuleParameters
- from library.modules.bigip_policy_rule import ApiParameters
- from library.modules.bigip_policy_rule import ModuleManager
- from library.modules.bigip_policy_rule import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_policy_rule import ModuleParameters
- from ansible.modules.network.f5.bigip_policy_rule import ApiParameters
- from ansible.modules.network.f5.bigip_policy_rule import ModuleManager
- from ansible.modules.network.f5.bigip_policy_rule import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters_policy(self):
- args = dict(
- policy='Policy - Foo'
- )
- p = ModuleParameters(params=args)
- assert p.policy == 'Policy - Foo'
-
- def test_module_parameters_actions(self):
- args = dict(
- actions=[
- dict(
- type='forward',
- pool='pool-svrs'
- )
- ]
- )
- p = ModuleParameters(params=args)
- assert len(p.actions) == 1
-
- def test_module_parameters_conditions(self):
- args = dict(
- conditions=[
- dict(
- type='http_uri',
- path_begins_with_any=['/ABC']
- )
- ]
- )
- p = ModuleParameters(params=args)
- assert len(p.conditions) == 1
-
- def test_module_parameters_name(self):
- args = dict(
- name='rule1'
- )
- p = ModuleParameters(params=args)
- assert p.name == 'rule1'
-
- def test_api_parameters(self):
- args = load_fixture('load_ltm_policy_draft_rule_http-uri_forward.json')
- p = ApiParameters(params=args)
- assert len(p.actions) == 1
- assert len(p.conditions) == 1
-
-
-class TestManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
-
- def test_create_policy_rule_no_existence(self, *args):
- set_module_args(dict(
- name="rule1",
- state='present',
- policy='policy1',
- actions=[
- dict(
- type='forward',
- pool='baz'
- )
- ],
- conditions=[
- dict(
- type='http_uri',
- path_begins_with_any=['/ABC']
- )
- ],
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods to force specific logic in the module to happen
- mm = ModuleManager(module=module)
- mm.exists = Mock(return_value=False)
- mm.publish_on_device = Mock(return_value=True)
- mm.draft_exists = Mock(return_value=False)
- mm._create_existing_policy_draft_on_device = Mock(return_value=True)
- mm.create_on_device = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
-
- def test_create_policy_rule_idempotent_check(self, *args):
- set_module_args(dict(
- name="rule1",
- state='present',
- policy='policy1',
- actions=[
- dict(
- type='forward',
- pool='baz'
- )
- ],
- conditions=[
- dict(
- type='http_uri',
- path_begins_with_any=['/ABC']
- )
- ],
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- current = ApiParameters(params=load_fixture('load_ltm_policy_draft_rule_http-uri_forward.json'))
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods to force specific logic in the module to happen
- mm = ModuleManager(module=module)
- mm.exists = Mock(return_value=True)
- mm.read_current_from_device = Mock(return_value=current)
- mm.draft_exists = Mock(return_value=False)
- mm.update_on_device = Mock(return_value=True)
- mm._create_existing_policy_draft_on_device = Mock(return_value=True)
- mm.publish_on_device = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
diff --git a/test/units/modules/network/f5/test_bigip_pool.py b/test/units/modules/network/f5/test_bigip_pool.py
deleted file mode 100644
index de74f24cd5..0000000000
--- a/test/units/modules/network/f5/test_bigip_pool.py
+++ /dev/null
@@ -1,546 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright (c) 2017 F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_pool import ApiParameters
- from library.modules.bigip_pool import ModuleParameters
- from library.modules.bigip_pool import ModuleManager
- from library.modules.bigip_pool import ArgumentSpec
-
- from library.module_utils.network.f5.common import F5ModuleError
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_pool import ApiParameters
- from ansible.modules.network.f5.bigip_pool import ModuleParameters
- from ansible.modules.network.f5.bigip_pool import ModuleManager
- from ansible.modules.network.f5.bigip_pool import ArgumentSpec
-
- from ansible.module_utils.network.f5.common import F5ModuleError
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- monitor_type='m_of_n',
- monitors=['/Common/Fake', '/Common/Fake2'],
- quorum=1,
- slow_ramp_time=200,
- reselect_tries=5,
- service_down_action='drop'
- )
-
- p = ModuleParameters(params=args)
- assert p.monitor_type == 'm_of_n'
- assert p.quorum == 1
- assert p.monitors == 'min 1 of { /Common/Fake /Common/Fake2 }'
- assert p.slow_ramp_time == 200
- assert p.reselect_tries == 5
- assert p.service_down_action == 'drop'
-
- def test_api_parameters(self):
- args = dict(
- monitor="/Common/Fake and /Common/Fake2 ",
- slowRampTime=200,
- reselectTries=5,
- serviceDownAction='drop'
- )
-
- p = ApiParameters(params=args)
- assert p.monitors == '/Common/Fake and /Common/Fake2'
- assert p.slow_ramp_time == 200
- assert p.reselect_tries == 5
- assert p.service_down_action == 'drop'
-
- def test_unknown_module_lb_method(self):
- args = dict(
- lb_method='obscure_hyphenated_fake_method',
- )
- with pytest.raises(F5ModuleError):
- p = ModuleParameters(params=args)
- assert p.lb_method == 'foo'
-
- def test_unknown_api_lb_method(self):
- args = dict(
- loadBalancingMode='obscure_hypenated_fake_method'
- )
- with pytest.raises(F5ModuleError):
- p = ApiParameters(params=args)
- assert p.lb_method == 'foo'
-
-
-class TestManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
-
- def test_create_pool(self, *args):
- set_module_args(dict(
- pool='fake_pool',
- description='fakepool',
- service_down_action='drop',
- lb_method='round-robin',
- partition='Common',
- slow_ramp_time=10,
- reselect_tries=1,
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- mutually_exclusive=self.spec.mutually_exclusive,
- required_one_of=self.spec.required_one_of
- )
-
- mm = ModuleManager(module=module)
- mm.create_on_device = Mock(return_value=True)
- mm.exists = Mock(return_value=False)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['name'] == 'fake_pool'
- assert results['description'] == 'fakepool'
- assert results['service_down_action'] == 'drop'
- assert results['lb_method'] == 'round-robin'
- assert results['slow_ramp_time'] == 10
- assert results['reselect_tries'] == 1
-
- def test_create_pool_monitor_type_missing(self, *args):
- set_module_args(dict(
- pool='fake_pool',
- lb_method='round-robin',
- partition='Common',
- monitors=['/Common/tcp', '/Common/http'],
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- mutually_exclusive=self.spec.mutually_exclusive,
- required_one_of=self.spec.required_one_of
- )
-
- mm = ModuleManager(module=module)
- mm.create_on_device = Mock(return_value=True)
- mm.exists = Mock(return_value=False)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['name'] == 'fake_pool'
- assert results['monitors'] == ['/Common/http', '/Common/tcp']
- assert results['monitor_type'] == 'and_list'
-
- def test_create_pool_monitors_missing(self, *args):
- set_module_args(dict(
- pool='fake_pool',
- lb_method='round-robin',
- partition='Common',
- monitor_type='and_list',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- mutually_exclusive=self.spec.mutually_exclusive,
- required_one_of=self.spec.required_one_of
- )
-
- mm = ModuleManager(module=module)
- mm.create_on_device = Mock(return_value=True)
- mm.exists = Mock(return_value=False)
-
- msg = "The 'monitors' parameter cannot be empty when " \
- "'monitor_type' parameter is specified"
- with pytest.raises(F5ModuleError) as err:
- mm.exec_module()
-
- assert str(err.value) == msg
-
- def test_create_pool_quorum_missing(self, *args):
- set_module_args(dict(
- pool='fake_pool',
- lb_method='round-robin',
- partition='Common',
- monitor_type='m_of_n',
- monitors=['/Common/tcp', '/Common/http'],
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- mutually_exclusive=self.spec.mutually_exclusive,
- required_one_of=self.spec.required_one_of
- )
-
- mm = ModuleManager(module=module)
- mm.create_on_device = Mock(return_value=True)
- mm.exists = Mock(return_value=False)
-
- msg = "Quorum value must be specified with monitor_type 'm_of_n'."
- with pytest.raises(F5ModuleError) as err:
- mm.exec_module()
-
- assert str(err.value) == msg
-
- def test_create_pool_monitor_and_list(self, *args):
- set_module_args(dict(
- pool='fake_pool',
- partition='Common',
- monitor_type='and_list',
- monitors=['/Common/tcp', '/Common/http'],
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- mutually_exclusive=self.spec.mutually_exclusive,
- required_one_of=self.spec.required_one_of
- )
-
- mm = ModuleManager(module=module)
- mm.create_on_device = Mock(return_value=True)
- mm.exists = Mock(return_value=False)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['name'] == 'fake_pool'
- assert results['monitors'] == ['/Common/http', '/Common/tcp']
- assert results['monitor_type'] == 'and_list'
-
- def test_create_pool_monitor_m_of_n(self, *args):
- set_module_args(dict(
- pool='fake_pool',
- partition='Common',
- monitor_type='m_of_n',
- quorum=1,
- monitors=['/Common/tcp', '/Common/http'],
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- mutually_exclusive=self.spec.mutually_exclusive,
- required_one_of=self.spec.required_one_of
- )
-
- mm = ModuleManager(module=module)
- mm.create_on_device = Mock(return_value=True)
- mm.exists = Mock(return_value=False)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['name'] == 'fake_pool'
- assert results['monitors'] == ['/Common/http', '/Common/tcp']
- assert results['monitor_type'] == 'm_of_n'
-
- def test_update_monitors(self, *args):
- set_module_args(dict(
- name='test_pool',
- partition='Common',
- monitor_type='and_list',
- monitors=['/Common/http', '/Common/tcp'],
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- mutually_exclusive=self.spec.mutually_exclusive,
- required_one_of=self.spec.required_one_of
- )
-
- mm = ModuleManager(module=module)
-
- current = ApiParameters(params=load_fixture('load_ltm_pool.json'))
-
- mm.update_on_device = Mock(return_value=True)
- mm.exists = Mock(return_value=True)
- mm.read_current_from_device = Mock(return_value=current)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['monitor_type'] == 'and_list'
-
- def test_create_pool_monitor_and_list_no_partition(self, *args):
- set_module_args(dict(
- pool='fake_pool',
- monitor_type='and_list',
- monitors=['tcp', 'http'],
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- mutually_exclusive=self.spec.mutually_exclusive,
- required_one_of=self.spec.required_one_of
- )
-
- mm = ModuleManager(module=module)
- mm.create_on_device = Mock(return_value=True)
- mm.exists = Mock(return_value=False)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['name'] == 'fake_pool'
- assert results['monitors'] == ['/Common/http', '/Common/tcp']
- assert results['monitor_type'] == 'and_list'
-
- def test_create_pool_monitor_m_of_n_no_partition(self, *args):
- set_module_args(dict(
- pool='fake_pool',
- monitor_type='m_of_n',
- quorum=1,
- monitors=['tcp', 'http'],
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- mutually_exclusive=self.spec.mutually_exclusive,
- required_one_of=self.spec.required_one_of
- )
-
- mm = ModuleManager(module=module)
- mm.create_on_device = Mock(return_value=True)
- mm.exists = Mock(return_value=False)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['name'] == 'fake_pool'
- assert results['monitors'] == ['/Common/http', '/Common/tcp']
- assert results['monitor_type'] == 'm_of_n'
-
- def test_create_pool_monitor_and_list_custom_partition(self, *args):
- set_module_args(dict(
- pool='fake_pool',
- partition='Testing',
- monitor_type='and_list',
- monitors=['tcp', 'http'],
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- mutually_exclusive=self.spec.mutually_exclusive,
- required_one_of=self.spec.required_one_of
- )
-
- mm = ModuleManager(module=module)
- mm.create_on_device = Mock(return_value=True)
- mm.exists = Mock(return_value=False)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['name'] == 'fake_pool'
- assert results['monitors'] == ['/Testing/http', '/Testing/tcp']
- assert results['monitor_type'] == 'and_list'
-
- def test_create_pool_monitor_m_of_n_custom_partition(self, *args):
- set_module_args(dict(
- pool='fake_pool',
- partition='Testing',
- monitor_type='m_of_n',
- quorum=1,
- monitors=['tcp', 'http'],
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- mutually_exclusive=self.spec.mutually_exclusive,
- required_one_of=self.spec.required_one_of
- )
-
- mm = ModuleManager(module=module)
- mm.create_on_device = Mock(return_value=True)
- mm.exists = Mock(return_value=False)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['name'] == 'fake_pool'
- assert results['monitors'] == ['/Testing/http', '/Testing/tcp']
- assert results['monitor_type'] == 'm_of_n'
-
- def test_create_pool_with_metadata(self, *args):
- set_module_args(dict(
- pool='fake_pool',
- metadata=dict(ansible='2.4'),
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- mutually_exclusive=self.spec.mutually_exclusive,
- required_one_of=self.spec.required_one_of
- )
-
- mm = ModuleManager(module=module)
- mm.create_on_device = Mock(return_value=True)
- mm.exists = Mock(return_value=False)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['name'] == 'fake_pool'
- assert 'metadata' in results
- assert 'ansible' in results['metadata']
- assert results['metadata']['ansible'] == '2.4'
-
- def test_create_aggregate_pools(self, *args):
- set_module_args(dict(
- aggregate=[
- dict(
- pool='fake_pool',
- description='fakepool',
- service_down_action='drop',
- lb_method='round-robin',
- partition='Common',
- slow_ramp_time=10,
- reselect_tries=1,
- ),
- dict(
- pool='fake_pool2',
- description='fakepool2',
- service_down_action='drop',
- lb_method='predictive-node',
- partition='Common',
- slow_ramp_time=110,
- reselect_tries=2,
- )
- ],
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- mutually_exclusive=self.spec.mutually_exclusive,
- required_one_of=self.spec.required_one_of
- )
-
- mm = ModuleManager(module=module)
- mm.create_on_device = Mock(return_value=True)
- mm.exists = Mock(return_value=False)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
diff --git a/test/units/modules/network/f5/test_bigip_pool_member.py b/test/units/modules/network/f5/test_bigip_pool_member.py
deleted file mode 100644
index acc4984e0d..0000000000
--- a/test/units/modules/network/f5/test_bigip_pool_member.py
+++ /dev/null
@@ -1,256 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright (c) 2017 F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_pool_member import ModuleParameters
- from library.modules.bigip_pool_member import ApiParameters
- from library.modules.bigip_pool_member import NodeApiParameters
- from library.modules.bigip_pool_member import ModuleManager
- from library.modules.bigip_pool_member import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_pool_member import ModuleParameters
- from ansible.modules.network.f5.bigip_pool_member import ApiParameters
- from ansible.modules.network.f5.bigip_pool_member import NodeApiParameters
- from ansible.modules.network.f5.bigip_pool_member import ModuleManager
- from ansible.modules.network.f5.bigip_pool_member import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- pool='my-pool',
- address='1.2.3.4',
- fqdn='fqdn.foo.bar',
- name='my-name',
- port=2345,
- connection_limit=100,
- description='this is a description',
- rate_limit=70,
- ratio=20,
- preserve_node=False,
- priority_group=10,
- state='present',
- partition='Common',
- fqdn_auto_populate=False,
- reuse_nodes=False,
- )
-
- p = ModuleParameters(params=args)
- assert p.name == 'my-name'
-
- def test_api_parameters(self):
- args = load_fixture('load_net_node_with_fqdn.json')
- p = ApiParameters(params=args)
- assert p.state == 'present'
-
-
-class TestManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
-
- def test_create_reuse_node_with_name(self, *args):
- # Configure the arguments that would be sent to the Ansible module
- set_module_args(dict(
- pool='my-pool',
- fqdn='foo.bar.com',
- port=2345,
- state='present',
- partition='Common',
- reuse_nodes=True,
- provider=dict(
- password='password',
- server='localhost',
- user='admin'
- )
- ))
-
- current_node = NodeApiParameters(params=load_fixture('load_net_node_with_fqdn.json'))
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- mutually_exclusive=self.spec.mutually_exclusive,
- required_one_of=self.spec.required_one_of,
- )
- mm = ModuleManager(module=module)
-
- # Override methods to force specific logic in the module to happen
- mm.exists = Mock(return_value=False)
- mm.create_on_device = Mock(return_value=True)
- mm.read_current_node_from_device = Mock(return_value=current_node)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['fqdn_auto_populate'] is True
- assert results['fqdn'] == 'foo.bar.com'
- assert results['state'] == 'present'
-
- def test_create_reuse_node_with_ipv4_address(self, *args):
- # Configure the arguments that would be sent to the Ansible module
- set_module_args(dict(
- pool='my-pool',
- address='7.3.67.8',
- port=2345,
- state='present',
- partition='Common',
- reuse_nodes=True,
- provider=dict(
- password='password',
- server='localhost',
- user='admin'
- )
- ))
-
- current_node = NodeApiParameters(params=load_fixture('load_net_node_with_ipv4_address.json'))
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- mutually_exclusive=self.spec.mutually_exclusive,
- required_one_of=self.spec.required_one_of,
- )
- mm = ModuleManager(module=module)
-
- # Override methods to force specific logic in the module to happen
- mm.exists = Mock(return_value=False)
- mm.create_on_device = Mock(return_value=True)
- mm.read_current_node_from_device = Mock(return_value=current_node)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['fqdn_auto_populate'] is False
- assert results['address'] == '7.3.67.8'
- assert results['state'] == 'present'
-
- def test_create_reuse_node_with_fqdn_auto_populate(self, *args):
- # Configure the arguments that would be sent to the Ansible module
- set_module_args(dict(
- pool='my-pool',
- fqdn='foo.bar.com',
- port=2345,
- state='present',
- partition='Common',
- reuse_nodes=True,
- fqdn_auto_populate=False,
- provider=dict(
- password='password',
- server='localhost',
- user='admin'
- )
- ))
-
- current_node = NodeApiParameters(params=load_fixture('load_net_node_with_fqdn.json'))
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- mutually_exclusive=self.spec.mutually_exclusive,
- required_one_of=self.spec.required_one_of,
- )
- mm = ModuleManager(module=module)
-
- # Override methods to force specific logic in the module to happen
- mm.exists = Mock(return_value=False)
- mm.create_on_device = Mock(return_value=True)
- mm.read_current_node_from_device = Mock(return_value=current_node)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['fqdn_auto_populate'] is True
- assert results['fqdn'] == 'foo.bar.com'
- assert results['state'] == 'present'
-
- def test_create_aggregate_pool_members(self, *args):
- set_module_args(dict(
- pool='fake_pool',
- aggregate=[
- dict(
- name='my-name',
- host="1.1.1.1",
- port=1234,
- state='present',
- partition='Common',
- reuse_nodes=True,
- fqdn_auto_populate=False,
- ),
- dict(
- name='my-name2',
- fqdn='google.com',
- port=2423,
- state='present',
- partition='Common',
- fqdn_auto_populate=True,
- reuse_nodes=True,
- )
- ],
- provider=dict(
- password='password',
- server='localhost',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- mutually_exclusive=self.spec.mutually_exclusive,
- required_one_of=self.spec.required_one_of,
- )
-
- mm = ModuleManager(module=module)
- mm.create_on_device = Mock(return_value=True)
- mm.exists = Mock(return_value=False)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
diff --git a/test/units/modules/network/f5/test_bigip_profile_analytics.py b/test/units/modules/network/f5/test_bigip_profile_analytics.py
deleted file mode 100644
index 0e81c75e64..0000000000
--- a/test/units/modules/network/f5/test_bigip_profile_analytics.py
+++ /dev/null
@@ -1,121 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2018, F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_profile_analytics import ApiParameters
- from library.modules.bigip_profile_analytics import ModuleParameters
- from library.modules.bigip_profile_analytics import ModuleManager
- from library.modules.bigip_profile_analytics import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_profile_analytics import ApiParameters
- from ansible.modules.network.f5.bigip_profile_analytics import ModuleParameters
- from ansible.modules.network.f5.bigip_profile_analytics import ModuleManager
- from ansible.modules.network.f5.bigip_profile_analytics import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- name='foo',
- parent='bar',
- description='foo',
- collect_geo=True,
- collect_ip=True,
- )
-
- p = ModuleParameters(params=args)
- assert p.name == 'foo'
- assert p.parent == '/Common/bar'
- assert p.description == 'foo'
- assert p.collect_geo == 'yes'
- assert p.collect_ip == 'yes'
-
- def test_api_parameters(self):
- args = load_fixture('load_ltm_profile_analytics_1.json')
- p = ApiParameters(params=args)
- assert p.name == 'foo'
- assert p.collect_geo == 'no'
-
-
-class TestManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
-
- def test_create(self, *args):
- # Configure the arguments that would be sent to the Ansible module
- set_module_args(dict(
- name='foo',
- parent='bar',
- description='foo',
- collect_geo=True,
- collect_ip=True,
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
- mm = ModuleManager(module=module)
-
- # Override methods to force specific logic in the module to happen
- mm.exists = Mock(return_value=False)
- mm.create_on_device = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
diff --git a/test/units/modules/network/f5/test_bigip_profile_client_ssl.py b/test/units/modules/network/f5/test_bigip_profile_client_ssl.py
deleted file mode 100644
index 18c1f27002..0000000000
--- a/test/units/modules/network/f5/test_bigip_profile_client_ssl.py
+++ /dev/null
@@ -1,129 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright (c) 2017 F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_profile_client_ssl import ModuleParameters
- from library.modules.bigip_profile_client_ssl import ApiParameters
- from library.modules.bigip_profile_client_ssl import ModuleManager
- from library.modules.bigip_profile_client_ssl import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_profile_client_ssl import ModuleParameters
- from ansible.modules.network.f5.bigip_profile_client_ssl import ApiParameters
- from ansible.modules.network.f5.bigip_profile_client_ssl import ModuleManager
- from ansible.modules.network.f5.bigip_profile_client_ssl import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- name='foo',
- parent='bar',
- ciphers='!SSLv3:!SSLv2:ECDHE+AES-GCM+SHA256:ECDHE-RSA-AES128-CBC-SHA',
- cert_key_chain=[
- dict(
- cert='bigip_ssl_cert1',
- key='bigip_ssl_key1',
- chain='bigip_ssl_cert1'
- )
- ]
- )
-
- p = ModuleParameters(params=args)
- assert p.name == 'foo'
- assert p.parent == '/Common/bar'
- assert p.ciphers == '!SSLv3:!SSLv2:ECDHE+AES-GCM+SHA256:ECDHE-RSA-AES128-CBC-SHA'
-
- def test_api_parameters(self):
- args = load_fixture('load_ltm_profile_clientssl.json')
- p = ApiParameters(params=args)
- assert p.name == 'foo'
- assert p.ciphers == 'DEFAULT'
-
-
-class TestManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
-
- def test_create(self, *args):
- # Configure the arguments that would be sent to the Ansible module
- set_module_args(dict(
- name='foo',
- parent='bar',
- ciphers='!SSLv3:!SSLv2:ECDHE+AES-GCM+SHA256:ECDHE-RSA-AES128-CBC-SHA',
- cert_key_chain=[
- dict(
- cert='bigip_ssl_cert1',
- key='bigip_ssl_key1',
- chain='bigip_ssl_cert1'
- )
- ],
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
- mm = ModuleManager(module=module)
-
- # Override methods to force specific logic in the module to happen
- mm.exists = Mock(return_value=False)
- mm.create_on_device = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
diff --git a/test/units/modules/network/f5/test_bigip_profile_dns.py b/test/units/modules/network/f5/test_bigip_profile_dns.py
deleted file mode 100644
index 4932002fa4..0000000000
--- a/test/units/modules/network/f5/test_bigip_profile_dns.py
+++ /dev/null
@@ -1,147 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_profile_dns import ApiParameters
- from library.modules.bigip_profile_dns import ModuleParameters
- from library.modules.bigip_profile_dns import ModuleManager
- from library.modules.bigip_profile_dns import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_profile_dns import ApiParameters
- from ansible.modules.network.f5.bigip_profile_dns import ModuleParameters
- from ansible.modules.network.f5.bigip_profile_dns import ModuleManager
- from ansible.modules.network.f5.bigip_profile_dns import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- name='foo',
- parent='bar',
- enable_dns_express=True,
- enable_zone_transfer=True,
- enable_dnssec=True,
- enable_gtm=True,
- process_recursion_desired=True,
- use_local_bind=True,
- enable_dns_firewall=True,
- )
-
- p = ModuleParameters(params=args)
- assert p.name == 'foo'
- assert p.parent == '/Common/bar'
- assert p.enable_dns_express is True
- assert p.enable_zone_transfer is True
- assert p.enable_dnssec is True
- assert p.enable_gtm is True
- assert p.process_recursion_desired is True
- assert p.use_local_bind is True
- assert p.enable_dns_firewall is True
-
- def test_api_parameters(self):
- args = load_fixture('load_ltm_profile_dns_1.json')
- p = ApiParameters(params=args)
- assert p.name == 'foo'
- assert p.parent == '/Common/dns'
- assert p.enable_dns_express is False
- assert p.enable_zone_transfer is True
- assert p.enable_dnssec is False
- assert p.enable_gtm is False
- assert p.process_recursion_desired is True
- assert p.use_local_bind is False
- assert p.enable_dns_firewall is True
-
-
-class TestManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
-
- def test_create(self, *args):
- # Configure the arguments that would be sent to the Ansible module
- set_module_args(dict(
- name='foo',
- parent='bar',
- enable_dns_express=True,
- enable_zone_transfer=True,
- enable_dnssec=True,
- enable_gtm=True,
- process_recursion_desired=True,
- use_local_bind=True,
- enable_dns_firewall=True,
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
- mm = ModuleManager(module=module)
-
- # Override methods to force specific logic in the module to happen
- mm.exists = Mock(return_value=False)
- mm.create_on_device = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['enable_dns_express'] == 'yes'
- assert results['enable_zone_transfer'] == 'yes'
- assert results['enable_dnssec'] == 'yes'
- assert results['enable_gtm'] == 'yes'
- assert results['process_recursion_desired'] == 'yes'
- assert results['use_local_bind'] == 'yes'
- assert results['enable_dns_firewall'] == 'yes'
diff --git a/test/units/modules/network/f5/test_bigip_profile_fastl4.py b/test/units/modules/network/f5/test_bigip_profile_fastl4.py
deleted file mode 100644
index 8425053d91..0000000000
--- a/test/units/modules/network/f5/test_bigip_profile_fastl4.py
+++ /dev/null
@@ -1,178 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2018, F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_profile_fastl4 import ApiParameters
- from library.modules.bigip_profile_fastl4 import ModuleParameters
- from library.modules.bigip_profile_fastl4 import ModuleManager
- from library.modules.bigip_profile_fastl4 import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_profile_fastl4 import ApiParameters
- from ansible.modules.network.f5.bigip_profile_fastl4 import ModuleParameters
- from ansible.modules.network.f5.bigip_profile_fastl4 import ModuleManager
- from ansible.modules.network.f5.bigip_profile_fastl4 import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- name='foo',
- parent='bar',
- idle_timeout=100,
- client_timeout=101,
- description='description one',
- explicit_flow_migration=False,
- ip_df_mode='pmtu',
- ip_tos_to_client=102,
- ip_tos_to_server=103,
- ip_ttl_v4=104,
- ip_ttl_v6=105,
- ip_ttl_mode='proxy',
- keep_alive_interval=106,
- late_binding=True,
- link_qos_to_client=7,
- link_qos_to_server=6,
- loose_close=False,
- loose_initialization=True,
- mss_override=4,
- reassemble_fragments=True,
- receive_window_size=109,
- reset_on_timeout=False,
- rtt_from_client=True,
- rtt_from_server=False,
- server_sack=True,
- server_timestamp=False,
- syn_cookie_mss=110,
- tcp_close_timeout=111,
- tcp_generate_isn=True,
- tcp_handshake_timeout=112,
- tcp_strip_sack=False,
- tcp_time_wait_timeout=113,
- tcp_timestamp_mode='rewrite',
- tcp_wscale_mode='strip',
- timeout_recovery='fallback',
- )
-
- p = ModuleParameters(params=args)
- assert p.name == 'foo'
- assert p.parent == '/Common/bar'
- assert p.description == 'description one'
- assert p.idle_timeout == 100
- assert p.client_timeout == 101
- assert p.explicit_flow_migration == 'no'
- assert p.ip_df_mode == 'pmtu'
- assert p.ip_tos_to_client == 102
- assert p.ip_tos_to_server == 103
- assert p.ip_ttl_v4 == 104
- assert p.ip_ttl_v6 == 105
- assert p.ip_ttl_mode == 'proxy'
- assert p.keep_alive_interval == 106
- assert p.late_binding == 'yes'
- assert p.link_qos_to_client == 7
- assert p.link_qos_to_server == 6
- assert p.loose_close == 'no'
- assert p.loose_initialization == 'yes'
- assert p.mss_override == 4
- assert p.reassemble_fragments == 'yes'
- assert p.receive_window_size == 109
- assert p.reset_on_timeout == 'no'
- assert p.rtt_from_client == 'yes'
- assert p.rtt_from_server == 'no'
- assert p.server_sack == 'yes'
- assert p.server_timestamp == 'no'
- assert p.syn_cookie_mss == 110
- assert p.tcp_close_timeout == 111
- assert p.tcp_generate_isn == 'yes'
- assert p.tcp_handshake_timeout == 112
- assert p.tcp_strip_sack == 'no'
- assert p.tcp_time_wait_timeout == 113
- assert p.tcp_timestamp_mode == 'rewrite'
- assert p.tcp_wscale_mode == 'strip'
- assert p.timeout_recovery == 'fallback'
-
- def test_api_parameters(self):
- args = load_fixture('load_ltm_fastl4_profile_1.json')
- p = ApiParameters(params=args)
- assert p.name == 'fastL4'
- assert p.description is None
-
-
-class TestManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
-
- def test_create(self, *args):
- # Configure the arguments that would be sent to the Ansible module
- set_module_args(dict(
- name='foo',
- parent='bar',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
- mm = ModuleManager(module=module)
-
- # Override methods to force specific logic in the module to happen
- mm.exists = Mock(return_value=False)
- mm.create_on_device = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
diff --git a/test/units/modules/network/f5/test_bigip_profile_http.py b/test/units/modules/network/f5/test_bigip_profile_http.py
deleted file mode 100644
index a913172dc2..0000000000
--- a/test/units/modules/network/f5/test_bigip_profile_http.py
+++ /dev/null
@@ -1,127 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2018, F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_profile_http import ApiParameters
- from library.modules.bigip_profile_http import ModuleParameters
- from library.modules.bigip_profile_http import ModuleManager
- from library.modules.bigip_profile_http import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_profile_http import ApiParameters
- from ansible.modules.network.f5.bigip_profile_http import ModuleParameters
- from ansible.modules.network.f5.bigip_profile_http import ModuleManager
- from ansible.modules.network.f5.bigip_profile_http import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- name='foo',
- parent='bar',
- description='This is a Test',
- proxy_type='transparent',
- insert_xforwarded_for=True,
- redirect_rewrite='all',
- encrypt_cookies=['FooCookie'],
- encrypt_cookie_secret='12345'
- )
-
- p = ModuleParameters(params=args)
- assert p.name == 'foo'
- assert p.parent == '/Common/bar'
- assert p.description == 'This is a Test'
- assert p.proxy_type == 'transparent'
- assert p.insert_xforwarded_for == 'enabled'
- assert p.redirect_rewrite == 'all'
- assert p.encrypt_cookies == ['FooCookie']
- assert p.encrypt_cookie_secret == '12345'
-
- def test_api_parameters(self):
- args = load_fixture('load_ltm_http_profile_1.json')
- p = ApiParameters(params=args)
- assert p.name == 'http'
- assert p.insert_xforwarded_for == 'disabled'
- assert p.description == 'none'
-
-
-class TestManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
-
- def test_create(self, *args):
- # Configure the arguments that would be sent to the Ansible module
- set_module_args(dict(
- name='foo',
- insert_xforwarded_for='yes',
- parent='bar',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
- mm = ModuleManager(module=module)
-
- # Override methods to force specific logic in the module to happen
- mm.exists = Mock(return_value=False)
- mm.create_on_device = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['insert_xforwarded_for'] == 'yes'
diff --git a/test/units/modules/network/f5/test_bigip_profile_http2.py b/test/units/modules/network/f5/test_bigip_profile_http2.py
deleted file mode 100644
index 6ae6ea6332..0000000000
--- a/test/units/modules/network/f5/test_bigip_profile_http2.py
+++ /dev/null
@@ -1,130 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2018, F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_profile_http2 import ApiParameters
- from library.modules.bigip_profile_http2 import ModuleParameters
- from library.modules.bigip_profile_http2 import ModuleManager
- from library.modules.bigip_profile_http2 import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_profile_http2 import ApiParameters
- from ansible.modules.network.f5.bigip_profile_http2 import ModuleParameters
- from ansible.modules.network.f5.bigip_profile_http2 import ModuleManager
- from ansible.modules.network.f5.bigip_profile_http2 import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- name='foo',
- parent='bar',
- description='This is a Test',
- streams=20,
- enforce_tls_requirements=True,
- frame_size=1024,
- activation_modes=['always'],
- insert_header=True,
- insert_header_name='FOO'
-
- )
-
- p = ModuleParameters(params=args)
- assert p.name == 'foo'
- assert p.parent == '/Common/bar'
- assert p.description == 'This is a Test'
- assert p.streams == 20
- assert p.enforce_tls_requirements == 'enabled'
- assert p.frame_size == 1024
- assert p.activation_modes == ['always']
- assert p.insert_header == 'enabled'
- assert p.insert_header_name == 'FOO'
-
- def test_api_parameters(self):
- args = load_fixture('load_ltm_http2_profile.json')
- p = ApiParameters(params=args)
- assert p.name == 'test'
- assert p.streams == 10
- assert p.enforce_tls_requirements == 'enabled'
-
-
-class TestManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
-
- def test_create(self, *args):
- # Configure the arguments that would be sent to the Ansible module
- set_module_args(dict(
- name='foo',
- enforce_tls_requirements='yes',
- parent='bar',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
- mm = ModuleManager(module=module)
-
- # Override methods to force specific logic in the module to happen
- mm.exists = Mock(return_value=False)
- mm.create_on_device = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['enforce_tls_requirements'] == 'yes'
diff --git a/test/units/modules/network/f5/test_bigip_profile_http_compression.py b/test/units/modules/network/f5/test_bigip_profile_http_compression.py
deleted file mode 100644
index f3d2da3ed7..0000000000
--- a/test/units/modules/network/f5/test_bigip_profile_http_compression.py
+++ /dev/null
@@ -1,129 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2018, F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_profile_http_compression import ApiParameters
- from library.modules.bigip_profile_http_compression import ModuleParameters
- from library.modules.bigip_profile_http_compression import ModuleManager
- from library.modules.bigip_profile_http_compression import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_profile_http_compression import ApiParameters
- from ansible.modules.network.f5.bigip_profile_http_compression import ModuleParameters
- from ansible.modules.network.f5.bigip_profile_http_compression import ModuleManager
- from ansible.modules.network.f5.bigip_profile_http_compression import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- name='foo',
- parent='bar',
- description='description1',
- buffer_size=1024,
- gzip_memory_level=64,
- gzip_level=2,
- gzip_window_size=128
- )
-
- p = ModuleParameters(params=args)
- assert p.name == 'foo'
- assert p.parent == '/Common/bar'
- assert p.description == 'description1'
- assert p.buffer_size == 1024
- assert p.gzip_memory_level == 64
- assert p.gzip_level == 2
- assert p.gzip_window_size == 128
-
- def test_api_parameters(self):
- p = ApiParameters(params=load_fixture('load_ltm_profile_http_compression_1.json'))
- assert p.description == 'my profile'
- assert p.buffer_size == 4096
- assert p.gzip_memory_level == 8
- assert p.gzip_level == 1
- assert p.gzip_window_size == 16
-
-
-class TestManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
-
- def test_create(self, *args):
- # Configure the arguments that would be sent to the Ansible module
- set_module_args(dict(
- name='foo',
- parent='bar',
- description='description1',
- buffer_size=1024,
- gzip_memory_level=64,
- gzip_level=2,
- gzip_window_size=128,
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
- mm = ModuleManager(module=module)
-
- # Override methods to force specific logic in the module to happen
- mm.exists = Mock(return_value=False)
- mm.create_on_device = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
diff --git a/test/units/modules/network/f5/test_bigip_profile_oneconnect.py b/test/units/modules/network/f5/test_bigip_profile_oneconnect.py
deleted file mode 100644
index 5057459350..0000000000
--- a/test/units/modules/network/f5/test_bigip_profile_oneconnect.py
+++ /dev/null
@@ -1,124 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_profile_oneconnect import ApiParameters
- from library.modules.bigip_profile_oneconnect import ModuleParameters
- from library.modules.bigip_profile_oneconnect import ModuleManager
- from library.modules.bigip_profile_oneconnect import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_profile_oneconnect import ApiParameters
- from ansible.modules.network.f5.bigip_profile_oneconnect import ModuleParameters
- from ansible.modules.network.f5.bigip_profile_oneconnect import ModuleManager
- from ansible.modules.network.f5.bigip_profile_oneconnect import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- name='foo',
- parent='bar',
- maximum_size=100,
- maximum_age=200,
- maximum_reuse=300,
- idle_timeout_override=20,
- limit_type='strict'
- )
-
- p = ModuleParameters(params=args)
- assert p.name == 'foo'
- assert p.parent == '/Common/bar'
- assert p.maximum_size == 100
- assert p.maximum_age == 200
- assert p.maximum_reuse == 300
- assert p.idle_timeout_override == 20
- assert p.limit_type == 'strict'
-
- def test_api_parameters(self):
- args = load_fixture('load_ltm_profile_oneconnect_1.json')
- p = ApiParameters(params=args)
- assert p.name == 'oneconnect'
- assert p.maximum_reuse == 1000
-
-
-class TestManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
-
- def test_create(self, *args):
- # Configure the arguments that would be sent to the Ansible module
- set_module_args(dict(
- name='foo',
- parent='bar',
- maximum_reuse=1000,
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
- mm = ModuleManager(module=module)
-
- # Override methods to force specific logic in the module to happen
- mm.exists = Mock(return_value=False)
- mm.create_on_device = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['maximum_reuse'] == 1000
diff --git a/test/units/modules/network/f5/test_bigip_profile_persistence_cookie.py b/test/units/modules/network/f5/test_bigip_profile_persistence_cookie.py
deleted file mode 100644
index 2bdecf1ff6..0000000000
--- a/test/units/modules/network/f5/test_bigip_profile_persistence_cookie.py
+++ /dev/null
@@ -1,124 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2018, F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_profile_persistence_cookie import ApiParameters
- from library.modules.bigip_profile_persistence_cookie import ModuleParameters
- from library.modules.bigip_profile_persistence_cookie import ModuleManager
- from library.modules.bigip_profile_persistence_cookie import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_profile_persistence_cookie import ApiParameters
- from ansible.modules.network.f5.bigip_profile_persistence_cookie import ModuleParameters
- from ansible.modules.network.f5.bigip_profile_persistence_cookie import ModuleManager
- from ansible.modules.network.f5.bigip_profile_persistence_cookie import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- name='foo',
- parent='bar',
- match_across_services=False,
- match_across_virtuals=True,
- match_across_pools=False,
- override_connection_limit=True
- )
-
- p = ModuleParameters(params=args)
- assert p.name == 'foo'
- assert p.parent == '/Common/bar'
- assert p.match_across_services == 'no'
- assert p.match_across_virtuals == 'yes'
- assert p.match_across_pools == 'no'
- assert p.override_connection_limit == 'yes'
-
- def test_api_parameters(self):
- args = load_fixture('load_ltm_profile_persistence_cookie_1.json')
- p = ApiParameters(params=args)
- assert p.name == 'cookie'
- assert p.match_across_pools == 'no'
- assert p.match_across_services == 'no'
- assert p.match_across_virtuals == 'no'
-
-
-class TestManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
-
- def test_create(self, *args):
- # Configure the arguments that would be sent to the Ansible module
- set_module_args(dict(
- name='foo',
- match_across_virtuals='yes',
- parent='bar',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
- mm = ModuleManager(module=module)
-
- # Override methods to force specific logic in the module to happen
- mm.exists = Mock(return_value=False)
- mm.create_on_device = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['match_across_virtuals'] == 'yes'
diff --git a/test/units/modules/network/f5/test_bigip_profile_persistence_src_addr.py b/test/units/modules/network/f5/test_bigip_profile_persistence_src_addr.py
deleted file mode 100644
index c8a2683f74..0000000000
--- a/test/units/modules/network/f5/test_bigip_profile_persistence_src_addr.py
+++ /dev/null
@@ -1,128 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_profile_persistence_src_addr import ApiParameters
- from library.modules.bigip_profile_persistence_src_addr import ModuleParameters
- from library.modules.bigip_profile_persistence_src_addr import ModuleManager
- from library.modules.bigip_profile_persistence_src_addr import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_profile_persistence_src_addr import ApiParameters
- from ansible.modules.network.f5.bigip_profile_persistence_src_addr import ModuleParameters
- from ansible.modules.network.f5.bigip_profile_persistence_src_addr import ModuleManager
- from ansible.modules.network.f5.bigip_profile_persistence_src_addr import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- name='foo',
- parent='bar',
- match_across_services=False,
- match_across_virtuals=True,
- match_across_pools=False,
- hash_algorithm='carp',
- entry_timeout=100,
- override_connection_limit=True
- )
-
- p = ModuleParameters(params=args)
- assert p.name == 'foo'
- assert p.parent == '/Common/bar'
- assert p.match_across_services == 'no'
- assert p.match_across_virtuals == 'yes'
- assert p.match_across_pools == 'no'
- assert p.hash_algorithm == 'carp'
- assert p.entry_timeout == 100
- assert p.override_connection_limit == 'yes'
-
- def test_api_parameters(self):
- args = load_fixture('load_ltm_profile_persistence_src_addr_1.json')
- p = ApiParameters(params=args)
- assert p.name == 'source_addr'
- assert p.match_across_pools == 'no'
- assert p.match_across_services == 'no'
- assert p.match_across_virtuals == 'no'
-
-
-class TestManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
-
- def test_create(self, *args):
- # Configure the arguments that would be sent to the Ansible module
- set_module_args(dict(
- name='foo',
- match_across_virtuals='yes',
- parent='bar',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
- mm = ModuleManager(module=module)
-
- # Override methods to force specific logic in the module to happen
- mm.exists = Mock(return_value=False)
- mm.create_on_device = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['match_across_virtuals'] == 'yes'
diff --git a/test/units/modules/network/f5/test_bigip_profile_server_ssl.py b/test/units/modules/network/f5/test_bigip_profile_server_ssl.py
deleted file mode 100644
index 9a51634473..0000000000
--- a/test/units/modules/network/f5/test_bigip_profile_server_ssl.py
+++ /dev/null
@@ -1,115 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2018, F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_profile_server_ssl import ApiParameters
- from library.modules.bigip_profile_server_ssl import ModuleParameters
- from library.modules.bigip_profile_server_ssl import ModuleManager
- from library.modules.bigip_profile_server_ssl import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_profile_server_ssl import ApiParameters
- from ansible.modules.network.f5.bigip_profile_server_ssl import ModuleParameters
- from ansible.modules.network.f5.bigip_profile_server_ssl import ModuleManager
- from ansible.modules.network.f5.bigip_profile_server_ssl import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- name='foo',
- server_name='foo.bar.com',
- secure_renegotiation='require',
- )
-
- p = ModuleParameters(params=args)
- assert p.name == 'foo'
- assert p.server_name == 'foo.bar.com'
- assert p.secure_renegotiation == 'require'
-
- def test_api_parameters(self):
- args = load_fixture('load_ltm_profile_serverssl_1.json')
- p = ApiParameters(params=args)
- assert p.name == 'asda'
- assert p.server_name is None
-
-
-class TestManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
-
- def test_create(self, *args):
- # Configure the arguments that would be sent to the Ansible module
- set_module_args(dict(
- name='foo',
- server_name='foo.bar.com',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- required_together=self.spec.required_together
- )
- mm = ModuleManager(module=module)
-
- # Override methods to force specific logic in the module to happen
- mm.exists = Mock(return_value=False)
- mm.create_on_device = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
diff --git a/test/units/modules/network/f5/test_bigip_profile_tcp.py b/test/units/modules/network/f5/test_bigip_profile_tcp.py
deleted file mode 100644
index a99fdb3312..0000000000
--- a/test/units/modules/network/f5/test_bigip_profile_tcp.py
+++ /dev/null
@@ -1,116 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_profile_tcp import ApiParameters
- from library.modules.bigip_profile_tcp import ModuleParameters
- from library.modules.bigip_profile_tcp import ModuleManager
- from library.modules.bigip_profile_tcp import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_profile_tcp import ApiParameters
- from ansible.modules.network.f5.bigip_profile_tcp import ModuleParameters
- from ansible.modules.network.f5.bigip_profile_tcp import ModuleManager
- from ansible.modules.network.f5.bigip_profile_tcp import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- name='foo',
- parent='bar',
- idle_timeout='500'
- )
-
- p = ModuleParameters(params=args)
- assert p.name == 'foo'
- assert p.parent == '/Common/bar'
- assert p.idle_timeout == 500
-
- def test_api_parameters(self):
- args = load_fixture('load_ltm_profile_tcp_1.json')
- p = ApiParameters(params=args)
- assert p.name == 'foo'
- assert p.idle_timeout == 300
-
-
-class TestManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
-
- def test_create(self, *args):
- # Configure the arguments that would be sent to the Ansible module
- set_module_args(dict(
- name='foo',
- parent='bar',
- idle_timeout=500,
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
- mm = ModuleManager(module=module)
-
- # Override methods to force specific logic in the module to happen
- mm.exists = Mock(return_value=False)
- mm.create_on_device = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['idle_timeout'] == 500
diff --git a/test/units/modules/network/f5/test_bigip_profile_udp.py b/test/units/modules/network/f5/test_bigip_profile_udp.py
deleted file mode 100644
index 0cdb30f3dc..0000000000
--- a/test/units/modules/network/f5/test_bigip_profile_udp.py
+++ /dev/null
@@ -1,119 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_profile_udp import ApiParameters
- from library.modules.bigip_profile_udp import ModuleParameters
- from library.modules.bigip_profile_udp import ModuleManager
- from library.modules.bigip_profile_udp import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_profile_udp import ApiParameters
- from ansible.modules.network.f5.bigip_profile_udp import ModuleParameters
- from ansible.modules.network.f5.bigip_profile_udp import ModuleManager
- from ansible.modules.network.f5.bigip_profile_udp import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- name='foo',
- parent='bar',
- idle_timeout='500',
- datagram_load_balancing=False
- )
-
- p = ModuleParameters(params=args)
- assert p.name == 'foo'
- assert p.parent == '/Common/bar'
- assert p.idle_timeout == 500
- assert p.datagram_load_balancing is False
-
- def test_api_parameters(self):
- args = load_fixture('load_ltm_profile_udp_1.json')
- p = ApiParameters(params=args)
- assert p.name == 'foo'
- assert p.idle_timeout == 60
-
-
-class TestManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
-
- def test_create(self, *args):
- # Configure the arguments that would be sent to the Ansible module
- set_module_args(dict(
- name='foo',
- parent='bar',
- idle_timeout=500,
- datagram_load_balancing=True,
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
- mm = ModuleManager(module=module)
-
- # Override methods to force specific logic in the module to happen
- mm.exists = Mock(return_value=False)
- mm.create_on_device = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['idle_timeout'] == 500
diff --git a/test/units/modules/network/f5/test_bigip_provision.py b/test/units/modules/network/f5/test_bigip_provision.py
deleted file mode 100644
index 39bf287483..0000000000
--- a/test/units/modules/network/f5/test_bigip_provision.py
+++ /dev/null
@@ -1,318 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright (c) 2017 F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_provision import ModuleParameters
- from library.modules.bigip_provision import ModuleManager
- from library.modules.bigip_provision import ArgumentSpec
- from library.modules.bigip_provision import ApiParameters
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
- from test.units.compat.mock import patch
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_provision import ModuleParameters
- from ansible.modules.network.f5.bigip_provision import ModuleManager
- from ansible.modules.network.f5.bigip_provision import ArgumentSpec
- from ansible.modules.network.f5.bigip_provision import ApiParameters
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
- from units.compat.mock import patch
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- module='gtm',
- level='nominal',
- )
- p = ModuleParameters(params=args)
- assert p.module == 'gtm'
- assert p.level == 'nominal'
-
- def test_api_parameters(self):
- args = load_fixture('load_sys_provision_default.json')
- p = ApiParameters(params=args)
- assert p.level == 'dedicated'
- assert p.memory == 'medium'
- assert p.module == 'urldb'
-
- def test_module_parameters_level_minimum(self):
- args = dict(
- level='minimum',
- )
- p = ModuleParameters(params=args)
- assert p.level == 'minimum'
-
- def test_module_parameters_level_nominal(self):
- args = dict(
- level='nominal',
- )
- p = ModuleParameters(params=args)
- assert p.level == 'nominal'
-
- def test_module_parameters_level_dedicated(self):
- args = dict(
- level='dedicated',
- )
- p = ModuleParameters(params=args)
- assert p.level == 'dedicated'
-
- def test_module_parameters_memory_small(self):
- args = dict(
- module='mgmt',
- memory='small',
- )
- p = ModuleParameters(params=args)
- assert p.memory == 0
-
- def test_module_parameters_memory_medium(self):
- args = dict(
- module='mgmt',
- memory='medium',
- )
- p = ModuleParameters(params=args)
- assert p.memory == 200
-
- def test_module_parameters_memory_large(self):
- args = dict(
- module='mgmt',
- memory='large',
- )
- p = ModuleParameters(params=args)
- assert p.memory == 500
-
- def test_module_parameters_memory_700(self):
- args = dict(
- module='mgmt',
- memory=700,
- )
- p = ModuleParameters(params=args)
- assert p.memory == 700
-
- def test_module_parameters_mod_afm(self):
- args = dict(
- module='afm',
- )
- p = ModuleParameters(params=args)
- assert p.module == 'afm'
-
- def test_module_parameters_mod_am(self):
- args = dict(
- module='am',
- )
- p = ModuleParameters(params=args)
- assert p.module == 'am'
-
- def test_module_parameters_mod_sam(self):
- args = dict(
- module='sam',
- )
- p = ModuleParameters(params=args)
- assert p.module == 'sam'
-
- def test_module_parameters_mod_asm(self):
- args = dict(
- module='asm',
- )
- p = ModuleParameters(params=args)
- assert p.module == 'asm'
-
- def test_module_parameters_mod_avr(self):
- args = dict(
- module='avr',
- )
- p = ModuleParameters(params=args)
- assert p.module == 'avr'
-
- def test_module_parameters_mod_fps(self):
- args = dict(
- module='fps',
- )
- p = ModuleParameters(params=args)
- assert p.module == 'fps'
-
- def test_module_parameters_mod_gtm(self):
- args = dict(
- module='gtm',
- )
- p = ModuleParameters(params=args)
- assert p.module == 'gtm'
-
- def test_module_parameters_mod_lc(self):
- args = dict(
- module='lc',
- )
- p = ModuleParameters(params=args)
- assert p.module == 'lc'
-
- def test_module_parameters_mod_pem(self):
- args = dict(
- module='pem',
- )
- p = ModuleParameters(params=args)
- assert p.module == 'pem'
-
- def test_module_parameters_mod_swg(self):
- args = dict(
- module='swg',
- )
- p = ModuleParameters(params=args)
- assert p.module == 'swg'
-
- def test_module_parameters_mod_ilx(self):
- args = dict(
- module='ilx',
- )
- p = ModuleParameters(params=args)
- assert p.module == 'ilx'
-
- def test_module_parameters_mod_apm(self):
- args = dict(
- module='apm',
- )
- p = ModuleParameters(params=args)
- assert p.module == 'apm'
-
- def test_module_parameters_mod_mgmt(self):
- args = dict(
- module='mgmt',
- )
- p = ModuleParameters(params=args)
- assert p.module == 'mgmt'
-
- def test_module_parameters_mod_sslo(self):
- args = dict(
- module='sslo',
- )
- p = ModuleParameters(params=args)
- assert p.module == 'sslo'
-
- def test_module_parameters_mod_urldb(self):
- args = dict(
- module='urldb',
- )
- p = ModuleParameters(params=args)
- assert p.module == 'urldb'
-
-
-class TestManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
- self.patcher1 = patch('time.sleep')
- self.patcher1.start()
-
- def tearDown(self):
- self.patcher1.stop()
-
- def test_provision_one_module_default_level(self, *args):
- # Configure the arguments that would be sent to the Ansible module
- set_module_args(dict(
- module='gtm',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- # Configure the parameters that would be returned by querying the
- # remote device
- current = ModuleParameters(
- dict(
- module='gtm',
- level='none'
- )
- )
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- mutually_exclusive=self.spec.mutually_exclusive
- )
- mm = ModuleManager(module=module)
-
- # Override methods to force specific logic in the module to happen
- mm.update_on_device = Mock(return_value=True)
- mm.read_current_from_device = Mock(return_value=current)
- mm.reboot_device = Mock(return_value=True)
- mm.save_on_device = Mock(return_value=True)
-
- # this forced sleeping can cause these tests to take 15
- # or more seconds to run. This is deliberate.
- mm._is_mprov_running_on_device = Mock(side_effect=[True, False, False, False, False])
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['level'] == 'nominal'
-
- def test_provision_all_modules(self, *args):
- modules = [
- 'afm', 'am', 'sam', 'asm', 'avr', 'fps',
- 'gtm', 'lc', 'ltm', 'pem', 'swg', 'ilx',
- 'apm', 'mgmt', 'sslo', 'urldb',
- ]
-
- for module in modules:
- # Configure the arguments that would be sent to the Ansible module
- set_module_args(dict(
- module=module,
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- with patch('ansible.module_utils.basic.AnsibleModule.fail_json') as mo:
- AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- mutually_exclusive=self.spec.mutually_exclusive
- )
- mo.assert_not_called()
diff --git a/test/units/modules/network/f5/test_bigip_qkview.py b/test/units/modules/network/f5/test_bigip_qkview.py
deleted file mode 100644
index 20d744087d..0000000000
--- a/test/units/modules/network/f5/test_bigip_qkview.py
+++ /dev/null
@@ -1,178 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright (c) 2017 F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_qkview import Parameters
- from library.modules.bigip_qkview import ModuleManager
- from library.modules.bigip_qkview import MadmLocationManager
- from library.modules.bigip_qkview import BulkLocationManager
- from library.modules.bigip_qkview import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
- from test.units.compat.mock import patch
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_qkview import Parameters
- from ansible.modules.network.f5.bigip_qkview import ModuleManager
- from ansible.modules.network.f5.bigip_qkview import MadmLocationManager
- from ansible.modules.network.f5.bigip_qkview import BulkLocationManager
- from ansible.modules.network.f5.bigip_qkview import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
- from units.compat.mock import patch
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- filename='foo.qkview',
- asm_request_log=False,
- max_file_size=1024,
- complete_information=True,
- exclude_core=True,
- force=False,
- exclude=['audit', 'secure'],
- dest='/tmp/foo.qkview'
- )
- p = Parameters(params=args)
- assert p.filename == 'foo.qkview'
- assert p.asm_request_log is None
- assert p.max_file_size == '-s 1024'
- assert p.complete_information == '-c'
- assert p.exclude_core == '-C'
- assert p.force is False
- assert len(p.exclude_core) == 2
- assert 'audit' in p.exclude
- assert 'secure' in p.exclude
- assert p.dest == '/tmp/foo.qkview'
-
- def test_module_asm_parameter(self):
- args = dict(
- asm_request_log=True,
- )
- p = Parameters(params=args)
- assert p.asm_request_log == '-o asm-request-log'
-
-
-class TestMadmLocationManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
-
- def test_create_qkview_default_options(self, *args):
- set_module_args(dict(
- dest='/tmp/foo.qkview',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods in the specific type of manager
- tm = MadmLocationManager(module=module, params=module.params)
- tm.exists = Mock(return_value=False)
- tm.execute_on_device = Mock(return_value=True)
- tm._move_qkview_to_download = Mock(return_value=True)
- tm._download_file = Mock(return_value=True)
- tm._delete_qkview = Mock(return_value=True)
-
- # Override methods to force specific logic in the module to happen
- mm = ModuleManager(module=module)
- mm.is_version_less_than_14 = Mock(return_value=True)
- mm.get_manager = Mock(return_value=tm)
-
- with patch('os.path.exists') as mo:
- mo.return_value = True
- results = mm.exec_module()
-
- assert results['changed'] is False
-
-
-class TestBulkLocationManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
-
- def test_create_qkview_default_options(self, *args):
- set_module_args(dict(
- dest='/tmp/foo.qkview',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods in the specific type of manager
- tm = BulkLocationManager(module=module, params=module.params)
- tm.exists = Mock(return_value=False)
- tm.execute_on_device = Mock(return_value=True)
- tm._move_qkview_to_download = Mock(return_value=True)
- tm._download_file = Mock(return_value=True)
- tm._delete_qkview = Mock(return_value=True)
-
- # Override methods to force specific logic in the module to happen
- mm = ModuleManager(module=module)
- mm.is_version_less_than_14 = Mock(return_value=False)
- mm.get_manager = Mock(return_value=tm)
-
- with patch('os.path.exists') as mo:
- mo.return_value = True
- results = mm.exec_module()
-
- assert results['changed'] is False
diff --git a/test/units/modules/network/f5/test_bigip_remote_role.py b/test/units/modules/network/f5/test_bigip_remote_role.py
deleted file mode 100644
index 0967e9bcf2..0000000000
--- a/test/units/modules/network/f5/test_bigip_remote_role.py
+++ /dev/null
@@ -1,110 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_remote_role import ApiParameters
- from library.modules.bigip_remote_role import ModuleParameters
- from library.modules.bigip_remote_role import ModuleManager
- from library.modules.bigip_remote_role import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_remote_role import ApiParameters
- from ansible.modules.network.f5.bigip_remote_role import ModuleParameters
- from ansible.modules.network.f5.bigip_remote_role import ModuleManager
- from ansible.modules.network.f5.bigip_remote_role import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- terminal_access='none',
- )
-
- p = ModuleParameters(params=args)
- assert p.terminal_access == 'disable'
-
- def test_api_parameters(self):
- args = load_fixture('load_auth_remote_role_role_info_1.json')
-
- p = ApiParameters(params=args)
- assert p.terminal_access == 'disable'
-
-
-class TestManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
-
- def test_create_remote_syslog(self, *args):
- set_module_args(dict(
- name='foo',
- line_order=1000,
- attribute_string='bar',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods in the specific type of manager
- mm = ModuleManager(module=module)
- mm.exists = Mock(side_effect=[False, True])
- mm.create_on_device = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
diff --git a/test/units/modules/network/f5/test_bigip_remote_syslog.py b/test/units/modules/network/f5/test_bigip_remote_syslog.py
deleted file mode 100644
index 9cf81bde45..0000000000
--- a/test/units/modules/network/f5/test_bigip_remote_syslog.py
+++ /dev/null
@@ -1,230 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright (c) 2017 F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_remote_syslog import ModuleParameters
- from library.modules.bigip_remote_syslog import ModuleManager
- from library.modules.bigip_remote_syslog import ArgumentSpec
-
- from library.module_utils.network.f5.common import F5ModuleError
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_remote_syslog import ModuleParameters
- from ansible.modules.network.f5.bigip_remote_syslog import ModuleManager
- from ansible.modules.network.f5.bigip_remote_syslog import ArgumentSpec
-
- from ansible.module_utils.network.f5.common import F5ModuleError
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- remote_host='10.10.10.10',
- remote_port=514,
- local_ip='1.1.1.1'
- )
-
- p = ModuleParameters(params=args)
- assert p.remote_host == '10.10.10.10'
- assert p.remote_port == 514
- assert p.local_ip == '1.1.1.1'
-
-
-class TestManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
-
- def test_create_remote_syslog(self, *args):
- set_module_args(dict(
- remote_host='1.1.1.1',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- fixture = load_fixture('load_tm_sys_syslog_1.json')
- current = fixture['remoteServers']
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods in the specific type of manager
- mm = ModuleManager(module=module)
- mm.exists = Mock(side_effect=[False, True])
- mm.update_on_device = Mock(return_value=True)
- mm.read_current_from_device = Mock(return_value=current)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
-
- def test_create_remote_syslog_idempotent(self, *args):
- set_module_args(dict(
- name='remotesyslog1',
- remote_host='10.10.10.10',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- fixture = load_fixture('load_tm_sys_syslog_1.json')
- current = fixture['remoteServers']
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods in the specific type of manager
- mm = ModuleManager(module=module)
- mm.exists = Mock(return_value=True)
- mm.read_current_from_device = Mock(return_value=current)
-
- results = mm.exec_module()
-
- assert results['changed'] is False
-
- def test_update_remote_port(self, *args):
- set_module_args(dict(
- remote_host='10.10.10.10',
- remote_port=800,
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- fixture = load_fixture('load_tm_sys_syslog_1.json')
- current = fixture['remoteServers']
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods in the specific type of manager
- mm = ModuleManager(module=module)
- mm.exists = Mock(return_value=True)
- mm.read_current_from_device = Mock(return_value=current)
- mm.update_on_device = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['remote_port'] == 800
-
- def test_update_local_ip(self, *args):
- set_module_args(dict(
- remote_host='10.10.10.10',
- local_ip='2.2.2.2',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- fixture = load_fixture('load_tm_sys_syslog_1.json')
- current = fixture['remoteServers']
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods in the specific type of manager
- mm = ModuleManager(module=module)
- mm.exists = Mock(return_value=True)
- mm.read_current_from_device = Mock(return_value=current)
- mm.update_on_device = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['local_ip'] == '2.2.2.2'
-
- def test_update_no_name_dupe_host(self, *args):
- set_module_args(dict(
- remote_host='10.10.10.10',
- local_ip='2.2.2.2',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- fixture = load_fixture('load_tm_sys_syslog_2.json')
- current = fixture['remoteServers']
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods in the specific type of manager
- mm = ModuleManager(module=module)
- mm.exists = Mock(return_value=True)
- mm.read_current_from_device = Mock(return_value=current)
- mm.update_on_device = Mock(return_value=True)
-
- with pytest.raises(F5ModuleError) as ex:
- mm.exec_module()
-
- assert "Multiple occurrences of hostname" in str(ex.value)
diff --git a/test/units/modules/network/f5/test_bigip_remote_user.py b/test/units/modules/network/f5/test_bigip_remote_user.py
deleted file mode 100644
index 89ccbfe36e..0000000000
--- a/test/units/modules/network/f5/test_bigip_remote_user.py
+++ /dev/null
@@ -1,126 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2019, F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_remote_user import ApiParameters
- from library.modules.bigip_remote_user import ModuleParameters
- from library.modules.bigip_remote_user import ModuleManager
- from library.modules.bigip_remote_user import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_remote_user import ApiParameters
- from ansible.modules.network.f5.bigip_remote_user import ModuleParameters
- from ansible.modules.network.f5.bigip_remote_user import ModuleManager
- from ansible.modules.network.f5.bigip_remote_user import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- default_partition='Common',
- default_role='admin',
- console_access='yes',
- description='this is a role'
-
- )
-
- p = ModuleParameters(params=args)
- assert p.default_partition == 'Common'
- assert p.default_role == 'admin'
- assert p.console_access == 'tmsh'
- assert p.description == 'this is a role'
-
- def test_api_parameters(self):
- args = load_fixture('load_remote_user_settings.json')
- p = ApiParameters(params=args)
- assert p.default_partition == 'all'
- assert p.default_role == 'no-access'
- assert p.console_access == 'disabled'
- assert p.description is None
-
-
-class TestManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
-
- def test_create_remote_syslog(self, *args):
- set_module_args(dict(
- default_partition='Foobar',
- default_role='auditor',
- console_access='yes',
- description='this is a role',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- current = ApiParameters(params=load_fixture('load_remote_user_settings.json'))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods in the specific type of manager
- mm = ModuleManager(module=module)
- mm.update_on_device = Mock(return_value=True)
- mm.read_current_from_device = Mock(return_value=current)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['description'] == 'this is a role'
- assert results['default_partition'] == 'Foobar'
- assert results['default_role'] == 'auditor'
- assert results['console_access'] == 'yes'
diff --git a/test/units/modules/network/f5/test_bigip_routedomain.py b/test/units/modules/network/f5/test_bigip_routedomain.py
deleted file mode 100644
index 7805152bae..0000000000
--- a/test/units/modules/network/f5/test_bigip_routedomain.py
+++ /dev/null
@@ -1,128 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_routedomain import ApiParameters
- from library.modules.bigip_routedomain import ModuleParameters
- from library.modules.bigip_routedomain import ModuleManager
- from library.modules.bigip_routedomain import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_routedomain import ApiParameters
- from ansible.modules.network.f5.bigip_routedomain import ModuleParameters
- from ansible.modules.network.f5.bigip_routedomain import ModuleManager
- from ansible.modules.network.f5.bigip_routedomain import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- name='foo',
- id='1234',
- description='my description',
- strict=True,
- parent='parent1',
- vlans=['vlan1', 'vlan2'],
- routing_protocol=['BFD', 'BGP'],
- bwc_policy='bwc1',
- connection_limit=200,
- flow_eviction_policy='evict1',
- service_policy='service1'
- )
-
- p = ModuleParameters(params=args)
- assert p.name == 'foo'
- assert p.id == 1234
- assert p.description == 'my description'
- assert p.strict is True
- assert p.connection_limit == 200
-
- def test_api_parameters(self):
- args = load_fixture('load_net_route_domain_1.json')
-
- p = ApiParameters(params=args)
- assert len(p.vlans) == 5
- assert p.id == 0
- assert p.strict is True
- assert p.connection_limit == 0
-
-
-class TestManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
-
- def test_create(self, *args):
- set_module_args(dict(
- name='foo',
- id=1234,
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- required_one_of=self.spec.required_one_of
- )
- mm = ModuleManager(module=module)
-
- # Override methods to force specific logic in the module to happen
- mm.exists = Mock(return_value=False)
- mm.create_on_device = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['id'] == 1234
diff --git a/test/units/modules/network/f5/test_bigip_selfip.py b/test/units/modules/network/f5/test_bigip_selfip.py
deleted file mode 100644
index 0e5c3a946a..0000000000
--- a/test/units/modules/network/f5/test_bigip_selfip.py
+++ /dev/null
@@ -1,207 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright (c) 2017 F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_selfip import ApiParameters
- from library.modules.bigip_selfip import ModuleParameters
- from library.modules.bigip_selfip import ModuleManager
- from library.modules.bigip_selfip import ArgumentSpec
-
- from library.module_utils.network.f5.common import F5ModuleError
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_selfip import ApiParameters
- from ansible.modules.network.f5.bigip_selfip import ModuleParameters
- from ansible.modules.network.f5.bigip_selfip import ModuleManager
- from ansible.modules.network.f5.bigip_selfip import ArgumentSpec
-
- from ansible.module_utils.network.f5.common import F5ModuleError
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- address='10.10.10.10',
- allow_service=[
- 'tcp:80',
- 'udp:53',
- 'gre'
- ],
- name='net1',
- netmask='255.255.255.0',
- partition='Common',
- route_domain='1',
- state='present',
- traffic_group='traffic-group-local-only',
- vlan='net1'
- )
- p = ModuleParameters(params=args)
- assert p.address == '10.10.10.10%1/24'
- assert p.allow_service == ['gre:0', 'tcp:80', 'udp:53']
- assert p.name == 'net1'
- assert p.netmask == 24
- assert p.route_domain == 1
- assert p.traffic_group == '/Common/traffic-group-local-only'
- assert p.vlan == '/Common/net1'
-
- def test_module_invalid_service(self):
- args = dict(
- allow_service=[
- 'tcp:80',
- 'udp:53',
- 'grp'
- ]
- )
- p = ModuleParameters(params=args)
- with pytest.raises(F5ModuleError) as ex:
- assert p.allow_service == ['grp', 'tcp:80', 'udp:53']
- assert 'The provided protocol' in str(ex.value)
-
- def test_api_parameters(self):
- args = dict(
- address='10.10.10.10%1/24',
- allowService=[
- 'tcp:80',
- 'udp:53',
- 'gre'
- ],
- name='net1',
- state='present',
- trafficGroup='/Common/traffic-group-local-only',
- vlan='net1'
- )
- p = ApiParameters(params=args)
- assert p.address == '10.10.10.10%1/24'
- assert p.allow_service == ['gre', 'tcp:80', 'udp:53']
- assert p.name == 'net1'
- assert p.netmask == 24
- assert p.traffic_group == '/Common/traffic-group-local-only'
- assert p.vlan == '/Common/net1'
-
-
-class TestManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
-
- def test_create_selfip(self, *args):
- set_module_args(dict(
- address='10.10.10.10',
- allow_service=[
- 'tcp:80',
- 'udp:53',
- 'gre'
- ],
- name='net1',
- netmask='255.255.255.0',
- partition='Common',
- route_domain='1',
- state='present',
- traffic_group='traffic-group-local-only',
- vlan='net1',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
- mm = ModuleManager(module=module)
-
- # Override methods to force specific logic in the module to happen
- mm.exists = Mock(side_effect=[False, True])
- mm.create_on_device = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
-
- def test_create_selfip_idempotent(self, *args):
- set_module_args(dict(
- address='10.10.10.10',
- allow_service=[
- 'tcp:80',
- 'udp:53',
- 'gre'
- ],
- name='net1',
- netmask='255.255.255.0',
- partition='Common',
- route_domain='1',
- state='present',
- traffic_group='traffic-group-local-only',
- vlan='net1',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- current = ApiParameters(params=load_fixture('load_tm_net_self.json'))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
- mm = ModuleManager(module=module)
-
- # Override methods to force specific logic in the module to happen
- mm.exists = Mock(side_effect=[True, True])
- mm.read_current_from_device = Mock(return_value=current)
-
- results = mm.exec_module()
-
- assert results['changed'] is False
diff --git a/test/units/modules/network/f5/test_bigip_service_policy.py b/test/units/modules/network/f5/test_bigip_service_policy.py
deleted file mode 100644
index 6c206cd2ec..0000000000
--- a/test/units/modules/network/f5/test_bigip_service_policy.py
+++ /dev/null
@@ -1,132 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_service_policy import ApiParameters
- from library.modules.bigip_service_policy import ModuleParameters
- from library.modules.bigip_service_policy import ModuleManager
- from library.modules.bigip_service_policy import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
- from test.units.compat.mock import patch
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_service_policy import ApiParameters
- from ansible.modules.network.f5.bigip_service_policy import ModuleParameters
- from ansible.modules.network.f5.bigip_service_policy import ModuleManager
- from ansible.modules.network.f5.bigip_service_policy import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
- from units.compat.mock import patch
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- name='foo',
- description='my description',
- timer_policy='timer1',
- port_misuse_policy='misuse1',
- )
-
- p = ModuleParameters(params=args)
- assert p.name == 'foo'
- assert p.description == 'my description'
- assert p.timer_policy == '/Common/timer1'
- assert p.port_misuse_policy == '/Common/misuse1'
-
- def test_api_parameters(self):
- args = load_fixture('load_net_service_policy_1.json')
- p = ApiParameters(params=args)
- assert p.name == 'baz'
- assert p.description == 'my description'
- assert p.timer_policy == '/Common/foo'
- assert p.port_misuse_policy == '/Common/bar'
-
-
-class TestManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
- try:
- self.p1 = patch('library.modules.bigip_service_policy.module_provisioned')
- self.m1 = self.p1.start()
- self.m1.return_value = True
- except Exception:
- self.p1 = patch('ansible.modules.network.f5.bigip_service_policy.module_provisioned')
- self.m1 = self.p1.start()
- self.m1.return_value = True
-
- def test_create_selfip(self, *args):
- set_module_args(dict(
- name='foo',
- description='my description',
- timer_policy='timer1',
- port_misuse_policy='misuse1',
- partition='Common',
- state='present',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
- mm = ModuleManager(module=module)
-
- # Override methods to force specific logic in the module to happen
- mm.exists = Mock(side_effect=[False, True])
- mm.create_on_device = Mock(return_value=True)
- mm.module_provisioned = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
diff --git a/test/units/modules/network/f5/test_bigip_smtp.py b/test/units/modules/network/f5/test_bigip_smtp.py
deleted file mode 100644
index 8203a092c7..0000000000
--- a/test/units/modules/network/f5/test_bigip_smtp.py
+++ /dev/null
@@ -1,152 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_smtp import ApiParameters
- from library.modules.bigip_smtp import ModuleParameters
- from library.modules.bigip_smtp import ModuleManager
- from library.modules.bigip_smtp import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_smtp import ApiParameters
- from ansible.modules.network.f5.bigip_smtp import ModuleParameters
- from ansible.modules.network.f5.bigip_smtp import ModuleManager
- from ansible.modules.network.f5.bigip_smtp import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- name='foo',
- smtp_server='1.1.1.1',
- smtp_server_port='25',
- smtp_server_username='admin',
- smtp_server_password='password',
- local_host_name='smtp.mydomain.com',
- encryption='tls',
- update_password='always',
- from_address='no-reply@mydomain.com',
- authentication=True,
- )
-
- p = ModuleParameters(params=args)
- assert p.name == 'foo'
- assert p.smtp_server == '1.1.1.1'
- assert p.smtp_server_port == 25
- assert p.smtp_server_username == 'admin'
- assert p.smtp_server_password == 'password'
- assert p.local_host_name == 'smtp.mydomain.com'
- assert p.encryption == 'tls'
- assert p.update_password == 'always'
- assert p.from_address == 'no-reply@mydomain.com'
- assert p.authentication_disabled is None
- assert p.authentication_enabled is True
-
- def test_api_parameters(self):
- p = ApiParameters(params=load_fixture('load_sys_smtp_server.json'))
- assert p.name == 'foo'
- assert p.smtp_server == 'mail.foo.bar'
- assert p.smtp_server_port == 465
- assert p.smtp_server_username == 'admin'
- assert p.smtp_server_password == '$M$Ch$this-is-encrypted=='
- assert p.local_host_name == 'mail-host.foo.bar'
- assert p.encryption == 'ssl'
- assert p.from_address == 'no-reply@foo.bar'
- assert p.authentication_disabled is None
- assert p.authentication_enabled is True
-
-
-class TestManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
-
- def test_create_monitor(self, *args):
- set_module_args(dict(
- name='foo',
- smtp_server='1.1.1.1',
- smtp_server_port='25',
- smtp_server_username='admin',
- smtp_server_password='password',
- local_host_name='smtp.mydomain.com',
- encryption='tls',
- update_password='always',
- from_address='no-reply@mydomain.com',
- authentication=True,
- partition='Common',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods in the specific type of manager
- mm = ModuleManager(module=module)
- mm.exists = Mock(side_effect=[False, True])
- mm.create_on_device = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['encryption'] == 'tls'
- assert results['smtp_server'] == '1.1.1.1'
- assert results['smtp_server_port'] == 25
- assert results['local_host_name'] == 'smtp.mydomain.com'
- assert results['authentication'] is True
- assert results['from_address'] == 'no-reply@mydomain.com'
- assert 'smtp_server_username' not in results
- assert 'smtp_server_password' not in results
diff --git a/test/units/modules/network/f5/test_bigip_snat_pool.py b/test/units/modules/network/f5/test_bigip_snat_pool.py
deleted file mode 100644
index 83ab106a48..0000000000
--- a/test/units/modules/network/f5/test_bigip_snat_pool.py
+++ /dev/null
@@ -1,187 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright (c) 2017 F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_snat_pool import ModuleParameters
- from library.modules.bigip_snat_pool import ApiParameters
- from library.modules.bigip_snat_pool import ModuleManager
- from library.modules.bigip_snat_pool import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_snat_pool import ModuleParameters
- from ansible.modules.network.f5.bigip_snat_pool import ApiParameters
- from ansible.modules.network.f5.bigip_snat_pool import ModuleManager
- from ansible.modules.network.f5.bigip_snat_pool import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- name='my-snat-pool',
- state='present',
- members=['10.10.10.10', '20.20.20.20'],
- description='A SNAT pool description',
- partition='Common'
- )
- p = ModuleParameters(params=args)
- assert p.name == 'my-snat-pool'
- assert p.state == 'present'
- assert p.description == 'A SNAT pool description'
- assert len(p.members) == 2
- assert '/Common/10.10.10.10' in p.members
- assert '/Common/20.20.20.20' in p.members
-
- def test_api_parameters(self):
- args = dict(
- members=['/Common/10.10.10.10', '/foo/20.20.20.20']
- )
- p = ApiParameters(params=args)
- assert len(p.members) == 2
- assert '/Common/10.10.10.10' in p.members
- assert '/foo/20.20.20.20' in p.members
-
-
-class TestManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
-
- def test_create_snat_pool(self, *args):
- set_module_args(dict(
- name='my-snat-pool',
- state='present',
- members=['10.10.10.10', '20.20.20.20'],
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- required_if=self.spec.required_if
- )
- mm = ModuleManager(module=module)
-
- # Override methods to force specific logic in the module to happen
- mm.exists = Mock(side_effect=[False, True])
- mm.create_on_device = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert len(results['members']) == 2
- assert '/Common/10.10.10.10' in results['members']
- assert '/Common/20.20.20.20' in results['members']
-
- def test_create_snat_pool_idempotent(self, *args):
- set_module_args(dict(
- name='asdasd',
- state='present',
- members=['1.1.1.1', '2.2.2.2'],
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- current = ApiParameters(params=load_fixture('load_ltm_snatpool.json'))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- required_if=self.spec.required_if
- )
- mm = ModuleManager(module=module)
-
- # Override methods to force specific logic in the module to happen
- mm.exists = Mock(side_effect=[True, True])
- mm.read_current_from_device = Mock(return_value=current)
-
- results = mm.exec_module()
-
- assert results['changed'] is False
-
- def test_update_snat_pool(self, *args):
- set_module_args(dict(
- name='asdasd',
- state='present',
- members=['30.30.30.30'],
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- current = ApiParameters(params=load_fixture('load_ltm_snatpool.json'))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- required_if=self.spec.required_if
- )
- mm = ModuleManager(module=module)
-
- # Override methods to force specific logic in the module to happen
- mm.read_current_from_device = Mock(return_value=current)
- mm.update_on_device = Mock(return_value=True)
- mm.exists = Mock(return_value=True)
- mm.create_on_device = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert len(results['members']) == 1
- assert '/Common/30.30.30.30' in results['members']
diff --git a/test/units/modules/network/f5/test_bigip_snat_translation.py b/test/units/modules/network/f5/test_bigip_snat_translation.py
deleted file mode 100644
index 6571711dfa..0000000000
--- a/test/units/modules/network/f5/test_bigip_snat_translation.py
+++ /dev/null
@@ -1,337 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2019, F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_snat_translation import ApiParameters
- from library.modules.bigip_snat_translation import ModuleParameters
- from library.modules.bigip_snat_translation import ModuleManager
- from library.modules.bigip_snat_translation import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_snat_translation import ApiParameters
- from ansible.modules.network.f5.bigip_snat_translation import ModuleParameters
- from ansible.modules.network.f5.bigip_snat_translation import ModuleManager
- from ansible.modules.network.f5.bigip_snat_translation import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- name='my-snat-translation',
- address='1.1.1.1',
- arp='yes',
- connection_limit=300,
- description='None',
- ip_idle_timeout='50',
- partition='Common',
- state='present',
- traffic_group='test',
- tcp_idle_timeout='20',
- udp_idle_timeout='100',
- )
-
- p = ModuleParameters(params=args)
- assert p.name == 'my-snat-translation'
- assert p.address == '1.1.1.1'
- assert p.arp == 'enabled'
- assert p.connection_limit == 300
- assert p.description == 'None'
- assert p.ip_idle_timeout == '50'
- assert p.partition == 'Common'
- assert p.state == 'present'
- assert p.traffic_group == '/Common/test'
- assert p.tcp_idle_timeout == '20'
- assert p.udp_idle_timeout == '100'
-
- def test_api_parameters(self):
- args = load_fixture('load_ltm_snat_translation_default.json')
- p = ApiParameters(params=args)
- assert p.address == '1.1.1.1'
- assert p.arp == 'no'
- assert p.connection_limit == 0
- assert p.description == 'My description'
- assert p.ip_idle_timeout == '50'
- assert p.partition == 'Common'
- assert p.traffic_group == '/Common/test'
- assert p.tcp_idle_timeout == '20'
- assert p.udp_idle_timeout == '100'
-
- def test_module_parameters_arp_yes(self):
- args = dict(
- arp='yes'
- )
- p = ModuleParameters(params=args)
- assert p.arp == 'enabled'
-
- def test_module_parameters_arp_no(self):
- args = dict(
- arp='no'
- )
- p = ModuleParameters(params=args)
- assert p.arp == 'disabled'
-
- def test_module_parameters_connection_limit_none(self):
- args = dict(
- connection_limit=0
- )
- p = ModuleParameters(params=args)
- assert p.connection_limit == 0
-
- def test_module_parameters_connection_limit_int(self):
- args = dict(
- connection_limit=500
- )
- p = ModuleParameters(params=args)
- assert p.connection_limit == 500
-
- def test_module_parameters_description_none(self):
- args = dict(
- description='none'
- )
- p = ModuleParameters(params=args)
- assert p.description == ''
-
- def test_module_parameters_description_empty(self):
- args = dict(
- description=''
- )
- p = ModuleParameters(params=args)
- assert p.description == ''
-
- def test_module_parameters_description_string_value(self):
- args = dict(
- description='My Snat Translation'
- )
- p = ModuleParameters(params=args)
- assert p.description == 'My Snat Translation'
-
- def test_module_parameters_ip_idle_timeout_indefinite(self):
- args = dict(
- ip_idle_timeout='indefinite'
- )
- p = ModuleParameters(params=args)
- assert p.ip_idle_timeout == 'indefinite'
-
- def test_module_parameters_ip_idle_timeout_string_value(self):
- args = dict(
- ip_idle_timeout='65000'
- )
- p = ModuleParameters(params=args)
- assert p.ip_idle_timeout == '65000'
-
- def test_module_no_partition_prefix_parameters(self):
- args = dict(
- partition='Common',
- address='10.10.10.10',
- traffic_group='traffic-group-1'
- )
- p = ModuleParameters(params=args)
- assert p.partition == 'Common'
- assert p.address == '10.10.10.10'
- assert p.traffic_group == '/Common/traffic-group-1'
-
- def test_module_partition_prefix_parameters(self):
- args = dict(
- partition='Common',
- address='10.10.10.10',
- traffic_group='/Common/traffic-group-1'
- )
- p = ModuleParameters(params=args)
- assert p.partition == 'Common'
- assert p.address == '10.10.10.10'
- assert p.traffic_group == '/Common/traffic-group-1'
-
- def test_module_parameters_state_present(self):
- args = dict(
- state='present'
- )
- p = ModuleParameters(params=args)
- assert p.state == 'present'
- assert p.enabled is True
-
- def test_module_parameters_state_absent(self):
- args = dict(
- state='absent'
- )
- p = ModuleParameters(params=args)
- assert p.state == 'absent'
-
- def test_module_parameters_state_enabled(self):
- args = dict(
- state='enabled'
- )
- p = ModuleParameters(params=args)
- assert p.state == 'enabled'
- assert p.enabled is True
-
- def test_module_parameters_state_disabled(self):
- args = dict(
- state='disabled'
- )
- p = ModuleParameters(params=args)
- assert p.state == 'disabled'
- assert p.disabled is True
-
- def test_module_parameters_tcp_idle_timeout_indefinite(self):
- args = dict(
- tcp_idle_timeout='indefinite'
- )
- p = ModuleParameters(params=args)
- assert p.tcp_idle_timeout == 'indefinite'
-
- def test_module_parameters_tcp_idle_timeout_string_value(self):
- args = dict(
- tcp_idle_timeout='65000'
- )
- p = ModuleParameters(params=args)
- assert p.tcp_idle_timeout == '65000'
-
- def test_module_parameters_udp_idle_timeout_indefinite(self):
- args = dict(
- udp_idle_timeout='indefinite'
- )
- p = ModuleParameters(params=args)
- assert p.udp_idle_timeout == 'indefinite'
-
- def test_module_parameters_udp_idle_timeout_string_value(self):
- args = dict(
- udp_idle_timeout='65000'
- )
- p = ModuleParameters(params=args)
- assert p.udp_idle_timeout == '65000'
-
-
-class TestManager(unittest.TestCase):
- def setUp(self):
- self.spec = ArgumentSpec()
-
- def test_create_snat_translation(self, *args):
- set_module_args(dict(
- name='my-snat-translation',
- address='1.1.1.1',
- arp='yes',
- connection_limit=300,
- description='My description',
- ip_idle_timeout='50',
- state='present',
- tcp_idle_timeout='20',
- udp_idle_timeout='100',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- required_if=self.spec.required_if
- )
- mm = ModuleManager(module=module)
-
- # Override methods to force specific logic in the module to happen
- mm.exists = Mock(side_effect=[False, True])
- mm.create_on_device = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['address'] == '1.1.1.1'
- assert results['arp'] == 'yes'
- assert results['connection_limit'] == 300
- assert results['description'] == 'My description'
- assert results['ip_idle_timeout'] == '50'
- assert results['tcp_idle_timeout'] == '20'
- assert results['udp_idle_timeout'] == '100'
-
- def test_update_snat_translation(self, *args):
- set_module_args(dict(
- name='my-snat-translation',
- address='1.1.1.1',
- arp='yes',
- connection_limit=300,
- description='',
- ip_idle_timeout='500',
- state='disabled',
- tcp_idle_timeout='indefinite',
- traffic_group='traffic-group-1',
- udp_idle_timeout='indefinite',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
- current = ApiParameters(params=load_fixture('load_ltm_snat_translation_default.json'))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- required_if=self.spec.required_if
- )
- mm = ModuleManager(module=module)
-
- # Override methods to force specific logic in the module to happen
- mm.read_current_from_device = Mock(return_value=current)
- mm.update_on_device = Mock(return_value=True)
- mm.exists = Mock(return_value=True)
- mm.create_on_device = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['arp'] == 'yes'
- assert results['connection_limit'] == 300
- assert results['description'] == ''
- assert results['ip_idle_timeout'] == '500'
- assert results['tcp_idle_timeout'] == 'indefinite'
- assert results['udp_idle_timeout'] == 'indefinite'
diff --git a/test/units/modules/network/f5/test_bigip_snmp.py b/test/units/modules/network/f5/test_bigip_snmp.py
deleted file mode 100644
index 52ca2898e7..0000000000
--- a/test/units/modules/network/f5/test_bigip_snmp.py
+++ /dev/null
@@ -1,266 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright (c) 2017 F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_snmp import ApiParameters
- from library.modules.bigip_snmp import ModuleParameters
- from library.modules.bigip_snmp import ModuleManager
- from library.modules.bigip_snmp import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_snmp import ApiParameters
- from ansible.modules.network.f5.bigip_snmp import ModuleParameters
- from ansible.modules.network.f5.bigip_snmp import ModuleManager
- from ansible.modules.network.f5.bigip_snmp import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- agent_status_traps='enabled',
- agent_authentication_traps='enabled',
- contact='Alice@foo.org',
- device_warning_traps='enabled',
- location='Lunar orbit',
- )
- p = ModuleParameters(params=args)
- assert p.agent_status_traps == 'enabled'
- assert p.agent_authentication_traps == 'enabled'
- assert p.device_warning_traps == 'enabled'
- assert p.location == 'Lunar orbit'
- assert p.contact == 'Alice@foo.org'
-
- def test_module_parameters_disabled(self):
- args = dict(
- agent_status_traps='disabled',
- agent_authentication_traps='disabled',
- device_warning_traps='disabled',
- )
- p = ModuleParameters(params=args)
- assert p.agent_status_traps == 'disabled'
- assert p.agent_authentication_traps == 'disabled'
- assert p.device_warning_traps == 'disabled'
-
- def test_api_parameters(self):
- args = dict(
- agentTrap='enabled',
- authTrap='enabled',
- bigipTraps='enabled',
- sysLocation='Lunar orbit',
- sysContact='Alice@foo.org',
- )
- p = ApiParameters(params=args)
- assert p.agent_status_traps == 'enabled'
- assert p.agent_authentication_traps == 'enabled'
- assert p.device_warning_traps == 'enabled'
- assert p.location == 'Lunar orbit'
- assert p.contact == 'Alice@foo.org'
-
- def test_api_parameters_disabled(self):
- args = dict(
- agentTrap='disabled',
- authTrap='disabled',
- bigipTraps='disabled',
- )
- p = ApiParameters(params=args)
- assert p.agent_status_traps == 'disabled'
- assert p.agent_authentication_traps == 'disabled'
- assert p.device_warning_traps == 'disabled'
-
-
-class TestManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
-
- def test_update_agent_status_traps(self, *args):
- set_module_args(dict(
- agent_status_traps='enabled',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- # Configure the parameters that would be returned by querying the
- # remote device
- current = ApiParameters(
- params=dict(
- agent_status_traps='disabled'
- )
- )
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
- mm = ModuleManager(module=module)
-
- # Override methods to force specific logic in the module to happen
- mm.update_on_device = Mock(return_value=True)
- mm.read_current_from_device = Mock(return_value=current)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['agent_status_traps'] == 'enabled'
-
- def test_update_allowed_addresses(self, *args):
- set_module_args(dict(
- allowed_addresses=[
- '127.0.0.0/8',
- '10.10.10.10',
- 'foo',
- 'baz.foo.com'
- ],
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- # Configure the parameters that would be returned by querying the
- # remote device
- current = ApiParameters(
- params=dict(
- allowed_addresses=['127.0.0.0/8']
- )
- )
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
- mm = ModuleManager(module=module)
-
- # Override methods to force specific logic in the module to happen
- mm.update_on_device = Mock(return_value=True)
- mm.read_current_from_device = Mock(return_value=current)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert len(results['allowed_addresses']) == 4
- assert results['allowed_addresses'] == [
- '10.10.10.10', '127.0.0.0/8', 'baz.foo.com', 'foo'
- ]
-
- def test_update_allowed_addresses_default(self, *args):
- set_module_args(dict(
- allowed_addresses=[
- 'default'
- ],
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- # Configure the parameters that would be returned by querying the
- # remote device
- current = ApiParameters(
- params=dict(
- allowed_addresses=['10.0.0.0']
- )
- )
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
- mm = ModuleManager(module=module)
-
- # Override methods to force specific logic in the module to happen
- mm.update_on_device = Mock(return_value=True)
- mm.read_current_from_device = Mock(return_value=current)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert len(results['allowed_addresses']) == 1
- assert results['allowed_addresses'] == ['127.0.0.0/8']
-
- def test_update_allowed_addresses_empty(self, *args):
- set_module_args(dict(
- allowed_addresses=[''],
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- # Configure the parameters that would be returned by querying the
- # remote device
- current = ApiParameters(
- params=dict(
- allowed_addresses=['10.0.0.0']
- )
- )
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
- mm = ModuleManager(module=module)
-
- # Override methods to force specific logic in the module to happen
- mm.update_on_device = Mock(return_value=True)
- mm.read_current_from_device = Mock(return_value=current)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert len(results['allowed_addresses']) == 1
- assert results['allowed_addresses'] == ['127.0.0.0/8']
diff --git a/test/units/modules/network/f5/test_bigip_snmp_community.py b/test/units/modules/network/f5/test_bigip_snmp_community.py
deleted file mode 100644
index da18b893fb..0000000000
--- a/test/units/modules/network/f5/test_bigip_snmp_community.py
+++ /dev/null
@@ -1,305 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_snmp_community import ApiParameters
- from library.modules.bigip_snmp_community import ModuleParameters
- from library.modules.bigip_snmp_community import ModuleManager
- from library.modules.bigip_snmp_community import V1Manager
- from library.modules.bigip_snmp_community import V2Manager
- from library.modules.bigip_snmp_community import ArgumentSpec
-
- from library.module_utils.network.f5.common import F5ModuleError
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_snmp_community import ApiParameters
- from ansible.modules.network.f5.bigip_snmp_community import ModuleParameters
- from ansible.modules.network.f5.bigip_snmp_community import ModuleManager
- from ansible.modules.network.f5.bigip_snmp_community import V1Manager
- from ansible.modules.network.f5.bigip_snmp_community import V2Manager
- from ansible.modules.network.f5.bigip_snmp_community import ArgumentSpec
-
- from ansible.module_utils.network.f5.common import F5ModuleError
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- version='v2c',
- community='foo',
- source='1.1.1.1',
- port='8080',
- oid='.1',
- access='ro',
- ip_version=4,
- snmp_username='admin',
- snmp_auth_protocol='sha',
- snmp_auth_password='secretsecret',
- snmp_privacy_protocol='des',
- snmp_privacy_password='secretsecret',
- update_password='always',
- state='present'
- )
-
- p = ModuleParameters(params=args)
- assert p.version == 'v2c'
- assert p.community == 'foo'
- assert p.source == '1.1.1.1'
- assert p.port == 8080
- assert p.oid == '.1'
- assert p.access == 'ro'
- assert p.ip_version == 4
- assert p.snmp_username == 'admin'
- assert p.snmp_auth_protocol == 'sha'
- assert p.snmp_auth_password == 'secretsecret'
- assert p.snmp_privacy_protocol == 'des'
- assert p.snmp_privacy_password == 'secretsecret'
- assert p.update_password == 'always'
- assert p.state == 'present'
-
- def test_api_parameters_community_1(self):
- args = load_fixture('load_sys_snmp_communities_1.json')
-
- p = ApiParameters(params=args)
- assert p.access == 'ro'
- assert p.community == 'foo'
- assert p.ip_version == 4
-
- def test_api_parameters_community_2(self):
- args = load_fixture('load_sys_snmp_communities_2.json')
-
- p = ApiParameters(params=args)
- assert p.access == 'rw'
- assert p.community == 'foo'
- assert p.ip_version == 4
- assert p.oid == '.1'
- assert p.source == '1.1.1.1'
-
- def test_api_parameters_community_3(self):
- args = load_fixture('load_sys_snmp_communities_3.json')
-
- p = ApiParameters(params=args)
- assert p.access == 'ro'
- assert p.community == 'foo'
- assert p.ip_version == 6
- assert p.oid == '.1'
- assert p.source == '2001:0db8:85a3:0000:0000:8a2e:0370:7334'
-
- def test_api_parameters_community_4(self):
- args = load_fixture('load_sys_snmp_communities_4.json')
-
- p = ApiParameters(params=args)
- assert p.access == 'ro'
- assert p.community == 'foo'
- assert p.ip_version == 6
-
- def test_api_parameters_users_1(self):
- args = load_fixture('load_sys_snmp_users_1.json')
-
- p = ApiParameters(params=args)
- assert p.access == 'ro'
- assert p.snmp_auth_protocol == 'sha'
- assert p.oid == '.1'
- assert p.snmp_privacy_protocol == 'aes'
- assert p.snmp_username == 'foo'
-
-
-class TestManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
-
- def test_create_v2c_community_1(self, *args):
- set_module_args(dict(
- version='v2c',
- community='foo',
- source='1.1.1.1',
- port='8080',
- oid='.1',
- access='ro',
- ip_version=4,
- state='present',
- partition='Common',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- required_if=self.spec.required_if
- )
- m1 = V1Manager(module=module)
-
- # Override methods to force specific logic in the module to happen
- m1.exists = Mock(side_effect=[False, True])
- m1.create_on_device = Mock(return_value=True)
-
- m0 = ModuleManager(module=module)
- m0.get_manager = Mock(return_value=m1)
-
- results = m0.exec_module()
-
- assert results['changed'] is True
-
- def test_create_v1_community_1(self, *args):
- set_module_args(dict(
- name='foo',
- version='v1',
- community='foo',
- source='1.1.1.1',
- port='8080',
- oid='.1',
- access='ro',
- ip_version=4,
- state='present',
- partition='Common',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- required_if=self.spec.required_if
- )
- m1 = V1Manager(module=module)
-
- # Override methods to force specific logic in the module to happen
- m1.exists = Mock(side_effect=[False, True])
- m1.create_on_device = Mock(return_value=True)
-
- m0 = ModuleManager(module=module)
- m0.get_manager = Mock(return_value=m1)
-
- results = m0.exec_module()
-
- assert results['changed'] is True
-
- def test_create_v3_community_1(self, *args):
- set_module_args(dict(
- version='v3',
- oid='.1',
- access='ro',
- snmp_username='admin',
- snmp_auth_protocol='md5',
- snmp_auth_password='secretsecret',
- snmp_privacy_protocol='des',
- snmp_privacy_password='secretsecret',
- state='present',
- partition='Common',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- required_if=self.spec.required_if
- )
- m1 = V2Manager(module=module)
-
- # Override methods to force specific logic in the module to happen
- m1.exists = Mock(side_effect=[False, True])
- m1.create_on_device = Mock(return_value=True)
-
- m0 = ModuleManager(module=module)
- m0.get_manager = Mock(return_value=m1)
-
- results = m0.exec_module()
-
- assert results['changed'] is True
-
- def test_create_v3_community_2(self, *args):
- set_module_args(dict(
- version='v3',
- access='ro',
- snmp_username='admin',
- snmp_auth_protocol='md5',
- snmp_auth_password='secretsecret',
- snmp_privacy_protocol='des',
- snmp_privacy_password='secretsecret',
- state='present',
- partition='Common',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- required_if=self.spec.required_if
- )
- m1 = V2Manager(module=module)
-
- # Override methods to force specific logic in the module to happen
- m1.exists = Mock(side_effect=[False, True])
- m1.create_on_device = Mock(return_value=True)
-
- m0 = ModuleManager(module=module)
- m0.get_manager = Mock(return_value=m1)
-
- with pytest.raises(F5ModuleError) as ex:
- m0.exec_module()
-
- assert 'oid must be specified when creating a new v3 community.' == str(ex.value)
diff --git a/test/units/modules/network/f5/test_bigip_snmp_trap.py b/test/units/modules/network/f5/test_bigip_snmp_trap.py
deleted file mode 100644
index 6d1fd951c8..0000000000
--- a/test/units/modules/network/f5/test_bigip_snmp_trap.py
+++ /dev/null
@@ -1,203 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright (c) 2017 F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_snmp_trap import V2Parameters
- from library.modules.bigip_snmp_trap import V1Parameters
- from library.modules.bigip_snmp_trap import ModuleManager
- from library.modules.bigip_snmp_trap import V2Manager
- from library.modules.bigip_snmp_trap import V1Manager
- from library.modules.bigip_snmp_trap import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
- from test.units.compat.mock import patch
- from test.units.compat.mock import DEFAULT
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_snmp_trap import V2Parameters
- from ansible.modules.network.f5.bigip_snmp_trap import V1Parameters
- from ansible.modules.network.f5.bigip_snmp_trap import ModuleManager
- from ansible.modules.network.f5.bigip_snmp_trap import V2Manager
- from ansible.modules.network.f5.bigip_snmp_trap import V1Manager
- from ansible.modules.network.f5.bigip_snmp_trap import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
- from units.compat.mock import patch
- from units.compat.mock import DEFAULT
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_networked_parameters(self):
- args = dict(
- name='foo',
- snmp_version='1',
- community='public',
- destination='10.10.10.10',
- port=1000,
- network='other',
- )
- p = V2Parameters(params=args)
- assert p.name == 'foo'
- assert p.snmp_version == '1'
- assert p.community == 'public'
- assert p.destination == '10.10.10.10'
- assert p.port == 1000
- assert p.network == 'other'
-
- def test_module_non_networked_parameters(self):
- args = dict(
- name='foo',
- snmp_version='1',
- community='public',
- destination='10.10.10.10',
- port=1000,
- network='other',
- )
- p = V1Parameters(params=args)
- assert p.name == 'foo'
- assert p.snmp_version == '1'
- assert p.community == 'public'
- assert p.destination == '10.10.10.10'
- assert p.port == 1000
- assert p.network is None
-
- def test_api_parameters(self):
- args = dict(
- name='foo',
- community='public',
- host='10.10.10.10',
- network='other',
- version=1,
- port=1000
- )
- p = V2Parameters(params=args)
- assert p.name == 'foo'
- assert p.snmp_version == '1'
- assert p.community == 'public'
- assert p.destination == '10.10.10.10'
- assert p.port == 1000
- assert p.network == 'other'
-
-
-class TestManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
-
- def test_create_trap(self, *args):
- set_module_args(dict(
- name='foo',
- snmp_version='1',
- community='public',
- destination='10.10.10.10',
- port=1000,
- network='other',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods to force specific logic in the module to happen
- m0 = ModuleManager(module=module)
- m0.is_version_without_network = Mock(return_value=False)
- m0.is_version_with_default_network = Mock(return_value=True)
-
- patches = dict(
- create_on_device=DEFAULT,
- exists=DEFAULT
- )
- with patch.multiple(V2Manager, **patches) as mo:
- mo['create_on_device'].side_effect = Mock(return_value=True)
- mo['exists'].side_effect = Mock(return_value=False)
- results = m0.exec_module()
-
- assert results['changed'] is True
- assert results['port'] == 1000
- assert results['snmp_version'] == '1'
-
- def test_create_trap_non_network(self, *args):
- set_module_args(dict(
- name='foo',
- snmp_version='1',
- community='public',
- destination='10.10.10.10',
- port=1000,
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods to force specific logic in the module to happen
- m0 = ModuleManager(module=module)
- m0.is_version_without_network = Mock(return_value=True)
-
- patches = dict(
- create_on_device=DEFAULT,
- exists=DEFAULT
- )
- with patch.multiple(V1Manager, **patches) as mo:
- mo['create_on_device'].side_effect = Mock(return_value=True)
- mo['exists'].side_effect = Mock(return_value=False)
- results = m0.exec_module()
-
- assert results['changed'] is True
- assert results['port'] == 1000
- assert results['snmp_version'] == '1'
diff --git a/test/units/modules/network/f5/test_bigip_software_image.py b/test/units/modules/network/f5/test_bigip_software_image.py
deleted file mode 100644
index 4fa46a7593..0000000000
--- a/test/units/modules/network/f5/test_bigip_software_image.py
+++ /dev/null
@@ -1,123 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_software_image import ApiParameters
- from library.modules.bigip_software_image import ModuleParameters
- from library.modules.bigip_software_image import ModuleManager
- from library.modules.bigip_software_image import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_software_image import ApiParameters
- from ansible.modules.network.f5.bigip_software_image import ModuleParameters
- from ansible.modules.network.f5.bigip_software_image import ModuleManager
- from ansible.modules.network.f5.bigip_software_image import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- filename='/path/to/BIGIP-13.0.0.0.0.1645.iso',
- image='/path/to/BIGIP-13.0.0.0.0.1645.iso',
- )
-
- p = ModuleParameters(params=args)
- assert p.filename == 'BIGIP-13.0.0.0.0.1645.iso'
- assert p.image == '/path/to/BIGIP-13.0.0.0.0.1645.iso'
-
- def test_api_parameters(self):
- args = dict(
- file_size='1000 MB',
- build='0.0.3',
- checksum='8cdbd094195fab4b2b47ff4285577b70',
- image_type='release',
- version='13.1.0.8'
- )
-
- p = ApiParameters(params=args)
- assert p.file_size == 1000
- assert p.build == '0.0.3'
- assert p.checksum == '8cdbd094195fab4b2b47ff4285577b70'
- assert p.image_type == 'release'
- assert p.version == '13.1.0.8'
-
-
-class TestManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
-
- def test_create(self, *args):
- set_module_args(dict(
- image='/path/to/BIGIP-13.0.0.0.0.1645.iso',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- current = ApiParameters(params=load_fixture('load_sys_software_image_1.json'))
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods in the specific type of manager
- mm = ModuleManager(module=module)
- mm.exists = Mock(side_effect=[False, True])
- mm.read_current_from_device = Mock(return_value=current)
- mm.create_on_device = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['file_size'] == 1948
diff --git a/test/units/modules/network/f5/test_bigip_software_install.py b/test/units/modules/network/f5/test_bigip_software_install.py
deleted file mode 100644
index 9f85eae6f3..0000000000
--- a/test/units/modules/network/f5/test_bigip_software_install.py
+++ /dev/null
@@ -1,119 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_software_install import ApiParameters
- from library.modules.bigip_software_install import ModuleParameters
- from library.modules.bigip_software_install import ModuleManager
- from library.modules.bigip_software_install import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_software_install import ApiParameters
- from ansible.modules.network.f5.bigip_software_install import ModuleParameters
- from ansible.modules.network.f5.bigip_software_install import ModuleManager
- from ansible.modules.network.f5.bigip_software_install import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- volume='HD1.2',
- image='BIGIP-13.0.0.0.0.1645.iso',
- )
-
- p = ModuleParameters(params=args)
- assert p.volume == 'HD1.2'
- assert p.image == 'BIGIP-13.0.0.0.0.1645.iso'
-
-
-class TestManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
-
- def test_create(self, *args):
- set_module_args(dict(
- image='BIGIP-13.0.0.0.0.1645.iso',
- volume='HD1.2',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- current = ApiParameters()
- current.read_image_from_device = Mock(
- side_effect=[
- ['BIGIP-13.0.0.0.0.1645.iso'],
- ['BIGIP-12.1.3.4-0.0.2.iso'],
- ]
- )
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods in the specific type of manager
- mm = ModuleManager(module=module)
- mm.have = current
-
- mm.exists = Mock(side_effect=[False, True])
- mm.create_on_device = Mock(return_value=True)
- mm.volume_exists = Mock(return_value=True)
- mm.update_on_device = Mock(return_value=True)
- mm.wait_for_device_reboot = Mock(return_value=True)
- mm.wait_for_software_install_on_device = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
diff --git a/test/units/modules/network/f5/test_bigip_software_update.py b/test/units/modules/network/f5/test_bigip_software_update.py
deleted file mode 100644
index f178744f28..0000000000
--- a/test/units/modules/network/f5/test_bigip_software_update.py
+++ /dev/null
@@ -1,119 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright (c) 2017 F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_software_update import ApiParameters
- from library.modules.bigip_software_update import ModuleParameters
- from library.modules.bigip_software_update import ModuleManager
- from library.modules.bigip_software_update import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_software_update import ApiParameters
- from ansible.modules.network.f5.bigip_software_update import ModuleParameters
- from ansible.modules.network.f5.bigip_software_update import ModuleManager
- from ansible.modules.network.f5.bigip_software_update import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- auto_check=True,
- frequency="daily"
- )
- p = ModuleParameters(params=args)
- assert p.auto_check == 'enabled'
- assert p.frequency == 'daily'
-
- def test_api_parameters(self):
- args = dict(
- autoCheck="enabled",
- frequency="daily"
- )
- p = ApiParameters(params=args)
- assert p.auto_check == 'enabled'
- assert p.frequency == 'daily'
-
-
-class TestManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
-
- def test_update(self, *args):
- # Configure the arguments that would be sent to the Ansible module
- set_module_args(dict(
- auto_check='no',
- auto_phone_home='no',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- # Configure the parameters that would be returned by querying the
- # remote device
- current = ApiParameters(params=load_fixture('load_sys_software_update.json'))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
- mm = ModuleManager(module=module)
-
- # Override methods to force specific logic in the module to happen
- mm.update_on_device = Mock(return_value=True)
- mm.read_current_from_device = Mock(return_value=current)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['auto_check'] is False
diff --git a/test/units/modules/network/f5/test_bigip_ssl_certificate.py b/test/units/modules/network/f5/test_bigip_ssl_certificate.py
deleted file mode 100644
index bb5562d736..0000000000
--- a/test/units/modules/network/f5/test_bigip_ssl_certificate.py
+++ /dev/null
@@ -1,152 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright (c) 2017 F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_ssl_certificate import ArgumentSpec
- from library.modules.bigip_ssl_certificate import ApiParameters
- from library.modules.bigip_ssl_certificate import ModuleParameters
- from library.modules.bigip_ssl_certificate import ModuleManager
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_ssl_certificate import ArgumentSpec
- from ansible.modules.network.f5.bigip_ssl_certificate import ApiParameters
- from ansible.modules.network.f5.bigip_ssl_certificate import ModuleParameters
- from ansible.modules.network.f5.bigip_ssl_certificate import ModuleManager
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters_cert(self):
- cert_content = load_fixture('create_insecure_cert1.crt')
- args = dict(
- content=cert_content,
- name="cert1",
- partition="Common",
- state="present",
- )
- p = ModuleParameters(params=args)
- assert p.name == 'cert1'
- assert p.filename == 'cert1.crt'
- assert 'Signature Algorithm' in p.content
- assert '-----BEGIN CERTIFICATE-----' in p.content
- assert '-----END CERTIFICATE-----' in p.content
- assert p.checksum == '1e55aa57ee166a380e756b5aa4a835c5849490fe'
- assert p.state == 'present'
-
- def test_module_issuer_cert_key(self):
- args = dict(
- issuer_cert='foo',
- partition="Common",
- )
- p = ModuleParameters(params=args)
- assert p.issuer_cert == '/Common/foo.crt'
-
- def test_api_issuer_cert_key(self):
- args = load_fixture('load_sys_file_ssl_cert_with_issuer_cert.json')
- p = ApiParameters(params=args)
- assert p.issuer_cert == '/Common/intermediate.crt'
-
-
-class TestCertificateManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
-
- def test_import_certificate_and_key_no_key_passphrase(self, *args):
- set_module_args(dict(
- name='foo',
- content=load_fixture('cert1.crt'),
- state='present',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods in the specific type of manager
- mm = ModuleManager(module=module)
- mm.exists = Mock(side_effect=[False, True])
- mm.create_on_device = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
-
- def test_import_certificate_chain(self, *args):
- set_module_args(dict(
- name='foo',
- content=load_fixture('chain1.crt'),
- state='present',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods in the specific type of manager
- mm = ModuleManager(module=module)
- mm.exists = Mock(side_effect=[False, True])
- mm.create_on_device = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
diff --git a/test/units/modules/network/f5/test_bigip_ssl_key.py b/test/units/modules/network/f5/test_bigip_ssl_key.py
deleted file mode 100644
index 0af4c9e2c2..0000000000
--- a/test/units/modules/network/f5/test_bigip_ssl_key.py
+++ /dev/null
@@ -1,113 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright (c) 2017 F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_ssl_key import ArgumentSpec
- from library.modules.bigip_ssl_key import ModuleParameters
- from library.modules.bigip_ssl_key import ModuleManager
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_ssl_key import ArgumentSpec
- from ansible.modules.network.f5.bigip_ssl_key import ModuleParameters
- from ansible.modules.network.f5.bigip_ssl_key import ModuleManager
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters_key(self):
- key_content = load_fixture('create_insecure_key1.key')
- args = dict(
- content=key_content,
- name="cert1",
- partition="Common",
- state="present",
- password='password',
- server='localhost',
- user='admin'
- )
- p = ModuleParameters(params=args)
- assert p.name == 'cert1'
- assert p.key_filename == 'cert1.key'
- assert '-----BEGIN RSA PRIVATE KEY-----' in p.content
- assert '-----END RSA PRIVATE KEY-----' in p.content
- assert p.key_checksum == '91bdddcf0077e2bb2a0258aae2ae3117be392e83'
- assert p.state == 'present'
-
-
-class TestModuleManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
-
- def test_import_key_no_key_passphrase(self, *args):
- set_module_args(dict(
- name='foo',
- content=load_fixture('cert1.key'),
- state='present',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods in the specific type of manager
- cm = ModuleManager(module=module)
- cm.exists = Mock(side_effect=[False, True])
- cm.create_on_device = Mock(return_value=True)
-
- results = cm.exec_module()
-
- assert results['changed'] is True
diff --git a/test/units/modules/network/f5/test_bigip_ssl_ocsp.py b/test/units/modules/network/f5/test_bigip_ssl_ocsp.py
deleted file mode 100644
index f7c7c4d52e..0000000000
--- a/test/units/modules/network/f5/test_bigip_ssl_ocsp.py
+++ /dev/null
@@ -1,130 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2018, F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_ssl_ocsp import ApiParameters
- from library.modules.bigip_ssl_ocsp import ModuleParameters
- from library.modules.bigip_ssl_ocsp import ModuleManager
- from library.modules.bigip_ssl_ocsp import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
- from test.units.compat.mock import patch
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_ssl_ocsp import ApiParameters
- from ansible.modules.network.f5.bigip_ssl_ocsp import ModuleParameters
- from ansible.modules.network.f5.bigip_ssl_ocsp import ModuleManager
- from ansible.modules.network.f5.bigip_ssl_ocsp import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
- from units.compat.mock import patch
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- name='foo',
- clock_skew=100,
- connections_limit=101,
- )
-
- p = ModuleParameters(params=args)
- assert p.name == 'foo'
- assert p.clock_skew == 100
- assert p.connections_limit == 101
-
- def test_api_parameters(self):
- args = load_fixture('load_sys_crypto_cert_validator_1.json')
- p = ApiParameters(params=args)
- assert p.name == 'asd'
- assert p.clock_skew == 300
-
-
-class TestManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
-
- try:
- self.p1 = patch('library.modules.bigip_ssl_ocsp.tmos_version')
- self.m1 = self.p1.start()
- self.m1.return_value = '13.0.0'
- except Exception:
- self.p1 = patch('ansible.modules.network.f5.bigip_ssl_ocsp.tmos_version')
- self.m1 = self.p1.start()
- self.m1.return_value = '13.0.0'
-
- def tearDown(self):
- self.p1.stop()
-
- def test_create(self, *args):
- # Configure the arguments that would be sent to the Ansible module
- set_module_args(dict(
- name='foo',
- clock_skew=100,
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- mutually_exclusive=self.spec.mutually_exclusive,
- required_together=self.spec.required_together
- )
- mm = ModuleManager(module=module)
-
- # Override methods to force specific logic in the module to happen
- mm.exists = Mock(return_value=False)
- mm.create_on_device = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
diff --git a/test/units/modules/network/f5/test_bigip_static_route.py b/test/units/modules/network/f5/test_bigip_static_route.py
deleted file mode 100644
index 189bfa1756..0000000000
--- a/test/units/modules/network/f5/test_bigip_static_route.py
+++ /dev/null
@@ -1,377 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright (c) 2017 F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_static_route import ApiParameters
- from library.modules.bigip_static_route import ModuleParameters
- from library.modules.bigip_static_route import ModuleManager
- from library.modules.bigip_static_route import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
- from test.units.compat.mock import patch
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_static_route import ApiParameters
- from ansible.modules.network.f5.bigip_static_route import ModuleParameters
- from ansible.modules.network.f5.bigip_static_route import ModuleManager
- from ansible.modules.network.f5.bigip_static_route import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
- from units.compat.mock import patch
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- vlan="foo",
- gateway_address="10.10.10.10"
- )
- p = ModuleParameters(params=args)
- assert p.vlan == '/Common/foo'
- assert p.gateway_address == '10.10.10.10'
-
- def test_api_parameters(self):
- args = dict(
- tmInterface="foo",
- gw="10.10.10.10"
- )
- p = ApiParameters(params=args)
- assert p.vlan == 'foo'
- assert p.gateway_address == '10.10.10.10'
-
- def test_reject_parameter_types(self):
- # boolean true
- args = dict(reject=True)
- p = ModuleParameters(params=args)
- assert p.reject is True
-
- # boolean false
- args = dict(reject=False)
- p = ModuleParameters(params=args)
- assert p.reject is None
-
- # string
- args = dict(reject="yes")
- p = ModuleParameters(params=args)
- assert p.reject is True
-
- # integer
- args = dict(reject=1)
- p = ModuleParameters(params=args)
- assert p.reject is True
-
- # none
- args = dict(reject=None)
- p = ModuleParameters(params=args)
- assert p.reject is None
-
- def test_destination_parameter_types(self):
- # cidr address
- args = dict(
- destination="10.10.10.10",
- netmask='32'
- )
- p = ModuleParameters(params=args)
- assert p.destination == '10.10.10.10/32'
-
- # netmask
- args = dict(
- destination="10.10.10.10",
- netmask="255.255.255.255"
- )
- p = ModuleParameters(params=args)
- assert p.destination == '10.10.10.10/32'
-
- def test_vlan_with_partition(self):
- args = dict(
- vlan="/Common/foo",
- gateway_address="10.10.10.10"
- )
- p = ModuleParameters(params=args)
- assert p.vlan == '/Common/foo'
- assert p.gateway_address == '10.10.10.10'
-
- def test_api_route_domain(self):
- args = dict(
- destination="1.1.1.1/32%2"
- )
- p = ApiParameters(params=args)
- assert p.route_domain == 2
-
- args = dict(
- destination="2700:bc00:1f10:101::6/64%2"
- )
- p = ApiParameters(params=args)
- assert p.route_domain == 2
-
-
-class TestManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
-
- def test_create_blackhole(self, *args):
- set_module_args(dict(
- name='test-route',
- state='present',
- destination='10.10.10.10',
- netmask='255.255.255.255',
- reject='yes',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- mutually_exclusive=self.spec.mutually_exclusive,
- supports_check_mode=self.spec.supports_check_mode
- )
- mm = ModuleManager(module=module)
-
- # Override methods to force specific logic in the module to happen
- mm.exists = Mock(return_value=False)
- mm.create_on_device = Mock(return_value=True)
-
- results = mm.exec_module()
- assert results['changed'] is True
-
- def test_create_route_to_pool(self, *args):
- set_module_args(dict(
- name='test-route',
- state='present',
- destination='10.10.10.10',
- netmask='255.255.255.255',
- pool="test-pool",
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- mutually_exclusive=self.spec.mutually_exclusive,
- supports_check_mode=self.spec.supports_check_mode
- )
- mm = ModuleManager(module=module)
-
- # Override methods to force specific logic in the module to happen
- mm.exists = Mock(return_value=False)
- mm.create_on_device = Mock(return_value=True)
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['pool'] == 'test-pool'
-
- def test_create_route_to_vlan(self, *args):
- set_module_args(dict(
- name='test-route',
- state='present',
- destination='10.10.10.10',
- netmask='255.255.255.255',
- vlan="test-vlan",
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- mutually_exclusive=self.spec.mutually_exclusive,
- supports_check_mode=self.spec.supports_check_mode
- )
- mm = ModuleManager(module=module)
-
- # Override methods to force specific logic in the module to happen
- mm.exists = Mock(return_value=False)
- mm.create_on_device = Mock(return_value=True)
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['vlan'] == '/Common/test-vlan'
-
- def test_update_description(self, *args):
- set_module_args(dict(
- name='test-route',
- state='present',
- description='foo description',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- mutually_exclusive=self.spec.mutually_exclusive,
- supports_check_mode=self.spec.supports_check_mode
- )
- mm = ModuleManager(module=module)
-
- # Override methods to force specific logic in the module to happen
- current = ApiParameters(params=load_fixture('load_net_route_description.json'))
- mm.exists = Mock(return_value=True)
- mm.update_on_device = Mock(return_value=True)
- mm.read_current_from_device = Mock(return_value=current)
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['description'] == 'foo description'
-
- def test_update_description_idempotent(self, *args):
- set_module_args(dict(
- name='test-route',
- state='present',
- description='asdasd',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- mutually_exclusive=self.spec.mutually_exclusive,
- supports_check_mode=self.spec.supports_check_mode
- )
- mm = ModuleManager(module=module)
-
- # Override methods to force specific logic in the module to happen
- current = ApiParameters(params=load_fixture('load_net_route_description.json'))
- mm.exists = Mock(return_value=True)
- mm.update_on_device = Mock(return_value=True)
- mm.read_current_from_device = Mock(return_value=current)
- results = mm.exec_module()
-
- # There is no assert for the description, because it should
- # not have changed
- assert results['changed'] is False
-
- def test_delete(self, *args):
- set_module_args(dict(
- name='test-route',
- state='absent',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- mutually_exclusive=self.spec.mutually_exclusive,
- supports_check_mode=self.spec.supports_check_mode
- )
- mm = ModuleManager(module=module)
-
- # Override methods to force specific logic in the module to happen
- mm.exists = Mock(side_effect=[True, False])
- mm.remove_from_device = Mock(return_value=True)
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert 'description' not in results
-
- def test_invalid_unknown_params(self, *args):
- set_module_args(dict(
- name='test-route',
- state='present',
- foo="bar",
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
- with patch('ansible.module_utils.f5_utils.AnsibleModule.fail_json') as mo:
- mo.return_value = True
- AnsibleModule(
- argument_spec=self.spec.argument_spec,
- mutually_exclusive=self.spec.mutually_exclusive,
- supports_check_mode=self.spec.supports_check_mode
- )
- assert mo.call_count == 1
-
- def test_create_with_route_domain(self, *args):
- set_module_args(dict(
- name='test-route',
- state='present',
- destination='10.10.10.10',
- netmask='255.255.255.255',
- route_domain=1,
- reject='yes',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- mutually_exclusive=self.spec.mutually_exclusive,
- supports_check_mode=self.spec.supports_check_mode
- )
- mm = ModuleManager(module=module)
-
- # Override methods to force specific logic in the module to happen
- mm.exists = Mock(return_value=False)
- mm.create_on_device = Mock(return_value=True)
-
- results = mm.exec_module()
- assert results['changed'] is True
- assert results['route_domain'] == 1
- assert results['destination'] == '10.10.10.10%1/32'
diff --git a/test/units/modules/network/f5/test_bigip_sys_daemon_log_tmm.py b/test/units/modules/network/f5/test_bigip_sys_daemon_log_tmm.py
deleted file mode 100644
index 2c7e5330b1..0000000000
--- a/test/units/modules/network/f5/test_bigip_sys_daemon_log_tmm.py
+++ /dev/null
@@ -1,138 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2018, F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_sys_daemon_log_tmm import ApiParameters
- from library.modules.bigip_sys_daemon_log_tmm import ModuleParameters
- from library.modules.bigip_sys_daemon_log_tmm import ModuleManager
- from library.modules.bigip_sys_daemon_log_tmm import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_sys_daemon_log_tmm import ApiParameters
- from ansible.modules.network.f5.bigip_sys_daemon_log_tmm import ModuleParameters
- from ansible.modules.network.f5.bigip_sys_daemon_log_tmm import ModuleManager
- from ansible.modules.network.f5.bigip_sys_daemon_log_tmm import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- arp_log_level='warning',
- http_compression_log_level='error',
- http_log_level='error',
- ip_log_level='warning',
- irule_log_level='informational',
- layer4_log_level='notice',
- net_log_level='warning',
- os_log_level='notice',
- pva_log_level='debug',
- ssl_log_level='warning',
- )
- p = ModuleParameters(params=args)
- assert p.arp_log_level == 'warning'
- assert p.http_compression_log_level == 'error'
- assert p.http_log_level == 'error'
- assert p.ip_log_level == 'warning'
- assert p.irule_log_level == 'informational'
- assert p.layer4_log_level == 'notice'
- assert p.net_log_level == 'warning'
- assert p.os_log_level == 'notice'
- assert p.pva_log_level == 'debug'
- assert p.ssl_log_level == 'warning'
-
- def test_api_parameters(self):
- args = load_fixture('load_tmm_log.json')
- p = ApiParameters(params=args)
- assert p.arp_log_level == 'warning'
- assert p.http_compression_log_level == 'error'
- assert p.http_log_level == 'error'
- assert p.ip_log_level == 'warning'
- assert p.irule_log_level == 'informational'
- assert p.layer4_log_level == 'notice'
- assert p.net_log_level == 'warning'
- assert p.os_log_level == 'notice'
- assert p.pva_log_level == 'informational'
- assert p.ssl_log_level == 'warning'
-
-
-class TestManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
-
- def test_update(self, *args):
- set_module_args(dict(
- arp_log_level='debug',
- layer4_log_level='debug',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- # Configure the parameters that would be returned by querying the
- # remote device
- current = ApiParameters(params=load_fixture('load_tmm_log.json'))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
- mm = ModuleManager(module=module)
-
- # Override methods to force specific logic in the module to happen
- mm.exists = Mock(return_value=False)
- mm.read_current_from_device = Mock(return_value=current)
- mm.update_on_device = Mock(return_value=True)
-
- results = mm.exec_module()
- assert results['changed'] is True
diff --git a/test/units/modules/network/f5/test_bigip_sys_db.py b/test/units/modules/network/f5/test_bigip_sys_db.py
deleted file mode 100644
index 94d12fa000..0000000000
--- a/test/units/modules/network/f5/test_bigip_sys_db.py
+++ /dev/null
@@ -1,130 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright (c) 2017 F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_sys_db import Parameters
- from library.modules.bigip_sys_db import ModuleManager
- from library.modules.bigip_sys_db import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_sys_db import Parameters
- from ansible.modules.network.f5.bigip_sys_db import ModuleManager
- from ansible.modules.network.f5.bigip_sys_db import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- key='foo',
- value='bar',
- )
- p = Parameters(params=args)
- assert p.key == 'foo'
- assert p.value == 'bar'
-
- def test_api_parameters(self):
- args = dict(
- key='foo',
- value='bar',
- defaultValue='baz',
-
- )
- p = Parameters(params=args)
- assert p.key == 'foo'
- assert p.value == 'bar'
-
-
-class TestManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
-
- def test_create_blackhole(self, *args):
- set_module_args(dict(
- key='provision.cpu.afm',
- value='1',
- state='present',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- # Configure the parameters that would be returned by querying the
- # remote device
- current = Parameters(
- dict(
- kind="tm:sys:db:dbstate",
- name="provision.cpu.afm",
- fullPath="provision.cpu.afm",
- generation=1,
- selfLink="https://localhost/mgmt/tm/sys/db/provision.cpu.afm?ver=11.6.1",
- defaultValue="0",
- scfConfig="false",
- value="0",
- valueRange="integer min:0 max:100"
- )
- )
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
- mm = ModuleManager(module=module)
-
- # Override methods to force specific logic in the module to happen
- mm.exists = Mock(return_value=False)
- mm.read_current_from_device = Mock(return_value=current)
- mm.update_on_device = Mock(return_value=True)
-
- results = mm.exec_module()
- assert results['changed'] is True
diff --git a/test/units/modules/network/f5/test_bigip_sys_global.py b/test/units/modules/network/f5/test_bigip_sys_global.py
deleted file mode 100644
index 78920c191d..0000000000
--- a/test/units/modules/network/f5/test_bigip_sys_global.py
+++ /dev/null
@@ -1,133 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright (c) 2017 F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_sys_global import ApiParameters
- from library.modules.bigip_sys_global import ModuleParameters
- from library.modules.bigip_sys_global import ModuleManager
- from library.modules.bigip_sys_global import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_sys_global import ApiParameters
- from ansible.modules.network.f5.bigip_sys_global import ModuleParameters
- from ansible.modules.network.f5.bigip_sys_global import ModuleManager
- from ansible.modules.network.f5.bigip_sys_global import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- banner_text='this is a banner',
- console_timeout=100,
- gui_setup='yes',
- lcd_display='yes',
- mgmt_dhcp='yes',
- net_reboot='yes',
- quiet_boot='yes',
- security_banner='yes',
- )
- p = ModuleParameters(params=args)
- assert p.banner_text == 'this is a banner'
- assert p.console_timeout == 100
- assert p.gui_setup == 'yes'
- assert p.lcd_display == 'yes'
- assert p.mgmt_dhcp == 'yes'
- assert p.net_reboot == 'yes'
- assert p.quiet_boot == 'yes'
- assert p.security_banner == 'yes'
-
- def test_api_parameters(self):
- args = load_fixture('load_sys_global_settings.json')
- p = ApiParameters(params=args)
- assert 'Welcome to the BIG-IP Configuration Utility' in p.banner_text
- assert p.console_timeout == 0
- assert p.gui_setup == 'no'
- assert p.lcd_display == 'yes'
- assert p.mgmt_dhcp == 'yes'
- assert p.net_reboot == 'no'
- assert p.quiet_boot == 'yes'
- assert p.security_banner == 'yes'
-
-
-class TestManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
-
- def test_update(self, *args):
- set_module_args(dict(
- banner_text='this is a banner',
- console_timeout=100,
- state='present',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- # Configure the parameters that would be returned by querying the
- # remote device
- current = ApiParameters(params=load_fixture('load_sys_global_settings.json'))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
- mm = ModuleManager(module=module)
-
- # Override methods to force specific logic in the module to happen
- mm.exists = Mock(return_value=False)
- mm.read_current_from_device = Mock(return_value=current)
- mm.update_on_device = Mock(return_value=True)
-
- results = mm.exec_module()
- assert results['changed'] is True
diff --git a/test/units/modules/network/f5/test_bigip_timer_policy.py b/test/units/modules/network/f5/test_bigip_timer_policy.py
deleted file mode 100644
index 58526385ef..0000000000
--- a/test/units/modules/network/f5/test_bigip_timer_policy.py
+++ /dev/null
@@ -1,112 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_timer_policy import ApiParameters
- from library.modules.bigip_timer_policy import ModuleParameters
- from library.modules.bigip_timer_policy import ModuleManager
- from library.modules.bigip_timer_policy import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_timer_policy import ApiParameters
- from ansible.modules.network.f5.bigip_timer_policy import ModuleParameters
- from ansible.modules.network.f5.bigip_timer_policy import ModuleManager
- from ansible.modules.network.f5.bigip_timer_policy import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- name='foo',
- description='my description'
- )
-
- p = ModuleParameters(params=args)
- assert p.name == 'foo'
- assert p.description == 'my description'
-
- def test_api_parameters(self):
- args = load_fixture('load_net_timer_policy_1.json')
-
- p = ApiParameters(params=args)
- assert p.name == 'timer1'
- assert p.description == 'my description'
-
-
-class TestManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
-
- def test_create(self, *args):
- set_module_args(dict(
- name='foo',
- description='my description',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- mm = ModuleManager(module=module)
- mm.create_on_device = Mock(return_value=True)
- mm.exists = Mock(return_value=False)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['description'] == 'my description'
diff --git a/test/units/modules/network/f5/test_bigip_traffic_selector.py b/test/units/modules/network/f5/test_bigip_traffic_selector.py
deleted file mode 100644
index 63ac7b3a88..0000000000
--- a/test/units/modules/network/f5/test_bigip_traffic_selector.py
+++ /dev/null
@@ -1,108 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2018, F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_traffic_selector import ApiParameters
- from library.modules.bigip_traffic_selector import ModuleParameters
- from library.modules.bigip_traffic_selector import ModuleManager
- from library.modules.bigip_traffic_selector import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_traffic_selector import ApiParameters
- from ansible.modules.network.f5.bigip_traffic_selector import ModuleParameters
- from ansible.modules.network.f5.bigip_traffic_selector import ModuleManager
- from ansible.modules.network.f5.bigip_traffic_selector import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- name='selector1',
- )
- p = ModuleParameters(params=args)
- assert p.name == 'selector1'
-
- def test_api_parameters(self):
- args = dict(
- name='selector1',
- )
- p = ApiParameters(params=args)
- assert p.name == 'selector1'
-
-
-class TestUntypedManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
-
- def test_create(self, *args):
- set_module_args(dict(
- name='selector1',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods to force specific logic in the module to happen
- mm = ModuleManager(module=module)
- mm.create_on_device = Mock(return_value=True)
- mm.exists = Mock(return_value=False)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
diff --git a/test/units/modules/network/f5/test_bigip_trunk.py b/test/units/modules/network/f5/test_bigip_trunk.py
deleted file mode 100644
index e3f285283e..0000000000
--- a/test/units/modules/network/f5/test_bigip_trunk.py
+++ /dev/null
@@ -1,141 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_trunk import ApiParameters
- from library.modules.bigip_trunk import ModuleParameters
- from library.modules.bigip_trunk import ModuleManager
- from library.modules.bigip_trunk import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_trunk import ApiParameters
- from ansible.modules.network.f5.bigip_trunk import ModuleParameters
- from ansible.modules.network.f5.bigip_trunk import ModuleManager
- from ansible.modules.network.f5.bigip_trunk import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- name='foo',
- interfaces=[
- '1.3', '1.1'
- ],
- link_selection_policy='auto',
- frame_distribution_hash='destination-mac',
- lacp_enabled=True,
- lacp_mode='active',
- lacp_timeout='long'
- )
-
- p = ModuleParameters(params=args)
- assert p.name == 'foo'
- assert p.interfaces == ['1.1', '1.3']
- assert p.link_selection_policy == 'auto'
- assert p.frame_distribution_hash == 'dst-mac'
- assert p.lacp_enabled is True
- assert p.lacp_mode == 'active'
- assert p.lacp_timeout == 'long'
-
- def test_api_parameters(self):
- args = load_fixture('load_tm_net_trunk_1.json')
-
- p = ApiParameters(params=args)
- assert p.name == 'foo'
- assert p.frame_distribution_hash == 'dst-mac'
- assert p.lacp_enabled is False
- assert p.lacp_mode == 'active'
- assert p.lacp_timeout == 'long'
- assert p.interfaces == ['1.3']
- assert p.link_selection_policy == 'maximum-bandwidth'
-
-
-class TestManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
-
- def test_create(self, *args):
- set_module_args(dict(
- name='foo',
- interfaces=[
- '1.3', '1.1'
- ],
- link_selection_policy='auto',
- frame_distribution_hash='destination-mac',
- lacp_enabled=True,
- lacp_mode='active',
- lacp_timeout='long',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods to force specific logic in the module to happen
- mm = ModuleManager(module=module)
- mm.create_on_device = Mock(return_value=True)
- mm.exists = Mock(return_value=False)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['link_selection_policy'] == 'auto'
- assert results['frame_distribution_hash'] == 'destination-mac'
- assert results['lacp_enabled'] is True
- assert results['lacp_mode'] == 'active'
- assert results['lacp_timeout'] == 'long'
diff --git a/test/units/modules/network/f5/test_bigip_tunnel.py b/test/units/modules/network/f5/test_bigip_tunnel.py
deleted file mode 100644
index cee0391259..0000000000
--- a/test/units/modules/network/f5/test_bigip_tunnel.py
+++ /dev/null
@@ -1,112 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_tunnel import ApiParameters
- from library.modules.bigip_tunnel import ModuleParameters
- from library.modules.bigip_tunnel import ModuleManager
- from library.modules.bigip_tunnel import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_tunnel import ApiParameters
- from ansible.modules.network.f5.bigip_tunnel import ModuleParameters
- from ansible.modules.network.f5.bigip_tunnel import ModuleManager
- from ansible.modules.network.f5.bigip_tunnel import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- name='foo',
- profile='ipip',
- )
-
- p = ModuleParameters(params=args)
- assert p.name == 'foo'
- assert p.profile == '/Common/ipip'
-
- def test_api_parameters(self):
- args = load_fixture('load_net_tunnel_1.json')
-
- p = ApiParameters(params=args)
- assert p.name == 'tunnel1'
-
-
-class TestManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
-
- def test_create(self, *args):
- set_module_args(dict(
- name='foo',
- profile='ipip',
- local_address='2.2.2.2.',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods to force specific logic in the module to happen
- mm = ModuleManager(module=module)
- mm.create_on_device = Mock(return_value=True)
- mm.exists = Mock(return_value=False)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
diff --git a/test/units/modules/network/f5/test_bigip_ucs.py b/test/units/modules/network/f5/test_bigip_ucs.py
deleted file mode 100644
index 9f7e716b99..0000000000
--- a/test/units/modules/network/f5/test_bigip_ucs.py
+++ /dev/null
@@ -1,411 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright (c) 2017 F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_ucs import ModuleParameters
- from library.modules.bigip_ucs import ModuleManager
- from library.modules.bigip_ucs import ArgumentSpec
- from library.modules.bigip_ucs import V1Manager
- from library.modules.bigip_ucs import V2Manager
-
- from library.module_utils.network.f5.common import F5ModuleError
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
- from test.units.compat.mock import patch
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_ucs import ModuleParameters
- from ansible.modules.network.f5.bigip_ucs import ModuleManager
- from ansible.modules.network.f5.bigip_ucs import ArgumentSpec
- from ansible.modules.network.f5.bigip_ucs import V1Manager
- from ansible.modules.network.f5.bigip_ucs import V2Manager
-
- from ansible.module_utils.network.f5.common import F5ModuleError
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
- from units.compat.mock import patch
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- ucs="/root/bigip.localhost.localdomain.ucs",
- force=True,
- include_chassis_level_config=True,
- no_license=True,
- no_platform_check=True,
- passphrase="foobar",
- reset_trust=True,
- state='installed'
- )
-
- p = ModuleParameters(params=args)
- assert p.ucs == '/root/bigip.localhost.localdomain.ucs'
- assert p.force is True
- assert p.include_chassis_level_config is True
- assert p.no_license is True
- assert p.no_platform_check is True
- assert p.passphrase == "foobar"
- assert p.reset_trust is True
- assert p.install_command == \
- "tmsh load sys ucs /var/local/ucs/bigip.localhost.localdomain.ucs " \
- "include-chassis-level-config no-license no-platform-check " \
- "passphrase foobar reset-trust"
-
- def test_module_parameters_false_ucs_booleans(self):
- args = dict(
- ucs="/root/bigip.localhost.localdomain.ucs",
- include_chassis_level_config=False,
- no_license=False,
- no_platform_check=False,
- reset_trust=False
- )
-
- p = ModuleParameters(params=args)
- assert p.ucs == '/root/bigip.localhost.localdomain.ucs'
- assert p.include_chassis_level_config is False
- assert p.no_license is False
- assert p.no_platform_check is False
- assert p.reset_trust is False
- assert p.install_command == "tmsh load sys ucs /var/local/ucs/bigip.localhost.localdomain.ucs"
-
-
-class TestV1Manager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
- self.patcher1 = patch('time.sleep')
- self.patcher1.start()
-
- def tearDown(self):
- self.patcher1.stop()
-
- def test_ucs_default_present(self, *args):
- set_module_args(dict(
- ucs="/root/bigip.localhost.localdomain.ucs",
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods to force specific logic in the module to happen
- mm = ModuleManager(module=module)
- mm.is_version_v1 = Mock(return_value=True)
-
- vm = V1Manager(module=module)
- vm.create_on_device = Mock(return_value=True)
- vm.exists = Mock(side_effect=[False, True])
-
- results = vm.exec_module()
-
- assert results['changed'] is True
-
- def test_ucs_explicit_present(self, *args):
- set_module_args(dict(
- ucs="/root/bigip.localhost.localdomain.ucs",
- state='present',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods to force specific logic in the module to happen
- mm = ModuleManager(module=module)
- mm.is_version_v1 = Mock(return_value=True)
-
- vm = V1Manager(module=module)
- vm.create_on_device = Mock(return_value=True)
- vm.exists = Mock(side_effect=[False, True])
-
- results = vm.exec_module()
-
- assert results['changed'] is True
-
- def test_ucs_installed(self, *args):
- set_module_args(dict(
- ucs="/root/bigip.localhost.localdomain.ucs",
- state='installed',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods to force specific logic in the module to happen
- mm = ModuleManager(module=module)
- mm.is_version_v1 = Mock(return_value=True)
-
- vm = V1Manager(module=module)
- vm.create_on_device = Mock(return_value=True)
- vm.exists = Mock(return_value=True)
- vm.install_on_device = Mock(return_value=True)
-
- results = vm.exec_module()
-
- assert results['changed'] is True
-
- def test_ucs_absent_exists(self, *args):
- set_module_args(dict(
- ucs="/root/bigip.localhost.localdomain.ucs",
- state='absent',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods to force specific logic in the module to happen
- mm = ModuleManager(module=module)
- mm.is_version_v1 = Mock(return_value=True)
-
- vm = V1Manager(module=module)
- vm.remove_from_device = Mock(return_value=True)
- vm.exists = Mock(side_effect=[True, False])
-
- results = vm.exec_module()
-
- assert results['changed'] is True
-
- def test_ucs_absent_fails(self, *args):
- set_module_args(dict(
- ucs="/root/bigip.localhost.localdomain.ucs",
- state='absent',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods to force specific logic in the module to happen
- mm = ModuleManager(module=module)
- mm.is_version_v1 = Mock(return_value=True)
-
- vm = V1Manager(module=module)
- vm.remove_from_device = Mock(return_value=True)
- vm.exists = Mock(side_effect=[True, True])
-
- with pytest.raises(F5ModuleError) as ex:
- vm.exec_module()
- assert 'Failed to delete' in str(ex.value)
-
-
-class TestV2Manager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
-
- def test_ucs_default_present(self, *args):
- set_module_args(dict(
- ucs="/root/bigip.localhost.localdomain.ucs",
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods to force specific logic in the module to happen
- mm = ModuleManager(module=module)
- mm.is_version_v1 = Mock(return_value=False)
-
- vm = V2Manager(module=module)
- vm.create_on_device = Mock(return_value=True)
- vm.exists = Mock(side_effect=[False, True])
-
- results = vm.exec_module()
-
- assert results['changed'] is True
-
- def test_ucs_explicit_present(self, *args):
- set_module_args(dict(
- ucs="/root/bigip.localhost.localdomain.ucs",
- state='present',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods to force specific logic in the module to happen
- mm = ModuleManager(module=module)
- mm.is_version_v1 = Mock(return_value=False)
-
- vm = V2Manager(module=module)
- vm.create_on_device = Mock(return_value=True)
- vm.exists = Mock(side_effect=[False, True])
-
- results = vm.exec_module()
-
- assert results['changed'] is True
-
- def test_ucs_installed(self, *args):
- set_module_args(dict(
- ucs="/root/bigip.localhost.localdomain.ucs",
- state='installed',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods to force specific logic in the module to happen
- mm = ModuleManager(module=module)
- mm.is_version_v1 = Mock(return_value=False)
-
- vm = V2Manager(module=module)
- vm.create_on_device = Mock(return_value=True)
- vm.exists = Mock(return_value=True)
- vm.install_on_device = Mock(return_value=True)
-
- results = vm.exec_module()
-
- assert results['changed'] is True
-
- def test_ucs_absent_exists(self, *args):
- set_module_args(dict(
- ucs="/root/bigip.localhost.localdomain.ucs",
- state='absent',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods to force specific logic in the module to happen
- mm = ModuleManager(module=module)
- mm.is_version_v1 = Mock(return_value=False)
-
- vm = V1Manager(module=module)
- vm.remove_from_device = Mock(return_value=True)
- vm.exists = Mock(side_effect=[True, False])
-
- results = vm.exec_module()
-
- assert results['changed'] is True
-
- def test_ucs_absent_fails(self, *args):
- set_module_args(dict(
- ucs="/root/bigip.localhost.localdomain.ucs",
- state='absent',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods to force specific logic in the module to happen
- mm = ModuleManager(module=module)
- mm.is_version_v1 = Mock(return_value=False)
-
- vm = V1Manager(module=module)
- vm.remove_from_device = Mock(return_value=True)
- vm.exists = Mock(side_effect=[True, True])
-
- with pytest.raises(F5ModuleError) as ex:
- vm.exec_module()
- assert 'Failed to delete' in str(ex.value)
diff --git a/test/units/modules/network/f5/test_bigip_ucs_fetch.py b/test/units/modules/network/f5/test_bigip_ucs_fetch.py
deleted file mode 100644
index 1582b7705d..0000000000
--- a/test/units/modules/network/f5/test_bigip_ucs_fetch.py
+++ /dev/null
@@ -1,131 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright (c) 2017 F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_ucs_fetch import Parameters
- from library.modules.bigip_ucs_fetch import ModuleManager
- from library.modules.bigip_ucs_fetch import V1Manager
- from library.modules.bigip_ucs_fetch import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
- from test.units.compat.mock import patch
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_ucs_fetch import Parameters
- from ansible.modules.network.f5.bigip_ucs_fetch import ModuleManager
- from ansible.modules.network.f5.bigip_ucs_fetch import V1Manager
- from ansible.modules.network.f5.bigip_ucs_fetch import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
- from units.compat.mock import patch
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- backup='yes',
- create_on_missing='yes',
- encryption_password='my-password',
- dest='/tmp/foo.ucs',
- force='yes',
- fail_on_missing='no',
- src='remote.ucs',
- )
- p = Parameters(params=args)
- assert p.backup == 'yes'
-
-
-class TestV1Manager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
-
- def test_create(self, *args):
- set_module_args(dict(
- backup='yes',
- create_on_missing='yes',
- dest='/tmp/foo.ucs',
- force='yes',
- fail_on_missing='no',
- src='remote.ucs',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- add_file_common_args=self.spec.add_file_common_args
- )
-
- # Override methods to force specific logic in the module to happen
- m1 = V1Manager(module=module)
- m1.exists = Mock(return_value=False)
- m1.create_on_device = Mock(return_value=True)
- m1._get_backup_file = Mock(return_value='/tmp/foo.backup')
- m1.download_from_device = Mock(return_value=True)
- m1._set_checksum = Mock(return_value=12345)
- m1._set_md5sum = Mock(return_value=54321)
-
- mm = ModuleManager(module=module)
- mm.get_manager = Mock(return_value=m1)
- mm.is_version_v1 = Mock(return_value=True)
-
- p1 = patch('os.path.exists', return_value=True)
- p1.start()
- p2 = patch('os.path.isdir', return_value=False)
- p2.start()
-
- results = mm.exec_module()
-
- p1.stop()
- p2.stop()
-
- assert results['changed'] is True
diff --git a/test/units/modules/network/f5/test_bigip_user.py b/test/units/modules/network/f5/test_bigip_user.py
deleted file mode 100644
index 3065b6c136..0000000000
--- a/test/units/modules/network/f5/test_bigip_user.py
+++ /dev/null
@@ -1,892 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright (c) 2017 F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_user import Parameters
- from library.modules.bigip_user import ModuleManager
- from library.modules.bigip_user import ArgumentSpec
- from library.modules.bigip_user import UnpartitionedManager
- from library.modules.bigip_user import PartitionedManager
-
- from library.module_utils.network.f5.common import F5ModuleError
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_user import Parameters
- from ansible.modules.network.f5.bigip_user import ModuleManager
- from ansible.modules.network.f5.bigip_user import ArgumentSpec
- from ansible.modules.network.f5.bigip_user import UnpartitionedManager
- from ansible.modules.network.f5.bigip_user import PartitionedManager
-
- from ansible.module_utils.network.f5.common import F5ModuleError
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- access = [{'name': 'Common', 'role': 'guest'}]
- args = dict(
- username_credential='someuser',
- password_credential='testpass',
- full_name='Fake Person',
- partition_access=access,
- update_password='always'
- )
-
- p = Parameters(params=args)
- assert p.username_credential == 'someuser'
- assert p.password_credential == 'testpass'
- assert p.full_name == 'Fake Person'
- assert p.partition_access == access
- assert p.update_password == 'always'
-
- def test_api_parameters(self):
- access = [{'name': 'Common', 'role': 'guest'}]
- args = dict(
- name='someuser',
- description='Fake Person',
- partitionAccess=access,
- shell='none'
- )
-
- p = Parameters(params=args)
- assert p.name == 'someuser'
- assert p.full_name == 'Fake Person'
- assert p.partition_access == access
- assert p.shell == 'none'
-
-
-class TestManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
-
- def test_create_user(self, *args):
- access = [{'name': 'Common', 'role': 'guest'}]
- set_module_args(dict(
- username_credential='someuser',
- password_credential='testpass',
- partition_access=access,
- update_password='on_create',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods to force specific logic in the module to happen
- pm = PartitionedManager(module=module, params=module.params)
- pm.create_on_device = Mock(return_value=True)
- pm.exists = Mock(return_value=False)
-
- mm = ModuleManager(module=module)
- mm.is_version_less_than_13 = Mock(return_value=False)
- mm.get_manager = Mock(return_value=pm)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['partition_access'] == access
-
- def test_create_user_no_password(self, *args):
- access = [{'name': 'Common', 'role': 'guest'}]
- set_module_args(dict(
- username_credential='someuser',
- partition_access=access,
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods to force specific logic in the module to happen
- pm = PartitionedManager(module=module, params=module.params)
- pm.create_on_device = Mock(return_value=True)
- pm.exists = Mock(return_value=False)
-
- mm = ModuleManager(module=module)
- mm.is_version_less_than_13 = Mock(return_value=False)
- mm.get_manager = Mock(return_value=pm)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['partition_access'] == access
-
- def test_create_user_partition_access_raises(self, *args):
- set_module_args(dict(
- username_credential='someuser',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods to force specific logic in the module to happen
- pm = PartitionedManager(module=module, params=module.params)
- pm.create_on_device = Mock(return_value=True)
- pm.exists = Mock(return_value=False)
-
- mm = ModuleManager(module=module)
- mm.is_version_less_than_13 = Mock(return_value=False)
- mm.get_manager = Mock(return_value=pm)
-
- msg = "The 'partition_access' option " \
- "is required when creating a resource."
-
- with pytest.raises(F5ModuleError) as ex:
- mm.exec_module()
- assert str(ex.value) == msg
-
- def test_create_user_shell_bash(self, *args):
- access = [{'name': 'all', 'role': 'admin'}]
- set_module_args(dict(
- username_credential='someuser',
- password_credential='testpass',
- partition_access=access,
- update_password='on_create',
- shell='bash',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods to force specific logic in the module to happen
- pm = PartitionedManager(module=module, params=module.params)
- pm.create_on_device = Mock(return_value=True)
- pm.exists = Mock(return_value=False)
-
- mm = ModuleManager(module=module)
- mm.is_version_less_than_13 = Mock(return_value=False)
- mm.get_manager = Mock(return_value=pm)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['partition_access'] == access
-
- def test_create_user_shell_not_permitted_raises(self, *args):
- access = [{'name': 'Common', 'role': 'guest'}]
- set_module_args(dict(
- username_credential='someuser',
- password_credential='testpass',
- partition_access=access,
- update_password='on_create',
- shell='bash',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods to force specific logic in the module to happen
- pm = PartitionedManager(module=module, params=module.params)
- pm.create_on_device = Mock(return_value=True)
- pm.exists = Mock(return_value=False)
-
- mm = ModuleManager(module=module)
- mm.is_version_less_than_13 = Mock(return_value=False)
- mm.get_manager = Mock(return_value=pm)
-
- msg = "Shell access is only available to 'admin' or " \
- "'resource-admin' roles."
-
- with pytest.raises(F5ModuleError) as ex:
- mm.exec_module()
- assert str(ex.value) == msg
-
- def test_update_user_password_no_pass(self, *args):
- set_module_args(dict(
- username_credential='someuser',
- password_credential='testpass',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Configure the parameters that would be returned by querying the
- # remote device
- current = Parameters(params=load_fixture('load_auth_user_no_pass.json'))
-
- # Override methods to force specific logic in the module to happen
- pm = PartitionedManager(module=module, params=module.params)
- pm.exists = Mock(return_value=True)
- pm.update_on_device = Mock(return_value=True)
- pm.read_current_from_device = Mock(return_value=current)
-
- mm = ModuleManager(module=module)
- mm.is_version_less_than_13 = Mock(return_value=False)
- mm.get_manager = Mock(return_value=pm)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
-
- def test_update_user_password_with_pass(self, *args):
- set_module_args(dict(
- username_credential='someuser',
- password_credential='testpass',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Configure the parameters that would be returned by querying the
- # remote device
- current = Parameters(params=load_fixture('load_auth_user_with_pass.json'))
-
- # Override methods to force specific logic in the module to happen
- pm = PartitionedManager(module=module, params=module.params)
- pm.exists = Mock(return_value=True)
- pm.update_on_device = Mock(return_value=True)
- pm.read_current_from_device = Mock(return_value=current)
-
- mm = ModuleManager(module=module)
- mm.is_version_less_than_13 = Mock(return_value=False)
- mm.get_manager = Mock(return_value=pm)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
-
- def test_update_user_shell_to_none(self, *args):
- set_module_args(dict(
- username_credential='someuser',
- shell='none',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Configure the parameters that would be returned by querying the
- # remote device
- current = Parameters(
- params=dict(
- user='admin',
- shell='tmsh'
- )
- )
-
- # Override methods to force specific logic in the module to happen
- pm = PartitionedManager(module=module, params=module.params)
- pm.exists = Mock(return_value=True)
- pm.update_on_device = Mock(return_value=True)
- pm.read_current_from_device = Mock(return_value=current)
-
- mm = ModuleManager(module=module)
- mm.is_version_less_than_13 = Mock(return_value=False)
- mm.get_manager = Mock(return_value=pm)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['shell'] == 'none'
-
- def test_update_user_shell_to_none_shell_attribute_missing(self, *args):
- set_module_args(dict(
- username_credential='someuser',
- shell='none',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Configure the parameters that would be returned by querying the
- # remote device
- access = [{'name': 'Common', 'role': 'guest'}]
- current = Parameters(
- params=dict(
- user='admin',
- partition_access=access
- )
- )
-
- # Override methods to force specific logic in the module to happen
- pm = PartitionedManager(module=module, params=module.params)
- pm.exists = Mock(return_value=True)
- pm.update_on_device = Mock(return_value=True)
- pm.read_current_from_device = Mock(return_value=current)
-
- mm = ModuleManager(module=module)
- mm.is_version_less_than_13 = Mock(return_value=False)
- mm.get_manager = Mock(return_value=pm)
-
- results = mm.exec_module()
-
- assert results['changed'] is False
- assert not hasattr(results, 'shell')
-
- def test_update_user_shell_to_bash(self, *args):
- set_module_args(dict(
- username_credential='someuser',
- shell='bash',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Configure the parameters that would be returned by querying the
- # remote device
- access = [{'name': 'all', 'role': 'admin'}]
- current = Parameters(
- params=dict(
- user='admin',
- shell='tmsh',
- partition_access=access
- )
- )
-
- # Override methods to force specific logic in the module to happen
- upm = UnpartitionedManager(module=module, params=module.params)
- upm.exists = Mock(return_value=True)
- upm.update_on_device = Mock(return_value=True)
- upm.read_current_from_device = Mock(return_value=current)
-
- mm = ModuleManager(module=module)
- mm.is_version_less_than_13 = Mock(return_value=True)
- mm.get_manager = Mock(return_value=upm)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['shell'] == 'bash'
-
- def test_update_user_shell_to_bash_mutliple_roles(self, *args):
- set_module_args(dict(
- username_credential='someuser',
- shell='bash',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Configure the parameters that would be returned by querying the
- # remote device
- access = [
- {'name': 'Common', 'role': 'operator'},
- {'name': 'all', 'role': 'guest'}
- ]
- current = Parameters(
- params=dict(
- user='admin',
- shell='tmsh',
- partition_access=access
- )
- )
-
- # Override methods to force specific logic in the module to happen
- upm = UnpartitionedManager(module=module, params=module.params)
- upm.exists = Mock(return_value=True)
- upm.update_on_device = Mock(return_value=True)
- upm.read_current_from_device = Mock(return_value=current)
-
- mm = ModuleManager(module=module)
- mm.is_version_less_than_13 = Mock(return_value=True)
- mm.get_manager = Mock(return_value=upm)
-
- msg = "Shell access is only available to 'admin' or " \
- "'resource-admin' roles."
-
- with pytest.raises(F5ModuleError) as ex:
- mm.exec_module()
- assert str(ex.value) == msg
-
-
-class TestLegacyManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
-
- def test_create_user(self, *args):
- access = [{'name': 'Common', 'role': 'guest'}]
- set_module_args(dict(
- username_credential='someuser',
- password_credential='testpass',
- partition_access=access,
- update_password='on_create',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods to force specific logic in the module to happen
- upm = UnpartitionedManager(module=module, params=module.params)
- upm.create_on_device = Mock(return_value=True)
- upm.exists = Mock(return_value=False)
-
- mm = ModuleManager(module=module)
- mm.is_version_less_than_13 = Mock(return_value=True)
- mm.get_manager = Mock(return_value=upm)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['partition_access'] == access
-
- def test_create_user_no_password(self, *args):
- access = [{'name': 'Common', 'role': 'guest'}]
- set_module_args(dict(
- username_credential='someuser',
- partition_access=access,
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods to force specific logic in the module to happen
- upm = UnpartitionedManager(module=module, params=module.params)
- upm.create_on_device = Mock(return_value=True)
- upm.exists = Mock(return_value=False)
-
- mm = ModuleManager(module=module)
- mm.is_version_less_than_13 = Mock(return_value=True)
- mm.get_manager = Mock(return_value=upm)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['partition_access'] == access
-
- def test_create_user_partition_access_raises(self, *args):
- set_module_args(dict(
- username_credential='someuser',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods to force specific logic in the module to happen
- upm = UnpartitionedManager(module=module, params=module.params)
- upm.create_on_device = Mock(return_value=True)
- upm.exists = Mock(return_value=False)
-
- mm = ModuleManager(module=module)
- mm.is_version_less_than_13 = Mock(return_value=True)
- mm.get_manager = Mock(return_value=upm)
-
- msg = "The 'partition_access' option " \
- "is required when creating a resource."
-
- with pytest.raises(F5ModuleError) as ex:
- mm.exec_module()
- assert str(ex.value) == msg
-
- def test_create_user_shell_bash(self, *args):
- access = [{'name': 'all', 'role': 'admin'}]
- set_module_args(dict(
- username_credential='someuser',
- password_credential='testpass',
- partition_access=access,
- update_password='on_create',
- shell='bash',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods to force specific logic in the module to happen
- upm = UnpartitionedManager(module=module, params=module.params)
- upm.create_on_device = Mock(return_value=True)
- upm.exists = Mock(return_value=False)
-
- mm = ModuleManager(module=module)
- mm.is_version_less_than_13 = Mock(return_value=True)
- mm.get_manager = Mock(return_value=upm)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['partition_access'] == access
-
- def test_create_user_shell_not_permitted_raises(self, *args):
- access = [{'name': 'Common', 'role': 'guest'}]
- set_module_args(dict(
- username_credential='someuser',
- password_credential='testpass',
- partition_access=access,
- update_password='on_create',
- shell='bash',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods to force specific logic in the module to happen
- upm = UnpartitionedManager(module=module, params=module.params)
- upm.create_on_device = Mock(return_value=True)
- upm.exists = Mock(return_value=False)
-
- mm = ModuleManager(module=module)
- mm.is_version_less_than_13 = Mock(return_value=True)
- mm.get_manager = Mock(return_value=upm)
-
- msg = "Shell access is only available to 'admin' or " \
- "'resource-admin' roles."
-
- with pytest.raises(F5ModuleError) as ex:
- mm.exec_module()
- assert str(ex.value) == msg
-
- def test_update_user_password(self, *args):
- set_module_args(dict(
- username_credential='someuser',
- password_credential='testpass',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Configure the parameters that would be returned by querying the
- # remote device
- access = [{'name': 'Common', 'role': 'guest'}]
- current = Parameters(
- params=dict(
- shell='tmsh',
- partition_access=access
- )
- )
-
- # Override methods to force specific logic in the module to happen
- upm = UnpartitionedManager(module=module, params=module.params)
- upm.exists = Mock(return_value=True)
- upm.update_on_device = Mock(return_value=True)
- upm.read_current_from_device = Mock(return_value=current)
-
- mm = ModuleManager(module=module)
- mm.is_version_less_than_13 = Mock(return_value=True)
- mm.get_manager = Mock(return_value=upm)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
-
- def test_update_user_shell_to_none(self, *args):
- set_module_args(dict(
- username_credential='someuser',
- shell='none',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Configure the parameters that would be returned by querying the
- # remote device
- current = Parameters(
- params=dict(
- user='admin',
- shell='tmsh'
- )
- )
-
- # Override methods to force specific logic in the module to happen
- upm = UnpartitionedManager(module=module, params=module.params)
- upm.exists = Mock(return_value=True)
- upm.update_on_device = Mock(return_value=True)
- upm.read_current_from_device = Mock(return_value=current)
-
- mm = ModuleManager(module=module)
- mm.is_version_less_than_13 = Mock(return_value=True)
- mm.get_manager = Mock(return_value=upm)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['shell'] == 'none'
-
- def test_update_user_shell_to_none_shell_attribute_missing(self, *args):
- set_module_args(dict(
- username_credential='someuser',
- shell='none',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Configure the parameters that would be returned by querying the
- # remote device
- access = [{'name': 'Common', 'role': 'guest'}]
- current = Parameters(
- params=dict(
- user='admin',
- partition_access=access
- )
- )
-
- # Override methods to force specific logic in the module to happen
- upm = UnpartitionedManager(module=module, params=module.params)
- upm.exists = Mock(return_value=True)
- upm.update_on_device = Mock(return_value=True)
- upm.read_current_from_device = Mock(return_value=current)
-
- mm = ModuleManager(module=module)
- mm.is_version_less_than_13 = Mock(return_value=True)
- mm.get_manager = Mock(return_value=upm)
-
- results = mm.exec_module()
-
- assert results['changed'] is False
- assert not hasattr(results, 'shell')
-
- def test_update_user_shell_to_bash(self, *args):
- set_module_args(dict(
- username_credential='someuser',
- shell='bash',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Configure the parameters that would be returned by querying the
- # remote device
- access = [{'name': 'all', 'role': 'admin'}]
- current = Parameters(
- params=dict(
- user='admin',
- shell='tmsh',
- partition_access=access
- )
- )
-
- # Override methods to force specific logic in the module to happen
- upm = UnpartitionedManager(module=module, params=module.params)
- upm.exists = Mock(return_value=True)
- upm.update_on_device = Mock(return_value=True)
- upm.read_current_from_device = Mock(return_value=current)
-
- mm = ModuleManager(module=module)
- mm.is_version_less_than_13 = Mock(return_value=True)
- mm.get_manager = Mock(return_value=upm)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['shell'] == 'bash'
-
- def test_update_user_shell_to_bash_mutliple_roles(self, *args):
- set_module_args(dict(
- username_credential='someuser',
- shell='bash',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Configure the parameters that would be returned by querying the
- # remote device
- access = [
- {'name': 'Common', 'role': 'operator'},
- {'name': 'all', 'role': 'guest'}
- ]
- current = Parameters(
- params=dict(
- user='admin',
- shell='tmsh',
- partition_access=access
- )
- )
-
- # Override methods to force specific logic in the module to happen
- upm = UnpartitionedManager(module=module, params=module.params)
- upm.exists = Mock(return_value=True)
- upm.update_on_device = Mock(return_value=True)
- upm.read_current_from_device = Mock(return_value=current)
-
- mm = ModuleManager(module=module)
- mm.is_version_less_than_13 = Mock(return_value=True)
- mm.get_manager = Mock(return_value=upm)
-
- msg = "Shell access is only available to 'admin' or " \
- "'resource-admin' roles."
-
- with pytest.raises(F5ModuleError) as ex:
- mm.exec_module()
- assert str(ex.value) == msg
diff --git a/test/units/modules/network/f5/test_bigip_vcmp_guest.py b/test/units/modules/network/f5/test_bigip_vcmp_guest.py
deleted file mode 100644
index 72230b05c2..0000000000
--- a/test/units/modules/network/f5/test_bigip_vcmp_guest.py
+++ /dev/null
@@ -1,262 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright (c) 2017 F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_vcmp_guest import ModuleParameters
- from library.modules.bigip_vcmp_guest import ApiParameters
- from library.modules.bigip_vcmp_guest import ModuleManager
- from library.modules.bigip_vcmp_guest import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
- from test.units.compat.mock import patch
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_vcmp_guest import ModuleParameters
- from ansible.modules.network.f5.bigip_vcmp_guest import ApiParameters
- from ansible.modules.network.f5.bigip_vcmp_guest import ModuleManager
- from ansible.modules.network.f5.bigip_vcmp_guest import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
- from units.compat.mock import patch
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- initial_image='BIGIP-12.1.0.1.0.1447-HF1.iso',
- mgmt_network='bridged',
- mgmt_address='1.2.3.4/24',
- vlans=[
- 'vlan1',
- 'vlan2'
- ]
- )
-
- p = ModuleParameters(params=args)
- assert p.initial_image == 'BIGIP-12.1.0.1.0.1447-HF1.iso'
- assert p.mgmt_network == 'bridged'
-
- def test_module_parameters_mgmt_bridged_without_subnet(self):
- args = dict(
- mgmt_network='bridged',
- mgmt_address='1.2.3.4'
- )
-
- p = ModuleParameters(params=args)
- assert p.mgmt_network == 'bridged'
- assert p.mgmt_address == '1.2.3.4/32'
-
- def test_module_parameters_mgmt_address_cidr(self):
- args = dict(
- mgmt_network='bridged',
- mgmt_address='1.2.3.4/24'
- )
-
- p = ModuleParameters(params=args)
- assert p.mgmt_network == 'bridged'
- assert p.mgmt_address == '1.2.3.4/24'
-
- def test_module_parameters_mgmt_address_subnet(self):
- args = dict(
- mgmt_network='bridged',
- mgmt_address='1.2.3.4/255.255.255.0'
- )
-
- p = ModuleParameters(params=args)
- assert p.mgmt_network == 'bridged'
- assert p.mgmt_address == '1.2.3.4/24'
-
- def test_module_parameters_mgmt_route(self):
- args = dict(
- mgmt_route='1.2.3.4'
- )
-
- p = ModuleParameters(params=args)
- assert p.mgmt_route == '1.2.3.4'
-
- def test_module_parameters_vcmp_software_image_facts(self):
- # vCMP images may include a forward slash in their names. This is probably
- # related to the slots on the system, but it is not a valid value to specify
- # that slot when providing an initial image
- args = dict(
- initial_image='BIGIP-12.1.0.1.0.1447-HF1.iso/1',
- )
-
- p = ModuleParameters(params=args)
- assert p.initial_image == 'BIGIP-12.1.0.1.0.1447-HF1.iso/1'
-
- def test_api_parameters(self):
- args = dict(
- initialImage="BIGIP-tmos-tier2-13.1.0.0.0.931.iso",
- managementGw="2.2.2.2",
- managementIp="1.1.1.1/24",
- managementNetwork="bridged",
- state="deployed",
- vlans=[
- "/Common/vlan1",
- "/Common/vlan2"
- ]
- )
-
- p = ApiParameters(params=args)
- assert p.initial_image == 'BIGIP-tmos-tier2-13.1.0.0.0.931.iso'
- assert p.mgmt_route == '2.2.2.2'
- assert p.mgmt_address == '1.1.1.1/24'
- assert '/Common/vlan1' in p.vlans
- assert '/Common/vlan2' in p.vlans
-
- def test_api_parameters_with_hotfix(self):
- args = dict(
- initialImage="BIGIP-14.1.0.3-0.0.6.iso",
- initialHotfix="Hotfix-BIGIP-14.1.0.3.0.5.6-ENG.iso",
- managementGw="2.2.2.2",
- managementIp="1.1.1.1/24",
- managementNetwork="bridged",
- state="deployed",
- vlans=[
- "/Common/vlan1",
- "/Common/vlan2"
- ]
- )
-
- p = ApiParameters(params=args)
- assert p.initial_image == 'BIGIP-14.1.0.3-0.0.6.iso'
- assert p.initial_hotfix == 'Hotfix-BIGIP-14.1.0.3.0.5.6-ENG.iso'
- assert p.mgmt_route == '2.2.2.2'
- assert p.mgmt_address == '1.1.1.1/24'
- assert '/Common/vlan1' in p.vlans
- assert '/Common/vlan2' in p.vlans
-
-
-class TestManager(unittest.TestCase):
- def setUp(self):
- self.spec = ArgumentSpec()
- self.patcher1 = patch('time.sleep')
- self.patcher1.start()
-
- try:
- self.p1 = patch('library.modules.bigip_vcmp_guest.ModuleParameters.initial_image_exists')
- self.m1 = self.p1.start()
- self.m1.return_value = True
- self.p2 = patch('library.modules.bigip_vcmp_guest.ModuleParameters.initial_hotfix_exists')
- self.m2 = self.p2.start()
- self.m2.return_value = True
- except Exception:
- self.p1 = patch('ansible.modules.network.f5.bigip_vcmp_guest.ModuleParameters.initial_image_exists')
- self.m1 = self.p1.start()
- self.m1.return_value = True
- self.p2 = patch('ansible.modules.network.f5.bigip_vcmp_guest.ModuleParameters.initial_hotfix_exists')
- self.m2 = self.p2.start()
- self.m2.return_value = True
-
- def tearDown(self):
- self.patcher1.stop()
- self.p1.stop()
- self.p2.stop()
-
- def test_create_vcmpguest(self, *args):
- set_module_args(dict(
- name="guest1",
- mgmt_network="bridged",
- mgmt_address="10.10.10.10/24",
- initial_image="BIGIP-13.1.0.0.0.931.iso",
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- required_if=self.spec.required_if
- )
-
- # Override methods to force specific logic in the module to happen
- mm = ModuleManager(module=module)
- mm.create_on_device = Mock(return_value=True)
- mm.exists = Mock(return_value=False)
- mm.is_deployed = Mock(side_effect=[False, True, True, True, True])
- mm.deploy_on_device = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['name'] == 'guest1'
-
- def test_create_vcmpguest_with_hotfix(self, *args):
- set_module_args(dict(
- name="guest2",
- mgmt_network="bridged",
- mgmt_address="10.10.10.10/24",
- initial_image="BIGIP-14.1.0.3-0.0.6.iso",
- initial_hotfix="Hotfix-BIGIP-14.1.0.3.0.5.6-ENG.iso",
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- required_if=self.spec.required_if
- )
-
- # Override methods to force specific logic in the module to happen
- mm = ModuleManager(module=module)
- mm.create_on_device = Mock(return_value=True)
- mm.exists = Mock(return_value=False)
- mm.is_deployed = Mock(side_effect=[False, True, True, True, True])
- mm.deploy_on_device = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['name'] == 'guest2'
diff --git a/test/units/modules/network/f5/test_bigip_virtual_address.py b/test/units/modules/network/f5/test_bigip_virtual_address.py
deleted file mode 100644
index 0af9e06018..0000000000
--- a/test/units/modules/network/f5/test_bigip_virtual_address.py
+++ /dev/null
@@ -1,235 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright (c) 2017 F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_virtual_address import ApiParameters
- from library.modules.bigip_virtual_address import ModuleParameters
- from library.modules.bigip_virtual_address import ModuleManager
- from library.modules.bigip_virtual_address import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_virtual_address import ApiParameters
- from ansible.modules.network.f5.bigip_virtual_address import ModuleParameters
- from ansible.modules.network.f5.bigip_virtual_address import ModuleManager
- from ansible.modules.network.f5.bigip_virtual_address import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- state='present',
- address='1.1.1.1',
- netmask='2.2.2.2',
- connection_limit='10',
- arp_state='enabled',
- auto_delete='enabled',
- icmp_echo='enabled',
- availability_calculation='always',
- )
- p = ModuleParameters(params=args)
- assert p.state == 'present'
- assert p.address == '1.1.1.1'
- assert p.netmask == '2.2.2.2'
- assert p.connection_limit == 10
- assert p.arp is True
- assert p.auto_delete is True
- assert p.icmp_echo == 'enabled'
- assert p.availability_calculation == 'none'
-
- def test_api_parameters(self):
- args = load_fixture('load_ltm_virtual_address_default.json')
- p = ApiParameters(params=args)
- assert p.name == '1.1.1.1'
- assert p.address == '1.1.1.1'
- assert p.arp is True
- assert p.auto_delete is True
- assert p.connection_limit == 0
- assert p.state == 'enabled'
- assert p.icmp_echo == 'enabled'
- assert p.netmask == '255.255.255.255'
- assert p.route_advertisement_type == 'disabled'
- assert p.availability_calculation == 'any'
-
- def test_module_parameters_advertise_route_all(self):
- args = dict(
- availability_calculation='when_all_available'
- )
- p = ModuleParameters(params=args)
- assert p.availability_calculation == 'all'
-
- def test_module_parameters_advertise_route_any(self):
- args = dict(
- availability_calculation='when_any_available'
- )
- p = ModuleParameters(params=args)
- assert p.availability_calculation == 'any'
-
- def test_module_parameters_icmp_echo_disabled(self):
- args = dict(
- icmp_echo='disabled'
- )
- p = ModuleParameters(params=args)
- assert p.icmp_echo == 'disabled'
-
- def test_module_parameters_icmp_echo_selective(self):
- args = dict(
- icmp_echo='selective'
- )
- p = ModuleParameters(params=args)
- assert p.icmp_echo == 'selective'
-
- def test_module_parameters_auto_delete_disabled(self):
- args = dict(
- auto_delete='disabled'
- )
- p = ModuleParameters(params=args)
- assert p.auto_delete is False
-
- def test_module_parameters_arp_state_disabled(self):
- args = dict(
- arp_state='disabled'
- )
- p = ModuleParameters(params=args)
- assert p.arp_state == 'disabled'
-
- def test_module_parameters_state_present(self):
- args = dict(
- state='present'
- )
- p = ModuleParameters(params=args)
- assert p.state == 'present'
- assert p.enabled == 'yes'
-
- def test_module_parameters_state_absent(self):
- args = dict(
- state='absent'
- )
- p = ModuleParameters(params=args)
- assert p.state == 'absent'
-
- def test_module_parameters_state_enabled(self):
- args = dict(
- state='enabled'
- )
- p = ModuleParameters(params=args)
- assert p.state == 'enabled'
- assert p.enabled == 'yes'
-
- def test_module_parameters_state_disabled(self):
- args = dict(
- state='disabled'
- )
- p = ModuleParameters(params=args)
- assert p.state == 'disabled'
- assert p.enabled == 'no'
-
-
-class TestManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
-
- def test_create_virtual_address(self, *args):
- set_module_args(dict(
- state='present',
- address='1.1.1.1',
- netmask='2.2.2.2',
- connection_limit='10',
- arp_state='enabled',
- auto_delete='enabled',
- icmp_echo='enabled',
- advertise_route='always',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- mutually_exclusive=self.spec.mutually_exclusive,
- required_one_of=self.spec.required_one_of
- )
- mm = ModuleManager(module=module)
-
- # Override methods to force specific logic in the module to happen
- mm.exists = Mock(side_effect=[False, True])
- mm.create_on_device = Mock(return_value=True)
-
- results = mm.exec_module()
- assert results['changed'] is True
-
- def test_delete_virtual_address(self, *args):
- set_module_args(dict(
- state='absent',
- address='1.1.1.1',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- mutually_exclusive=self.spec.mutually_exclusive,
- required_one_of=self.spec.required_one_of
- )
- mm = ModuleManager(module=module)
-
- # Override methods to force specific logic in the module to happen
- mm.exists = Mock(side_effect=[True, False])
- mm.remove_from_device = Mock(return_value=True)
-
- results = mm.exec_module()
- assert results['changed'] is True
diff --git a/test/units/modules/network/f5/test_bigip_virtual_server.py b/test/units/modules/network/f5/test_bigip_virtual_server.py
deleted file mode 100644
index 07a63389f9..0000000000
--- a/test/units/modules/network/f5/test_bigip_virtual_server.py
+++ /dev/null
@@ -1,995 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright (c) 2017 F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_virtual_server import ModuleParameters
- from library.modules.bigip_virtual_server import ApiParameters
- from library.modules.bigip_virtual_server import ModuleManager
- from library.modules.bigip_virtual_server import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
- from test.units.compat.mock import patch
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_virtual_server import ApiParameters
- from ansible.modules.network.f5.bigip_virtual_server import ModuleParameters
- from ansible.modules.network.f5.bigip_virtual_server import ModuleManager
- from ansible.modules.network.f5.bigip_virtual_server import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
- from units.compat.mock import patch
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_destination_mutex_1(self):
- args = dict(
- destination='1.1.1.1'
- )
- p = ApiParameters(params=args)
- assert p.destination_tuple.ip == '1.1.1.1'
-
- def test_destination_mutex_2(self):
- args = dict(
- destination='1.1.1.1%2'
- )
- p = ApiParameters(params=args)
- assert p.destination_tuple.ip == '1.1.1.1'
- assert p.destination_tuple.route_domain == 2
-
- def test_destination_mutex_3(self):
- args = dict(
- destination='1.1.1.1:80'
- )
- p = ApiParameters(params=args)
- assert p.destination_tuple.ip == '1.1.1.1'
- assert p.destination_tuple.port == 80
-
- def test_destination_mutex_4(self):
- args = dict(
- destination='1.1.1.1%2:80'
- )
- p = ApiParameters(params=args)
- assert p.destination_tuple.ip == '1.1.1.1'
- assert p.destination_tuple.port == 80
- assert p.destination_tuple.route_domain == 2
-
- def test_api_destination_mutex_5(self):
- args = dict(
- destination='/Common/1.1.1.1'
- )
- p = ApiParameters(params=args)
- assert p.destination_tuple.ip == '1.1.1.1'
-
- def test_api_destination_mutex_6(self):
- args = dict(
- destination='/Common/1.1.1.1%2'
- )
- p = ApiParameters(params=args)
- assert p.destination_tuple.ip == '1.1.1.1'
- assert p.destination_tuple.route_domain == 2
-
- def test_api_destination_mutex_7(self):
- args = dict(
- destination='/Common/1.1.1.1:80'
- )
- p = ApiParameters(params=args)
- assert p.destination_tuple.ip == '1.1.1.1'
- assert p.destination_tuple.port == 80
-
- def test_api_destination_mutex_8(self):
- args = dict(
- destination='/Common/1.1.1.1%2:80'
- )
- p = ApiParameters(params=args)
- assert p.destination_tuple.ip == '1.1.1.1'
- assert p.destination_tuple.port == 80
- assert p.destination_tuple.route_domain == 2
-
- def test_destination_mutex_9(self):
- args = dict(
- destination='2700:bc00:1f10:101::6'
- )
- p = ApiParameters(params=args)
- assert p.destination_tuple.ip == '2700:bc00:1f10:101::6'
-
- def test_destination_mutex_10(self):
- args = dict(
- destination='2700:bc00:1f10:101::6%2'
- )
- p = ApiParameters(params=args)
- assert p.destination_tuple.ip == '2700:bc00:1f10:101::6'
- assert p.destination_tuple.route_domain == 2
-
- def test_destination_mutex_11(self):
- args = dict(
- destination='2700:bc00:1f10:101::6.80'
- )
- p = ApiParameters(params=args)
- assert p.destination_tuple.ip == '2700:bc00:1f10:101::6'
- assert p.destination_tuple.port == 80
-
- def test_destination_mutex_12(self):
- args = dict(
- destination='2700:bc00:1f10:101::6%2.80'
- )
- p = ApiParameters(params=args)
- assert p.destination_tuple.ip == '2700:bc00:1f10:101::6'
- assert p.destination_tuple.port == 80
- assert p.destination_tuple.route_domain == 2
-
- def test_module_no_partition_prefix_parameters(self):
- args = dict(
- state='present',
- partition='Common',
- name='my-virtual-server',
- destination='10.10.10.10',
- port=443,
- pool='my-pool',
- snat='Automap',
- description='Test Virtual Server',
- profiles=[
- dict(
- name='fix',
- context='all'
- )
- ],
- enabled_vlans=['vlan2']
- )
- p = ModuleParameters(params=args)
- assert p.name == 'my-virtual-server'
- assert p.partition == 'Common'
- assert p.port == 443
- assert p.destination == '/Common/10.10.10.10:443'
- assert p.pool == '/Common/my-pool'
- assert p.snat == {'type': 'automap'}
- assert p.description == 'Test Virtual Server'
- assert len(p.profiles) == 1
- assert 'context' in p.profiles[0]
- assert 'name' in p.profiles[0]
- assert '/Common/vlan2' in p.enabled_vlans
-
- def test_module_partition_prefix_parameters(self):
- args = dict(
- state='present',
- partition='Common',
- name='my-virtual-server',
- destination='10.10.10.10',
- port=443,
- pool='/Common/my-pool',
- snat='Automap',
- description='Test Virtual Server',
- profiles=[
- dict(
- name='fix',
- context='all'
- )
- ],
- enabled_vlans=['/Common/vlan2']
- )
- p = ModuleParameters(params=args)
- assert p.name == 'my-virtual-server'
- assert p.partition == 'Common'
- assert p.port == 443
- assert p.destination == '/Common/10.10.10.10:443'
- assert p.pool == '/Common/my-pool'
- assert p.snat == {'type': 'automap'}
- assert p.description == 'Test Virtual Server'
- assert len(p.profiles) == 1
- assert 'context' in p.profiles[0]
- assert 'name' in p.profiles[0]
- assert '/Common/vlan2' in p.enabled_vlans
-
- def test_api_parameters_variables(self):
- args = {
- "kind": "tm:ltm:virtual:virtualstate",
- "name": "my-virtual-server",
- "partition": "Common",
- "fullPath": "/Common/my-virtual-server",
- "generation": 54,
- "selfLink": "https://localhost/mgmt/tm/ltm/virtual/~Common~my-virtual-server?expandSubcollections=true&ver=12.1.2",
- "addressStatus": "yes",
- "autoLasthop": "default",
- "cmpEnabled": "yes",
- "connectionLimit": 0,
- "description": "Test Virtual Server",
- "destination": "/Common/10.10.10.10:443",
- "enabled": True,
- "gtmScore": 0,
- "ipProtocol": "tcp",
- "mask": "255.255.255.255",
- "mirror": "disabled",
- "mobileAppTunnel": "disabled",
- "nat64": "disabled",
- "rateLimit": "disabled",
- "rateLimitDstMask": 0,
- "rateLimitMode": "object",
- "rateLimitSrcMask": 0,
- "serviceDownImmediateAction": "none",
- "source": "0.0.0.0/0",
- "sourceAddressTranslation": {
- "type": "automap"
- },
- "sourcePort": "preserve",
- "synCookieStatus": "not-activated",
- "translateAddress": "enabled",
- "translatePort": "enabled",
- "vlansEnabled": True,
- "vsIndex": 3,
- "vlans": [
- "/Common/net1"
- ],
- "vlansReference": [
- {
- "link": "https://localhost/mgmt/tm/net/vlan/~Common~net1?ver=12.1.2"
- }
- ],
- "policiesReference": {
- "link": "https://localhost/mgmt/tm/ltm/virtual/~Common~my-virtual-server/policies?ver=12.1.2",
- "isSubcollection": True
- },
- "profilesReference": {
- "link": "https://localhost/mgmt/tm/ltm/virtual/~Common~my-virtual-server/profiles?ver=12.1.2",
- "isSubcollection": True,
- "items": [
- {
- "kind": "tm:ltm:virtual:profiles:profilesstate",
- "name": "http",
- "partition": "Common",
- "fullPath": "/Common/http",
- "generation": 54,
- "selfLink": "https://localhost/mgmt/tm/ltm/virtual/~Common~my-virtual-server/profiles/~Common~http?ver=12.1.2",
- "context": "all",
- "nameReference": {
- "link": "https://localhost/mgmt/tm/ltm/profile/http/~Common~http?ver=12.1.2"
- }
- },
- {
- "kind": "tm:ltm:virtual:profiles:profilesstate",
- "name": "serverssl",
- "partition": "Common",
- "fullPath": "/Common/serverssl",
- "generation": 54,
- "selfLink": "https://localhost/mgmt/tm/ltm/virtual/~Common~my-virtual-server/profiles/~Common~serverssl?ver=12.1.2",
- "context": "serverside",
- "nameReference": {
- "link": "https://localhost/mgmt/tm/ltm/profile/server-ssl/~Common~serverssl?ver=12.1.2"
- }
- },
- {
- "kind": "tm:ltm:virtual:profiles:profilesstate",
- "name": "tcp",
- "partition": "Common",
- "fullPath": "/Common/tcp",
- "generation": 54,
- "selfLink": "https://localhost/mgmt/tm/ltm/virtual/~Common~my-virtual-server/profiles/~Common~tcp?ver=12.1.2",
- "context": "all",
- "nameReference": {
- "link": "https://localhost/mgmt/tm/ltm/profile/tcp/~Common~tcp?ver=12.1.2"
- }
- }
- ]
- }
- }
- p = ApiParameters(params=args)
- assert p.name == 'my-virtual-server'
- assert p.partition == 'Common'
- assert p.port == 443
- assert p.destination == '/Common/10.10.10.10:443'
- assert p.snat == {'type': 'automap'}
- assert p.description == 'Test Virtual Server'
- assert 'context' in p.profiles[0]
- assert 'name' in p.profiles[0]
- assert 'fullPath' in p.profiles[0]
- assert p.profiles[0]['context'] == 'all'
- assert p.profiles[0]['name'] == 'http'
- assert p.profiles[0]['fullPath'] == '/Common/http'
- assert '/Common/net1' in p.vlans
-
- def test_module_address_translation_enabled(self):
- args = dict(
- address_translation=True
- )
- p = ModuleParameters(params=args)
- assert p.address_translation == 'enabled'
-
- def test_module_address_translation_disabled(self):
- args = dict(
- address_translation=False
- )
- p = ModuleParameters(params=args)
- assert p.address_translation == 'disabled'
-
-
-class TestManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
-
- try:
- self.p1 = patch('library.modules.bigip_virtual_server.modules_provisioned')
- self.m1 = self.p1.start()
- self.m1.return_value = ['ltm', 'gtm', 'asm']
- self.p2 = patch(
- 'library.modules.bigip_virtual_server.Parameters._read_current_clientssl_profiles_from_device'
- )
- self.p3 = patch(
- 'library.modules.bigip_virtual_server.Parameters._read_current_serverssl_profiles_from_device'
- )
- self.p4 = patch(
- 'library.modules.bigip_virtual_server.VirtualServerValidator.check_create'
- )
-
- self.p5 = patch(
- 'library.modules.bigip_virtual_server.VirtualServerValidator.check_update'
- )
-
- self.m2 = self.p2.start()
- self.m3 = self.p3.start()
- self.m4 = self.p4.start()
- self.m5 = self.p5.start()
- self.m2.return_value = ['asda', 'clientssl', 'cs_foobar.star.local']
- self.m3.return_value = ['baz', 'serverssl', 'ss_foobar.star.local']
- self.m4.return_value = Mock(return_value=True)
- self.m5.return_value = Mock(return_value=True)
- except Exception:
- self.p1 = patch('ansible.modules.network.f5.bigip_virtual_server.modules_provisioned')
- self.m1 = self.p1.start()
- self.m1.return_value = ['ltm', 'gtm', 'asm']
- self.p2 = patch(
- 'ansible.modules.network.f5.bigip_virtual_server.Parameters._read_current_clientssl_profiles_from_device'
- )
- self.p3 = patch(
- 'ansible.modules.network.f5.bigip_virtual_server.Parameters._read_current_serverssl_profiles_from_device'
- )
- self.p4 = patch(
- 'ansible.modules.network.f5.bigip_virtual_server.VirtualServerValidator.check_create'
- )
- self.p5 = patch(
- 'ansible.modules.network.f5.bigip_virtual_server.VirtualServerValidator.check_update'
- )
- self.m2 = self.p2.start()
- self.m3 = self.p3.start()
- self.m4 = self.p4.start()
- self.m5 = self.p5.start()
- self.m2.return_value = ['asda', 'clientssl', 'cs_foobar.star.local']
- self.m3.return_value = ['baz', 'serverssl', 'ss_foobar.star.local']
- self.m4.return_value = Mock(return_value=True)
- self.m5.return_value = Mock(return_value=True)
-
- def tearDown(self):
- self.p1.stop()
- self.p2.stop()
- self.p3.stop()
- self.p4.stop()
- self.p5.stop()
-
- def test_create_virtual_server(self, *args):
- set_module_args(dict(
- all_profiles=[
- dict(
- name='http'
- ),
- dict(
- name='clientssl'
- )
- ],
- description="Test Virtual Server",
- destination="10.10.10.10",
- name="my-snat-pool",
- partition="Common",
- port="443",
- snat="Automap",
- state="present",
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
-
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- mutually_exclusive=self.spec.mutually_exclusive
- )
-
- # Override methods to force specific logic in the module to happen
- mm = ModuleManager(module=module)
- mm.exists = Mock(return_value=False)
- mm.create_on_device = Mock(return_value=True)
- results = mm.exec_module()
-
- assert results['changed'] is True
-
- def test_delete_virtual_server(self, *args):
- set_module_args(dict(
- all_profiles=[
- 'http', 'clientssl'
- ],
- description="Test Virtual Server",
- destination="10.10.10.10",
- name="my-snat-pool",
- partition="Common",
- port="443",
- snat="Automap",
- state="absent",
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- mutually_exclusive=self.spec.mutually_exclusive
- )
-
- # Override methods to force specific logic in the module to happen
- mm = ModuleManager(module=module)
- mm.exists = Mock(return_value=False)
-
- results = mm.exec_module()
-
- assert results['changed'] is False
-
- def test_enable_vs_that_is_already_enabled(self, *args):
- set_module_args(dict(
- all_profiles=[
- 'http', 'clientssl'
- ],
- description="Test Virtual Server",
- destination="10.10.10.10",
- name="my-snat-pool",
- partition="Common",
- port="443",
- snat="Automap",
- state="absent",
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- # Configure the parameters that would be returned by querying the
- # remote device
- current = ApiParameters(
- dict(
- agent_status_traps='disabled'
- )
- )
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- mutually_exclusive=self.spec.mutually_exclusive
- )
-
- # Override methods to force specific logic in the module to happen
- mm = ModuleManager(module=module)
- mm.exists = Mock(return_value=False)
- mm.update_on_device = Mock(return_value=True)
- mm.read_current_from_device = Mock(return_value=current)
- results = mm.exec_module()
-
- assert results['changed'] is False
-
- def test_modify_port(self, *args):
- set_module_args(dict(
- name="my-virtual-server",
- partition="Common",
- port="10443",
- state="present",
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- # Configure the parameters that would be returned by querying the
- # remote device
- current = ApiParameters(params=load_fixture('load_ltm_virtual_1.json'))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- mutually_exclusive=self.spec.mutually_exclusive
- )
-
- # Override methods to force specific logic in the module to happen
- mm = ModuleManager(module=module)
- mm.exists = Mock(return_value=True)
- mm.read_current_from_device = Mock(return_value=current)
- mm.update_on_device = Mock(return_value=True)
- results = mm.exec_module()
-
- assert results['changed'] is True
-
- def test_modify_port_idempotent(self, *args):
- set_module_args(dict(
- name="my-virtual-server",
- partition="Common",
- port="443",
- state="present",
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- # Configure the parameters that would be returned by querying the
- # remote device
- current = ApiParameters(params=load_fixture('load_ltm_virtual_1.json'))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- mutually_exclusive=self.spec.mutually_exclusive
- )
-
- # Override methods to force specific logic in the module to happen
- mm = ModuleManager(module=module)
- mm.exists = Mock(return_value=True)
- mm.read_current_from_device = Mock(return_value=current)
- results = mm.exec_module()
-
- assert results['changed'] is False
-
- def test_modify_vlans_idempotent(self, *args):
- set_module_args(dict(
- name="my-virtual-server",
- partition="Common",
- disabled_vlans=[
- "net1"
- ],
- state="present",
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- # Configure the parameters that would be returned by querying the
- # remote device
- current = ApiParameters(params=load_fixture('load_ltm_virtual_2.json'))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- mutually_exclusive=self.spec.mutually_exclusive
- )
-
- # Override methods to force specific logic in the module to happen
- mm = ModuleManager(module=module)
- mm.exists = Mock(return_value=True)
- mm.read_current_from_device = Mock(return_value=current)
-
- results = mm.exec_module()
-
- assert results['changed'] is False
-
- def test_modify_profiles(self, *args):
- set_module_args(dict(
- name="my-virtual-server",
- partition="Common",
- profiles=[
- 'http', 'clientssl'
- ],
- state="present",
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- # Configure the parameters that would be returned by querying the
- # remote device
- current = ApiParameters(params=load_fixture('load_ltm_virtual_2.json'))
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- mutually_exclusive=self.spec.mutually_exclusive
- )
-
- # Override methods to force specific logic in the module to happen
- mm = ModuleManager(module=module)
- mm.exists = Mock(return_value=True)
- mm.read_current_from_device = Mock(return_value=current)
- mm.update_on_device = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert len(results['profiles']) == 2
- assert 'name' in results['profiles'][0]
- assert 'context' in results['profiles'][0]
- assert results['profiles'][0]['name'] == 'http'
- assert results['profiles'][0]['context'] == 'all'
- assert 'name' in results['profiles'][1]
- assert 'context' in results['profiles'][1]
- assert results['profiles'][1]['name'] == 'clientssl'
- assert results['profiles'][1]['context'] == 'clientside'
-
- def test_update_virtual_server(self, *args):
- set_module_args(dict(
- profiles=[
- dict(
- name='http'
- ),
- dict(
- name='clientssl'
- )
- ],
- description="foo virtual",
- destination="1.1.1.1",
- name="my-virtual-server",
- partition="Common",
- port="8443",
- snat="snat-pool1",
- state="disabled",
- source='1.2.3.4/32',
- irules=[
- 'irule1',
- 'irule2'
- ],
- policies=[
- 'policy1',
- 'policy2'
- ],
- enabled_vlans=[
- 'vlan1',
- 'vlan2'
- ],
- pool='my-pool',
- default_persistence_profile='source_addr',
- fallback_persistence_profile='dest_addr',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- # Configure the parameters that would be returned by querying the
- # remote device
- current = ApiParameters(params=load_fixture('load_ltm_virtual_3.json'))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- mutually_exclusive=self.spec.mutually_exclusive
- )
-
- # Override methods to force specific logic in the module to happen
- mm = ModuleManager(module=module)
- mm.exists = Mock(return_value=True)
- mm.read_current_from_device = Mock(return_value=current)
- mm.update_on_device = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['source'] == '1.2.3.4/32'
- assert results['description'] == 'foo virtual'
- assert results['snat'] == '/Common/snat-pool1'
- assert results['destination'] == '1.1.1.1'
- assert results['port'] == 8443
- assert results['default_persistence_profile'] == '/Common/source_addr'
- assert results['fallback_persistence_profile'] == '/Common/dest_addr'
-
- # policies
- assert len(results['policies']) == 2
- assert '/Common/policy1' in results['policies']
- assert '/Common/policy2' in results['policies']
-
- # irules
- assert len(results['irules']) == 2
- assert '/Common/irule1' in results['irules']
- assert '/Common/irule2' in results['irules']
-
- # vlans
- assert len(results['enabled_vlans']) == 2
- assert '/Common/vlan1' in results['enabled_vlans']
- assert '/Common/vlan2' in results['enabled_vlans']
-
- # profiles
- assert len(results['profiles']) == 2
- assert 'name' in results['profiles'][0]
- assert 'context' in results['profiles'][0]
- assert results['profiles'][0]['name'] == 'http'
- assert results['profiles'][0]['context'] == 'all'
- assert 'name' in results['profiles'][1]
- assert 'context' in results['profiles'][1]
- assert results['profiles'][1]['name'] == 'clientssl'
- assert results['profiles'][1]['context'] == 'clientside'
-
- def test_create_virtual_server_with_address_translation_bool_true(self, *args):
- set_module_args(dict(
- destination="10.10.10.10",
- address_translation=True,
- name="my-snat-pool",
- partition="Common",
- port="443",
- state="present",
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- mutually_exclusive=self.spec.mutually_exclusive
- )
-
- # Override methods to force specific logic in the module to happen
- mm = ModuleManager(module=module)
- mm.exists = Mock(return_value=False)
- mm.create_on_device = Mock(return_value=True)
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['address_translation'] is True
-
- def test_create_virtual_server_with_address_translation_string_yes(self, *args):
- set_module_args(dict(
- destination="10.10.10.10",
- address_translation='yes',
- name="my-snat-pool",
- partition="Common",
- port="443",
- state="present",
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- mutually_exclusive=self.spec.mutually_exclusive
- )
-
- # Override methods to force specific logic in the module to happen
- mm = ModuleManager(module=module)
- mm.exists = Mock(return_value=False)
- mm.create_on_device = Mock(return_value=True)
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['address_translation'] is True
-
- def test_create_virtual_server_with_address_translation_bool_false(self, *args):
- set_module_args(dict(
- destination="10.10.10.10",
- address_translation=False,
- name="my-snat-pool",
- partition="Common",
- port="443",
- state="present",
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- mutually_exclusive=self.spec.mutually_exclusive
- )
-
- # Override methods to force specific logic in the module to happen
- mm = ModuleManager(module=module)
- mm.exists = Mock(return_value=False)
- mm.create_on_device = Mock(return_value=True)
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['address_translation'] is False
-
- def test_create_virtual_server_with_address_translation_string_no(self, *args):
- set_module_args(dict(
- destination="10.10.10.10",
- address_translation='no',
- name="my-snat-pool",
- partition="Common",
- port="443",
- state="present",
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- mutually_exclusive=self.spec.mutually_exclusive
- )
-
- # Override methods to force specific logic in the module to happen
- mm = ModuleManager(module=module)
- mm.exists = Mock(return_value=False)
- mm.create_on_device = Mock(return_value=True)
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['address_translation'] is False
-
- def test_create_virtual_server_with_port_translation_bool_true(self, *args):
- set_module_args(dict(
- destination="10.10.10.10",
- port_translation=True,
- name="my-snat-pool",
- partition="Common",
- port="443",
- state="present",
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- mutually_exclusive=self.spec.mutually_exclusive
- )
-
- # Override methods to force specific logic in the module to happen
- mm = ModuleManager(module=module)
- mm.exists = Mock(return_value=False)
- mm.create_on_device = Mock(return_value=True)
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['port_translation'] is True
-
- def test_create_virtual_server_with_port_translation_string_yes(self, *args):
- set_module_args(dict(
- destination="10.10.10.10",
- port_translation='yes',
- name="my-snat-pool",
- partition="Common",
- port="443",
- state="present",
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- mutually_exclusive=self.spec.mutually_exclusive
- )
-
- # Override methods to force specific logic in the module to happen
- mm = ModuleManager(module=module)
- mm.exists = Mock(return_value=False)
- mm.create_on_device = Mock(return_value=True)
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['port_translation'] is True
-
- def test_create_virtual_server_with_port_translation_bool_false(self, *args):
- set_module_args(dict(
- destination="10.10.10.10",
- port_translation=False,
- name="my-snat-pool",
- partition="Common",
- port="443",
- state="present",
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- mutually_exclusive=self.spec.mutually_exclusive
- )
-
- # Override methods to force specific logic in the module to happen
- mm = ModuleManager(module=module)
- mm.exists = Mock(return_value=False)
- mm.create_on_device = Mock(return_value=True)
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['port_translation'] is False
-
- def test_create_virtual_server_with_port_translation_string_no(self, *args):
- set_module_args(dict(
- destination="10.10.10.10",
- port_translation='no',
- name="my-snat-pool",
- partition="Common",
- port="443",
- state="present",
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- mutually_exclusive=self.spec.mutually_exclusive
- )
-
- # Override methods to force specific logic in the module to happen
- mm = ModuleManager(module=module)
- mm.exists = Mock(return_value=False)
- mm.create_on_device = Mock(return_value=True)
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['port_translation'] is False
diff --git a/test/units/modules/network/f5/test_bigip_vlan.py b/test/units/modules/network/f5/test_bigip_vlan.py
deleted file mode 100644
index 89e421e2f7..0000000000
--- a/test/units/modules/network/f5/test_bigip_vlan.py
+++ /dev/null
@@ -1,344 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright (c) 2017 F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_vlan import ApiParameters
- from library.modules.bigip_vlan import ModuleParameters
- from library.modules.bigip_vlan import ModuleManager
- from library.modules.bigip_vlan import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_vlan import ApiParameters
- from ansible.modules.network.f5.bigip_vlan import ModuleParameters
- from ansible.modules.network.f5.bigip_vlan import ModuleManager
- from ansible.modules.network.f5.bigip_vlan import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class BigIpObj(object):
- def __init__(self, **kwargs):
- self.__dict__.update(kwargs)
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- name='somevlan',
- tag=213,
- description='fakevlan',
- untagged_interfaces=['1.1'],
- )
- p = ModuleParameters(params=args)
-
- assert p.name == 'somevlan'
- assert p.tag == 213
- assert p.description == 'fakevlan'
- assert p.untagged_interfaces == ['1.1']
-
- def test_api_parameters(self):
- args = dict(
- name='somevlan',
- description='fakevlan',
- tag=213
- )
-
- p = ApiParameters(params=args)
-
- assert p.name == 'somevlan'
- assert p.tag == 213
- assert p.description == 'fakevlan'
-
-
-class TestManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
-
- def test_create_vlan(self, *args):
- set_module_args(dict(
- name='somevlan',
- description='fakevlan',
- partition='Common',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- mutually_exclusive=self.spec.mutually_exclusive
- )
-
- # Override methods to force specific logic in the module to happen
- mm = ModuleManager(module=module)
- mm.create_on_device = Mock(return_value=True)
- mm.exists = Mock(return_value=False)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['description'] == 'fakevlan'
-
- def test_create_vlan_tagged_interface(self, *args):
- set_module_args(dict(
- name='somevlan',
- tagged_interface=['2.1'],
- tag=213,
- partition='Common',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- mutually_exclusive=self.spec.mutually_exclusive
- )
-
- # Override methods to force specific logic in the module to happen
- mm = ModuleManager(module=module)
- mm.create_on_device = Mock(return_value=True)
- mm.exists = Mock(return_value=False)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['tagged_interfaces'] == ['2.1']
- assert results['tag'] == 213
-
- def test_create_vlan_untagged_interface(self, *args):
- set_module_args(dict(
- name='somevlan',
- untagged_interface=['2.1'],
- partition='Common',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- mutually_exclusive=self.spec.mutually_exclusive
- )
-
- # Override methods to force specific logic in the module to happen
- mm = ModuleManager(module=module)
- mm.create_on_device = Mock(return_value=True)
- mm.exists = Mock(return_value=False)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['untagged_interfaces'] == ['2.1']
-
- def test_create_vlan_tagged_interfaces(self, *args):
- set_module_args(dict(
- name='somevlan',
- tagged_interface=['2.1', '1.1'],
- tag=213,
- partition='Common',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- mutually_exclusive=self.spec.mutually_exclusive
- )
-
- # Override methods to force specific logic in the module to happen
- mm = ModuleManager(module=module)
- mm.create_on_device = Mock(return_value=True)
- mm.exists = Mock(return_value=False)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['tagged_interfaces'] == ['1.1', '2.1']
- assert results['tag'] == 213
-
- def test_create_vlan_untagged_interfaces(self, *args):
- set_module_args(dict(
- name='somevlan',
- untagged_interface=['2.1', '1.1'],
- partition='Common',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- mutually_exclusive=self.spec.mutually_exclusive
- )
-
- # Override methods to force specific logic in the module to happen
- mm = ModuleManager(module=module)
- mm.create_on_device = Mock(return_value=True)
- mm.exists = Mock(return_value=False)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['untagged_interfaces'] == ['1.1', '2.1']
-
- def test_update_vlan_untag_interface(self, *args):
- set_module_args(dict(
- name='somevlan',
- untagged_interface=['2.1'],
- partition='Common',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- mutually_exclusive=self.spec.mutually_exclusive
- )
-
- # Override methods to force specific logic in the module to happen
- mm = ModuleManager(module=module)
-
- current = ApiParameters(params=load_fixture('load_vlan.json'))
- interfaces = load_fixture('load_vlan_interfaces.json')
- current.update({'interfaces': interfaces})
-
- mm.update_on_device = Mock(return_value=True)
- mm.exists = Mock(return_value=True)
- mm.read_current_from_device = Mock(return_value=current)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['untagged_interfaces'] == ['2.1']
-
- def test_update_vlan_tag_interface(self, *args):
- set_module_args(dict(
- name='somevlan',
- tagged_interface=['2.1'],
- partition='Common',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- mutually_exclusive=self.spec.mutually_exclusive
- )
-
- # Override methods to force specific logic in the module to happen
- mm = ModuleManager(module=module)
-
- current = ApiParameters(params=load_fixture('load_vlan.json'))
-
- mm.update_on_device = Mock(return_value=True)
- mm.exists = Mock(return_value=True)
- mm.read_current_from_device = Mock(return_value=current)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['tagged_interfaces'] == ['2.1']
-
- def test_update_vlan_description(self, *args):
- set_module_args(dict(
- name='somevlan',
- description='changed_that',
- partition='Common',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- mutually_exclusive=self.spec.mutually_exclusive
- )
-
- # Override methods to force specific logic in the module to happen
- mm = ModuleManager(module=module)
-
- current = ApiParameters(params=load_fixture('update_vlan_description.json'))
-
- mm.update_on_device = Mock(return_value=True)
- mm.exists = Mock(return_value=True)
- mm.read_current_from_device = Mock(return_value=current)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['description'] == 'changed_that'
diff --git a/test/units/modules/network/f5/test_bigip_wait.py b/test/units/modules/network/f5/test_bigip_wait.py
deleted file mode 100644
index ca09778f0b..0000000000
--- a/test/units/modules/network/f5/test_bigip_wait.py
+++ /dev/null
@@ -1,128 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright (c) 2017 F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigip_wait import Parameters
- from library.modules.bigip_wait import ModuleManager
- from library.modules.bigip_wait import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
- from test.units.compat.mock import patch
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigip_wait import Parameters
- from ansible.modules.network.f5.bigip_wait import ModuleManager
- from ansible.modules.network.f5.bigip_wait import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
- from units.compat.mock import patch
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- delay=3,
- timeout=500,
- sleep=10,
- msg='We timed out during waiting for BIG-IP :-('
- )
-
- p = Parameters(params=args)
- assert p.delay == 3
- assert p.timeout == 500
- assert p.sleep == 10
- assert p.msg == 'We timed out during waiting for BIG-IP :-('
-
- def test_module_string_parameters(self):
- args = dict(
- delay='3',
- timeout='500',
- sleep='10',
- msg='We timed out during waiting for BIG-IP :-('
- )
-
- p = Parameters(params=args)
- assert p.delay == 3
- assert p.timeout == 500
- assert p.sleep == 10
- assert p.msg == 'We timed out during waiting for BIG-IP :-('
-
-
-class TestManager(unittest.TestCase):
- def setUp(self):
- self.spec = ArgumentSpec()
- self.patcher1 = patch('time.sleep')
- self.patcher1.start()
-
- def tearDown(self):
- self.patcher1.stop()
-
- def test_wait_already_available(self, *args):
- set_module_args(dict(
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods to force specific logic in the module to happen
- mm = ModuleManager(module=module)
- mm._connect_to_device = Mock(return_value=True)
- mm._device_is_rebooting = Mock(return_value=False)
- mm._is_mprov_running_on_device = Mock(return_value=False)
- mm._get_client_connection = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is False
- assert results['elapsed'] == 0
diff --git a/test/units/modules/network/f5/test_bigiq_application_fasthttp.py b/test/units/modules/network/f5/test_bigiq_application_fasthttp.py
deleted file mode 100644
index 6700449450..0000000000
--- a/test/units/modules/network/f5/test_bigiq_application_fasthttp.py
+++ /dev/null
@@ -1,242 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigiq_application_fasthttp import ModuleParameters
- from library.modules.bigiq_application_fasthttp import ModuleManager
- from library.modules.bigiq_application_fasthttp import ArgumentSpec
- from library.module_utils.network.f5.common import F5ModuleError
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
- from test.units.compat.mock import patch
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigiq_application_fasthttp import ModuleParameters
- from ansible.modules.network.f5.bigiq_application_fasthttp import ModuleManager
- from ansible.modules.network.f5.bigiq_application_fasthttp import ArgumentSpec
- from ansible.module_utils.network.f5.common import F5ModuleError
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
- from units.compat.mock import patch
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- name='foo',
- description='my description',
- service_environment='bar',
- servers=[
- dict(
- address='1.2.3.4',
- port=8080
- ),
- dict(
- address='5.6.7.8',
- port=8000
- )
- ],
- inbound_virtual=dict(
- address='2.2.2.2',
- netmask='255.255.255.255',
- port=80
- )
- )
-
- p = ModuleParameters(params=args)
- assert p.name == 'foo'
- assert p.config_set_name == 'foo'
- assert p.sub_path == 'foo'
- assert p.http_profile == 'profile_http'
- assert p.service_environment == 'bar'
- assert len(p.servers) == 2
- assert 'address' in p.servers[0]
- assert 'port' in p.servers[0]
- assert 'address' in p.servers[1]
- assert 'port' in p.servers[1]
- assert p.servers[0]['address'] == '1.2.3.4'
- assert p.servers[0]['port'] == 8080
- assert p.servers[1]['address'] == '5.6.7.8'
- assert p.servers[1]['port'] == 8000
- assert 'address' in p.inbound_virtual
- assert 'netmask' in p.inbound_virtual
- assert 'port' in p.inbound_virtual
- assert p.inbound_virtual['address'] == '2.2.2.2'
- assert p.inbound_virtual['netmask'] == '255.255.255.255'
- assert p.inbound_virtual['port'] == 80
-
-
-class TestManager(unittest.TestCase):
- def setUp(self):
- self.spec = ArgumentSpec()
- self.patcher1 = patch('time.sleep')
- self.patcher1.start()
-
- try:
- self.p1 = patch('library.modules.bigiq_application_fasthttp.bigiq_version')
- self.p2 = patch('library.modules.bigiq_application_fasthttp.ModuleParameters.template_reference')
- self.p3 = patch('library.modules.bigiq_application_fasthttp.ModuleParameters.ssg_reference')
- self.p4 = patch('library.modules.bigiq_application_fasthttp.ModuleParameters.default_device_reference')
-
- self.m1 = self.p1.start()
- self.m2 = self.p2.start()
- self.m3 = self.p3.start()
- self.m4 = self.p4.start()
-
- self.m1.return_value = '6.1.0'
- self.m2.return_value = Mock(return_value='https://localhost/mgmt/foobar1')
- self.m3.return_value = Mock(return_value='https://localhost/mgmt/foobar2')
- self.m4.return_value = Mock(return_value='https://localhost/mgmt/foobar3')
-
- except Exception:
- self.p1 = patch('ansible.modules.network.f5.bigiq_application_fasthttp.bigiq_version')
- self.p2 = patch('ansible.modules.network.f5.bigiq_application_fasthttp.ModuleParameters.template_reference')
- self.p3 = patch('ansible.modules.network.f5.bigiq_application_fasthttp.ModuleParameters.ssg_reference')
- self.p4 = patch('ansible.modules.network.f5.bigiq_application_fasthttp.ModuleParameters.default_device_reference')
-
- self.m1 = self.p1.start()
- self.m2 = self.p2.start()
- self.m3 = self.p3.start()
- self.m4 = self.p4.start()
-
- self.m1.return_value = '6.1.0'
- self.m2.return_value = Mock(return_value='https://localhost/mgmt/foobar1')
- self.m3.return_value = Mock(return_value='https://localhost/mgmt/foobar2')
- self.m4.return_value = Mock(return_value='https://localhost/mgmt/foobar3')
-
- def tearDown(self):
- self.patcher1.stop()
- self.p1.stop()
- self.p2.stop()
- self.p3.stop()
- self.p4.stop()
-
- def test_create(self, *args):
- set_module_args(dict(
- name='foo',
- description='my description',
- service_environment='bar',
- servers=[
- dict(
- address='1.2.3.4',
- port=8080
- ),
- dict(
- address='5.6.7.8',
- port=8000
- )
- ],
- inbound_virtual=dict(
- address='2.2.2.2',
- netmask='255.255.255.255',
- port=80
- ),
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods to force specific logic in the module to happen
- mm = ModuleManager(module=module)
- mm.check_bigiq_version = Mock(return_value=True)
- mm.has_no_service_environment = Mock(return_value=False)
- mm.wait_for_apply_template_task = Mock(return_value=True)
-
- mm.create_on_device = Mock(return_value=True)
- mm.exists = Mock(side_effect=[False, True])
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['description'] == 'my description'
-
- def test_bigiq_version_raises(self):
- set_module_args(dict(
- name='foo',
- description='my description',
- service_environment='bar',
- servers=[
- dict(
- address='1.2.3.4',
- port=8080
- ),
- dict(
- address='5.6.7.8',
- port=8000
- )
- ],
- inbound_virtual=dict(
- address='2.2.2.2',
- netmask='255.255.255.255',
- port=80
- ),
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- msg = 'Module supports only BIGIQ version 6.0.x or lower.'
- # Override methods to force specific logic in the module to happen
- mm = ModuleManager(module=module)
-
- with pytest.raises(F5ModuleError) as err:
- mm.exec_module()
- assert str(err.value) == msg
diff --git a/test/units/modules/network/f5/test_bigiq_application_fastl4_tcp.py b/test/units/modules/network/f5/test_bigiq_application_fastl4_tcp.py
deleted file mode 100644
index cd057565d6..0000000000
--- a/test/units/modules/network/f5/test_bigiq_application_fastl4_tcp.py
+++ /dev/null
@@ -1,235 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigiq_application_fastl4_tcp import ModuleParameters
- from library.modules.bigiq_application_fastl4_tcp import ModuleManager
- from library.modules.bigiq_application_fastl4_tcp import ArgumentSpec
- from library.module_utils.network.f5.common import F5ModuleError
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
- from test.units.compat.mock import patch
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigiq_application_fastl4_tcp import ModuleParameters
- from ansible.modules.network.f5.bigiq_application_fastl4_tcp import ModuleManager
- from ansible.modules.network.f5.bigiq_application_fastl4_tcp import ArgumentSpec
- from ansible.module_utils.network.f5.common import F5ModuleError
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
- from units.compat.mock import patch
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- name='foo',
- description='my description',
- service_environment='bar',
- servers=[
- dict(
- address='1.2.3.4',
- port=8080
- ),
- dict(
- address='5.6.7.8',
- port=8000
- )
- ],
- inbound_virtual=dict(
- address='2.2.2.2',
- netmask='255.255.255.255',
- port=80
- )
- )
-
- p = ModuleParameters(params=args)
- assert p.name == 'foo'
- assert p.config_set_name == 'foo'
- assert p.sub_path == 'foo'
- assert p.http_profile == 'profile_http'
- assert p.service_environment == 'bar'
- assert len(p.servers) == 2
- assert 'address' in p.servers[0]
- assert 'port' in p.servers[0]
- assert 'address' in p.servers[1]
- assert 'port' in p.servers[1]
- assert p.servers[0]['address'] == '1.2.3.4'
- assert p.servers[0]['port'] == 8080
- assert p.servers[1]['address'] == '5.6.7.8'
- assert p.servers[1]['port'] == 8000
- assert 'address' in p.inbound_virtual
- assert 'netmask' in p.inbound_virtual
- assert 'port' in p.inbound_virtual
- assert p.inbound_virtual['address'] == '2.2.2.2'
- assert p.inbound_virtual['netmask'] == '255.255.255.255'
- assert p.inbound_virtual['port'] == 80
-
-
-class TestManager(unittest.TestCase):
- def setUp(self):
- self.spec = ArgumentSpec()
- self.patcher1 = patch('time.sleep')
- self.patcher1.start()
-
- try:
- self.p1 = patch('library.modules.bigiq_application_fastl4_tcp.bigiq_version')
- self.p2 = patch('library.modules.bigiq_application_fastl4_tcp.ModuleParameters.template_reference')
- self.p3 = patch('library.modules.bigiq_application_fastl4_tcp.ModuleParameters.default_device_reference')
-
- self.m1 = self.p1.start()
- self.m2 = self.p2.start()
- self.m3 = self.p3.start()
-
- self.m1.return_value = '6.1.0'
- self.m2.return_value = Mock(return_value='https://localhost/mgmt/foobar1')
- self.m3.return_value = Mock(return_value='https://localhost/mgmt/foobar3')
-
- except Exception:
- self.p1 = patch('ansible.modules.network.f5.bigiq_application_fastl4_tcp.bigiq_version')
- self.p2 = patch('ansible.modules.network.f5.bigiq_application_fastl4_tcp.ModuleParameters.template_reference')
- self.p3 = patch('ansible.modules.network.f5.bigiq_application_fastl4_tcp.ModuleParameters.default_device_reference')
-
- self.m1 = self.p1.start()
- self.m2 = self.p2.start()
- self.m3 = self.p3.start()
-
- self.m1.return_value = '6.1.0'
- self.m2.return_value = Mock(return_value='https://localhost/mgmt/foobar1')
- self.m3.return_value = Mock(return_value='https://localhost/mgmt/foobar3')
-
- def tearDown(self):
- self.patcher1.stop()
- self.p1.stop()
- self.p2.stop()
- self.p3.stop()
-
- def test_create(self, *args):
- set_module_args(dict(
- name='foo',
- description='my description',
- service_environment='bar',
- servers=[
- dict(
- address='1.2.3.4',
- port=8080
- ),
- dict(
- address='5.6.7.8',
- port=8000
- )
- ],
- inbound_virtual=dict(
- address='2.2.2.2',
- netmask='255.255.255.255',
- port=80
- ),
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods to force specific logic in the module to happen
- mm = ModuleManager(module=module)
- mm.check_bigiq_version = Mock(return_value=True)
- mm.has_no_service_environment = Mock(return_value=False)
- mm.wait_for_apply_template_task = Mock(return_value=True)
-
- mm.create_on_device = Mock(return_value=True)
- mm.exists = Mock(side_effect=[False, True])
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['description'] == 'my description'
-
- def test_bigiq_version_raises(self):
- set_module_args(dict(
- name='foo',
- description='my description',
- service_environment='bar',
- servers=[
- dict(
- address='1.2.3.4',
- port=8080
- ),
- dict(
- address='5.6.7.8',
- port=8000
- )
- ],
- inbound_virtual=dict(
- address='2.2.2.2',
- netmask='255.255.255.255',
- port=80
- ),
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- msg = 'Module supports only BIGIQ version 6.0.x or lower.'
- # Override methods to force specific logic in the module to happen
- mm = ModuleManager(module=module)
-
- with pytest.raises(F5ModuleError) as err:
- mm.exec_module()
- assert str(err.value) == msg
diff --git a/test/units/modules/network/f5/test_bigiq_application_fastl4_udp.py b/test/units/modules/network/f5/test_bigiq_application_fastl4_udp.py
deleted file mode 100644
index 934876b36d..0000000000
--- a/test/units/modules/network/f5/test_bigiq_application_fastl4_udp.py
+++ /dev/null
@@ -1,235 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigiq_application_fastl4_udp import ModuleParameters
- from library.modules.bigiq_application_fastl4_udp import ModuleManager
- from library.modules.bigiq_application_fastl4_udp import ArgumentSpec
- from library.module_utils.network.f5.common import F5ModuleError
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
- from test.units.compat.mock import patch
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigiq_application_fastl4_udp import ModuleParameters
- from ansible.modules.network.f5.bigiq_application_fastl4_udp import ModuleManager
- from ansible.modules.network.f5.bigiq_application_fastl4_udp import ArgumentSpec
- from ansible.module_utils.network.f5.common import F5ModuleError
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
- from units.compat.mock import patch
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- name='foo',
- description='my description',
- service_environment='bar',
- servers=[
- dict(
- address='1.2.3.4',
- port=8080
- ),
- dict(
- address='5.6.7.8',
- port=8000
- )
- ],
- inbound_virtual=dict(
- address='2.2.2.2',
- netmask='255.255.255.255',
- port=80
- )
- )
-
- p = ModuleParameters(params=args)
- assert p.name == 'foo'
- assert p.config_set_name == 'foo'
- assert p.sub_path == 'foo'
- assert p.http_profile == 'profile_http'
- assert p.service_environment == 'bar'
- assert len(p.servers) == 2
- assert 'address' in p.servers[0]
- assert 'port' in p.servers[0]
- assert 'address' in p.servers[1]
- assert 'port' in p.servers[1]
- assert p.servers[0]['address'] == '1.2.3.4'
- assert p.servers[0]['port'] == 8080
- assert p.servers[1]['address'] == '5.6.7.8'
- assert p.servers[1]['port'] == 8000
- assert 'address' in p.inbound_virtual
- assert 'netmask' in p.inbound_virtual
- assert 'port' in p.inbound_virtual
- assert p.inbound_virtual['address'] == '2.2.2.2'
- assert p.inbound_virtual['netmask'] == '255.255.255.255'
- assert p.inbound_virtual['port'] == 80
-
-
-class TestManager(unittest.TestCase):
- def setUp(self):
- self.spec = ArgumentSpec()
- self.patcher1 = patch('time.sleep')
- self.patcher1.start()
-
- try:
- self.p1 = patch('library.modules.bigiq_application_fastl4_udp.bigiq_version')
- self.p2 = patch('library.modules.bigiq_application_fastl4_udp.ModuleParameters.template_reference')
- self.p3 = patch('library.modules.bigiq_application_fastl4_udp.ModuleParameters.default_device_reference')
-
- self.m1 = self.p1.start()
- self.m2 = self.p2.start()
- self.m3 = self.p3.start()
-
- self.m1.return_value = '6.1.0'
- self.m2.return_value = Mock(return_value='https://localhost/mgmt/foobar1')
- self.m3.return_value = Mock(return_value='https://localhost/mgmt/foobar3')
-
- except Exception:
- self.p1 = patch('ansible.modules.network.f5.bigiq_application_fastl4_udp.bigiq_version')
- self.p2 = patch('ansible.modules.network.f5.bigiq_application_fastl4_udp.ModuleParameters.template_reference')
- self.p3 = patch('ansible.modules.network.f5.bigiq_application_fastl4_udp.ModuleParameters.default_device_reference')
-
- self.m1 = self.p1.start()
- self.m2 = self.p2.start()
- self.m3 = self.p3.start()
-
- self.m1.return_value = '6.1.0'
- self.m2.return_value = Mock(return_value='https://localhost/mgmt/foobar1')
- self.m3.return_value = Mock(return_value='https://localhost/mgmt/foobar3')
-
- def tearDown(self):
- self.patcher1.stop()
- self.p1.stop()
- self.p2.stop()
- self.p3.stop()
-
- def test_create(self, *args):
- set_module_args(dict(
- name='foo',
- description='my description',
- service_environment='bar',
- servers=[
- dict(
- address='1.2.3.4',
- port=8080
- ),
- dict(
- address='5.6.7.8',
- port=8000
- )
- ],
- inbound_virtual=dict(
- address='2.2.2.2',
- netmask='255.255.255.255',
- port=80
- ),
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods to force specific logic in the module to happen
- mm = ModuleManager(module=module)
- mm.check_bigiq_version = Mock(return_value=True)
- mm.has_no_service_environment = Mock(return_value=False)
- mm.wait_for_apply_template_task = Mock(return_value=True)
-
- mm.create_on_device = Mock(return_value=True)
- mm.exists = Mock(side_effect=[False, True])
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['description'] == 'my description'
-
- def test_bigiq_version_raises(self):
- set_module_args(dict(
- name='foo',
- description='my description',
- service_environment='bar',
- servers=[
- dict(
- address='1.2.3.4',
- port=8080
- ),
- dict(
- address='5.6.7.8',
- port=8000
- )
- ],
- inbound_virtual=dict(
- address='2.2.2.2',
- netmask='255.255.255.255',
- port=80
- ),
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- msg = 'Module supports only BIGIQ version 6.0.x or lower.'
- # Override methods to force specific logic in the module to happen
- mm = ModuleManager(module=module)
-
- with pytest.raises(F5ModuleError) as err:
- mm.exec_module()
- assert str(err.value) == msg
diff --git a/test/units/modules/network/f5/test_bigiq_application_http.py b/test/units/modules/network/f5/test_bigiq_application_http.py
deleted file mode 100644
index 5bb25af2cb..0000000000
--- a/test/units/modules/network/f5/test_bigiq_application_http.py
+++ /dev/null
@@ -1,242 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigiq_application_http import ModuleParameters
- from library.modules.bigiq_application_http import ModuleManager
- from library.modules.bigiq_application_http import ArgumentSpec
- from library.module_utils.network.f5.common import F5ModuleError
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
- from test.units.compat.mock import patch
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigiq_application_http import ModuleParameters
- from ansible.modules.network.f5.bigiq_application_http import ModuleManager
- from ansible.modules.network.f5.bigiq_application_http import ArgumentSpec
- from ansible.module_utils.network.f5.common import F5ModuleError
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
- from units.compat.mock import patch
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- name='foo',
- description='my description',
- service_environment='bar',
- servers=[
- dict(
- address='1.2.3.4',
- port=8080
- ),
- dict(
- address='5.6.7.8',
- port=8000
- )
- ],
- inbound_virtual=dict(
- address='2.2.2.2',
- netmask='255.255.255.255',
- port=80
- )
- )
-
- p = ModuleParameters(params=args)
- assert p.name == 'foo'
- assert p.config_set_name == 'foo'
- assert p.sub_path == 'foo'
- assert p.http_profile == 'profile_http'
- assert p.service_environment == 'bar'
- assert len(p.servers) == 2
- assert 'address' in p.servers[0]
- assert 'port' in p.servers[0]
- assert 'address' in p.servers[1]
- assert 'port' in p.servers[1]
- assert p.servers[0]['address'] == '1.2.3.4'
- assert p.servers[0]['port'] == 8080
- assert p.servers[1]['address'] == '5.6.7.8'
- assert p.servers[1]['port'] == 8000
- assert 'address' in p.inbound_virtual
- assert 'netmask' in p.inbound_virtual
- assert 'port' in p.inbound_virtual
- assert p.inbound_virtual['address'] == '2.2.2.2'
- assert p.inbound_virtual['netmask'] == '255.255.255.255'
- assert p.inbound_virtual['port'] == 80
-
-
-class TestManager(unittest.TestCase):
- def setUp(self):
- self.spec = ArgumentSpec()
- self.patcher1 = patch('time.sleep')
- self.patcher1.start()
-
- try:
- self.p1 = patch('library.modules.bigiq_application_http.bigiq_version')
- self.p2 = patch('library.modules.bigiq_application_http.ModuleParameters.template_reference')
- self.p3 = patch('library.modules.bigiq_application_http.ModuleParameters.ssg_reference')
- self.p4 = patch('library.modules.bigiq_application_http.ModuleParameters.default_device_reference')
-
- self.m1 = self.p1.start()
- self.m2 = self.p2.start()
- self.m3 = self.p3.start()
- self.m4 = self.p4.start()
-
- self.m1.return_value = '6.1.0'
- self.m2.return_value = Mock(return_value='https://localhost/mgmt/foobar1')
- self.m3.return_value = Mock(return_value='https://localhost/mgmt/foobar2')
- self.m4.return_value = Mock(return_value='https://localhost/mgmt/foobar3')
-
- except Exception:
- self.p1 = patch('ansible.modules.network.f5.bigiq_application_http.bigiq_version')
- self.p2 = patch('ansible.modules.network.f5.bigiq_application_http.ModuleParameters.template_reference')
- self.p3 = patch('ansible.modules.network.f5.bigiq_application_http.ModuleParameters.ssg_reference')
- self.p4 = patch('ansible.modules.network.f5.bigiq_application_http.ModuleParameters.default_device_reference')
-
- self.m1 = self.p1.start()
- self.m2 = self.p2.start()
- self.m3 = self.p3.start()
- self.m4 = self.p4.start()
-
- self.m1.return_value = '6.1.0'
- self.m2.return_value = Mock(return_value='https://localhost/mgmt/foobar1')
- self.m3.return_value = Mock(return_value='https://localhost/mgmt/foobar2')
- self.m4.return_value = Mock(return_value='https://localhost/mgmt/foobar3')
-
- def tearDown(self):
- self.patcher1.stop()
- self.p1.stop()
- self.p2.stop()
- self.p3.stop()
- self.p4.stop()
-
- def test_create(self, *args):
- set_module_args(dict(
- name='foo',
- description='my description',
- service_environment='bar',
- servers=[
- dict(
- address='1.2.3.4',
- port=8080
- ),
- dict(
- address='5.6.7.8',
- port=8000
- )
- ],
- inbound_virtual=dict(
- address='2.2.2.2',
- netmask='255.255.255.255',
- port=80
- ),
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods to force specific logic in the module to happen
- mm = ModuleManager(module=module)
- mm.check_bigiq_version = Mock(return_value=True)
- mm.has_no_service_environment = Mock(return_value=False)
- mm.wait_for_apply_template_task = Mock(return_value=True)
-
- mm.create_on_device = Mock(return_value=True)
- mm.exists = Mock(side_effect=[False, True])
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['description'] == 'my description'
-
- def test_bigiq_version_raises(self):
- set_module_args(dict(
- name='foo',
- description='my description',
- service_environment='bar',
- servers=[
- dict(
- address='1.2.3.4',
- port=8080
- ),
- dict(
- address='5.6.7.8',
- port=8000
- )
- ],
- inbound_virtual=dict(
- address='2.2.2.2',
- netmask='255.255.255.255',
- port=80
- ),
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- msg = 'Module supports only BIGIQ version 6.0.x or lower.'
- # Override methods to force specific logic in the module to happen
- mm = ModuleManager(module=module)
-
- with pytest.raises(F5ModuleError) as err:
- mm.exec_module()
- assert str(err.value) == msg
diff --git a/test/units/modules/network/f5/test_bigiq_application_https_offload.py b/test/units/modules/network/f5/test_bigiq_application_https_offload.py
deleted file mode 100644
index ebac1d8206..0000000000
--- a/test/units/modules/network/f5/test_bigiq_application_https_offload.py
+++ /dev/null
@@ -1,260 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigiq_application_https_offload import ModuleParameters
- from library.modules.bigiq_application_https_offload import ModuleManager
- from library.modules.bigiq_application_https_offload import ArgumentSpec
- from library.module_utils.network.f5.common import F5ModuleError
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
- from test.units.compat.mock import patch
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigiq_application_https_offload import ModuleParameters
- from ansible.modules.network.f5.bigiq_application_https_offload import ModuleManager
- from ansible.modules.network.f5.bigiq_application_https_offload import ArgumentSpec
- from ansible.module_utils.network.f5.common import F5ModuleError
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
- from units.compat.mock import patch
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- name='foo',
- description='my description',
- service_environment='bar',
- servers=[
- dict(
- address='1.2.3.4',
- port=8080
- ),
- dict(
- address='5.6.7.8',
- port=8000
- )
- ],
- inbound_virtual=dict(
- address='2.2.2.2',
- netmask='255.255.255.255',
- port=80
- ),
- redirect_virtual=dict(
- address='3.3.3.3',
- netmask='255.255.255.255',
- port=80
- )
- )
-
- p = ModuleParameters(params=args)
- assert p.name == 'foo'
- assert p.config_set_name == 'foo'
- assert p.sub_path == 'foo'
- assert p.http_profile == 'profile_http'
- assert p.service_environment == 'bar'
- assert len(p.servers) == 2
- assert 'address' in p.servers[0]
- assert 'port' in p.servers[0]
- assert 'address' in p.servers[1]
- assert 'port' in p.servers[1]
- assert p.servers[0]['address'] == '1.2.3.4'
- assert p.servers[0]['port'] == 8080
- assert p.servers[1]['address'] == '5.6.7.8'
- assert p.servers[1]['port'] == 8000
- assert 'address' in p.inbound_virtual
- assert 'netmask' in p.inbound_virtual
- assert 'port' in p.inbound_virtual
- assert p.inbound_virtual['address'] == '2.2.2.2'
- assert p.inbound_virtual['netmask'] == '255.255.255.255'
- assert p.inbound_virtual['port'] == 80
- assert 'address' in p.redirect_virtual
- assert 'netmask' in p.redirect_virtual
- assert 'port' in p.redirect_virtual
- assert p.redirect_virtual['address'] == '3.3.3.3'
- assert p.redirect_virtual['netmask'] == '255.255.255.255'
- assert p.redirect_virtual['port'] == 80
-
-
-class TestManager(unittest.TestCase):
- def setUp(self):
- self.spec = ArgumentSpec()
- self.patcher1 = patch('time.sleep')
- self.patcher1.start()
-
- try:
- self.p1 = patch('library.modules.bigiq_application_https_offload.bigiq_version')
- self.p2 = patch('library.modules.bigiq_application_https_offload.ModuleParameters.template_reference')
- self.p3 = patch('library.modules.bigiq_application_https_offload.ModuleParameters.ssg_reference')
- self.p4 = patch('library.modules.bigiq_application_https_offload.ModuleParameters.default_device_reference')
-
- self.m1 = self.p1.start()
- self.m2 = self.p2.start()
- self.m3 = self.p3.start()
- self.m4 = self.p4.start()
-
- self.m1.return_value = '6.1.0'
- self.m2.return_value = Mock(return_value='https://localhost/mgmt/foobar1')
- self.m3.return_value = Mock(return_value='https://localhost/mgmt/foobar2')
- self.m4.return_value = Mock(return_value='https://localhost/mgmt/foobar3')
-
- except Exception:
- self.p1 = patch('ansible.modules.network.f5.bigiq_application_https_offload.bigiq_version')
- self.p2 = patch('ansible.modules.network.f5.bigiq_application_https_offload.ModuleParameters.template_reference')
- self.p3 = patch('ansible.modules.network.f5.bigiq_application_https_offload.ModuleParameters.ssg_reference')
- self.p4 = patch('ansible.modules.network.f5.bigiq_application_https_offload.ModuleParameters.default_device_reference')
-
- self.m1 = self.p1.start()
- self.m2 = self.p2.start()
- self.m3 = self.p3.start()
- self.m4 = self.p4.start()
-
- self.m1.return_value = '6.1.0'
- self.m2.return_value = Mock(return_value='https://localhost/mgmt/foobar1')
- self.m3.return_value = Mock(return_value='https://localhost/mgmt/foobar2')
- self.m4.return_value = Mock(return_value='https://localhost/mgmt/foobar3')
-
- def tearDown(self):
- self.patcher1.stop()
- self.p1.stop()
- self.p2.stop()
- self.p3.stop()
- self.p4.stop()
-
- def test_create(self, *args):
- set_module_args(dict(
- name='foo',
- description='my description',
- service_environment='bar',
- servers=[
- dict(
- address='1.2.3.4',
- port=8080
- ),
- dict(
- address='5.6.7.8',
- port=8000
- )
- ],
- inbound_virtual=dict(
- address='2.2.2.2',
- netmask='255.255.255.255',
- port=80
- ),
- redirect_virtual=dict(
- address='3.3.3.3',
- netmask='255.255.255.255',
- port=80
- ),
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- mutually_exclusive=self.spec.mutually_exclusive
- )
-
- # Override methods to force specific logic in the module to happen
- mm = ModuleManager(module=module)
- mm.check_bigiq_version = Mock(return_value=True)
- mm.has_no_service_environment = Mock(return_value=False)
- mm.wait_for_apply_template_task = Mock(return_value=True)
-
- mm.create_on_device = Mock(return_value=True)
- mm.exists = Mock(side_effect=[False, True])
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['description'] == 'my description'
-
- def test_bigiq_version_raises(self):
- set_module_args(dict(
- name='foo',
- description='my description',
- service_environment='bar',
- servers=[
- dict(
- address='1.2.3.4',
- port=8080
- ),
- dict(
- address='5.6.7.8',
- port=8000
- )
- ],
- inbound_virtual=dict(
- address='2.2.2.2',
- netmask='255.255.255.255',
- port=80
- ),
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- mutually_exclusive=self.spec.mutually_exclusive
- )
-
- msg = 'Module supports only BIGIQ version 6.0.x or lower.'
- # Override methods to force specific logic in the module to happen
- mm = ModuleManager(module=module)
-
- with pytest.raises(F5ModuleError) as err:
- mm.exec_module()
- assert str(err.value) == msg
diff --git a/test/units/modules/network/f5/test_bigiq_application_https_waf.py b/test/units/modules/network/f5/test_bigiq_application_https_waf.py
deleted file mode 100644
index 0a6abfdab6..0000000000
--- a/test/units/modules/network/f5/test_bigiq_application_https_waf.py
+++ /dev/null
@@ -1,268 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigiq_application_https_waf import ModuleParameters
- from library.modules.bigiq_application_https_waf import ModuleManager
- from library.modules.bigiq_application_https_waf import ArgumentSpec
- from library.module_utils.network.f5.common import F5ModuleError
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
- from test.units.compat.mock import patch
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigiq_application_https_waf import ModuleParameters
- from ansible.modules.network.f5.bigiq_application_https_waf import ModuleManager
- from ansible.modules.network.f5.bigiq_application_https_waf import ArgumentSpec
- from ansible.module_utils.network.f5.common import F5ModuleError
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
- from units.compat.mock import patch
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- name='foo',
- description='my description',
- service_environment='bar',
- servers=[
- dict(
- address='1.2.3.4',
- port=8080
- ),
- dict(
- address='5.6.7.8',
- port=8000
- )
- ],
- inbound_virtual=dict(
- address='2.2.2.2',
- netmask='255.255.255.255',
- port=80
- ),
- redirect_virtual=dict(
- address='3.3.3.3',
- netmask='255.255.255.255',
- port=80
- ),
- domain_names=[
- 'foo.baz.com',
- 'bar.baz.com'
- ]
- )
-
- p = ModuleParameters(params=args)
- assert p.name == 'foo'
- assert p.config_set_name == 'foo'
- assert p.sub_path == 'foo'
- assert p.http_profile == 'profile_http'
- assert p.service_environment == 'bar'
- assert len(p.servers) == 2
- assert 'address' in p.servers[0]
- assert 'port' in p.servers[0]
- assert 'address' in p.servers[1]
- assert 'port' in p.servers[1]
- assert p.servers[0]['address'] == '1.2.3.4'
- assert p.servers[0]['port'] == 8080
- assert p.servers[1]['address'] == '5.6.7.8'
- assert p.servers[1]['port'] == 8000
- assert 'address' in p.inbound_virtual
- assert 'netmask' in p.inbound_virtual
- assert 'port' in p.inbound_virtual
- assert p.inbound_virtual['address'] == '2.2.2.2'
- assert p.inbound_virtual['netmask'] == '255.255.255.255'
- assert p.inbound_virtual['port'] == 80
- assert 'address' in p.redirect_virtual
- assert 'netmask' in p.redirect_virtual
- assert 'port' in p.redirect_virtual
- assert p.redirect_virtual['address'] == '3.3.3.3'
- assert p.redirect_virtual['netmask'] == '255.255.255.255'
- assert p.redirect_virtual['port'] == 80
-
-
-class TestManager(unittest.TestCase):
- def setUp(self):
- self.spec = ArgumentSpec()
- self.patcher1 = patch('time.sleep')
- self.patcher1.start()
-
- try:
- self.p1 = patch('library.modules.bigiq_application_https_waf.bigiq_version')
- self.p2 = patch('library.modules.bigiq_application_https_waf.ModuleParameters.template_reference')
- self.p3 = patch('library.modules.bigiq_application_https_waf.ModuleParameters.ssg_reference')
- self.p4 = patch('library.modules.bigiq_application_https_waf.ModuleParameters.default_device_reference')
-
- self.m1 = self.p1.start()
- self.m2 = self.p2.start()
- self.m3 = self.p3.start()
- self.m4 = self.p4.start()
-
- self.m1.return_value = '6.1.0'
- self.m2.return_value = Mock(return_value='https://localhost/mgmt/foobar1')
- self.m3.return_value = Mock(return_value='https://localhost/mgmt/foobar2')
- self.m4.return_value = Mock(return_value='https://localhost/mgmt/foobar3')
-
- except Exception:
- self.p1 = patch('ansible.modules.network.f5.bigiq_application_https_waf.bigiq_version')
- self.p2 = patch('ansible.modules.network.f5.bigiq_application_https_waf.ModuleParameters.template_reference')
- self.p3 = patch('ansible.modules.network.f5.bigiq_application_https_waf.ModuleParameters.ssg_reference')
- self.p4 = patch('ansible.modules.network.f5.bigiq_application_https_waf.ModuleParameters.default_device_reference')
-
- self.m1 = self.p1.start()
- self.m2 = self.p2.start()
- self.m3 = self.p3.start()
- self.m4 = self.p4.start()
-
- self.m1.return_value = '6.1.0'
- self.m2.return_value = Mock(return_value='https://localhost/mgmt/foobar1')
- self.m3.return_value = Mock(return_value='https://localhost/mgmt/foobar2')
- self.m4.return_value = Mock(return_value='https://localhost/mgmt/foobar3')
-
- def tearDown(self):
- self.patcher1.stop()
- self.p1.stop()
- self.p2.stop()
- self.p3.stop()
- self.p4.stop()
-
- def test_create(self, *args):
- set_module_args(dict(
- name='foo',
- description='my description',
- service_environment='bar',
- servers=[
- dict(
- address='1.2.3.4',
- port=8080
- ),
- dict(
- address='5.6.7.8',
- port=8000
- )
- ],
- inbound_virtual=dict(
- address='2.2.2.2',
- netmask='255.255.255.255',
- port=80
- ),
- redirect_virtual=dict(
- address='3.3.3.3',
- netmask='255.255.255.255',
- port=80
- ),
- domain_names=[
- 'foo.baz.com',
- 'bar.baz.com'
- ],
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- mutually_exclusive=self.spec.mutually_exclusive
- )
-
- # Override methods to force specific logic in the module to happen
- mm = ModuleManager(module=module)
- mm.check_bigiq_version = Mock(return_value=True)
- mm.has_no_service_environment = Mock(return_value=False)
- mm.wait_for_apply_template_task = Mock(return_value=True)
-
- mm.create_on_device = Mock(return_value=True)
- mm.exists = Mock(side_effect=[False, True])
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['description'] == 'my description'
-
- def test_bigiq_version_raises(self):
- set_module_args(dict(
- name='foo',
- description='my description',
- service_environment='bar',
- servers=[
- dict(
- address='1.2.3.4',
- port=8080
- ),
- dict(
- address='5.6.7.8',
- port=8000
- )
- ],
- inbound_virtual=dict(
- address='2.2.2.2',
- netmask='255.255.255.255',
- port=80
- ),
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- mutually_exclusive=self.spec.mutually_exclusive
- )
-
- msg = 'Module supports only BIGIQ version 6.0.x or lower.'
- # Override methods to force specific logic in the module to happen
- mm = ModuleManager(module=module)
-
- with pytest.raises(F5ModuleError) as err:
- mm.exec_module()
- assert str(err.value) == msg
diff --git a/test/units/modules/network/f5/test_bigiq_device_discovery.py b/test/units/modules/network/f5/test_bigiq_device_discovery.py
deleted file mode 100644
index efcd3769b4..0000000000
--- a/test/units/modules/network/f5/test_bigiq_device_discovery.py
+++ /dev/null
@@ -1,134 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2019, F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigiq_device_discovery import ApiParameters
- from library.modules.bigiq_device_discovery import ModuleParameters
- from library.modules.bigiq_device_discovery import ModuleManager
- from library.modules.bigiq_device_discovery import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
- from test.units.compat.mock import patch
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigiq_device_discovery import ApiParameters
- from ansible.modules.network.f5.bigiq_device_discovery import ModuleParameters
- from ansible.modules.network.f5.bigiq_device_discovery import ModuleManager
- from ansible.modules.network.f5.bigiq_device_discovery import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
- from units.compat.mock import patch
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- device_address='192.168.1.1',
- device_username='admin',
- device_password='admin',
- device_port=10443,
- ha_name='bazfoo',
- use_bigiq_sync='yes',
- modules=['asm', 'ltm', 'security_shared']
- )
-
- p = ModuleParameters(params=args)
- assert p.device_address == '192.168.1.1'
- assert p.device_username == 'admin'
- assert p.device_password == 'admin'
- assert p.device_port == 10443
- assert p.ha_name == 'bazfoo'
- assert p.use_bigiq_sync is True
- assert p.modules == ['asm', 'adc_core', 'security_shared']
-
- def test_api_parameters(self):
- args = load_fixture('load_machine_resolver.json')
-
- p = ApiParameters(params=args)
- assert sorted(p.modules) == sorted(['asm', 'adc_core', 'security_shared'])
-
-
-class TestManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
- self.patcher1 = patch('time.sleep')
- self.patcher1.start()
-
- def tearDown(self):
- self.patcher1.stop()
-
- def test_create(self, *args):
- set_module_args(dict(
- device_address='192.168.1.1',
- device_username='admin',
- device_password='admin',
- modules=['asm', 'ltm', 'security_shared'],
- provider=dict(
- password='password',
- server='localhost',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- required_if=self.spec.required_if
- )
- mm = ModuleManager(module=module)
-
- # Override methods to force specific logic in the module to happen
- mm.exists = Mock(side_effect=[False, True])
- mm.set_trust_with_device = Mock(return_value=True)
- mm.discover_on_device = Mock(return_value=True)
- mm.import_modules_on_device = Mock(return_value=True)
- mm.check_bigiq_version = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
diff --git a/test/units/modules/network/f5/test_bigiq_device_info.py b/test/units/modules/network/f5/test_bigiq_device_info.py
deleted file mode 100644
index 14273dfb38..0000000000
--- a/test/units/modules/network/f5/test_bigiq_device_info.py
+++ /dev/null
@@ -1,106 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2018, F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigiq_device_info import Parameters
- from library.modules.bigiq_device_info import SystemInfoFactManager
- from library.modules.bigiq_device_info import ModuleManager
- from library.modules.bigiq_device_info import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigiq_device_info import Parameters
- from ansible.modules.network.f5.bigiq_device_info import SystemInfoFactManager
- from ansible.modules.network.f5.bigiq_device_info import ModuleManager
- from ansible.modules.network.f5.bigiq_device_info import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- gather_subset=['system-info'],
- )
- p = Parameters(params=args)
- assert p.gather_subset == ['system-info']
-
-
-class TestManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
-
- def test_get_facts(self, *args):
- set_module_args(dict(
- gather_subset=['system-info'],
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- fixture1 = load_fixture('load_shared_system_setup_1.json')
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- tm = SystemInfoFactManager(module=module)
- tm.read_collection_from_device = Mock(return_value=fixture1)
-
- # Override methods to force specific logic in the module to happen
- mm = ModuleManager(module=module)
- mm.get_manager = Mock(return_value=tm)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert 'system_info' in results
diff --git a/test/units/modules/network/f5/test_bigiq_regkey_license.py b/test/units/modules/network/f5/test_bigiq_regkey_license.py
deleted file mode 100644
index f83af44de1..0000000000
--- a/test/units/modules/network/f5/test_bigiq_regkey_license.py
+++ /dev/null
@@ -1,125 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigiq_regkey_license import ModuleParameters
- from library.modules.bigiq_regkey_license import ApiParameters
- from library.modules.bigiq_regkey_license import ModuleManager
- from library.modules.bigiq_regkey_license import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
- from test.units.compat.mock import patch
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigiq_regkey_license import ModuleParameters
- from ansible.modules.network.f5.bigiq_regkey_license import ApiParameters
- from ansible.modules.network.f5.bigiq_regkey_license import ModuleManager
- from ansible.modules.network.f5.bigiq_regkey_license import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
- from units.compat.mock import patch
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- regkey_pool='foo',
- license_key='XXXX-XXXX-XXXX-XXXX-XXXX',
- accept_eula=True,
- description='this is a description'
- )
-
- p = ModuleParameters(params=args)
- assert p.regkey_pool == 'foo'
- assert p.license_key == 'XXXX-XXXX-XXXX-XXXX-XXXX'
- assert p.accept_eula is True
- assert p.description == 'this is a description'
-
- def test_api_parameters(self):
- args = load_fixture('load_regkey_license_key.json')
-
- p = ApiParameters(params=args)
- assert p.description == 'foo bar baz'
-
-
-class TestManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
- self.patcher1 = patch('time.sleep')
- self.patcher1.start()
-
- def tearDown(self):
- self.patcher1.stop()
-
- def test_create(self, *args):
- set_module_args(dict(
- regkey_pool='foo',
- license_key='XXXX-XXXX-XXXX-XXXX-XXXX',
- accept_eula=True,
- description='this is a description',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
- mm = ModuleManager(module=module)
-
- # Override methods to force specific logic in the module to happen
- mm.exists = Mock(side_effect=[False, True])
- mm.create_on_device = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
- assert results['description'] == 'this is a description'
diff --git a/test/units/modules/network/f5/test_bigiq_regkey_license_assignment.py b/test/units/modules/network/f5/test_bigiq_regkey_license_assignment.py
deleted file mode 100644
index 387757a1e0..0000000000
--- a/test/units/modules/network/f5/test_bigiq_regkey_license_assignment.py
+++ /dev/null
@@ -1,141 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigiq_regkey_license_assignment import ModuleParameters
- from library.modules.bigiq_regkey_license_assignment import ModuleManager
- from library.modules.bigiq_regkey_license_assignment import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
- from test.units.compat.mock import patch
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigiq_regkey_license_assignment import ModuleParameters
- from ansible.modules.network.f5.bigiq_regkey_license_assignment import ModuleManager
- from ansible.modules.network.f5.bigiq_regkey_license_assignment import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
- from units.compat.mock import patch
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters_unmanaged(self):
- args = dict(
- pool='foo-pool',
- key='XXXX-XXXX-XXXX-XXXX-XXXX',
- device='1.1.1.1',
- managed=False,
- device_username='admin',
- device_password='secret',
- device_port='8443'
- )
-
- p = ModuleParameters(params=args)
- assert p.pool == 'foo-pool'
- assert p.key == 'XXXX-XXXX-XXXX-XXXX-XXXX'
- assert p.device == '1.1.1.1'
- assert p.managed is False
- assert p.device_username == 'admin'
- assert p.device_password == 'secret'
- assert p.device_port == 8443
-
- def test_module_parameters_managed(self):
- args = dict(
- pool='foo-pool',
- key='XXXX-XXXX-XXXX-XXXX-XXXX',
- device='1.1.1.1',
- managed=True,
- )
-
- p = ModuleParameters(params=args)
- assert p.pool == 'foo-pool'
- assert p.key == 'XXXX-XXXX-XXXX-XXXX-XXXX'
- assert p.device == '1.1.1.1'
- assert p.managed is True
-
-
-class TestManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
- self.patcher1 = patch('time.sleep')
- self.patcher1.start()
-
- def tearDown(self):
- self.patcher1.stop()
-
- def test_create(self, *args):
- set_module_args(dict(
- pool='foo-pool',
- key='XXXX-XXXX-XXXX-XXXX-XXXX',
- device='1.1.1.1',
- device_username='admin',
- device_password='secret',
- managed='no',
- state='present',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- required_if=self.spec.required_if
- )
- mm = ModuleManager(module=module)
-
- # Override methods to force specific logic in the module to happen
- mm.exists = Mock(side_effect=[False, True])
- mm.create_on_device = Mock(return_value=True)
- mm.wait_for_device_to_be_licensed = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
diff --git a/test/units/modules/network/f5/test_bigiq_regkey_pool.py b/test/units/modules/network/f5/test_bigiq_regkey_pool.py
deleted file mode 100644
index 0d368e22f3..0000000000
--- a/test/units/modules/network/f5/test_bigiq_regkey_pool.py
+++ /dev/null
@@ -1,109 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright (c) 2017 F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigiq_regkey_pool import ModuleParameters
- from library.modules.bigiq_regkey_pool import ApiParameters
- from library.modules.bigiq_regkey_pool import ModuleManager
- from library.modules.bigiq_regkey_pool import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigiq_regkey_pool import ModuleParameters
- from ansible.modules.network.f5.bigiq_regkey_pool import ApiParameters
- from ansible.modules.network.f5.bigiq_regkey_pool import ModuleManager
- from ansible.modules.network.f5.bigiq_regkey_pool import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- description='this is a description'
- )
-
- p = ModuleParameters(params=args)
- assert p.description == 'this is a description'
-
- def test_api_parameters(self):
- args = load_fixture('load_regkey_license_pool.json')
-
- p = ApiParameters(params=args)
- assert p.description == 'this is a description'
-
-
-class TestManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
-
- def test_create(self, *args):
- set_module_args(dict(
- name='foo',
- description='bar baz',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode
- )
-
- # Override methods in the specific type of manager
- mm = ModuleManager(module=module)
- mm.exists = Mock(return_value=False)
- mm.create_on_device = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
diff --git a/test/units/modules/network/f5/test_bigiq_utility_license.py b/test/units/modules/network/f5/test_bigiq_utility_license.py
deleted file mode 100644
index 7aea7f081a..0000000000
--- a/test/units/modules/network/f5/test_bigiq_utility_license.py
+++ /dev/null
@@ -1,113 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigiq_utility_license import ModuleParameters
- from library.modules.bigiq_utility_license import ModuleManager
- from library.modules.bigiq_utility_license import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
- from test.units.compat.mock import patch
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigiq_utility_license import ModuleParameters
- from ansible.modules.network.f5.bigiq_utility_license import ModuleManager
- from ansible.modules.network.f5.bigiq_utility_license import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
- from units.compat.mock import patch
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters(self):
- args = dict(
- license_key='XXXX-XXXX-XXXX-XXXX-XXXX',
- accept_eula=True,
- )
-
- p = ModuleParameters(params=args)
- assert p.license_key == 'XXXX-XXXX-XXXX-XXXX-XXXX'
- assert p.accept_eula is True
-
-
-class TestManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
- self.patcher1 = patch('time.sleep')
- self.patcher1.start()
-
- def tearDown(self):
- self.patcher1.stop()
-
- def test_create(self, *args):
- set_module_args(dict(
- license_key='XXXX-XXXX-XXXX-XXXX-XXXX',
- accept_eula=True,
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- required_if=self.spec.required_if
- )
- mm = ModuleManager(module=module)
-
- # Override methods to force specific logic in the module to happen
- mm.exists = Mock(side_effect=[False, True])
- mm.create_on_device = Mock(return_value=True)
- mm.wait_for_initial_license_activation = Mock(return_value=True)
- mm.wait_for_utility_license_activation = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True
diff --git a/test/units/modules/network/f5/test_bigiq_utility_license_assignment.py b/test/units/modules/network/f5/test_bigiq_utility_license_assignment.py
deleted file mode 100644
index 406c277115..0000000000
--- a/test/units/modules/network/f5/test_bigiq_utility_license_assignment.py
+++ /dev/null
@@ -1,134 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2017, F5 Networks Inc.
-# 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 os
-import json
-import pytest
-import sys
-
-if sys.version_info < (2, 7):
- pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
-
-from ansible.module_utils.basic import AnsibleModule
-
-try:
- from library.modules.bigiq_utility_license_assignment import ModuleParameters
- from library.modules.bigiq_utility_license_assignment import ModuleManager
- from library.modules.bigiq_utility_license_assignment import ArgumentSpec
-
- # In Ansible 2.8, Ansible changed import paths.
- from test.units.compat import unittest
- from test.units.compat.mock import Mock
-
- from test.units.modules.utils import set_module_args
-except ImportError:
- from ansible.modules.network.f5.bigiq_utility_license_assignment import ModuleParameters
- from ansible.modules.network.f5.bigiq_utility_license_assignment import ModuleManager
- from ansible.modules.network.f5.bigiq_utility_license_assignment import ArgumentSpec
-
- # Ansible 2.8 imports
- from units.compat import unittest
- from units.compat.mock import Mock
-
- from units.modules.utils import set_module_args
-
-
-fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
-fixture_data = {}
-
-
-def load_fixture(name):
- path = os.path.join(fixture_path, name)
-
- if path in fixture_data:
- return fixture_data[path]
-
- with open(path) as f:
- data = f.read()
-
- try:
- data = json.loads(data)
- except Exception:
- pass
-
- fixture_data[path] = data
- return data
-
-
-class TestParameters(unittest.TestCase):
- def test_module_parameters_unmanaged(self):
- args = dict(
- offering='asdf',
- key='XXXX-XXXX-XXXX-XXXX-XXXX',
- device='1.1.1.1',
- managed=False,
- device_username='admin',
- device_password='secret',
- device_port='8443'
- )
-
- p = ModuleParameters(params=args)
- assert p.offering == 'asdf'
- assert p.key == 'XXXX-XXXX-XXXX-XXXX-XXXX'
- assert p.device == '1.1.1.1'
- assert p.managed is False
- assert p.device_username == 'admin'
- assert p.device_password == 'secret'
- assert p.device_port == 8443
-
- def test_module_parameters_managed(self):
- args = dict(
- offering='asdf',
- key='XXXX-XXXX-XXXX-XXXX-XXXX',
- device='1.1.1.1',
- managed=True,
- )
-
- p = ModuleParameters(params=args)
- assert p.offering == 'asdf'
- assert p.key == 'XXXX-XXXX-XXXX-XXXX-XXXX'
- assert p.device == '1.1.1.1'
- assert p.managed is True
-
-
-class TestManager(unittest.TestCase):
-
- def setUp(self):
- self.spec = ArgumentSpec()
-
- def test_create(self, *args):
- set_module_args(dict(
- offering='asdf',
- key='XXXX-XXXX-XXXX-XXXX-XXXX',
- device='1.1.1.1',
- device_username='admin',
- device_password='secret',
- managed='no',
- state='present',
- provider=dict(
- server='localhost',
- password='password',
- user='admin'
- )
- ))
-
- module = AnsibleModule(
- argument_spec=self.spec.argument_spec,
- supports_check_mode=self.spec.supports_check_mode,
- required_if=self.spec.required_if
- )
- mm = ModuleManager(module=module)
-
- # Override methods to force specific logic in the module to happen
- mm.exists = Mock(side_effect=[False, True])
- mm.create_on_device = Mock(return_value=True)
- mm.wait_for_device_to_be_licensed = Mock(return_value=True)
-
- results = mm.exec_module()
-
- assert results['changed'] is True