├── .gitignore ├── LICENSE ├── README.md ├── ansible.cfg ├── docs ├── IAC.md ├── INSTALL.md ├── MODULES.md └── PRECEDENCE.md ├── group_vars └── all ├── host_vars └── all ├── hosts ├── library ├── __init__.py ├── _bigip_facts.py ├── _bigip_monitor_http.py ├── _bigip_node.py ├── _bigip_pool.py ├── _bigip_pool_member.py ├── _bigip_virtual_server.py ├── bigip_command.py ├── bigip_config.py ├── bigip_configsync_action.py ├── bigip_device_connectivity.py ├── bigip_device_dns.py ├── bigip_device_group.py ├── bigip_device_group_member.py ├── bigip_device_ntp.py ├── bigip_device_sshd.py ├── bigip_device_trust.py ├── bigip_dns_record.py ├── bigip_dns_record_facts.py ├── bigip_dns_zone.py ├── bigip_drop_connection.py ├── bigip_gtm_datacenter.py ├── bigip_gtm_facts.py ├── bigip_gtm_pool.py ├── bigip_gtm_server.py ├── bigip_gtm_virtual_server.py ├── bigip_gtm_wide_ip.py ├── bigip_hostname.py ├── bigip_iapp_service.py ├── bigip_iapp_template.py ├── bigip_iapplx_package.py ├── bigip_irule.py ├── bigip_license.py ├── bigip_monitor_http.py ├── bigip_monitor_https.py ├── bigip_monitor_snmp_dca.py ├── bigip_monitor_tcp.py ├── bigip_monitor_tcp_echo.py ├── bigip_monitor_tcp_half_open.py ├── bigip_node.py ├── bigip_partition.py ├── bigip_policy.py ├── bigip_policy_rule.py ├── bigip_pool.py ├── bigip_profile_client_ssl.py ├── bigip_provision.py ├── bigip_qkview.py ├── bigip_raw.py ├── bigip_remote_syslog.py ├── bigip_routedomain.py ├── bigip_routedomain_facts.py ├── bigip_selfip.py ├── bigip_service.py ├── bigip_snat_pool.py ├── bigip_snmp.py ├── bigip_snmp_community.py ├── bigip_snmp_trap.py ├── bigip_snmp_user.py ├── bigip_software.py ├── bigip_software_facts.py ├── bigip_software_update.py ├── bigip_ssl_certificate.py ├── bigip_ssl_key.py ├── bigip_static_route.py ├── bigip_sys_db.py ├── bigip_sys_global.py ├── bigip_ucs.py ├── bigip_ucs_fetch.py ├── bigip_user.py ├── bigip_user_facts.py ├── bigip_vcmp_guest.py ├── bigip_view.py ├── bigip_virtual_address.py ├── bigip_virtual_server.py ├── bigip_vlan.py ├── bigiq_license_pool.py ├── bigiq_license_pool_member.py ├── f5_support_upload.py ├── iworkflow_device.py ├── iworkflow_iapp_template.py ├── iworkflow_license.py ├── iworkflow_license_pool.py ├── iworkflow_license_pool_member.py ├── iworkflow_local_connector.py ├── iworkflow_local_connector_device.py ├── iworkflow_local_connector_node.py ├── iworkflow_service.py ├── iworkflow_service_template.py ├── iworkflow_system_setup.py ├── iworkflow_tenant.py ├── iworkflow_tenant_connector.py ├── iworkflow_user.py ├── module_utils │ ├── __init__.py │ ├── f5_utils.py │ └── f5networks │ │ ├── __init__.py │ │ └── common.py └── wait_for_bigip.py ├── library_old ├── __init__.py ├── bigip_command.py ├── bigip_config.py ├── bigip_configsync_actions.py ├── bigip_device_connectivity.py ├── bigip_device_dns.py ├── bigip_device_group.py ├── bigip_device_ntp.py ├── bigip_device_sshd.py ├── bigip_dns_record.py ├── bigip_dns_record_facts.py ├── bigip_dns_zone.py ├── bigip_drop_connection.py ├── bigip_facts.py ├── bigip_gtm_datacenter.py ├── bigip_gtm_facts.py ├── bigip_gtm_pool.py ├── bigip_gtm_virtual_server.py ├── bigip_gtm_wide_ip.py ├── bigip_hostname.py ├── bigip_iapp_service.py ├── bigip_iapp_template.py ├── bigip_iapplx_package.py ├── bigip_irule.py ├── bigip_license.py ├── bigip_monitor_http.py ├── bigip_monitor_tcp.py ├── bigip_node.py ├── bigip_node2.py ├── bigip_partition.py ├── bigip_policy.py ├── bigip_policy_rule.py ├── bigip_pool.py ├── bigip_pool2.py ├── bigip_pool_member.py ├── bigip_provision.py ├── bigip_qkview.py ├── bigip_remote_syslog.py ├── bigip_routedomain.py ├── bigip_routedomain_facts.py ├── bigip_selfip.py ├── bigip_service.py ├── bigip_snat_pool.py ├── bigip_snmp.py ├── bigip_snmp_community.py ├── bigip_snmp_trap.py ├── bigip_snmp_user.py ├── bigip_software.py ├── bigip_software_update.py ├── bigip_ssl_certificate.py ├── bigip_static_route.py ├── bigip_sys_db.py ├── bigip_sys_global.py ├── bigip_ucs.py ├── bigip_ucs_fetch.py ├── bigip_user.py ├── bigip_user_facts.py ├── bigip_view.py ├── bigip_virtual_address.py ├── bigip_virtual_server.py ├── bigip_virtual_server2.py ├── bigip_vlan.py ├── bigiq_license_pool.py ├── bigiq_license_pool_member.py ├── f5_support_upload.py ├── iworkflow_device.py ├── iworkflow_iapp_template.py ├── iworkflow_license.py ├── iworkflow_license_pool.py ├── iworkflow_license_pool_member.py ├── iworkflow_local_connector.py ├── iworkflow_local_connector_device.py ├── iworkflow_local_connector_node.py ├── iworkflow_service.py ├── iworkflow_service_template.py ├── iworkflow_system_setup.py ├── iworkflow_tenant.py ├── iworkflow_tenant_connector.py ├── iworkflow_user.py └── wait_for_bigip.py ├── misc └── user_repos.json ├── password.yml ├── playbooks ├── custom_facts.yml ├── onboarding.yml └── operations.yml ├── roles ├── custom_facts │ ├── README.md │ ├── defaults │ │ └── main.yml │ ├── files │ │ ├── datacenter.fact │ │ ├── domain.fact │ │ ├── product.fact │ │ ├── role.fact │ │ └── zone.fact │ ├── handlers │ │ └── main.yml │ ├── meta │ │ └── main.yml │ ├── tasks │ │ └── main.yml │ ├── tests │ │ ├── inventory │ │ └── test.yml │ └── vars │ │ └── main.yml ├── onboarding │ ├── README.md │ ├── defaults │ │ └── main.yml │ ├── files │ │ ├── domain.crt │ │ └── domain.key │ ├── handlers │ │ └── main.yml │ ├── meta │ │ └── main.yml │ ├── tasks │ │ ├── bigip_device_dns │ │ │ └── set_dns.yml │ │ ├── bigip_device_ntp │ │ │ ├── set_ntp_server.yml │ │ │ └── set_timezone.yml │ │ ├── bigip_hostname │ │ │ └── set_hostname.yml │ │ ├── bigip_license │ │ │ └── license.yml │ │ ├── bigip_partition │ │ │ └── add_partition.yml │ │ ├── bigip_provision │ │ │ └── provision_module.yml │ │ ├── bigip_remote_syslog │ │ │ └── set_syslog_server.yml │ │ ├── bigip_selfip │ │ │ └── add_selfip.yml │ │ ├── bigip_snmp_trap │ │ │ └── add_trap.yml │ │ ├── bigip_ssl_certificate │ │ │ └── import_certificate.yml │ │ ├── bigip_user │ │ │ ├── add_user.yml │ │ │ ├── change_advanced_shell.yml │ │ │ ├── change_role_shell.yml │ │ │ └── remove_user.yml │ │ ├── bigip_vlan │ │ │ ├── add_tagged_vlan.yml │ │ │ └── add_untagged_vlan.yml │ │ └── main.yml │ ├── tests │ │ ├── inventory │ │ └── test.yml │ └── vars │ │ └── main.yml └── operations │ ├── README.md │ ├── defaults │ └── main.yml │ ├── files │ ├── appsvcs.json │ ├── appsvcs_integration_v2.0.003.tmpl │ └── irules │ │ └── bodgeit-rewrite.tcl │ ├── handlers │ └── main.yml │ ├── meta │ └── main.yml │ ├── tasks │ ├── bigip_iapp_service │ │ └── appsvcs.yml │ ├── bigip_iapp_template │ │ └── appsvcs.yml │ ├── bigip_irule │ │ └── manage_irule.yml │ ├── bigip_monitor_http │ │ └── manage_http_monitor.yml │ ├── bigip_monitor_tcp │ │ └── manage_tcp_monitor.yml │ ├── bigip_node │ │ ├── add_node.yml │ │ └── remove_node.yml │ ├── bigip_pool │ │ └── manage_pool.yml │ ├── bigip_pool_member │ │ └── manage_members.yml │ ├── bigip_virtual_server │ │ └── manage_vip.yml │ └── main.yml │ ├── tests │ ├── inventory │ └── test.yml │ └── vars │ └── main.yml └── run_ansible.sh /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | *.retry 3 | *.swp 4 | .DS_Store 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Installing Ansible 2 | 3 | [Installing Ansible on a Mac Documentation](docs/INSTALL.md) 4 | 5 | ## YAML Syntax Overview 6 | 7 | [YAML Syntax Overview](https://learn.getgrav.org/advanced/yaml) 8 | 9 | ## Module Documentation 10 | 11 | [Ansible Module Documents Used in this Collection](docs/MODULES.md) 12 | 13 | ## Social Coding with Github 14 | 15 | [![Social Coding with Github](https://img.youtube.com/vi/vTiINnsHSc4/0.jpg)](https://youtu.be/vTiINnsHSc4 "Social Coding with Github") 16 | 17 | 18 | ## Useful vimrc macro for editing YaML files 19 | ``` 20 | autocmd FileType yaml setlocal ai ts=2 sw=2 et colorcolumn=1,3,5,7,9,11,13 nu 21 | ``` 22 | ### To turn off colorized lines 23 | ``` 24 | set cc= 25 | ``` 26 | 27 | ## [user_repos.json](misc/user_repos.json) 28 | ``` 29 | { 30 | "repos": [ 31 | { 32 | "name":"mcgonagle-ansible_f5", 33 | "repo":"https://github.com/mcgonagle/ansible_f5.git", 34 | "branch":"master", 35 | "skip":false, 36 | "skipinstall":true 37 | } 38 | ] 39 | } 40 | ``` 41 | 42 | ## [F5 Super NetOps/DevOps Tools Container](https://hub.docker.com/r/f5devcentral/f5-super-netops-container/) 43 | 44 | ``` 45 | docker run -p 8080:80 -p 2222:22 --rm -it -v /Users/mcgonagle/Dropbox/_F5/super-netops-ansible-container/user_repos.json:/tmp/user_repos.json -e SNOPS_GH_BRANCH=develop f5devcentral/f5-super-netops-container:develop-ansible 46 | ``` 47 | 48 | ## Running the Ansible Code 49 | This Ansible code base comes with a shell helper script that runs the playbooks. 50 | ``` 51 | $ANSIBLE_HOME_DIRECTORY/run_ansible.sh --all 52 | $ANSIBLE_HOME_DIRECTORY/run_ansible.sh --onboarding 53 | $ANSIBLE_HOME_DIRECTORY/run_ansible.sh --operation 54 | $ANSIBLE_HOME_DIRECTORY/run_ansible.sh --teardown 55 | ``` 56 | 57 | ## Ansible Variable Precedence 58 | 59 | [Ansible 2.x Order of Variable Precedence](docs/PRECEDENCE.md) 60 | 61 | ## Ansible Vault 62 | This code base leverages the ansible vault tool and includes an encrypted password protected file. 63 | To edit the username and password run: 64 | ``` 65 | ansible-vault edit password.yml 66 | ``` 67 | The password for the password file is *password* 68 | 69 | ## Ansible Roles 70 | This ansible repository is organized into roles. Roles are collections of templates, files, tasks, 71 | and variables. Tasks are organized based on the particular module they are implementing. For example, 72 | the bigip_device_ntp module is a subdirectory under the onboarding role and has a task 73 | set_ntp.yml (*roles/tasks/bigip_device_ntp/set_ntp.yml*). 74 | 75 | ## Ansible Playbooks 76 | The playbooks in in the ansible playbook directory include the roles. 77 | 78 | ``` 79 | $ANSIBLE_HOME_DIRECTORY/site.yml 80 | $ANSIBLE_HOME_DIRECTORY/playbooks/onboarding.yml 81 | $ANSIBLE_HOME_DIRECTORY/playbooks/operation.yml 82 | $ANSIBLE_HOME_DIRECTORY/playbooks/teardown.yml 83 | $ANSIBLE_HOME_DIRECTORY/playbooks/today.yml 84 | ``` 85 | 86 | ## Ansible Library 87 | Includes the BigIP Modules and distributes them for use. 88 | 89 | [F5 Network's Ansible Modules](https://github.com/F5Networks/f5-ansible/tree/devel/library) 90 | 91 | ## Infrastructure as Code Principles, Practices and Patterns 92 | [Infrastructure as Code Benefits](docs/IAC.md) 93 | 94 | ## License 95 | ### Apache V2.0 96 | 97 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at 98 | 99 | http://www.apache.org/licenses/LICENSE-2.0 100 | 101 | Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. 102 | -------------------------------------------------------------------------------- /ansible.cfg: -------------------------------------------------------------------------------- 1 | [defaults] 2 | inventory = ./hosts 3 | roles_path = ./roles 4 | #library = ./library 5 | retry_files_enabled = False 6 | -------------------------------------------------------------------------------- /docs/IAC.md: -------------------------------------------------------------------------------- 1 | # Infrastructure as Code Principles, Practices, and Patterns 2 | 3 | ## Principles of Infrastructure as Code 4 | 5 | * Modularity – Our services should be small and simple –think at the level of the simplest 6 | Free-standing, useful component. 7 | 8 | * Cooperation – Our design should discourage overlap of services, and should encourage other people and services to use our service in a way which fosters continuous improvement of our design and implementation. 9 | 10 | * Composability – Our services should be like building blocks – we should be able to build complete, complex systems by integrating them. 11 | 12 | * Extensibility – Our services should be asy to modify, enhance, and improve in response to new demands. 13 | 14 | * Flexibility – We should build our services using tools that provide unlimited power to ensure we have the (theoretical) ability to solve even the most complicate of problems. 15 | 16 | * Repeatability-Our services should produce the same results, in the same way, with the same inputs every time. 17 | 18 | * Declaration-We should specifiy our services in terms of what we want to do, not how we want to do it. 19 | 20 | * Abstraction – We should not worry about the details of the implementation, and think at the level of the component and its function. 21 | 22 | * Idempotence – Our service should only be configured when required – action should only be taken once. 23 | 24 | * Convergence – Convergence our servers should take responsibility for their own state being in line with policy; over time, the overall system will tend to correctness. 25 | 26 | ## Practices 27 | 28 | * Repeatability – Because we’re building systems in a high level programming language, and committing our code, we start to become more confident that our systems are ordered and repeatable. With that same inputs, the same code should produce the same outputs. This means we can now be confident (and ensure on a regular basis) that what we believe will recreate our environment really will do that. 29 | 30 | * Automation – We already have mature tools for deploying applications written in modern programming languages., and the very act of abstracting out infrastructures brings us the benefits of automation. 31 | 32 | * Agility – The discipline of source code management and version control means we have the ability to roll forwards or backwards to a known state. In the event of a problem, we can go to the commit logs and identify what changed and who changed it. This brings down the average time to fix problems and encourages root cause analysis. 33 | 34 | * Scalability – Repeatability plus automation makes scalability much easier, especially when combined with the rapid hardware provisioning that the cloud provides. 35 | 36 | * Reassurance – The fact that the architecture, design, and implementation of our infrastructure is modeled in code means we that we can automatically have documentation. Any programmer can look at the source code and see at a glance who the systems work. This is a welcome change from the common scenario in which only a s single sysadmin or architect holds the understanding of how the system hangs together. That is risky- this person is now able to hold the organization ransom, and should they leave or become ill, the company is endangered. 37 | 38 | * Disaster Recovery – In the event of a catastrophic event that wipes out the production systems, if your entire infrastructure has been broken down into modular components and described as code, recovery is as simple as provisioning new compute power, restoring from backup, and deploying the infrastructure and application code. What may have been a business ending event in the old paradigm of custom-built, partially automated infrastructure becomes a manageable few hour outage, potentially delivering competitive value over those organizations suffering from the same external influecnes, but without the power and flexibility brought about by infrastructure as code. 39 | 40 | ## Patterns 41 | * Design – Our infrastructure code should seek to be simple, iterative, and we should avoid feature creep 42 | 43 | * Collective Ownership – All members of the team should be involved in the design and writing of infrastructure as code and, wherever possible, code should be written in pairs. 44 | 45 | * Code Review – The team should be set up in a such a way as to both pair frequently and to see regular notifications of when changes are made. 46 | 47 | * Code Standards – Infrastructure code should follow the same community standards as the Ruby world, where standards and patterns have grown up around the configuration management framework, these should be adhered to. 48 | 49 | * Refactoring – 50 | 51 | * Testing - 52 | -------------------------------------------------------------------------------- /docs/INSTALL.md: -------------------------------------------------------------------------------- 1 | # ansible_f5 2 | 3 | ## Overview 4 | 5 | This repository provides the foundation for working with F5 devices and Ansible. 6 | The architecture of the modules makes inherent use of the BIG-IP SOAP and REST 7 | APIs as well as the tmsh API where required. 8 | 9 | These modules are freely provided to the open source community for automating 10 | BIG-IP device configurations using Ansible. Support for the modules is provided 11 | on a best effort basis by the F5 community. Please file any bugs, questions or 12 | enhancement requests using [Github Issues](https://github.com/F5Networks/f5-ansible/issues) 13 | 14 | ### Requirements 15 | 16 | * [Ansible 2.2.0 or greater][installing] 17 | * Advanced shell for user account enabled - Note this requierment it caught me and took me a while to realize. 18 | * [bigsuds Python Client 1.0.4 or later][bigsuds] 19 | * [f5-sdk Python Client, latest available][f5-sdk] 20 | 21 | ### Documentation 22 | Pip does not come pre-installed on a mac. To install run 23 | 24 | ``` 25 | sudo easy_install pip 26 | sudo pip install --upgrade pip 27 | ``` 28 | 29 | Next, make sure virtualenv is installed. 30 | 31 | ``` 32 | pip install virtualenv 33 | ``` 34 | 35 | This will make available to you a virtualenv command. You can use that it make a virtual environment for your Ansible installation. 36 | 37 | ``` 38 | virtualenv ansible2 39 | ``` 40 | 41 | In your current working directory, you will find a new directory called ansible2. In this directory resides a copy of Python that is configured to install any modules inside of that local directory. Via this method, we can install Python modules without stomping on the system wide ones. 42 | 43 | To use this new location, you must activate it. 44 | 45 | ``` 46 | . ansible2/bin/activate 47 | ``` 48 | 49 | You should see your prompt change so that the name of the virtualenv is prefixing the normal prompt. For example. 50 | 51 | ``` 52 | (ansible2) tom@tompro:~/Ansible/ansible-f5> 53 | ``` 54 | 55 | Now that our virtualenv is active, all future Python commands (such as pip) will install modules into the virtualenv. So let’s install the development copy of ansible. 56 | 57 | ``` 58 | pip install git+git://github.com/ansible/ansible.git@devel 59 | ``` 60 | 61 | You should be able to verify that you are running the new version of Ansible by using the –version argument to the ansible command, like so. 62 | 63 | ``` 64 | ansible --version 65 | ``` 66 | 67 | You should be presented with output that resembles the following 68 | 69 | ``` 70 | ansible --version 71 | ansible 2.3.0 72 | config file = 73 | configured module search path = Default w/o overrides 74 | ``` 75 | 76 | I had to set the PYTHONPATH to find the bigsuds and suds modules. 77 | 78 | ``` 79 | export PYTHONPATH=/Users/tom/ansible2/lib/python2.7/site-packages 80 | ``` 81 | 82 | I also had to set the **validate_certs: "false"** in my site.yml for each bigip module call. As of Python 2.7.9, python won't work with self signed certificates, which I use in my lab environment. 83 | 84 | Several of the BigIP ansible modules depend on Bigsuds, and or the Python F5-SDK. Make sure to install both via pip. 85 | 86 | ``` 87 | pip install bigsuds 88 | pip install f5-sdk 89 | ``` 90 | 91 | ## ansible-vault 92 | ``` 93 | sudo pip install ansible-vault 94 | ``` 95 | 96 | Create the ansible-vault file 97 | ``` 98 | ansible-vault create password.yml 99 | ``` 100 | 101 | Edit the ansible-vault file 102 | ``` 103 | ansible-vault edit password.yml 104 | ``` 105 | Contents of the ansible-vault file 106 | ``` 107 | username: admin 108 | password: admin 109 | ``` 110 | 111 | Run the ansible-playbook command with the ansible-vault file 112 | ``` 113 | ansible-playbook site.yml --ask-vault-pass -e @password.yml -vvv 114 | ``` 115 | ansible-vault password for file password.yml is ```password``` 116 | 117 | 118 | -------------------------------------------------------------------------------- /docs/MODULES.md: -------------------------------------------------------------------------------- 1 | ### Onboarding Module Documentation 2 | [bigip_device_dns](https://f5-ansible.readthedocs.io/en/devel/modules/bigip_device_dns_module.html) 3 | 4 | [bigip_device_ntp](https://f5-ansible.readthedocs.io/en/devel/modules/bigip_device_ntp_module.html) 5 | 6 | [bigip_hostname](https://f5-ansible.readthedocs.io/en/devel/modules/bigip_hostname_module.html) 7 | 8 | [bigip_remote_syslog](https://f5-ansible.readthedocs.io/en/devel/modules/bigip_remote_syslog_module.html) 9 | 10 | [bigip_selfip](https://f5-ansible.readthedocs.io/en/devel/modules/bigip_selfip_module.html) 11 | 12 | [bigip_ssl_certificate](https://f5-ansible.readthedocs.io/en/devel/modules/bigip_ssl_certificate_module.html) 13 | 14 | [bigip_user](https://f5-ansible.readthedocs.io/en/devel/modules/bigip_user_module.html) 15 | 16 | [bigip_vlan](https://f5-ansible.readthedocs.io/en/devel/modules/bigip_vlan_module.html) 17 | 18 | 19 | ### Operations Module Documentation 20 | [bigip_node](https://f5-ansible.readthedocs.io/en/devel/modules/bigip_node_module.html) 21 | 22 | [bigip_pool](https://f5-ansible.readthedocs.io/en/devel/modules/bigip_pool_module.html) 23 | 24 | [bigip_pool_member](https://f5-ansible.readthedocs.io/en/devel/modules/bigip_pool_member_module.html) 25 | 26 | [bigip_irule](https://f5-ansible.readthedocs.io/en/devel/modules/bigip_irule_module.html) 27 | 28 | [bigip_virtual_server](https://f5-ansible.readthedocs.io/en/devel/modules/bigip_virtual_server_module.html) 29 | 30 | -------------------------------------------------------------------------------- /docs/PRECEDENCE.md: -------------------------------------------------------------------------------- 1 | ## Ansible 2.x Order of Variable Precedence 2 | 3 | * role defaults 4 | * inventory INI or script group vars 5 | * inventory group_vars/all 6 | * playbook group_vars/all 7 | * inventory group_vars/* 8 | * playbook group_vars/* 9 | * inventory INI or script host vars 10 | * inventory host_vars/* 11 | * playbook host_vars/* 12 | * host facts 13 | * play vars 14 | * play vars_prompt 15 | * play vars_files 16 | * role vars (defined in role/vars/main.yml) 17 | * block vars (only for tasks in block) 18 | * task vars (only for the task) 19 | * role (and include_role) params 20 | * include params 21 | * include_vars 22 | * set_facts / registered vars 23 | * extra vars (always win precedence) 24 | -------------------------------------------------------------------------------- /group_vars/all: -------------------------------------------------------------------------------- 1 | --- 2 | ... 3 | -------------------------------------------------------------------------------- /host_vars/all: -------------------------------------------------------------------------------- 1 | --- 2 | ... 3 | -------------------------------------------------------------------------------- /hosts: -------------------------------------------------------------------------------- 1 | [bigip] 2 | 107.23.70.142 3 | -------------------------------------------------------------------------------- /library/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcgonagle/ansible_f5/ec93eb36b0098cdb93931fdfcba8fabcaec4a7ee/library/__init__.py -------------------------------------------------------------------------------- /library/bigip_device_ntp.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | # 4 | # Copyright (c) 2017 F5 Networks Inc. 5 | # GNU General Public License v3.0 (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) 6 | from __future__ import absolute_import, division, print_function 7 | __metaclass__ = type 8 | 9 | 10 | ANSIBLE_METADATA = {'metadata_version': '1.1', 11 | 'status': ['preview'], 12 | 'supported_by': 'community'} 13 | 14 | DOCUMENTATION = r''' 15 | --- 16 | module: bigip_device_ntp 17 | short_description: Manage NTP servers on a BIG-IP 18 | description: 19 | - Manage NTP servers on a BIG-IP. 20 | version_added: "2.2" 21 | options: 22 | ntp_servers: 23 | description: 24 | - A list of NTP servers to set on the device. At least one of C(ntp_servers) 25 | or C(timezone) is required. 26 | state: 27 | description: 28 | - The state of the NTP servers on the system. When C(present), guarantees 29 | that the NTP servers are set on the system. When C(absent), removes the 30 | specified NTP servers from the device configuration. 31 | default: present 32 | choices: 33 | - absent 34 | - present 35 | timezone: 36 | description: 37 | - The timezone to set for NTP lookups. At least one of C(ntp_servers) or 38 | C(timezone) is required. 39 | default: UTC 40 | notes: 41 | - Requires the f5-sdk Python package on the host. This is as easy as pip 42 | install f5-sdk. 43 | extends_documentation_fragment: f5 44 | requirements: 45 | - f5-sdk 46 | authors: 47 | - Tim Rupp (@caphrim007) 48 | - Wojciech Wypior (@wojtek0806) 49 | ''' 50 | 51 | EXAMPLES = r''' 52 | - name: Set NTP server 53 | bigip_device_ntp: 54 | ntp_servers: 55 | - 192.0.2.23 56 | password: secret 57 | server: lb.mydomain.com 58 | user: admin 59 | validate_certs: no 60 | delegate_to: localhost 61 | 62 | - name: Set timezone 63 | bigip_device_ntp: 64 | password: secret 65 | server: lb.mydomain.com 66 | timezone: America/Los_Angeles 67 | user: admin 68 | validate_certs: no 69 | delegate_to: localhost 70 | ''' 71 | 72 | RETURN = r''' 73 | ntp_servers: 74 | description: The NTP servers that were set on the device 75 | returned: changed 76 | type: list 77 | sample: ["192.0.2.23", "192.0.2.42"] 78 | timezone: 79 | description: The timezone that was set on the device 80 | returned: changed 81 | type: string 82 | sample: true 83 | ''' 84 | 85 | 86 | from ansible.module_utils.f5_utils import AnsibleF5Client 87 | from ansible.module_utils.f5_utils import AnsibleF5Parameters 88 | from ansible.module_utils.f5_utils import HAS_F5SDK 89 | from ansible.module_utils.f5_utils import F5ModuleError 90 | from ansible.module_utils.six import iteritems 91 | from collections import defaultdict 92 | 93 | try: 94 | from ansible.module_utils.f5_utils import iControlUnexpectedHTTPError 95 | except ImportError: 96 | HAS_F5SDK = False 97 | 98 | 99 | class Parameters(AnsibleF5Parameters): 100 | api_map = { 101 | 'servers': 'ntp_servers' 102 | } 103 | 104 | api_attributes = [ 105 | 'servers', 'timezone', 106 | ] 107 | 108 | updatables = [ 109 | 'ntp_servers', 'timezone' 110 | ] 111 | 112 | returnables = [ 113 | 'ntp_servers', 'timezone' 114 | ] 115 | 116 | absentables = [ 117 | 'ntp_servers' 118 | ] 119 | 120 | def to_return(self): 121 | result = {} 122 | for returnable in self.returnables: 123 | result[returnable] = getattr(self, returnable) 124 | result = self._filter_params(result) 125 | return result 126 | 127 | def api_params(self): 128 | result = {} 129 | for api_attribute in self.api_attributes: 130 | if self.api_map is not None and api_attribute in self.api_map: 131 | result[api_attribute] = getattr(self, 132 | self.api_map[api_attribute]) 133 | else: 134 | result[api_attribute] = getattr(self, api_attribute) 135 | result = self._filter_params(result) 136 | return result 137 | 138 | 139 | class ModuleManager(object): 140 | def __init__(self, client): 141 | self.client = client 142 | self.have = None 143 | self.want = Parameters(self.client.module.params) 144 | self.changes = Parameters() 145 | 146 | def _update_changed_options(self): 147 | changed = {} 148 | for key in Parameters.updatables: 149 | if getattr(self.want, key) is not None: 150 | attr1 = getattr(self.want, key) 151 | attr2 = getattr(self.have, key) 152 | if attr1 != attr2: 153 | changed[key] = attr1 154 | if changed: 155 | self.changes = Parameters(changed) 156 | return True 157 | return False 158 | 159 | def _absent_changed_options(self): 160 | changed = {} 161 | for key in Parameters.absentables: 162 | if getattr(self.want, key) is not None: 163 | set_want = set(getattr(self.want, key)) 164 | set_have = set(getattr(self.have, key)) 165 | if set_want != set_have: 166 | changed[key] = list(set_want) 167 | if changed: 168 | self.changes = Parameters(changed) 169 | return True 170 | return False 171 | 172 | def exec_module(self): 173 | changed = False 174 | result = dict() 175 | state = self.want.state 176 | 177 | try: 178 | if state == "present": 179 | changed = self.update() 180 | elif state == "absent": 181 | changed = self.absent() 182 | except iControlUnexpectedHTTPError as e: 183 | raise F5ModuleError(str(e)) 184 | 185 | changes = self.changes.to_return() 186 | result.update(**changes) 187 | result.update(dict(changed=changed)) 188 | return result 189 | 190 | def update(self): 191 | self.have = self.read_current_from_device() 192 | if not self.should_update(): 193 | return False 194 | if self.client.check_mode: 195 | return True 196 | self.update_on_device() 197 | return True 198 | 199 | def should_update(self): 200 | result = self._update_changed_options() 201 | if result: 202 | return True 203 | return False 204 | 205 | def should_absent(self): 206 | result = self._absent_changed_options() 207 | if result: 208 | return True 209 | return False 210 | 211 | def absent(self): 212 | self.have = self.read_current_from_device() 213 | if not self.should_absent(): 214 | return False 215 | if self.client.check_mode: 216 | return True 217 | self.absent_on_device() 218 | return True 219 | 220 | def update_on_device(self): 221 | params = self.want.api_params() 222 | resource = self.client.api.tm.sys.ntp.load() 223 | resource.update(**params) 224 | 225 | def read_current_from_device(self): 226 | resource = self.client.api.tm.sys.ntp.load() 227 | result = resource.attrs 228 | return Parameters(result) 229 | 230 | def absent_on_device(self): 231 | params = self.changes.api_params() 232 | resource = self.client.api.tm.sys.ntp.load() 233 | resource.update(**params) 234 | 235 | 236 | class ArgumentSpec(object): 237 | def __init__(self): 238 | self.supports_check_mode = True 239 | self.argument_spec = dict( 240 | ntp_servers=dict( 241 | required=False, 242 | default=None, 243 | type='list', 244 | ), 245 | timezone=dict( 246 | required=False, 247 | default=None, 248 | ) 249 | ) 250 | self.required_one_of = [ 251 | ['ntp_servers', 'timezone'] 252 | ] 253 | self.f5_product_name = 'bigip' 254 | 255 | 256 | def main(): 257 | if not HAS_F5SDK: 258 | raise F5ModuleError("The python f5-sdk module is required") 259 | 260 | spec = ArgumentSpec() 261 | 262 | client = AnsibleF5Client( 263 | argument_spec=spec.argument_spec, 264 | supports_check_mode=spec.supports_check_mode, 265 | f5_product_name=spec.f5_product_name, 266 | required_one_of=spec.required_one_of 267 | ) 268 | 269 | try: 270 | mm = ModuleManager(client) 271 | results = mm.exec_module() 272 | client.module.exit_json(**results) 273 | except F5ModuleError as e: 274 | client.module.fail_json(msg=str(e)) 275 | 276 | if __name__ == '__main__': 277 | main() 278 | -------------------------------------------------------------------------------- /library/bigip_dns_record_facts.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | # 4 | # Copyright (c) 2017 F5 Networks Inc. 5 | # GNU General Public License v3.0 (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) 6 | from __future__ import absolute_import, division, print_function 7 | __metaclass__ = type 8 | 9 | 10 | ANSIBLE_METADATA = {'metadata_version': '1.1', 11 | 'status': ['preview'], 12 | 'supported_by': 'community'} 13 | 14 | DOCUMENTATION = r''' 15 | --- 16 | module: bigip_dns_record_facts 17 | short_description: foo 18 | description: 19 | - foo 20 | version_added: "2.2" 21 | options: 22 | server: 23 | description: 24 | - BIG-IP host 25 | required: true 26 | user: 27 | description: 28 | - BIG-IP username 29 | required: true 30 | aliases: 31 | - username 32 | password: 33 | description: 34 | - BIG-IP password 35 | required: true 36 | notes: 37 | - Requires the f5-sdk Python package on the remote host. This is as easy as 38 | pip install f5-sdk 39 | requirements: 40 | - f5-sdk 41 | author: 42 | - Tim Rupp (@caphrim007) 43 | ''' 44 | 45 | EXAMPLES = r''' 46 | 47 | ''' 48 | 49 | RETURN = r''' 50 | 51 | ''' 52 | 53 | from ansible.module_utils.basic import * 54 | from ansible.module_utils.f5_utils import * 55 | 56 | if __name__ == '__main__': 57 | main() 58 | -------------------------------------------------------------------------------- /library/bigip_dns_zone.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | # 4 | # Copyright (c) 2017 F5 Networks Inc. 5 | # GNU General Public License v3.0 (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) 6 | from __future__ import absolute_import, division, print_function 7 | __metaclass__ = type 8 | 9 | 10 | ANSIBLE_METADATA = {'metadata_version': '1.1', 11 | 'status': ['preview'], 12 | 'supported_by': 'community'} 13 | 14 | DOCUMENTATION = r''' 15 | --- 16 | module: bigip_dns_zone 17 | short_description: Manages DNS zones on a BIG-IP 18 | description: 19 | - This module manages DNS zones described in the iControl Management 20 | documentation 21 | version_added: "2.2" 22 | options: 23 | server: 24 | description: 25 | - BIG-IP host. 26 | required: True 27 | user: 28 | description: 29 | - BIG-IP username. 30 | required: True 31 | aliases: 32 | - username 33 | password: 34 | description: 35 | - BIG-IP password. 36 | required: True 37 | zone: 38 | description: 39 | - The name of the zone. 40 | required: True 41 | options: 42 | description: 43 | - A sequence of options for the view. 44 | state: 45 | description: 46 | - Whether the record should exist. When C(absent), removes 47 | the record. 48 | default: present 49 | choices: 50 | - present 51 | - absent 52 | notes: 53 | - Requires the bigsuds Python package on the remote host. This is as easy as 54 | pip install bigsuds 55 | - https://devcentral.f5.com/wiki/iControl.Management__Zone.ashx 56 | requirements: 57 | - bigsuds 58 | - distutils 59 | author: 60 | - Tim Rupp (@caphrim007) 61 | ''' 62 | 63 | EXAMPLES = r''' 64 | - name: Add a view, named "internal", to organization.com zone 65 | module: bigip_view: 66 | username: admin 67 | password: secret 68 | server: lb.mydomain.com 69 | zone_names: 70 | - organization.com 71 | state: present 72 | options: 73 | - domain_name: elliot.organization.com 74 | ip_address: 10.1.1.1 75 | ''' 76 | 77 | from distutils.version import StrictVersion 78 | import re 79 | 80 | VERSION_PATTERN = 'BIG-IP_v(?P\d+\.\d+\.\d+)' 81 | 82 | 83 | class ViewZoneException(Exception): 84 | pass 85 | 86 | 87 | class ViewZone(object): 88 | REQUIRED_BIGIP_VERSION = '9.0.3' 89 | 90 | def __init__(self, module): 91 | self.module = module 92 | 93 | self.username = module.params['username'] 94 | self.password = module.params['password'] 95 | self.hostname = module.params['hostname'] 96 | self.view_name = module.params['view_name'] 97 | self.zone_name = module.params['zone_name'] 98 | self.zone_type = module.params['zone_type'].lower() 99 | self.zone_file = module.params['zone_file'] 100 | self.options = module.params['options'] 101 | self.text = module.params['text'] 102 | 103 | if not self.zone_name.endswith('.'): 104 | self.zone_name += '.' 105 | 106 | self.client = bigsuds.BIGIP( 107 | hostname=self.hostname, 108 | username=self.username, 109 | password=self.password, 110 | debug=True 111 | ) 112 | 113 | # Do some checking of things 114 | self.check_version() 115 | 116 | def get_zone_type(self): 117 | zone_type_maps = dict( 118 | unset='UNSET', # Not yet initialized 119 | master='MASTER', # A master zone 120 | slave='SLAVE', # A slave zone 121 | stub='STUB', # A stub zone 122 | forward='FORWARD', # A forward zone 123 | hint='HINT' # A hint zone, "." 124 | ) 125 | 126 | if self.zone_type in zone_type_maps: 127 | return zone_type_maps[self.zone_type] 128 | else: 129 | raise ViewZoneException('Specified zone_type does not exist') 130 | 131 | def check_version(self): 132 | response = self.client.System.SystemInfo.get_version() 133 | match = re.search(VERSION_PATTERN, response) 134 | version = match.group('version') 135 | 136 | v1 = StrictVersion(version) 137 | v2 = StrictVersion(self.REQUIRED_BIGIP_VERSION) 138 | 139 | if v1 < v2: 140 | raise ViewException('The BIG-IP version %s does not support this feature' % version) 141 | 142 | def zone_exists(self): 143 | view_zone = dict( 144 | view_name=self.view_name, 145 | zone_name=self.zone_name, 146 | ) 147 | 148 | response = self.client.Management.Zone.zone_exist( 149 | view_zones=[view_zone] 150 | ) 151 | 152 | return response 153 | 154 | def create_zone(self): 155 | view_zone = dict( 156 | view_name=self.view_name, 157 | zone_name=self.zone_name, 158 | zone_type=self.get_zone_type(), 159 | zone_file=self.zone_file, 160 | option_seq=self.options 161 | ) 162 | 163 | self.client.Management.Zone.add_zone_text( 164 | zone_records=[view_zone], 165 | text=[[self.text]], 166 | sync_ptrs=[1] 167 | ) 168 | 169 | def delete_zone(self): 170 | view_zone = dict( 171 | view_name=self.view_name, 172 | zone_name=self.zone_name 173 | ) 174 | 175 | self.client.Management.Zone.delete_zone( 176 | view_zones=[view_zone] 177 | ) 178 | 179 | 180 | def main(): 181 | module = AnsibleModule( 182 | argument_spec=dict( 183 | username=dict(default='admin'), 184 | password=dict(default='admin'), 185 | hostname=dict(default='localhost'), 186 | view_name=dict(default='external'), 187 | zone_name=dict(required=True), 188 | zone_type=dict(default='master'), 189 | options=dict(required=False, type='list'), 190 | zone_file=dict(default=None), 191 | text=dict(default=None), 192 | state=dict(default="present", choices=["absent", "present"]), 193 | ) 194 | ) 195 | 196 | state = module.params["state"] 197 | zone_file = module.params['zone_file'] 198 | 199 | if not bigsuds_found: 200 | module.fail_json(msg="The python bigsuds module is required") 201 | 202 | view_zone = ViewZone(module) 203 | 204 | if state == "present": 205 | if not zone_file: 206 | raise ViewZoneException('A zone_file must be specified') 207 | 208 | if view_zone.zone_exists(): 209 | changed = False 210 | else: 211 | view_zone.create_zone() 212 | changed = True 213 | elif state == "absent": 214 | view_zone.delete_zone() 215 | changed = True 216 | 217 | module.exit_json(changed=changed) 218 | 219 | from ansible.module_utils.basic import * 220 | from ansible.module_utils.f5_utils import * 221 | 222 | if __name__ == '__main__': 223 | main() 224 | -------------------------------------------------------------------------------- /library/bigip_drop_connection.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | # 4 | # Copyright (c) 2017 F5 Networks Inc. 5 | # Copyright (c) 2016 Michael Perzel 6 | # GNU General Public License v3.0 (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) 7 | 8 | from __future__ import absolute_import, division, print_function 9 | __metaclass__ = type 10 | 11 | 12 | ANSIBLE_METADATA = {'metadata_version': '1.1', 13 | 'status': ['preview'], 14 | 'supported_by': 'community'} 15 | 16 | DOCUMENTATION = r''' 17 | --- 18 | module: bigip_sys_connection 19 | short_description: "Run commands on F5 devices via api" 20 | description: 21 | - "Run commands on F5 devices via api" 22 | version_added: "2.2" 23 | author: 'Michael Perzel' 24 | notes: 25 | - "F5 developed module 'f5-sdk' required" 26 | - "Best run as a local_action in your playbook" 27 | - "Requires administrative privileges for user" 28 | requirements: 29 | - f5-sdk 30 | options: 31 | server: 32 | description: 33 | - BIG-IP host 34 | required: true 35 | default: null 36 | choices: [] 37 | aliases: [] 38 | user: 39 | description: 40 | - BIG-IP username 41 | required: true 42 | default: null 43 | choices: [] 44 | aliases: [] 45 | password: 46 | description: 47 | - BIG-IP password 48 | required: true 49 | default: null 50 | choices: [] 51 | aliases: [] 52 | command: 53 | description: 54 | - Command to run 55 | required: true 56 | choices: [] 57 | aliases: [] 58 | ''' 59 | 60 | EXAMPLES = r''' 61 | - name: Show connections to LTM virtual server 62 | local_action: > 63 | bigip_sys_connection 64 | server={{ f5_ltm_server }} 65 | user={{ f5_ltm_username }} 66 | password={{ f5_ltm_password }} 67 | command="tmsh show sys connection cs-server-addr {{ ip_address }}" 68 | ''' 69 | try: 70 | from f5.bigip import ManagementRoot 71 | HAS_F5SDK = True 72 | except ImportError: 73 | HAS_F5SDK = False 74 | 75 | def main(): 76 | if not HAS_F5SDK: 77 | raise F5ModuleError("The python f5-sdk module is required") 78 | argument_spec = f5_argument_spec() 79 | 80 | meta_args = dict( 81 | command=dict(type='str', required=True), 82 | ) 83 | argument_spec.update(meta_args) 84 | 85 | module = AnsibleModule( 86 | argument_spec=argument_spec 87 | ) 88 | 89 | server = module.params['server'] 90 | user = module.params['user'] 91 | password = module.params['password'] 92 | command = '-c "{0}"'.format(module.params['command']) 93 | 94 | result = {} 95 | result['changed'] = False 96 | 97 | try: 98 | mgmt = ManagementRoot(server, user, password) 99 | output = mgmt.tm.util.bash.exec_cmd('run', utilCmdArgs=command) 100 | 101 | if hasattr(output, 'commandResult'): 102 | result['msg'] = output.commandResult 103 | 104 | result['changed'] = True 105 | 106 | except Exception as e: 107 | module.fail_json(msg="received exception: {0}".format(e)) 108 | 109 | module.exit_json(**result) 110 | 111 | 112 | # include magic from lib/ansible/module_common.py 113 | from ansible.module_utils.basic import * 114 | from ansible.module_utils.f5_utils import * 115 | 116 | if __name__ == '__main__': 117 | main() 118 | -------------------------------------------------------------------------------- /library/bigip_hostname.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | # 4 | # Copyright (c) 2017 F5 Networks Inc. 5 | # GNU General Public License v3.0 (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) 6 | 7 | from __future__ import absolute_import, division, print_function 8 | __metaclass__ = type 9 | 10 | 11 | ANSIBLE_METADATA = {'metadata_version': '1.1', 12 | 'status': ['preview'], 13 | 'supported_by': 'community'} 14 | 15 | DOCUMENTATION = r''' 16 | --- 17 | module: bigip_hostname 18 | short_description: Manage the hostname of a BIG-IP 19 | description: 20 | - Manage the hostname of a BIG-IP. 21 | version_added: "2.3" 22 | options: 23 | hostname: 24 | description: 25 | - Hostname of the BIG-IP host. 26 | required: True 27 | notes: 28 | - Requires the f5-sdk Python package on the host. This is as easy as pip 29 | install f5-sdk. 30 | extends_documentation_fragment: f5 31 | requirements: 32 | - f5-sdk 33 | author: 34 | - Tim Rupp (@caphrim007) 35 | - Matthew Lam (@mryanlam) 36 | ''' 37 | 38 | EXAMPLES = r''' 39 | - name: Set the hostname of the BIG-IP 40 | bigip_hostname: 41 | hostname: bigip.localhost.localdomain 42 | password: secret 43 | server: lb.mydomain.com 44 | user: admin 45 | delegate_to: localhost 46 | ''' 47 | 48 | RETURN = r''' 49 | hostname: 50 | description: The new hostname of the device 51 | returned: changed 52 | type: string 53 | sample: big-ip01.internal 54 | ''' 55 | 56 | from ansible.module_utils.f5_utils import AnsibleF5Client 57 | from ansible.module_utils.f5_utils import AnsibleF5Parameters 58 | from ansible.module_utils.f5_utils import HAS_F5SDK 59 | from ansible.module_utils.f5_utils import F5ModuleError 60 | 61 | try: 62 | from ansible.module_utils.f5_utils import iControlUnexpectedHTTPError 63 | except ImportError: 64 | HAS_F5SDK = False 65 | 66 | 67 | class Parameters(AnsibleF5Parameters): 68 | api_attributes = ['hostname'] 69 | updatables = ['hostname'] 70 | returnables = ['hostname'] 71 | 72 | def to_return(self): 73 | result = {} 74 | for returnable in self.returnables: 75 | result[returnable] = getattr(self, returnable) 76 | result = self._filter_params(result) 77 | return result 78 | 79 | def api_params(self): 80 | result = {} 81 | for api_attribute in self.api_attributes: 82 | if self.api_map is not None and api_attribute in self.api_map: 83 | result[api_attribute] = getattr(self, self.api_map[api_attribute]) 84 | else: 85 | result[api_attribute] = getattr(self, api_attribute) 86 | result = self._filter_params(result) 87 | return result 88 | 89 | @property 90 | def hostname(self): 91 | if self._values['hostname'] is None: 92 | return None 93 | return str(self._values['hostname']) 94 | 95 | 96 | class ModuleManager(object): 97 | def __init__(self, client): 98 | self.client = client 99 | self.have = None 100 | self.want = Parameters(self.client.module.params) 101 | self.changes = Parameters() 102 | 103 | def _set_changed_options(self): 104 | changed = {} 105 | for key in Parameters.returnables: 106 | if getattr(self.want, key) is not None: 107 | changed[key] = getattr(self.want, key) 108 | if changed: 109 | self.changes = Parameters(changed) 110 | 111 | def _update_changed_options(self): 112 | changed = {} 113 | for key in Parameters.updatables: 114 | if getattr(self.want, key) is not None: 115 | attr1 = getattr(self.want, key) 116 | attr2 = getattr(self.have, key) 117 | if attr1 != attr2: 118 | changed[key] = attr1 119 | self.changes = Parameters(changed) 120 | if changed: 121 | return True 122 | return False 123 | 124 | def exec_module(self): 125 | result = dict() 126 | 127 | try: 128 | changed = self.update() 129 | except iControlUnexpectedHTTPError as e: 130 | raise F5ModuleError(str(e)) 131 | 132 | changes = self.changes.to_return() 133 | result.update(**changes) 134 | result.update(dict(changed=changed)) 135 | return result 136 | 137 | def read_current_from_device(self): 138 | resource = self.client.api.tm.sys.global_settings.load() 139 | result = resource.attrs 140 | return Parameters(result) 141 | 142 | def update(self): 143 | self.have = self.read_current_from_device() 144 | if not self.should_update(): 145 | return False 146 | if self.client.check_mode: 147 | return True 148 | self.update_on_device() 149 | return True 150 | 151 | def should_update(self): 152 | result = self._update_changed_options() 153 | if result: 154 | return True 155 | return False 156 | 157 | def update_on_device(self): 158 | params = self.want.api_params() 159 | resource = self.client.api.tm.sys.global_settings.load() 160 | resource.modify(**params) 161 | self.client.api.tm.cm.devices.exec_cmd( 162 | 'mv', name=self.have.hostname, target=self.want.hostname 163 | ) 164 | 165 | 166 | class ArgumentSpec(object): 167 | def __init__(self): 168 | self.supports_check_mode = True 169 | self.argument_spec = dict( 170 | hostname=dict( 171 | required=True, 172 | default=None, 173 | type='str' 174 | ) 175 | ) 176 | self.f5_product_name = 'bigip' 177 | 178 | 179 | def main(): 180 | if not HAS_F5SDK: 181 | raise F5ModuleError("The python f5-sdk module is required") 182 | 183 | spec = ArgumentSpec() 184 | 185 | client = AnsibleF5Client( 186 | argument_spec=spec.argument_spec, 187 | supports_check_mode=spec.supports_check_mode, 188 | f5_product_name=spec.f5_product_name 189 | ) 190 | 191 | try: 192 | mm = ModuleManager(client) 193 | results = mm.exec_module() 194 | client.module.exit_json(**results) 195 | except F5ModuleError as e: 196 | client.module.fail_json(msg=str(e)) 197 | 198 | 199 | if __name__ == '__main__': 200 | main() 201 | -------------------------------------------------------------------------------- /library/bigip_routedomain_facts.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | # 4 | # Copyright (c) 2016 F5 Networks Inc. 5 | # GNU General Public License v3.0 (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) 6 | 7 | from __future__ import absolute_import, division, print_function 8 | __metaclass__ = type 9 | 10 | 11 | ANSIBLE_METADATA = {'metadata_version': '1.1', 12 | 'status': ['preview'], 13 | 'supported_by': 'community'} 14 | 15 | DOCUMENTATION = r''' 16 | --- 17 | module: bigip_routedomain_facts 18 | short_description: Retrieve route domain attributes from a BIG-IP 19 | description: 20 | - Retrieve route domain attributes from a BIG-IP 21 | version_added: "2.2" 22 | options: 23 | server: 24 | description: 25 | - BIG-IP host 26 | required: true 27 | password: 28 | description: 29 | - BIG-IP password 30 | required: true 31 | id: 32 | description: 33 | - The unique identifying integer representing the route domain. 34 | required: true 35 | partition: 36 | description: 37 | - The partition the route domain resides on 38 | required: false 39 | default: Common 40 | user: 41 | description: 42 | - BIG-IP username 43 | required: true 44 | validate_certs: 45 | description: 46 | - If C(no), SSL certificates will not be validated. This should only be 47 | used on personally controlled sites using self-signed certificates. 48 | required: false 49 | default: true 50 | notes: 51 | - Requires the f5-sdk Python package on the host. This is as easy as pip 52 | install f5-sdk 53 | requirements: 54 | - f5-sdk 55 | author: 56 | - Tim Rupp (@caphrim007) 57 | ''' 58 | 59 | EXAMPLES = r''' 60 | - name: Get the facts for a route domain 61 | bigip_routedomain_facts: 62 | id: 1234 63 | password: secret 64 | server: lb.mydomain.com 65 | user: admin 66 | delegate_to: localhost 67 | ''' 68 | 69 | RETURN = r''' 70 | bwc_policy: 71 | description: Bandwidth controller for the route domain 72 | returned: changed 73 | type: string 74 | sample: /Common/foo 75 | connection_limit: 76 | description: Maximum number of concurrent connections allowed for the route domain 77 | returned: changed 78 | type: integer 79 | sample: 0 80 | description: 81 | description: Descriptive text that identifies the route domain 82 | returned: changed 83 | type: string 84 | sample: The foo route domain 85 | evict_policy: 86 | description: Eviction policy to use with this route domain 87 | returned: changed 88 | type: string 89 | sample: /Common/default-eviction-policy 90 | id: 91 | description: ID of the route domain 92 | returned: changed 93 | type: integer 94 | sample: 1234 95 | service_policy: 96 | description: Service policy to associate with the route domain 97 | returned: changed 98 | type: string 99 | sample: /Common/abc 100 | strict: 101 | description: Whether the system enforces cross-routing restrictions 102 | returned: changed 103 | type: string 104 | sample: enabled 105 | routing_protocol: 106 | description: Dynamic routing protocols for the system to use in the route domain 107 | returned: changed 108 | type: list 109 | sample: ["BGP", "OSPFv2"] 110 | vlans: 111 | description: VLANs for the system to use in the route domain 112 | returned: changed 113 | type: list 114 | sample: ["/Common/abc", "/Common/xyz"] 115 | ''' 116 | 117 | try: 118 | from f5.bigip import ManagementRoot 119 | HAS_F5SDK = True 120 | except ImportError: 121 | HAS_F5SDK = False 122 | 123 | 124 | class BigIpRouteDomainFacts(object): 125 | def __init__(self, *args, **kwargs): 126 | if not HAS_F5SDK: 127 | raise F5ModuleError("The python f5-sdk module is required") 128 | 129 | self.params = kwargs 130 | self.api = ManagementRoot(kwargs['server'], 131 | kwargs['user'], 132 | kwargs['password'], 133 | port=kwargs['server_port']) 134 | 135 | def flush(self): 136 | result = dict() 137 | 138 | rds = self.api.tm.net.route_domains 139 | rd = rds.route_domain.load(name=kwargs['id'], 140 | partition=kwargs['partition']) 141 | 142 | result['id'] = rd.id 143 | result['name'] = rd.name 144 | result['parent'] = rd.parent 145 | 146 | if hasattr(r, 'bwcPolicy'): 147 | result['bwc_policy'] = rd.bwcPolicy 148 | if hasattr(r, 'connectionLimit'): 149 | result['connection_limit'] = rd.connectionLimit 150 | if hasattr(r, 'description'): 151 | result['description'] = rd.description 152 | if hasattr(r, 'flowEvictionPolicy'): 153 | result['evict_policy'] = rd.flowEvictionPolicy 154 | if hasattr(r, 'servicePolicy'): 155 | result['service_policy'] = rd.servicePolicy 156 | if hasattr(r, 'strict'): 157 | result['strict'] = rd.strict 158 | if hasattr(r, 'routingProtocol'): 159 | result['routing_protocol'] = rd.routingProtocol 160 | if hasattr(r, 'vlans'): 161 | result['vlans'] = rd.vlans 162 | return result 163 | 164 | 165 | def main(): 166 | argument_spec = f5_argument_spec() 167 | 168 | meta_args = dict( 169 | id=dict(required=True), 170 | ) 171 | argument_spec.update(meta_args) 172 | 173 | module = AnsibleModule( 174 | argument_spec=argument_spec, 175 | supports_check_mode=True 176 | ) 177 | 178 | try: 179 | obj = BigIpRouteDomainFacts(**module.params) 180 | result = obj.flush() 181 | 182 | module.exit_json(changed=True, bigip=result) 183 | except F5ModuleError as e: 184 | module.fail_json(msg=e.message) 185 | 186 | from ansible.module_utils.basic import * 187 | from ansible.module_utils.f5_utils import * 188 | 189 | if __name__ == '__main__': 190 | main() 191 | -------------------------------------------------------------------------------- /library/bigip_service.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | # 4 | # Copyright (c) 2016 F5 Networks Inc. 5 | # GNU General Public License v3.0 (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) 6 | 7 | from __future__ import absolute_import, division, print_function 8 | __metaclass__ = type 9 | 10 | 11 | ANSIBLE_METADATA = {'metadata_version': '1.1', 12 | 'status': ['preview'], 13 | 'supported_by': 'community'} 14 | 15 | DOCUMENTATION = r''' 16 | --- 17 | module: bigip_service 18 | short_description: Manage BIG-IP service states 19 | description: 20 | - Manage BIG-IP service states 21 | version_added: "2.2" 22 | options: 23 | server: 24 | description: 25 | - BIG-IP host 26 | required: true 27 | name: 28 | description: 29 | - Name of the service 30 | choices: 31 | - big3d 32 | - gtmd 33 | - named 34 | - ntpd 35 | - snmpd 36 | - sshd 37 | - zrd 38 | - websso 39 | required: true 40 | password: 41 | description: 42 | - BIG-IP password 43 | required: true 44 | default: admin 45 | state: 46 | description: 47 | - C(started)/C(stopped) are idempotent actions that will not run commands 48 | unless necessary. C(restarted) will always bounce the service. 49 | required: false 50 | default: None 51 | choices: 52 | - started 53 | - stopped 54 | - restarted 55 | user: 56 | description: 57 | - BIG-IP username 58 | required: true 59 | validate_certs: 60 | description: 61 | - If C(no), SSL certificates will not be validated. This should only be 62 | used on personally controlled sites using self-signed certificates. 63 | required: false 64 | default: yes 65 | choices: 66 | - yes 67 | - no 68 | notes: 69 | - Requires the bigsuds Python package on the host if using the iControl 70 | interface. This is as easy as pip install bigsuds 71 | requirements: 72 | - bigsuds 73 | author: 74 | - Tim Rupp (@caphrim007) 75 | ''' 76 | 77 | EXAMPLES = r''' 78 | - name: Restart the BIG-IP sshd service 79 | bigip_service: 80 | server: lb.mydomain.com 81 | name: sshd 82 | user: admin 83 | password: secret 84 | state: restarted 85 | delegate_to: localhost 86 | ''' 87 | 88 | import socket 89 | import time 90 | 91 | try: 92 | import bigsuds 93 | except ImportError: 94 | bigsuds_found = False 95 | else: 96 | bigsuds_found = True 97 | 98 | 99 | class BigIpCommon(object): 100 | def __init__(self, module): 101 | self._username = module.params.get('user') 102 | self._password = module.params.get('password') 103 | self._hostname = module.params.get('server') 104 | 105 | self._service = module.params.get('name') 106 | self._timeout = module.params.get('timeout') 107 | self._validate_certs = module.params.get('validate_certs') 108 | 109 | 110 | class BigIpIControl(BigIpCommon): 111 | def __init__(self, module): 112 | super(BigIpIControl, self).__init__(module) 113 | 114 | self.api = bigsuds.BIGIP( 115 | hostname=self._hostname, 116 | username=self._username, 117 | password=self._password, 118 | debug=True 119 | ) 120 | 121 | # We do not support all services because disabling/stopping some of 122 | # them would break the system 123 | service_map = { 124 | 'big3d': 'SERVICE_BIG3D', 125 | 'gtmd': 'SERVICE_GTMD', 126 | 'named': 'SERVICE_NAMED', 127 | 'ntpd': 'SERVICE_NTPD', 128 | 'snmpd': 'SERVICE_SNMPD', 129 | 'sshd': 'SERVICE_SSHD', 130 | 'zrd': 'SERVICE_ZRD', 131 | 'websso': 'SERVICE_WEBSSO' 132 | } 133 | 134 | service = service_map[self._service] 135 | self._service = service 136 | 137 | def is_supported_service(self): 138 | services = self.api.System.Services.get_list() 139 | if self._service in services: 140 | return True 141 | else: 142 | return False 143 | 144 | def get_service_status(self): 145 | result = self.api.System.Services.get_service_status([self._service]) 146 | if result[0]['status'] == 'SERVICE_STATUS_UP': 147 | return 'started' 148 | elif result[0]['status'] == 'SERVICE_STATUS_DOWN': 149 | return 'stopped' 150 | 151 | def _wait_for_service(self, state): 152 | timeout = time.time() + int(self._timeout) 153 | while True: 154 | status = self.get_service_status() 155 | 156 | if time.time() > timeout: 157 | break 158 | elif status == state: 159 | break 160 | else: 161 | time.sleep(1) 162 | 163 | def started(self): 164 | try: 165 | self.api.System.Services.set_service( 166 | services=[self._service], 167 | service_action='SERVICE_ACTION_START' 168 | ) 169 | changed = True 170 | except Exception: 171 | raise Exception('Failed to start the service') 172 | self._wait_for_service('started') 173 | 174 | return changed 175 | 176 | def stopped(self): 177 | try: 178 | self.api.System.Services.set_service( 179 | services=[self._service], 180 | service_action='SERVICE_ACTION_STOP' 181 | ) 182 | changed = True 183 | except Exception: 184 | raise Exception('Failed to stop the service') 185 | self._wait_for_service('stopped') 186 | 187 | return changed 188 | 189 | def restarted(self): 190 | try: 191 | self.api.System.Services.set_service( 192 | services=[self._service], 193 | service_action='SERVICE_ACTION_RESTART' 194 | ) 195 | changed = True 196 | except Exception: 197 | raise Exception('Failed to restart the service') 198 | 199 | self._wait_for_service('started') 200 | 201 | return changed 202 | 203 | 204 | def main(): 205 | changed = False 206 | 207 | service_choices = [ 208 | 'big3d', 'gtmd', 'named', 'ntpd', 'snmpd', 'sshd', 'zrd', 'websso' 209 | ] 210 | 211 | module = AnsibleModule( 212 | argument_spec=dict( 213 | connection=dict(default='icontrol', choices=['icontrol', 'rest']), 214 | server=dict(required=True), 215 | name=dict(required=True, choices=service_choices), 216 | password=dict(default='admin'), 217 | state=dict(default=None, choices=['started', 'stopped', 'restarted']), 218 | user=dict(required=True), 219 | validate_certs=dict(default='yes', type='bool', choices=['yes', 'no']), 220 | timeout=dict(default='60') 221 | ) 222 | ) 223 | 224 | connection = module.params.get('connection') 225 | hostname = module.params.get('server') 226 | password = module.params.get('password') 227 | username = module.params.get('user') 228 | state = module.params.get('state') 229 | 230 | try: 231 | if connection == 'icontrol': 232 | if not bigsuds_found: 233 | raise Exception("The python bigsuds module is required") 234 | 235 | icontrol = test_icontrol(username, password, hostname) 236 | if icontrol: 237 | obj = BigIpIControl(module) 238 | elif connection == 'rest': 239 | if not requests_found: 240 | raise Exception("The REST connection is not currently supported") 241 | 242 | if not obj.is_supported_service(): 243 | module.fail_json(msg="The specified service is not supported on this platform") 244 | 245 | status = obj.get_service_status() 246 | 247 | if state == "started" and status != 'started': 248 | if obj.started(): 249 | changed = True 250 | elif state == "stopped" and status != 'stopped': 251 | if obj.stopped(): 252 | changed = True 253 | elif state == "restarted": 254 | if obj.restarted(): 255 | changed = True 256 | except bigsuds.ConnectionError: 257 | module.fail_json(msg="Could not connect to BIG-IP host %s" % hostname) 258 | except socket.timeout: 259 | module.fail_json(msg="Timed out connecting to the BIG-IP") 260 | 261 | module.exit_json(changed=changed) 262 | 263 | from ansible.module_utils.basic import * 264 | from ansible.module_utils.f5_utils import * 265 | 266 | if __name__ == '__main__': 267 | main() 268 | -------------------------------------------------------------------------------- /library/bigip_snmp.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | # 4 | # Copyright (c) 2017 F5 Networks Inc. 5 | # GNU General Public License v3.0 (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) 6 | 7 | from __future__ import absolute_import, division, print_function 8 | __metaclass__ = type 9 | 10 | 11 | ANSIBLE_METADATA = {'metadata_version': '1.1', 12 | 'status': ['preview'], 13 | 'supported_by': 'community'} 14 | 15 | DOCUMENTATION = r''' 16 | module: bigip_snmp 17 | short_description: Manipulate general SNMP settings on a BIG-IP 18 | description: 19 | - Manipulate general SNMP settings on a BIG-IP. 20 | version_added: 2.4 21 | options: 22 | contact: 23 | description: 24 | - Specifies the name of the person who administers the SNMP 25 | service for this system. 26 | agent_status_traps: 27 | description: 28 | - When C(enabled), ensures that the system sends a trap whenever the 29 | SNMP agent starts running or stops running. This is usually enabled 30 | by default on a BIG-IP. 31 | choices: 32 | - enabled 33 | - disabled 34 | agent_authentication_traps: 35 | description: 36 | - When C(enabled), ensures that the system sends authentication warning 37 | traps to the trap destinations. This is usually disabled by default on 38 | a BIG-IP. 39 | choices: 40 | - enabled 41 | - disabled 42 | device_warning_traps: 43 | description: 44 | - When C(enabled), ensures that the system sends device warning traps 45 | to the trap destinations. This is usually enabled by default on a 46 | BIG-IP. 47 | choices: 48 | - enabled 49 | - disabled 50 | location: 51 | description: 52 | - Specifies the description of this system's physical location. 53 | notes: 54 | - Requires the f5-sdk Python package on the host. This is as easy as pip 55 | install f5-sdk. 56 | extends_documentation_fragment: f5 57 | requirements: 58 | - f5-sdk >= 2.2.0 59 | author: 60 | - Tim Rupp (@caphrim007) 61 | ''' 62 | 63 | EXAMPLES = r''' 64 | - name: Set snmp contact 65 | bigip_snmp: 66 | contact: "Joe User" 67 | password: "secret" 68 | server: "lb.mydomain.com" 69 | user: "admin" 70 | validate_certs: "false" 71 | delegate_to: localhost 72 | 73 | - name: Set snmp location 74 | bigip_snmp: 75 | location: "US West 1 76 | password: "secret 77 | server: "lb.mydomain.com 78 | user: "admin 79 | validate_certs: no 80 | delegate_to: localhost 81 | ''' 82 | 83 | RETURN = r''' 84 | agent_status_traps: 85 | description: Value that the agent status traps was set to. 86 | returned: changed 87 | type: string 88 | sample: enabled 89 | agent_authentication_traps: 90 | description: Value that the authentication status traps was set to. 91 | returned: changed 92 | type: string 93 | sample: enabled 94 | device_warning_traps: 95 | description: Value that the warning status traps was set to. 96 | returned: changed 97 | type: string 98 | sample: enabled 99 | contact: 100 | description: The new value for the person who administers SNMP on the device. 101 | returned: changed 102 | type: string 103 | sample: Joe User 104 | location: 105 | description: The new value for the system's physical location. 106 | returned: changed 107 | type: string 108 | sample: US West 1a 109 | ''' 110 | 111 | from ansible.module_utils.f5_utils import AnsibleF5Client 112 | from ansible.module_utils.f5_utils import AnsibleF5Parameters 113 | from ansible.module_utils.f5_utils import HAS_F5SDK 114 | from ansible.module_utils.f5_utils import F5ModuleError 115 | 116 | try: 117 | from ansible.module_utils.f5_utils import iControlUnexpectedHTTPError 118 | except ImportError: 119 | HAS_F5SDK = False 120 | 121 | 122 | class Parameters(AnsibleF5Parameters): 123 | api_map = { 124 | 'agentTrap': 'agent_status_traps', 125 | 'authTrap': 'agent_authentication_traps', 126 | 'bigipTraps': 'device_warning_traps', 127 | 'sysLocation': 'location', 128 | 'sysContact': 'contact' 129 | } 130 | 131 | updatables = [ 132 | 'agent_status_traps', 'agent_authentication_traps', 133 | 'device_warning_traps', 'location', 'contact' 134 | ] 135 | 136 | returnables = [ 137 | 'agent_status_traps', 'agent_authentication_traps', 138 | 'device_warning_traps', 'location', 'contact' 139 | ] 140 | 141 | api_attributes = [ 142 | 'agentTrap', 'authTrap', 'bigipTraps', 'sysLocation', 'sysContact' 143 | ] 144 | 145 | def to_return(self): 146 | result = {} 147 | for returnable in self.returnables: 148 | result[returnable] = getattr(self, returnable) 149 | result = self._filter_params(result) 150 | return result 151 | 152 | def api_params(self): 153 | result = {} 154 | for api_attribute in self.api_attributes: 155 | if self.api_map is not None and api_attribute in self.api_map: 156 | result[api_attribute] = getattr(self, self.api_map[api_attribute]) 157 | else: 158 | result[api_attribute] = getattr(self, api_attribute) 159 | result = self._filter_params(result) 160 | return result 161 | 162 | 163 | class ModuleManager(object): 164 | def __init__(self, client): 165 | self.client = client 166 | self.have = None 167 | self.want = Parameters(self.client.module.params) 168 | self.changes = Parameters() 169 | 170 | def _update_changed_options(self): 171 | changed = {} 172 | for key in Parameters.updatables: 173 | if getattr(self.want, key) is not None: 174 | attr1 = getattr(self.want, key) 175 | attr2 = getattr(self.have, key) 176 | if attr1 != attr2: 177 | changed[key] = attr1 178 | if changed: 179 | self.changes = Parameters(changed) 180 | return True 181 | return False 182 | 183 | def exec_module(self): 184 | result = dict() 185 | 186 | try: 187 | changed = self.update() 188 | except iControlUnexpectedHTTPError as e: 189 | raise F5ModuleError(str(e)) 190 | 191 | changes = self.changes.to_return() 192 | result.update(**changes) 193 | result.update(dict(changed=changed)) 194 | return result 195 | 196 | def should_update(self): 197 | result = self._update_changed_options() 198 | if result: 199 | return True 200 | return False 201 | 202 | def update(self): 203 | self.have = self.read_current_from_device() 204 | if not self.should_update(): 205 | return False 206 | if self.client.check_mode: 207 | return True 208 | self.update_on_device() 209 | return True 210 | 211 | def update_on_device(self): 212 | params = self.want.api_params() 213 | result = self.client.api.tm.sys.snmp.load() 214 | result.modify(**params) 215 | 216 | def read_current_from_device(self): 217 | resource = self.client.api.tm.sys.snmp.load() 218 | result = resource.attrs 219 | return Parameters(result) 220 | 221 | 222 | class ArgumentSpec(object): 223 | def __init__(self): 224 | self.supports_check_mode = True 225 | self.choices = ['enabled', 'disabled'] 226 | self.argument_spec = dict( 227 | contact=dict(), 228 | agent_status_traps=dict( 229 | choices=self.choices 230 | ), 231 | agent_authentication_traps=dict( 232 | choices=self.choices 233 | ), 234 | device_warning_traps=dict( 235 | choices=self.choices 236 | ), 237 | location=dict() 238 | ) 239 | self.f5_product_name = 'bigip' 240 | 241 | 242 | def main(): 243 | if not HAS_F5SDK: 244 | raise F5ModuleError("The python f5-sdk module is required") 245 | 246 | spec = ArgumentSpec() 247 | 248 | client = AnsibleF5Client( 249 | argument_spec=spec.argument_spec, 250 | supports_check_mode=spec.supports_check_mode, 251 | f5_product_name=spec.f5_product_name 252 | ) 253 | 254 | try: 255 | mm = ModuleManager(client) 256 | results = mm.exec_module() 257 | client.module.exit_json(**results) 258 | except F5ModuleError as e: 259 | client.module.fail_json(msg=str(e)) 260 | 261 | 262 | if __name__ == '__main__': 263 | main() 264 | -------------------------------------------------------------------------------- /library/bigip_snmp_community.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | # 4 | # Copyright (c) 2016 F5 Networks Inc. 5 | # GNU General Public License v3.0 (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) 6 | 7 | from __future__ import absolute_import, division, print_function 8 | __metaclass__ = type 9 | 10 | 11 | ANSIBLE_METADATA = {'metadata_version': '1.1', 12 | 'status': ['preview'], 13 | 'supported_by': 'community'} 14 | 15 | DOCUMENTATION = ''' 16 | --- 17 | module: bigip_dns_record_facts 18 | short_description: foo 19 | description: 20 | - foo 21 | version_added: "2.2" 22 | options: 23 | server: 24 | description: 25 | - BIG-IP host 26 | required: true 27 | user: 28 | description: 29 | - BIG-IP username 30 | required: true 31 | aliases: 32 | - username 33 | password: 34 | description: 35 | - BIG-IP password 36 | required: true 37 | notes: 38 | - Requires the f5-sdk Python package on the remote host. This is as easy as 39 | pip install f5-sdk 40 | requirements: 41 | - f5-sdk 42 | author: 43 | - Tim Rupp (@caphrim007) 44 | ''' 45 | 46 | from ansible.module_utils.basic import * 47 | from ansible.module_utils.f5_utils import * 48 | 49 | if __name__ == '__main__': 50 | main() 51 | -------------------------------------------------------------------------------- /library/bigip_snmp_user.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | # 4 | # Copyright (c) 2016 F5 Networks Inc. 5 | # GNU General Public License v3.0 (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) 6 | 7 | from __future__ import absolute_import, division, print_function 8 | __metaclass__ = type 9 | 10 | 11 | ANSIBLE_METADATA = {'metadata_version': '1.1', 12 | 'status': ['preview'], 13 | 'supported_by': 'community'} 14 | 15 | DOCUMENTATION = ''' 16 | --- 17 | module: bigip_dns_record_facts 18 | short_description: foo 19 | description: 20 | - foo 21 | version_added: "2.2" 22 | options: 23 | server: 24 | description: 25 | - BIG-IP host 26 | required: true 27 | user: 28 | description: 29 | - BIG-IP username 30 | required: true 31 | aliases: 32 | - username 33 | password: 34 | description: 35 | - BIG-IP password 36 | required: true 37 | notes: 38 | - Requires the f5-sdk Python package on the remote host. This is as easy as 39 | pip install f5-sdk 40 | requirements: 41 | - f5-sdk 42 | author: 43 | - Tim Rupp (@caphrim007) 44 | ''' 45 | 46 | from ansible.module_utils.basic import * 47 | from ansible.module_utils.f5_utils import * 48 | 49 | if __name__ == '__main__': 50 | main() 51 | -------------------------------------------------------------------------------- /library/bigip_software_update.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | # 4 | # Copyright (c) 2017 F5 Networks Inc. 5 | # GNU General Public License v3.0 (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) 6 | 7 | from __future__ import absolute_import, division, print_function 8 | __metaclass__ = type 9 | 10 | 11 | ANSIBLE_METADATA = {'metadata_version': '1.1', 12 | 'status': ['preview'], 13 | 'supported_by': 'community'} 14 | 15 | DOCUMENTATION = ''' 16 | --- 17 | module: bigip_software_update 18 | short_description: Manage the software update settings of a BIG-IP 19 | description: 20 | - Manage the software update settings of a BIG-IP. 21 | version_added: "2.4" 22 | options: 23 | auto_check: 24 | description: 25 | - Specifies whether to automatically check for updates on the F5 26 | Networks downloads server. 27 | required: False 28 | default: None 29 | choices: 30 | - yes 31 | - no 32 | frequency: 33 | description: 34 | - Specifies the schedule for the automatic update check. 35 | required: False 36 | default: None 37 | choices: 38 | - daily 39 | - monthly 40 | - weekly 41 | notes: 42 | - Requires the f5-sdk Python package on the host This is as easy as pip 43 | install f5-sdk 44 | extends_documentation_fragment: f5 45 | requirements: 46 | - f5-sdk >= 2.2.3 47 | author: 48 | - Tim Rupp (@caphrim007) 49 | ''' 50 | 51 | EXAMPLES = ''' 52 | ''' 53 | 54 | RETURN = ''' 55 | ''' 56 | 57 | from ansible.module_utils.f5_utils import ( 58 | AnsibleF5Client, 59 | AnsibleF5Parameters, 60 | HAS_F5SDK, 61 | F5ModuleError, 62 | iControlUnexpectedHTTPError 63 | ) 64 | 65 | 66 | class Parameters(AnsibleF5Parameters): 67 | api_map = { 68 | 'autoCheck': 'auto_check' 69 | } 70 | 71 | updatables = [ 72 | 'auto_check', 'frequency' 73 | ] 74 | 75 | returnables = [ 76 | 'auto_check', 'frequency' 77 | ] 78 | 79 | @property 80 | def auto_check(self): 81 | if self._values['auto_check'] is None: 82 | return None 83 | elif self._values['auto_check'] in [True, 'enabled']: 84 | return 'enabled' 85 | else: 86 | return 'disabled' 87 | 88 | def api_params(self): 89 | result = {} 90 | for api_attribute in self.api_attributes: 91 | if self.network == 'default': 92 | result['network'] = None 93 | elif self.api_map is not None and api_attribute in self.api_map: 94 | result[api_attribute] = getattr(self, self.api_map[api_attribute]) 95 | else: 96 | result[api_attribute] = getattr(self, api_attribute) 97 | result = self._filter_params(result) 98 | return result 99 | 100 | 101 | class ModuleManager(object): 102 | def __init__(self, client): 103 | self.client = client 104 | self.have = None 105 | self.want = Parameters(self.client.module.params) 106 | self.changes = Parameters() 107 | 108 | def exec_module(self): 109 | result = dict() 110 | 111 | try: 112 | changed = self.update() 113 | except iControlUnexpectedHTTPError as e: 114 | raise F5ModuleError(str(e)) 115 | 116 | changes = self.changes.to_return() 117 | result.update(**changes) 118 | result.update(dict(changed=changed)) 119 | return result 120 | 121 | def _update_changed_options(self): 122 | changed = {} 123 | for key in Parameters.updatables: 124 | if getattr(self.want, key) is not None: 125 | attr1 = getattr(self.want, key) 126 | attr2 = getattr(self.have, key) 127 | if attr1 != attr2: 128 | changed[key] = attr1 129 | if changed: 130 | self.changes = Parameters(changed) 131 | return True 132 | return False 133 | 134 | def should_update(self): 135 | result = self._update_changed_options() 136 | if result: 137 | return True 138 | return False 139 | 140 | def update(self): 141 | self.have = self.read_current_from_device() 142 | if not self.should_update(): 143 | return False 144 | if self.client.check_mode: 145 | return True 146 | self.update_on_device() 147 | return True 148 | 149 | def update_on_device(self): 150 | params = self.want.api_params() 151 | result = self.client.api.tm.sys.software.update.load() 152 | result.modify(**params) 153 | 154 | def read_current_from_device(self): 155 | resource = self.client.api.tm.sys.software.update.load() 156 | result = resource.attrs 157 | return Parameters(result) 158 | 159 | 160 | class ArgumentSpec(object): 161 | def __init__(self): 162 | self.supports_check_mode = True 163 | self.argument_spec = dict( 164 | auto_check=dict( 165 | type='bool' 166 | ), 167 | frequency=dict( 168 | choices=['daily', 'monthly', 'weekly'] 169 | ) 170 | ) 171 | self.f5_product_name = 'bigip' 172 | 173 | 174 | def main(): 175 | if not HAS_F5SDK: 176 | raise F5ModuleError("The python f5-sdk module is required") 177 | 178 | spec = ArgumentSpec() 179 | 180 | client = AnsibleF5Client( 181 | argument_spec=spec.argument_spec, 182 | supports_check_mode=spec.supports_check_mode, 183 | f5_product_name=spec.f5_product_name 184 | ) 185 | 186 | mm = ModuleManager(client) 187 | results = mm.exec_module() 188 | client.module.exit_json(**results) 189 | 190 | if __name__ == '__main__': 191 | main() 192 | -------------------------------------------------------------------------------- /library/bigip_user_facts.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | # 4 | # Copyright (c) 2016 F5 Networks Inc. 5 | # GNU General Public License v3.0 (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) 6 | 7 | from __future__ import absolute_import, division, print_function 8 | __metaclass__ = type 9 | 10 | 11 | ANSIBLE_METADATA = { 12 | 'status': ['preview'], 13 | 'supported_by': 'community', 14 | 'metadata_version': '1.1' 15 | } 16 | 17 | DOCUMENTATION = ''' 18 | --- 19 | module: bigip_user_facts 20 | short_description: Retrieve user account attributes from a BIG-IP 21 | description: 22 | - Retrieve user account attributes from a BIG-IP 23 | version_added: "2.2" 24 | options: 25 | username_credential: 26 | description: 27 | - Name of the user to retrieve facts for 28 | required: true 29 | notes: 30 | - Requires the f5-sdk Python package on the host. This is as easy as pip 31 | install f5-sdk 32 | - Facts are placed in the C(bigip) variable 33 | extends_documentation_fragment: f5 34 | requirements: 35 | - f5-sdk 36 | author: 37 | - Tim Rupp (@caphrim007) 38 | ''' 39 | 40 | EXAMPLES = ''' 41 | - name: Gather facts about user 'johnd' 42 | bigip_user_facts: 43 | name: "johnd" 44 | password: "secret" 45 | server: "lb.mydomain.com" 46 | user: "admin" 47 | validate_certs: "no" 48 | delegate_to: localhost 49 | 50 | - name: Display the user facts 51 | debug: 52 | var: bigip 53 | ''' 54 | 55 | RETURN = ''' 56 | description: 57 | description: The description of the user 58 | returned: changed 59 | type: string 60 | sample: "John Doe" 61 | username_credential: 62 | description: The username beign searched for 63 | returned: changed 64 | type: string 65 | sample: "jdoe" 66 | encrypted_password: 67 | description: The encrypted value of the password 68 | returned: changed 69 | type: string 70 | sample: "$6$/cgtFz0....yzv465uAJ/" 71 | partition_access: 72 | description: Access permissions for the account 73 | returned: changed 74 | type: list 75 | sample: 76 | - name: "all-partitions" 77 | role: "admin" 78 | ''' 79 | 80 | try: 81 | from f5.bigip import ManagementRoot 82 | HAS_F5SDK = True 83 | except ImportError: 84 | HAS_F5SDK = False 85 | 86 | 87 | class BigIpUserFacts(object): 88 | def __init__(self, *args, **kwargs): 89 | if not HAS_F5SDK: 90 | raise F5ModuleError("The python f5-sdk module is required") 91 | 92 | self.params = kwargs 93 | self.api = ManagementRoot(kwargs['server'], 94 | kwargs['user'], 95 | kwargs['password'], 96 | port=kwargs['server_port']) 97 | 98 | def exists(self): 99 | username_credential = self.params['username_credential'] 100 | if self.api.tm.auth.users.user.exists(name=username_credential): 101 | return True 102 | else: 103 | return False 104 | 105 | def flush(self): 106 | if self.exists: 107 | result = dict( 108 | changed=True, 109 | ansible_facts=dict( 110 | bigip=self.read() 111 | ) 112 | ) 113 | else: 114 | result = dict( 115 | changed=False 116 | ) 117 | return result 118 | 119 | def read(self): 120 | result = {} 121 | 122 | username_credential = self.params['username_credential'] 123 | user = self.api.tm.auth.users.user.load(name=username_credential) 124 | 125 | result['username_credential'] = username_credential 126 | 127 | if hasattr(user, 'description'): 128 | result['description'] = user.description 129 | 130 | if hasattr(user, 'encryptedPassword'): 131 | result['encrypted_password'] = user.encryptedPassword 132 | 133 | if hasattr(user, 'shell'): 134 | result['shell'] = user.shell 135 | 136 | if hasattr(user, 'partitionAccess'): 137 | result['partition_access'] = user.partitionAccess 138 | 139 | return result 140 | 141 | 142 | def main(): 143 | argument_spec = f5_argument_spec() 144 | 145 | meta_args = dict( 146 | username_credential=dict(required=True, aliases=['name'], no_log=False) 147 | ) 148 | argument_spec.update(meta_args) 149 | 150 | module = AnsibleModule( 151 | argument_spec=argument_spec, 152 | supports_check_mode=True 153 | ) 154 | 155 | try: 156 | result = dict() 157 | obj = BigIpUserFacts(check_mode=module.check_mode, **module.params) 158 | result = obj.flush() 159 | 160 | module.exit_json(**result) 161 | except F5ModuleError as e: 162 | module.fail_json(msg=str(e)) 163 | 164 | from ansible.module_utils.basic import * 165 | from ansible.module_utils.f5_utils import * 166 | 167 | if __name__ == '__main__': 168 | main() 169 | -------------------------------------------------------------------------------- /library/f5_support_upload.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | # 4 | # Copyright (c) 2016 F5 Networks Inc. 5 | # GNU General Public License v3.0 (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) 6 | 7 | from __future__ import absolute_import, division, print_function 8 | __metaclass__ = type 9 | 10 | 11 | ANSIBLE_METADATA = { 12 | 'status': ['preview'], 13 | 'supported_by': 'community', 14 | 'metadata_version': '1.1' 15 | } 16 | 17 | DOCUMENTATION = ''' 18 | --- 19 | module: bigip_partition 20 | short_description: Manage BIG-IP partitions 21 | description: 22 | - Manage BIG-IP partitions 23 | version_added: "2.3" 24 | options: 25 | description: 26 | description: 27 | - The description to attach to the Partition 28 | required: False 29 | default: None 30 | route_domain: 31 | description: 32 | - The default Route Domain to assign to the Partition. If no route domain 33 | is specified, then the default route domain for the system (typically 34 | zero) will be used only when creating a new partition. C(route_domain) 35 | and C(route_domain_id) are mutually exclusive. 36 | required: False 37 | default: None 38 | notes: 39 | - Requires the bigsuds Python package on the host if using the iControl 40 | interface. This is as easy as pip install bigsuds 41 | requirements: 42 | - bigsuds 43 | - requests 44 | extends_documentation_fragment: f5 45 | author: 46 | - Tim Rupp (@caphrim007) 47 | ''' 48 | 49 | EXAMPLES = ''' 50 | 51 | ''' 52 | -------------------------------------------------------------------------------- /library/iworkflow_local_connector.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | # 4 | # Copyright (c) 2017 F5 Networks Inc. 5 | # GNU General Public License v3.0 (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) 6 | 7 | from __future__ import absolute_import, division, print_function 8 | __metaclass__ = type 9 | 10 | 11 | ANSIBLE_METADATA = { 12 | 'status': ['preview'], 13 | 'supported_by': 'community', 14 | 'metadata_version': '1.1' 15 | } 16 | 17 | DOCUMENTATION = ''' 18 | module: iworkflow_bigip_connector 19 | short_description: Manipulate cloud BIG-IP connectors in iWorkflow 20 | description: 21 | - Manipulate cloud BIG-IP connectors in iWorkflow. 22 | version_added: 2.4 23 | options: 24 | name: 25 | description: 26 | - Name of the connector to create. 27 | required: True 28 | state: 29 | description: 30 | - When C(present), ensures that the cloud connector exists. When 31 | C(absent), ensures that the cloud connector does not exist. 32 | required: false 33 | default: present 34 | choices: 35 | - present 36 | - absent 37 | notes: 38 | - Requires the f5-sdk Python package on the host. This is as easy as pip 39 | install f5-sdk. 40 | extends_documentation_fragment: f5 41 | requirements: 42 | - f5-sdk >= 2.3.0 43 | - iWorkflow >= 2.1.0 44 | author: 45 | - Tim Rupp (@caphrim007) 46 | ''' 47 | 48 | EXAMPLES = ''' 49 | - name: Create cloud connector named Private Cloud 50 | iworkflow_bigip_connector: 51 | name: "Private Cloud" 52 | password: "secret" 53 | server: "iwf.mydomain.com" 54 | user: "admin" 55 | delegate_to: localhost 56 | ''' 57 | 58 | RETURN = ''' 59 | 60 | ''' 61 | 62 | from ansible.module_utils.f5_utils import ( 63 | AnsibleF5Client, 64 | AnsibleF5Parameters, 65 | F5ModuleError, 66 | HAS_F5SDK, 67 | iControlUnexpectedHTTPError 68 | ) 69 | 70 | 71 | class Parameters(AnsibleF5Parameters): 72 | returnables = ['name'] 73 | api_attributes = ['description'] 74 | updatables = ['description'] 75 | 76 | def to_return(self): 77 | result = {} 78 | for returnable in self.returnables: 79 | result[returnable] = getattr(self, returnable) 80 | result = self._filter_params(result) 81 | return result 82 | 83 | def api_params(self): 84 | result = {} 85 | for api_attribute in self.api_attributes: 86 | if self.api_map is not None and api_attribute in self.api_map: 87 | result[api_attribute] = getattr(self, self.api_map[api_attribute]) 88 | else: 89 | result[api_attribute] = getattr(self, api_attribute) 90 | result = self._filter_params(result) 91 | return result 92 | 93 | 94 | class ArgumentSpec(object): 95 | def __init__(self): 96 | self.supports_check_mode = True 97 | self.argument_spec = dict( 98 | name=dict(required=True), 99 | state=dict( 100 | required=False, 101 | default='present', 102 | choices=['absent', 'present'] 103 | ) 104 | ) 105 | self.f5_product_name = 'iworkflow' 106 | 107 | 108 | class ModuleManager(object): 109 | def __init__(self, client): 110 | self.client = client 111 | self.have = None 112 | self.want = Parameters(self.client.module.params) 113 | self.changes = Parameters() 114 | 115 | def _set_changed_options(self): 116 | changed = {} 117 | for key in Parameters.returnables: 118 | if getattr(self.want, key) is not None: 119 | changed[key] = getattr(self.want, key) 120 | if changed: 121 | self.changes = Parameters(changed) 122 | 123 | def _update_changed_options(self): 124 | changed = {} 125 | for key in Parameters.updatables: 126 | if getattr(self.want, key) is not None: 127 | attr1 = getattr(self.want, key) 128 | attr2 = getattr(self.have, key) 129 | if attr1 != attr2: 130 | changed[key] = attr1 131 | if changed: 132 | self.changes = Parameters(changed) 133 | return True 134 | return False 135 | 136 | def exec_module(self): 137 | changed = False 138 | result = dict() 139 | state = self.want.state 140 | 141 | try: 142 | if state == "present": 143 | changed = self.present() 144 | elif state == "absent": 145 | changed = self.absent() 146 | except iControlUnexpectedHTTPError as e: 147 | raise F5ModuleError(str(e)) 148 | 149 | result.update(**self.changes.to_return()) 150 | result.update(dict(changed=changed)) 151 | return result 152 | 153 | def exists(self): 154 | """Checks to see if a connector exists. 155 | 156 | This method does not use ODATA queries because that functionality 157 | is broken in iWorkflow. Therefore, we iterate over all connectors 158 | until we find the one we're interested in. 159 | 160 | :return: 161 | """ 162 | collection = self.client.api.cm.cloud.connectors.locals.get_collection() 163 | for item in collection: 164 | if item.displayName != "BIG-IP": 165 | continue 166 | if item.name != self.want.name: 167 | continue 168 | return True 169 | return False 170 | 171 | def present(self): 172 | if self.exists(): 173 | return self.update() 174 | else: 175 | return self.create() 176 | 177 | def create(self): 178 | self._set_changed_options() 179 | if self.client.check_mode: 180 | return True 181 | self.create_on_device() 182 | return True 183 | 184 | def update(self): 185 | self.have = self.read_current_from_device() 186 | if not self.should_update(): 187 | return False 188 | if self.client.check_mode: 189 | return True 190 | self.update_on_device() 191 | return True 192 | 193 | def should_update(self): 194 | result = self._update_changed_options() 195 | if result: 196 | return True 197 | return False 198 | 199 | def update_on_device(self): 200 | pass 201 | 202 | def read_current_from_device(self): 203 | connector = None 204 | collection = self.client.api.cm.cloud.connectors.locals.get_collection() 205 | for item in collection: 206 | if item.displayName != "BIG-IP": 207 | continue 208 | if item.name != self.want.name: 209 | continue 210 | connector = item 211 | break 212 | if not connector: 213 | return None 214 | result = connector.attrs 215 | return Parameters(result) 216 | 217 | def create_on_device(self): 218 | params = self.want.api_params() 219 | self.client.api.cm.cloud.connectors.locals.local.create( 220 | name=self.want.name, 221 | **params 222 | ) 223 | 224 | def absent(self): 225 | if self.exists(): 226 | return self.remove() 227 | return False 228 | 229 | def remove(self): 230 | if self.client.check_mode: 231 | return True 232 | self.remove_from_device() 233 | if self.exists(): 234 | raise F5ModuleError("Failed to delete the BIG-IP connector") 235 | return True 236 | 237 | def remove_from_device(self): 238 | resource = None 239 | collection = self.client.api.cm.cloud.connectors.locals.get_collection() 240 | for item in collection: 241 | if item.displayName != "BIG-IP": 242 | continue 243 | if item.name != self.want.name: 244 | continue 245 | resource = item 246 | break 247 | if resource: 248 | resource.delete() 249 | 250 | 251 | def main(): 252 | if not HAS_F5SDK: 253 | raise F5ModuleError("The python f5-sdk module is required") 254 | 255 | spec = ArgumentSpec() 256 | 257 | client = AnsibleF5Client( 258 | argument_spec=spec.argument_spec, 259 | supports_check_mode=spec.supports_check_mode, 260 | f5_product_name=spec.f5_product_name 261 | ) 262 | 263 | try: 264 | mm = ModuleManager(client) 265 | results = mm.exec_module() 266 | client.module.exit_json(**results) 267 | except F5ModuleError as e: 268 | client.module.fail_json(msg=str(e)) 269 | 270 | 271 | if __name__ == '__main__': 272 | main() 273 | -------------------------------------------------------------------------------- /library/iworkflow_tenant.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | # 4 | # Copyright (c) 2017 F5 Networks Inc. 5 | # GNU General Public License v3.0 (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) 6 | 7 | from __future__ import absolute_import, division, print_function 8 | __metaclass__ = type 9 | 10 | 11 | ANSIBLE_METADATA = { 12 | 'status': ['preview'], 13 | 'supported_by': 'community', 14 | 'metadata_version': '1.1' 15 | } 16 | 17 | DOCUMENTATION = ''' 18 | module: iworkflow_tenant 19 | short_description: Manage tenants in iWorkflow 20 | description: 21 | - Manage tenants in iWorkflow. 22 | version_added: 2.4 23 | options: 24 | name: 25 | description: 26 | - Name of the tenant that you want to manage. 27 | required: True 28 | description: 29 | description: 30 | - An optional description for the tenant. 31 | required: False 32 | default: None 33 | contact_address: 34 | description: 35 | - An optional contact address associated with the tenant. 36 | required: False 37 | default: None 38 | contact_phone: 39 | description: 40 | - An optional contact phone number associated with the tenant. 41 | required: False 42 | default: None 43 | contact_email: 44 | description: 45 | - An optional contact email address associated with the tenant. 46 | required: False 47 | default: None 48 | state: 49 | description: 50 | - When C(state) is C(present), ensures that the tenant exists. When 51 | C(state) is C(absent), ensures that the tenant is removed. 52 | required: False 53 | default: present 54 | choices: 55 | - present 56 | - absent 57 | notes: 58 | - Requires the f5-sdk Python package on the host. This is as easy as pip 59 | install f5-sdk. 60 | - Tenants are not useful unless you associate them with a connector 61 | using the C(iworkflow_tenant_connector) module. 62 | extends_documentation_fragment: f5 63 | requirements: 64 | - f5-sdk >= 2.3.0 65 | - iWorkflow >= 2.1.0 66 | author: 67 | - Tim Rupp (@caphrim007) 68 | ''' 69 | 70 | EXAMPLES = ''' 71 | 72 | ''' 73 | 74 | RETURN = ''' 75 | 76 | ''' 77 | 78 | 79 | from ansible.module_utils.f5_utils import ( 80 | AnsibleF5Client, 81 | AnsibleF5Parameters, 82 | F5ModuleError, 83 | HAS_F5SDK, 84 | iControlUnexpectedHTTPError 85 | ) 86 | 87 | 88 | class Parameters(AnsibleF5Parameters): 89 | api_map = { 90 | 'addressContact': 'address' 91 | } 92 | returnables = [] 93 | 94 | api_attributes = [ 95 | 'description', 'addressContact', 'phone', 'email' 96 | ] 97 | 98 | updatables = [] 99 | 100 | def to_return(self): 101 | result = {} 102 | try: 103 | for returnable in self.returnables: 104 | result[returnable] = getattr(self, returnable) 105 | result = self._filter_params(result) 106 | except Exception: 107 | pass 108 | return result 109 | 110 | def api_params(self): 111 | result = {} 112 | for api_attribute in self.api_attributes: 113 | if self.api_map is not None and api_attribute in self.api_map: 114 | result[api_attribute] = getattr(self, self.api_map[api_attribute]) 115 | else: 116 | result[api_attribute] = getattr(self, api_attribute) 117 | result = self._filter_params(result) 118 | return result 119 | 120 | 121 | class ModuleManager(object): 122 | def __init__(self, client): 123 | self.client = client 124 | self.have = None 125 | self.want = Parameters(self.client.module.params) 126 | self.changes = Parameters() 127 | 128 | def _set_changed_options(self): 129 | changed = {} 130 | for key in Parameters.returnables: 131 | if getattr(self.want, key) is not None: 132 | changed[key] = getattr(self.want, key) 133 | if changed: 134 | self.changes = Parameters(changed) 135 | 136 | def _update_changed_options(self): 137 | changed = {} 138 | for key in Parameters.updatables: 139 | if getattr(self.want, key) is not None: 140 | attr1 = getattr(self.want, key) 141 | attr2 = getattr(self.have, key) 142 | if attr1 != attr2: 143 | changed[key] = attr1 144 | if changed: 145 | self.changes = Parameters(changed) 146 | return True 147 | return False 148 | 149 | def exec_module(self): 150 | changed = False 151 | result = dict() 152 | state = self.want.state 153 | 154 | try: 155 | if state == "present": 156 | changed = self.present() 157 | elif state == "absent": 158 | changed = self.absent() 159 | except iControlUnexpectedHTTPError as e: 160 | raise F5ModuleError(str(e)) 161 | 162 | changes = self.changes.to_return() 163 | result.update(**changes) 164 | result.update(dict(changed=changed)) 165 | return result 166 | 167 | def exists(self): 168 | collection = self.client.api.cm.cloud.tenants_s.get_collection( 169 | requests_params=dict( 170 | params="$filter=name+eq+'{0}'".format(self.want.name) 171 | ) 172 | ) 173 | if len(collection) == 1: 174 | return True 175 | elif len(collection) == 0: 176 | return False 177 | else: 178 | raise F5ModuleError( 179 | "Multiple tenants with the provided name were found!" 180 | ) 181 | 182 | def present(self): 183 | if self.exists(): 184 | return self.update() 185 | else: 186 | return self.create() 187 | 188 | def create(self): 189 | if self.client.check_mode: 190 | return True 191 | self.create_on_device() 192 | return True 193 | 194 | def update(self): 195 | pass 196 | 197 | def read_current_from_device(self): 198 | collection = self.client.api.cm.cloud.tenants_s.get_collection( 199 | requests_params=dict( 200 | params="$filter=name+eq+'{0}'".format(self.want.name) 201 | ) 202 | ) 203 | resource = collection.pop() 204 | result = resource.attrs 205 | return Parameters(result) 206 | 207 | def create_on_device(self): 208 | params = self.want.api_params() 209 | self.client.api.cm.cloud.tenants_s.tenant.create( 210 | name=self.want.name, 211 | **params 212 | ) 213 | return True 214 | 215 | def absent(self): 216 | if self.exists(): 217 | return self.remove() 218 | return False 219 | 220 | def remove(self): 221 | if self.client.check_mode: 222 | return True 223 | self.remove_from_device() 224 | if self.exists(): 225 | raise F5ModuleError("Failed to delete the tenant") 226 | return True 227 | 228 | def remove_from_device(self): 229 | collection = self.client.api.cm.cloud.tenants_s.get_collection( 230 | requests_params=dict( 231 | params="$filter=name+eq+'{0}'".format(self.want.name) 232 | ) 233 | ) 234 | resource = collection.pop() 235 | resource.delete() 236 | 237 | 238 | class ArgumentSpec(object): 239 | def __init__(self): 240 | self.supports_check_mode = True 241 | self.argument_spec = dict( 242 | name=dict(required=True), 243 | description=dict(type='str'), 244 | contact_address=dict(type='str'), 245 | contact_phone=dict(type='str'), 246 | contact_email=dict(type='str'), 247 | state=dict( 248 | required=False, 249 | default='present', 250 | choices=['absent', 'present'] 251 | ) 252 | ) 253 | self.f5_product_name = 'iworkflow' 254 | 255 | 256 | def main(): 257 | if not HAS_F5SDK: 258 | raise F5ModuleError("The python f5-sdk module is required") 259 | 260 | spec = ArgumentSpec() 261 | 262 | client = AnsibleF5Client( 263 | argument_spec=spec.argument_spec, 264 | supports_check_mode=spec.supports_check_mode, 265 | f5_product_name=spec.f5_product_name 266 | ) 267 | 268 | try: 269 | mm = ModuleManager(client) 270 | results = mm.exec_module() 271 | client.module.exit_json(**results) 272 | except F5ModuleError as e: 273 | client.module.fail_json(msg=str(e)) 274 | 275 | 276 | if __name__ == '__main__': 277 | main() 278 | -------------------------------------------------------------------------------- /library/iworkflow_user.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | # 4 | # Copyright (c) 2017 F5 Networks Inc. 5 | # GNU General Public License v3.0 (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) 6 | 7 | from __future__ import absolute_import, division, print_function 8 | __metaclass__ = type 9 | 10 | 11 | ANSIBLE_METADATA = { 12 | 'status': ['preview'], 13 | 'supported_by': 'community', 14 | 'metadata_version': '1.1' 15 | } 16 | 17 | DOCUMENTATION = ''' 18 | module: iworkflow_user 19 | short_description: Manage users in iWorkflow 20 | description: 21 | - Manage users in iWorkflow. 22 | version_added: 2.4 23 | options: 24 | name: 25 | description: 26 | - Name of the user that you want to manage. 27 | required: True 28 | description: 29 | description: 30 | - An optional description for the user. 31 | required: False 32 | default: None 33 | state: 34 | description: 35 | - When C(state) is C(present), ensures that the user exists. When 36 | C(state) is C(absent), ensures that the user is removed. 37 | required: False 38 | default: present 39 | choices: 40 | - present 41 | - absent 42 | notes: 43 | - Requires the f5-sdk Python package on the host. This is as easy as pip 44 | install f5-sdk. 45 | extends_documentation_fragment: f5 46 | requirements: 47 | - f5-sdk >= 2.3.0 48 | - iWorkflow >= 2.1.0 49 | author: 50 | - Tim Rupp (@caphrim007) 51 | ''' 52 | 53 | EXAMPLES = ''' 54 | 55 | ''' 56 | 57 | RETURN = ''' 58 | 59 | ''' 60 | 61 | 62 | from ansible.module_utils.f5_utils import ( 63 | AnsibleF5Client, 64 | AnsibleF5Parameters, 65 | F5ModuleError, 66 | HAS_F5SDK, 67 | iControlUnexpectedHTTPError 68 | ) 69 | 70 | 71 | class Parameters(AnsibleF5Parameters): 72 | api_map = { 73 | 'displayName': 'description' 74 | } 75 | returnables = [] 76 | 77 | api_attributes = [ 78 | 'description', 79 | ] 80 | 81 | updatables = [] 82 | 83 | def to_return(self): 84 | result = {} 85 | try: 86 | for returnable in self.returnables: 87 | result[returnable] = getattr(self, returnable) 88 | result = self._filter_params(result) 89 | except Exception: 90 | pass 91 | return result 92 | 93 | def api_params(self): 94 | result = {} 95 | for api_attribute in self.api_attributes: 96 | if self.api_map is not None and api_attribute in self.api_map: 97 | result[api_attribute] = getattr(self, self.api_map[api_attribute]) 98 | else: 99 | result[api_attribute] = getattr(self, api_attribute) 100 | result = self._filter_params(result) 101 | return result 102 | 103 | 104 | class ModuleManager(object): 105 | def __init__(self, client): 106 | self.client = client 107 | self.have = None 108 | self.want = Parameters(self.client.module.params) 109 | self.changes = Parameters() 110 | 111 | def _set_changed_options(self): 112 | changed = {} 113 | for key in Parameters.returnables: 114 | if getattr(self.want, key) is not None: 115 | changed[key] = getattr(self.want, key) 116 | if changed: 117 | self.changes = Parameters(changed) 118 | 119 | def _update_changed_options(self): 120 | changed = {} 121 | for key in Parameters.updatables: 122 | if getattr(self.want, key) is not None: 123 | attr1 = getattr(self.want, key) 124 | attr2 = getattr(self.have, key) 125 | if attr1 != attr2: 126 | changed[key] = attr1 127 | if changed: 128 | self.changes = Parameters(changed) 129 | return True 130 | return False 131 | 132 | def exec_module(self): 133 | changed = False 134 | result = dict() 135 | state = self.want.state 136 | 137 | try: 138 | if state == "present": 139 | changed = self.present() 140 | elif state == "absent": 141 | changed = self.absent() 142 | except iControlUnexpectedHTTPError as e: 143 | raise F5ModuleError(str(e)) 144 | 145 | changes = self.changes.to_return() 146 | result.update(**changes) 147 | result.update(dict(changed=changed)) 148 | return result 149 | 150 | def exists(self): 151 | return self.client.api.shared.authz.users.user.exists( 152 | name=self.want.name 153 | ) 154 | 155 | def present(self): 156 | if self.exists(): 157 | return self.update() 158 | else: 159 | return self.create() 160 | 161 | def create(self): 162 | if self.client.check_mode: 163 | return True 164 | self.create_on_device() 165 | return True 166 | 167 | def update(self): 168 | pass 169 | 170 | def read_current_from_device(self): 171 | collection = self.client.api.cm.cloud.tenants_s.get_collection( 172 | requests_params=dict( 173 | params="$filter=name+eq+'{0}'".format(self.want.name) 174 | ) 175 | ) 176 | resource = collection.pop() 177 | result = resource.attrs 178 | return Parameters(result) 179 | 180 | def create_on_device(self): 181 | params = self.want.api_params() 182 | self.client.api.cm.cloud.tenants_s.tenant.create( 183 | name=self.want.name, 184 | **params 185 | ) 186 | return True 187 | 188 | def absent(self): 189 | if self.exists(): 190 | return self.remove() 191 | return False 192 | 193 | def remove(self): 194 | if self.client.check_mode: 195 | return True 196 | self.remove_from_device() 197 | if self.exists(): 198 | raise F5ModuleError("Failed to delete the tenant") 199 | return True 200 | 201 | def remove_from_device(self): 202 | collection = self.client.api.cm.cloud.tenants_s.get_collection( 203 | requests_params=dict( 204 | params="$filter=name+eq+'{0}'".format(self.want.name) 205 | ) 206 | ) 207 | resource = collection.pop() 208 | resource.delete() 209 | 210 | 211 | class ArgumentSpec(object): 212 | def __init__(self): 213 | self.supports_check_mode = True 214 | self.argument_spec = dict( 215 | name=dict(required=True), 216 | description=dict(type='str'), 217 | contact_address=dict(type='str'), 218 | contact_phone=dict(type='str'), 219 | contact_email=dict(type='str'), 220 | state=dict( 221 | required=False, 222 | default='present', 223 | choices=['absent', 'present'] 224 | ) 225 | ) 226 | self.f5_product_name = 'iworkflow' 227 | 228 | 229 | def main(): 230 | if not HAS_F5SDK: 231 | raise F5ModuleError("The python f5-sdk module is required") 232 | 233 | spec = ArgumentSpec() 234 | 235 | client = AnsibleF5Client( 236 | argument_spec=spec.argument_spec, 237 | supports_check_mode=spec.supports_check_mode, 238 | f5_product_name=spec.f5_product_name 239 | ) 240 | 241 | try: 242 | mm = ModuleManager(client) 243 | results = mm.exec_module() 244 | client.module.exit_json(**results) 245 | except F5ModuleError as e: 246 | client.module.fail_json(msg=str(e)) 247 | 248 | 249 | if __name__ == '__main__': 250 | main() 251 | -------------------------------------------------------------------------------- /library/module_utils/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcgonagle/ansible_f5/ec93eb36b0098cdb93931fdfcba8fabcaec4a7ee/library/module_utils/__init__.py -------------------------------------------------------------------------------- /library/module_utils/f5networks/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcgonagle/ansible_f5/ec93eb36b0098cdb93931fdfcba8fabcaec4a7ee/library/module_utils/f5networks/__init__.py -------------------------------------------------------------------------------- /library/module_utils/f5networks/common.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | # Copyright: (c) 2017, F5 Networks Inc. 4 | # GNU General Public License v3.0 (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) 5 | 6 | 7 | class Noop(object): 8 | """Represent no-operation required 9 | 10 | This class is used in the Difference engine to specify when an attribute 11 | has not changed. Difference attributes may return an instance of this 12 | class as a means to indicate when the attribute has not changed. 13 | 14 | The Noop object allows attributes to be set to None when sending updates 15 | to the API. `None` is technically a valid value in some cases (it indicates 16 | that the attribute should be removed from the resource). 17 | """ 18 | pass 19 | 20 | 21 | def fqdn_name(partition, value): 22 | if value is not None and not value.startswith('/'): 23 | return '/{0}/{1}'.format(partition, value) 24 | return value 25 | -------------------------------------------------------------------------------- /library_old/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcgonagle/ansible_f5/ec93eb36b0098cdb93931fdfcba8fabcaec4a7ee/library_old/__init__.py -------------------------------------------------------------------------------- /library_old/bigip_dns_record_facts.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | # 4 | # Copyright 2016 F5 Networks Inc. 5 | # 6 | # This file is part of Ansible 7 | # 8 | # Ansible is free software: you can redistribute it and/or modify 9 | # it under the terms of the GNU General Public License as published by 10 | # the Free Software Foundation, either version 3 of the License, or 11 | # (at your option) any later version. 12 | # 13 | # Ansible is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | # GNU General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU General Public License 19 | # along with Ansible. If not, see . 20 | 21 | ANSIBLE_METADATA = { 22 | 'status': ['preview'], 23 | 'supported_by': 'community', 24 | 'metadata_version': '1.0' 25 | } 26 | 27 | DOCUMENTATION = ''' 28 | --- 29 | module: bigip_dns_record_facts 30 | short_description: foo 31 | description: 32 | - foo 33 | version_added: "2.2" 34 | options: 35 | server: 36 | description: 37 | - BIG-IP host 38 | required: true 39 | user: 40 | description: 41 | - BIG-IP username 42 | required: true 43 | aliases: 44 | - username 45 | password: 46 | description: 47 | - BIG-IP password 48 | required: true 49 | notes: 50 | - Requires the f5-sdk Python package on the remote host. This is as easy as 51 | pip install f5-sdk 52 | requirements: 53 | - f5-sdk 54 | author: 55 | - Tim Rupp (@caphrim007) 56 | ''' 57 | 58 | EXAMPLES = ''' 59 | 60 | ''' 61 | 62 | RETURN = ''' 63 | 64 | ''' 65 | 66 | from ansible.module_utils.basic import * 67 | from ansible.module_utils.f5_utils import * 68 | 69 | if __name__ == '__main__': 70 | main() 71 | -------------------------------------------------------------------------------- /library_old/bigip_dns_zone.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | # 4 | # Copyright 2016 F5 Networks Inc. 5 | # 6 | # This file is part of Ansible 7 | # 8 | # Ansible is free software: you can redistribute it and/or modify 9 | # it under the terms of the GNU General Public License as published by 10 | # the Free Software Foundation, either version 3 of the License, or 11 | # (at your option) any later version. 12 | # 13 | # Ansible is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | # GNU General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU General Public License 19 | # along with Ansible. If not, see . 20 | 21 | ANSIBLE_METADATA = { 22 | 'status': ['preview'], 23 | 'supported_by': 'community', 24 | 'metadata_version': '1.0' 25 | } 26 | 27 | DOCUMENTATION = ''' 28 | --- 29 | module: bigip_dns_zone 30 | short_description: Manages DNS zones on a BIG-IP 31 | description: 32 | - This module manages DNS zones described in the iControl Management 33 | documentation 34 | version_added: "2.2" 35 | options: 36 | server: 37 | description: 38 | - BIG-IP host 39 | required: true 40 | user: 41 | description: 42 | - BIG-IP username 43 | required: true 44 | aliases: 45 | - username 46 | password: 47 | description: 48 | - BIG-IP password 49 | required: true 50 | zone: 51 | description: 52 | - The name of the zone 53 | required: true 54 | options: 55 | description: 56 | - A sequence of options for the view 57 | state: 58 | description: 59 | - Whether the record should exist. When C(absent), removes 60 | the record. 61 | required: false 62 | default: present 63 | choices: 64 | - present 65 | - absent 66 | notes: 67 | - Requires the bigsuds Python package on the remote host. This is as easy as 68 | pip install bigsuds 69 | - https://devcentral.f5.com/wiki/iControl.Management__Zone.ashx 70 | requirements: 71 | - bigsuds 72 | - distutils 73 | author: 74 | - Tim Rupp (@caphrim007) 75 | ''' 76 | 77 | EXAMPLES = ''' 78 | - name: Add a view, named "internal", to organization.com zone 79 | local_action: 80 | module: bigip_view 81 | username: 'admin' 82 | password: 'admin' 83 | hostname: 'bigip.organization.com' 84 | zone_names: 85 | - 'organization.com' 86 | state: 'present' 87 | options: 88 | - domain_name: elliot.organization.com 89 | ip_address: 10.1.1.1 90 | ''' 91 | 92 | from distutils.version import StrictVersion 93 | import re 94 | 95 | VERSION_PATTERN = 'BIG-IP_v(?P\d+\.\d+\.\d+)' 96 | 97 | 98 | class ViewZoneException(Exception): 99 | pass 100 | 101 | 102 | class ViewZone(object): 103 | REQUIRED_BIGIP_VERSION = '9.0.3' 104 | 105 | def __init__(self, module): 106 | self.module = module 107 | 108 | self.username = module.params['username'] 109 | self.password = module.params['password'] 110 | self.hostname = module.params['hostname'] 111 | self.view_name = module.params['view_name'] 112 | self.zone_name = module.params['zone_name'] 113 | self.zone_type = module.params['zone_type'].lower() 114 | self.zone_file = module.params['zone_file'] 115 | self.options = module.params['options'] 116 | self.text = module.params['text'] 117 | 118 | if not self.zone_name.endswith('.'): 119 | self.zone_name += '.' 120 | 121 | self.client = bigsuds.BIGIP( 122 | hostname=self.hostname, 123 | username=self.username, 124 | password=self.password, 125 | debug=True 126 | ) 127 | 128 | # Do some checking of things 129 | self.check_version() 130 | 131 | def get_zone_type(self): 132 | zone_type_maps = dict( 133 | unset='UNSET', # Not yet initialized 134 | master='MASTER', # A master zone 135 | slave='SLAVE', # A slave zone 136 | stub='STUB', # A stub zone 137 | forward='FORWARD', # A forward zone 138 | hint='HINT' # A hint zone, "." 139 | ) 140 | 141 | if self.zone_type in zone_type_maps: 142 | return zone_type_maps[self.zone_type] 143 | else: 144 | raise ViewZoneException('Specified zone_type does not exist') 145 | 146 | def check_version(self): 147 | response = self.client.System.SystemInfo.get_version() 148 | match = re.search(VERSION_PATTERN, response) 149 | version = match.group('version') 150 | 151 | v1 = StrictVersion(version) 152 | v2 = StrictVersion(self.REQUIRED_BIGIP_VERSION) 153 | 154 | if v1 < v2: 155 | raise ViewException('The BIG-IP version %s does not support this feature' % version) 156 | 157 | def zone_exists(self): 158 | view_zone = dict( 159 | view_name=self.view_name, 160 | zone_name=self.zone_name, 161 | ) 162 | 163 | response = self.client.Management.Zone.zone_exist( 164 | view_zones=[view_zone] 165 | ) 166 | 167 | return response 168 | 169 | def create_zone(self): 170 | view_zone = dict( 171 | view_name=self.view_name, 172 | zone_name=self.zone_name, 173 | zone_type=self.get_zone_type(), 174 | zone_file=self.zone_file, 175 | option_seq=self.options 176 | ) 177 | 178 | self.client.Management.Zone.add_zone_text( 179 | zone_records=[view_zone], 180 | text=[[self.text]], 181 | sync_ptrs=[1] 182 | ) 183 | 184 | def delete_zone(self): 185 | view_zone = dict( 186 | view_name=self.view_name, 187 | zone_name=self.zone_name 188 | ) 189 | 190 | self.client.Management.Zone.delete_zone( 191 | view_zones=[view_zone] 192 | ) 193 | 194 | 195 | def main(): 196 | module = AnsibleModule( 197 | argument_spec=dict( 198 | username=dict(default='admin'), 199 | password=dict(default='admin'), 200 | hostname=dict(default='localhost'), 201 | view_name=dict(default='external'), 202 | zone_name=dict(required=True), 203 | zone_type=dict(default='master'), 204 | options=dict(required=False, type='list'), 205 | zone_file=dict(default=None), 206 | text=dict(default=None), 207 | state=dict(default="present", choices=["absent", "present"]), 208 | ) 209 | ) 210 | 211 | state = module.params["state"] 212 | zone_file = module.params['zone_file'] 213 | 214 | if not bigsuds_found: 215 | module.fail_json(msg="The python bigsuds module is required") 216 | 217 | view_zone = ViewZone(module) 218 | 219 | if state == "present": 220 | if not zone_file: 221 | raise ViewZoneException('A zone_file must be specified') 222 | 223 | if view_zone.zone_exists(): 224 | changed = False 225 | else: 226 | view_zone.create_zone() 227 | changed = True 228 | elif state == "absent": 229 | view_zone.delete_zone() 230 | changed = True 231 | 232 | module.exit_json(changed=changed) 233 | 234 | from ansible.module_utils.basic import * 235 | from ansible.module_utils.f5_utils import * 236 | 237 | if __name__ == '__main__': 238 | main() 239 | -------------------------------------------------------------------------------- /library_old/bigip_drop_connection.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | # 4 | # Copyright 2016 F5 Networks Inc. 5 | # 6 | # This file is part of Ansible 7 | # 8 | # Ansible is free software: you can redistribute it and/or modify 9 | # it under the terms of the GNU General Public License as published by 10 | # the Free Software Foundation, either version 3 of the License, or 11 | # (at your option) any later version. 12 | # 13 | # Ansible is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | # GNU General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU General Public License 19 | # along with Ansible. If not, see . 20 | 21 | ANSIBLE_METADATA = { 22 | 'status': ['preview'], 23 | 'supported_by': 'community', 24 | 'metadata_version': '1.0' 25 | } 26 | 27 | DOCUMENTATION = ''' 28 | --- 29 | module: bigip_dns_record_facts 30 | short_description: foo 31 | description: 32 | - foo 33 | version_added: "2.2" 34 | options: 35 | server: 36 | description: 37 | - BIG-IP host 38 | required: true 39 | user: 40 | description: 41 | - BIG-IP username 42 | required: true 43 | aliases: 44 | - username 45 | password: 46 | description: 47 | - BIG-IP password 48 | required: true 49 | notes: 50 | - Requires the f5-sdk Python package on the remote host. This is as easy as 51 | pip install f5-sdk 52 | requirements: 53 | - f5-sdk 54 | author: 55 | - Tim Rupp (@caphrim007) 56 | ''' 57 | 58 | from ansible.module_utils.basic import * 59 | from ansible.module_utils.f5_utils import * 60 | 61 | if __name__ == '__main__': 62 | main() 63 | -------------------------------------------------------------------------------- /library_old/bigip_hostname.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | # 4 | # Copyright 2016 F5 Networks Inc. 5 | # 6 | # This file is part of Ansible 7 | # 8 | # Ansible is free software: you can redistribute it and/or modify 9 | # it under the terms of the GNU General Public License as published by 10 | # the Free Software Foundation, either version 3 of the License, or 11 | # (at your option) any later version. 12 | # 13 | # Ansible is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | # GNU General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU General Public License 19 | # along with Ansible. If not, see . 20 | 21 | ANSIBLE_METADATA = { 22 | 'status': ['preview'], 23 | 'supported_by': 'community', 24 | 'metadata_version': '1.0' 25 | } 26 | 27 | DOCUMENTATION = ''' 28 | --- 29 | module: bigip_hostname 30 | short_description: Manage the hostname of a BIG-IP. 31 | description: 32 | - Manage the hostname of a BIG-IP. 33 | version_added: "2.3" 34 | options: 35 | hostname: 36 | description: 37 | - Hostname of the BIG-IP host. 38 | required: true 39 | notes: 40 | - Requires the f5-sdk Python package on the host. This is as easy as pip 41 | install f5-sdk. 42 | extends_documentation_fragment: f5 43 | requirements: 44 | - f5-sdk 45 | author: 46 | - Tim Rupp (@caphrim007) 47 | - Matthew Lam (@mryanlam) 48 | ''' 49 | 50 | EXAMPLES = ''' 51 | - name: Set the hostname of the BIG-IP 52 | bigip_hostname: 53 | hostname: "bigip.localhost.localdomain" 54 | password: "admin" 55 | server: "bigip.localhost.localdomain" 56 | user: "admin" 57 | delegate_to: localhost 58 | ''' 59 | 60 | RETURN = ''' 61 | hostname: 62 | description: The new hostname of the device 63 | returned: changed 64 | type: string 65 | sample: "big-ip01.internal" 66 | ''' 67 | 68 | from ansible.module_utils.f5_utils import * 69 | 70 | 71 | class Parameters(AnsibleF5Parameters): 72 | api_attributes = ['hostname'] 73 | updatables = ['hostname'] 74 | returnables = ['hostname'] 75 | 76 | def to_return(self): 77 | result = {} 78 | for returnable in self.returnables: 79 | result[returnable] = getattr(self, returnable) 80 | result = self._filter_params(result) 81 | return result 82 | 83 | def api_params(self): 84 | result = {} 85 | for api_attribute in self.api_attributes: 86 | if self.api_map is not None and api_attribute in self.api_map: 87 | result[api_attribute] = getattr(self, self.api_map[api_attribute]) 88 | else: 89 | result[api_attribute] = getattr(self, api_attribute) 90 | result = self._filter_params(result) 91 | return result 92 | 93 | @property 94 | def hostname(self): 95 | if self._values['hostname'] is None: 96 | return None 97 | return str(self._values['hostname']) 98 | 99 | 100 | class ModuleManager(object): 101 | def __init__(self, client): 102 | self.client = client 103 | self.have = None 104 | self.want = Parameters(self.client.module.params) 105 | self.changes = Parameters() 106 | 107 | def _set_changed_options(self): 108 | changed = {} 109 | for key in Parameters.returnables: 110 | if getattr(self.want, key) is not None: 111 | changed[key] = getattr(self.want, key) 112 | if changed: 113 | self.changes = Parameters(changed) 114 | 115 | def _update_changed_options(self): 116 | changed = {} 117 | for key in Parameters.updatables: 118 | if getattr(self.want, key) is not None: 119 | attr1 = getattr(self.want, key) 120 | attr2 = getattr(self.have, key) 121 | if attr1 != attr2: 122 | changed[key] = attr1 123 | self.changes = Parameters(changed) 124 | if changed: 125 | return True 126 | return False 127 | 128 | def exec_module(self): 129 | result = dict() 130 | 131 | try: 132 | changed = self.update() 133 | except iControlUnexpectedHTTPError as e: 134 | raise F5ModuleError(str(e)) 135 | 136 | changes = self.changes.to_return() 137 | result.update(**changes) 138 | result.update(dict(changed=changed)) 139 | return result 140 | 141 | def read_current_from_device(self): 142 | resource = self.client.api.tm.sys.global_settings.load() 143 | result = resource.attrs 144 | return Parameters(result) 145 | 146 | def update(self): 147 | self.have = self.read_current_from_device() 148 | if not self.should_update(): 149 | return False 150 | if self.client.check_mode: 151 | return True 152 | self.update_on_device() 153 | return True 154 | 155 | def should_update(self): 156 | result = self._update_changed_options() 157 | if result: 158 | return True 159 | return False 160 | 161 | def update_on_device(self): 162 | params = self.want.api_params() 163 | resource = self.client.api.tm.sys.global_settings.load() 164 | resource.modify(**params) 165 | self.client.api.tm.cm.devices.exec_cmd( 166 | 'mv', name=self.have.hostname, target=self.want.hostname 167 | ) 168 | 169 | 170 | class ArgumentSpec(object): 171 | def __init__(self): 172 | self.supports_check_mode = True 173 | self.argument_spec = dict( 174 | hostname=dict( 175 | required=True, 176 | default=None, 177 | type='str' 178 | ) 179 | ) 180 | self.f5_product_name = 'bigip' 181 | 182 | 183 | def main(): 184 | if not HAS_F5SDK: 185 | raise F5ModuleError("The python f5-sdk module is required") 186 | 187 | spec = ArgumentSpec() 188 | 189 | client = AnsibleF5Client( 190 | argument_spec=spec.argument_spec, 191 | supports_check_mode=spec.supports_check_mode, 192 | f5_product_name=spec.f5_product_name 193 | ) 194 | 195 | try: 196 | mm = ModuleManager(client) 197 | results = mm.exec_module() 198 | client.module.exit_json(**results) 199 | except F5ModuleError as e: 200 | client.module.fail_json(msg=str(e)) 201 | 202 | if __name__ == '__main__': 203 | main() 204 | -------------------------------------------------------------------------------- /library_old/bigip_iapplx_package.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | # 4 | # Copyright 2016 F5 Networks Inc. 5 | # 6 | # This file is part of Ansible 7 | # 8 | # Ansible is free software: you can redistribute it and/or modify 9 | # it under the terms of the GNU General Public License as published by 10 | # the Free Software Foundation, either version 3 of the License, or 11 | # (at your option) any later version. 12 | # 13 | # Ansible is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | # GNU General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU General Public License 19 | # along with Ansible. If not, see . 20 | 21 | ANSIBLE_METADATA = { 22 | 'status': ['preview'], 23 | 'supported_by': 'community', 24 | 'metadata_version': '1.0' 25 | } 26 | 27 | DOCUMENTATION = ''' 28 | --- 29 | module: bigip_dns_record_facts 30 | short_description: foo 31 | description: 32 | - foo 33 | version_added: "2.2" 34 | options: 35 | server: 36 | description: 37 | - BIG-IP host 38 | required: true 39 | user: 40 | description: 41 | - BIG-IP username 42 | required: true 43 | aliases: 44 | - username 45 | password: 46 | description: 47 | - BIG-IP password 48 | required: true 49 | notes: 50 | - Requires the f5-sdk Python package on the remote host. This is as easy as 51 | pip install f5-sdk 52 | - https://localhost:10443/mgmt/shared/iapp/global-installed-packages/ 53 | requirements: 54 | - f5-sdk 55 | author: 56 | - Tim Rupp (@caphrim007) 57 | ''' 58 | 59 | EXAMPLES = ''' 60 | 61 | ''' 62 | 63 | RETURN = ''' 64 | 65 | ''' 66 | 67 | from ansible.module_utils.basic import * 68 | from ansible.module_utils.f5_utils import * 69 | 70 | if __name__ == '__main__': 71 | main() 72 | 73 | 74 | -------------------------------------------------------------------------------- /library_old/bigip_policy_rule.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | # 4 | # Copyright 2016 F5 Networks Inc. 5 | # 6 | # This file is part of Ansible 7 | # 8 | # Ansible is free software: you can redistribute it and/or modify 9 | # it under the terms of the GNU General Public License as published by 10 | # the Free Software Foundation, either version 3 of the License, or 11 | # (at your option) any later version. 12 | # 13 | # Ansible is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | # GNU General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU General Public License 19 | # along with Ansible. If not, see . 20 | 21 | ANSIBLE_METADATA = { 22 | 'status': ['preview'], 23 | 'supported_by': 'community', 24 | 'metadata_version': '1.0' 25 | } 26 | 27 | DOCUMENTATION = ''' 28 | --- 29 | module: bigip_policy_rule 30 | short_description: foo 31 | description: 32 | - foo 33 | version_added: "2.2" 34 | options: 35 | server: 36 | description: 37 | - BIG-IP host 38 | required: true 39 | user: 40 | description: 41 | - BIG-IP username 42 | required: true 43 | aliases: 44 | - username 45 | password: 46 | description: 47 | - BIG-IP password 48 | required: true 49 | notes: 50 | - Requires the f5-sdk Python package on the remote host. This is as easy as 51 | pip install f5-sdk 52 | - https://localhost:10443/mgmt/shared/iapp/global-installed-packages/ 53 | requirements: 54 | - f5-sdk 55 | author: 56 | - Tim Rupp (@caphrim007) 57 | ''' 58 | 59 | EXAMPLES = ''' 60 | 61 | ''' 62 | 63 | RETURN = ''' 64 | 65 | ''' 66 | 67 | from ansible.module_utils.basic import * 68 | from ansible.module_utils.f5_utils import * 69 | 70 | if __name__ == '__main__': 71 | main() 72 | 73 | 74 | -------------------------------------------------------------------------------- /library_old/bigip_remote_syslog.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # 3 | # Copyright 2017 F5 Networks Inc. 4 | # 5 | # This file is part of Ansible 6 | # 7 | # Ansible is free software: you can redistribute it and/or modify 8 | # it under the terms of the GNU General Public License as published by 9 | # the Free Software Foundation, either version 3 of the License, or 10 | # (at your option) any later version. 11 | # 12 | # Ansible is distributed in the hope that it will be useful, 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | # GNU General Public License for more details. 16 | # 17 | # You should have received a copy of the GNU General Public License 18 | # along with Ansible. If not, see . 19 | 20 | ANSIBLE_METADATA = { 21 | 'status': ['preview'], 22 | 'supported_by': 'community', 23 | 'metadata_version': '1.0' 24 | } 25 | 26 | DOCUMENTATION = ''' 27 | module: bigip_remote_syslog 28 | short_description: Manipulate remote syslog settings on a BIG-IP. 29 | description: 30 | - Manipulate remote syslog settings on a BIG-IP. 31 | version_added: 2.4 32 | options: 33 | remote_host: 34 | description: 35 | - Specifies the IP address, or hostname, for the remote system to 36 | which the system sends log messages. 37 | required: True 38 | remote_port: 39 | description: 40 | - Specifies the port that the system uses to send messages to the 41 | remote logging server. The default is C(514) when the C(state) 42 | option is C(present). 43 | required: False 44 | default: None 45 | local_ip: 46 | description: 47 | - Specifies the local IP address of the system that is logging. 48 | required: False 49 | default: None 50 | notes: 51 | - Requires the f5-sdk Python package on the host. This is as easy as pip 52 | install f5-sdk. 53 | extends_documentation_fragment: f5 54 | requirements: 55 | - f5-sdk >= 2.2.0 56 | - ansible >= 2.3.0 57 | author: 58 | - Tim Rupp (@caphrim007) 59 | ''' 60 | 61 | EXAMPLES = ''' 62 | - name: Add a remote syslog server to log to 63 | bigip_remote_syslog: 64 | remote_host: "10.10.10.10" 65 | password: "secret" 66 | server: "lb.mydomain.com" 67 | user: "admin" 68 | validate_certs: "false" 69 | delegate_to: localhost 70 | 71 | - name: Add a remote syslog server on a non-standard port to log to 72 | bigip_remote_syslog: 73 | remote_host: "10.10.10.10" 74 | remote_port: "1234" 75 | password: "secret" 76 | server: "lb.mydomain.com" 77 | user: "admin" 78 | validate_certs: "false" 79 | delegate_to: localhost 80 | ''' 81 | 82 | RETURN = ''' 83 | 84 | ''' 85 | 86 | from ansible.module_utils.f5_utils import * 87 | 88 | 89 | class Parameters(AnsibleF5Parameters): 90 | updatables = [ 91 | 'remote_port', 'local_ip', 92 | ] 93 | 94 | returnables = [ 95 | 'remote_port', 'local_ip' 96 | ] 97 | 98 | api_attributes = [ 99 | 'remoteServers' 100 | ] 101 | 102 | def to_return(self): 103 | result = {} 104 | for returnable in self.returnables: 105 | result[returnable] = getattr(self, returnable) 106 | result = self._filter_params(result) 107 | return result 108 | 109 | def api_params(self): 110 | result = {} 111 | for api_attribute in self.api_attributes: 112 | if self.api_map is not None and api_attribute in self.api_map: 113 | result[api_attribute] = getattr(self, self.api_map[api_attribute]) 114 | else: 115 | result[api_attribute] = getattr(self, api_attribute) 116 | result = self._filter_params(result) 117 | return result 118 | 119 | 120 | class ModuleManager(object): 121 | def __init__(self, client): 122 | self.client = client 123 | self.have = None 124 | self.want = Parameters(self.client.module.params) 125 | self.changes = None 126 | 127 | def _update_changed_options(self): 128 | changed = {} 129 | for key in Parameters.updatables: 130 | if getattr(self.want, key) is not None: 131 | attr1 = getattr(self.want, key) 132 | attr2 = getattr(self.have, key) 133 | if attr1 != attr2: 134 | changed[key] = attr1 135 | if changed: 136 | self.changes = Parameters(changed) 137 | return True 138 | return False 139 | 140 | def exec_module(self): 141 | result = dict() 142 | 143 | try: 144 | changed = self.update() 145 | except iControlUnexpectedHTTPError as e: 146 | raise F5ModuleError(str(e)) 147 | 148 | changes = self.changes.to_return() 149 | result.update(**changes) 150 | result.update(dict(changed=changed)) 151 | return result 152 | 153 | def should_update(self): 154 | result = self._update_changed_options() 155 | if result: 156 | return True 157 | return False 158 | 159 | def update(self): 160 | self.have = self.read_current_from_device() 161 | if not self.should_update(): 162 | return False 163 | if self.client.check_mode: 164 | return True 165 | self.update_on_device() 166 | return True 167 | 168 | def update_on_device(self): 169 | params = self.want.api_params() 170 | result = self.client.api.tm.sys.snmp.load() 171 | result.modify(**params) 172 | 173 | def read_current_from_device(self): 174 | resource = self.client.api.tm.sys.snmp.load() 175 | result = resource.attrs 176 | return Parameters(result) 177 | 178 | 179 | class ArgumentSpec(object): 180 | def __init__(self): 181 | self.supports_check_mode = True 182 | self.argument_spec = dict( 183 | remote_host=dict( 184 | required=True, 185 | default=None 186 | ), 187 | remote_port=dict( 188 | required=False, 189 | default=None 190 | ), 191 | local_ip=dict( 192 | required=False, 193 | default=None 194 | ), 195 | state=dict( 196 | required=False, 197 | default='present', 198 | choices=['absent', 'present'] 199 | ) 200 | ) 201 | self.f5_product_name = 'bigip' 202 | 203 | 204 | def main(): 205 | if not HAS_F5SDK: 206 | raise F5ModuleError("The python f5-sdk module is required") 207 | 208 | spec = ArgumentSpec() 209 | 210 | client = AnsibleF5Client( 211 | argument_spec=spec.argument_spec, 212 | supports_check_mode=spec.supports_check_mode, 213 | f5_product_name=spec.f5_product_name 214 | ) 215 | 216 | try: 217 | mm = ModuleManager(client) 218 | results = mm.exec_module() 219 | client.module.exit_json(**results) 220 | except F5ModuleError as e: 221 | client.module.fail_json(msg=str(e)) 222 | 223 | if __name__ == '__main__': 224 | main() 225 | -------------------------------------------------------------------------------- /library_old/bigip_routedomain_facts.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | # 4 | # Copyright 2016 F5 Networks Inc. 5 | # 6 | # This file is part of Ansible 7 | # 8 | # Ansible is free software: you can redistribute it and/or modify 9 | # it under the terms of the GNU General Public License as published by 10 | # the Free Software Foundation, either version 3 of the License, or 11 | # (at your option) any later version. 12 | # 13 | # Ansible is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | # GNU General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU General Public License 19 | # along with Ansible. If not, see . 20 | 21 | ANSIBLE_METADATA = { 22 | 'status': ['preview'], 23 | 'supported_by': 'community', 24 | 'metadata_version': '1.0' 25 | } 26 | 27 | DOCUMENTATION = ''' 28 | --- 29 | module: bigip_routedomain_facts 30 | short_description: Retrieve route domain attributes from a BIG-IP 31 | description: 32 | - Retrieve route domain attributes from a BIG-IP 33 | version_added: "2.2" 34 | options: 35 | server: 36 | description: 37 | - BIG-IP host 38 | required: true 39 | password: 40 | description: 41 | - BIG-IP password 42 | required: true 43 | id: 44 | description: 45 | - The unique identifying integer representing the route domain. 46 | required: true 47 | partition: 48 | description: 49 | - The partition the route domain resides on 50 | required: false 51 | default: Common 52 | user: 53 | description: 54 | - BIG-IP username 55 | required: true 56 | validate_certs: 57 | description: 58 | - If C(no), SSL certificates will not be validated. This should only be 59 | used on personally controlled sites using self-signed certificates. 60 | required: false 61 | default: true 62 | notes: 63 | - Requires the f5-sdk Python package on the host. This is as easy as pip 64 | install f5-sdk 65 | requirements: 66 | - f5-sdk 67 | author: 68 | - Tim Rupp (@caphrim007) 69 | ''' 70 | 71 | EXAMPLES = ''' 72 | - name: Get the facts for a route domain 73 | bigip_routedomain_facts: 74 | id: "1234" 75 | password: "secret" 76 | server: "lb.mydomain.com" 77 | user: "admin" 78 | delegate_to: localhost 79 | ''' 80 | 81 | RETURN = ''' 82 | bwc_policy: 83 | description: Bandwidth controller for the route domain 84 | returned: changed 85 | type: string 86 | sample: "/Common/foo" 87 | connection_limit: 88 | description: > 89 | Maximum number of concurrent connections allowed for the 90 | route domain 91 | returned: changed 92 | type: integer 93 | sample: 0 94 | description: 95 | description: Descriptive text that identifies the route domain 96 | returned: changed 97 | type: string 98 | sample: "The foo route domain" 99 | evict_policy: 100 | description: Eviction policy to use with this route domain 101 | returned: changed 102 | type: string 103 | sample: "/Common/default-eviction-policy" 104 | id: 105 | description: ID of the route domain 106 | returned: changed 107 | type: integer 108 | sample: 1234 109 | service_policy: 110 | description: Service policy to associate with the route domain 111 | returned: changed 112 | type: string 113 | sample: "/Common/abc" 114 | strict: 115 | description: Whether the system enforces cross-routing restrictions 116 | returned: changed 117 | type: string 118 | sample: "enabled" 119 | routing_protocol: 120 | description: > 121 | Dynamic routing protocols for the system to use in the route 122 | domain 123 | returned: changed 124 | type: list 125 | sample: ["BGP", "OSPFv2"] 126 | vlans: 127 | description: VLANs for the system to use in the route domain 128 | returned: changed 129 | type: list 130 | sample: ["/Common/abc", "/Common/xyz"] 131 | ''' 132 | 133 | try: 134 | from f5.bigip import ManagementRoot 135 | HAS_F5SDK = True 136 | except ImportError: 137 | HAS_F5SDK = False 138 | 139 | 140 | class BigIpRouteDomainFacts(object): 141 | def __init__(self, *args, **kwargs): 142 | if not HAS_F5SDK: 143 | raise F5ModuleError("The python f5-sdk module is required") 144 | 145 | self.params = kwargs 146 | self.api = ManagementRoot(kwargs['server'], 147 | kwargs['user'], 148 | kwargs['password'], 149 | port=kwargs['server_port']) 150 | 151 | def flush(self): 152 | result = dict() 153 | 154 | rds = self.api.tm.net.route_domains 155 | rd = rds.route_domain.load(name=kwargs['id'], 156 | partition=kwargs['partition']) 157 | 158 | result['id'] = rd.id 159 | result['name'] = rd.name 160 | result['parent'] = rd.parent 161 | 162 | if hasattr(r, 'bwcPolicy'): 163 | result['bwc_policy'] = rd.bwcPolicy 164 | if hasattr(r, 'connectionLimit'): 165 | result['connection_limit'] = rd.connectionLimit 166 | if hasattr(r, 'description'): 167 | result['description'] = rd.description 168 | if hasattr(r, 'flowEvictionPolicy'): 169 | result['evict_policy'] = rd.flowEvictionPolicy 170 | if hasattr(r, 'servicePolicy'): 171 | result['service_policy'] = rd.servicePolicy 172 | if hasattr(r, 'strict'): 173 | result['strict'] = rd.strict 174 | if hasattr(r, 'routingProtocol'): 175 | result['routing_protocol'] = rd.routingProtocol 176 | if hasattr(r, 'vlans'): 177 | result['vlans'] = rd.vlans 178 | return result 179 | 180 | 181 | def main(): 182 | argument_spec = f5_argument_spec() 183 | 184 | meta_args = dict( 185 | id=dict(required=True), 186 | ) 187 | argument_spec.update(meta_args) 188 | 189 | module = AnsibleModule( 190 | argument_spec=argument_spec, 191 | supports_check_mode=True 192 | ) 193 | 194 | try: 195 | obj = BigIpRouteDomainFacts(**module.params) 196 | result = obj.flush() 197 | 198 | module.exit_json(changed=True, bigip=result) 199 | except F5ModuleError as e: 200 | module.fail_json(msg=e.message) 201 | 202 | from ansible.module_utils.basic import * 203 | from ansible.module_utils.f5_utils import * 204 | 205 | if __name__ == '__main__': 206 | main() 207 | -------------------------------------------------------------------------------- /library_old/bigip_snmp_community.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | # 4 | # Copyright 2016 F5 Networks Inc. 5 | # 6 | # This file is part of Ansible 7 | # 8 | # Ansible is free software: you can redistribute it and/or modify 9 | # it under the terms of the GNU General Public License as published by 10 | # the Free Software Foundation, either version 3 of the License, or 11 | # (at your option) any later version. 12 | # 13 | # Ansible is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | # GNU General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU General Public License 19 | # along with Ansible. If not, see . 20 | 21 | ANSIBLE_METADATA = { 22 | 'status': ['preview'], 23 | 'supported_by': 'community', 24 | 'metadata_version': '1.0' 25 | } 26 | 27 | DOCUMENTATION = ''' 28 | --- 29 | module: bigip_dns_record_facts 30 | short_description: foo 31 | description: 32 | - foo 33 | version_added: "2.2" 34 | options: 35 | server: 36 | description: 37 | - BIG-IP host 38 | required: true 39 | user: 40 | description: 41 | - BIG-IP username 42 | required: true 43 | aliases: 44 | - username 45 | password: 46 | description: 47 | - BIG-IP password 48 | required: true 49 | notes: 50 | - Requires the f5-sdk Python package on the remote host. This is as easy as 51 | pip install f5-sdk 52 | requirements: 53 | - f5-sdk 54 | author: 55 | - Tim Rupp (@caphrim007) 56 | ''' 57 | 58 | from ansible.module_utils.basic import * 59 | from ansible.module_utils.f5_utils import * 60 | 61 | if __name__ == '__main__': 62 | main() 63 | -------------------------------------------------------------------------------- /library_old/bigip_snmp_user.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | # 4 | # Copyright 2016 F5 Networks Inc. 5 | # 6 | # This file is part of Ansible 7 | # 8 | # Ansible is free software: you can redistribute it and/or modify 9 | # it under the terms of the GNU General Public License as published by 10 | # the Free Software Foundation, either version 3 of the License, or 11 | # (at your option) any later version. 12 | # 13 | # Ansible is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | # GNU General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU General Public License 19 | # along with Ansible. If not, see . 20 | 21 | ANSIBLE_METADATA = { 22 | 'status': ['preview'], 23 | 'supported_by': 'community', 24 | 'metadata_version': '1.0' 25 | } 26 | 27 | DOCUMENTATION = ''' 28 | --- 29 | module: bigip_dns_record_facts 30 | short_description: foo 31 | description: 32 | - foo 33 | version_added: "2.2" 34 | options: 35 | server: 36 | description: 37 | - BIG-IP host 38 | required: true 39 | user: 40 | description: 41 | - BIG-IP username 42 | required: true 43 | aliases: 44 | - username 45 | password: 46 | description: 47 | - BIG-IP password 48 | required: true 49 | notes: 50 | - Requires the f5-sdk Python package on the remote host. This is as easy as 51 | pip install f5-sdk 52 | requirements: 53 | - f5-sdk 54 | author: 55 | - Tim Rupp (@caphrim007) 56 | ''' 57 | 58 | from ansible.module_utils.basic import * 59 | from ansible.module_utils.f5_utils import * 60 | 61 | if __name__ == '__main__': 62 | main() 63 | -------------------------------------------------------------------------------- /library_old/bigip_software_update.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | # 4 | # Copyright 2017 F5 Networks Inc. 5 | # 6 | # This file is part of Ansible 7 | # 8 | # Ansible is free software: you can redistribute it and/or modify 9 | # it under the terms of the GNU General Public License as published by 10 | # the Free Software Foundation, either version 3 of the License, or 11 | # (at your option) any later version. 12 | # 13 | # Ansible is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | # GNU General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU General Public License 19 | # along with Ansible. If not, see . 20 | 21 | ANSIBLE_METADATA = { 22 | 'status': ['preview'], 23 | 'supported_by': 'community', 24 | 'metadata_version': '1.0' 25 | } 26 | 27 | DOCUMENTATION = ''' 28 | --- 29 | module: bigip_software_update 30 | short_description: Manage the software update settings of a BIG-IP. 31 | description: 32 | - Manage the software update settings of a BIG-IP. 33 | version_added: "2.4" 34 | options: 35 | auto_check: 36 | description: 37 | - Specifies whether to automatically check for updates on the F5 38 | Networks downloads server. 39 | required: False 40 | default: None 41 | choices: 42 | - yes 43 | - no 44 | frequency: 45 | description: 46 | - Specifies the schedule for the automatic update check. 47 | required: False 48 | default: None 49 | choices: 50 | - daily 51 | - monthly 52 | - weekly 53 | notes: 54 | - Requires the f5-sdk Python package on the host This is as easy as pip 55 | install f5-sdk 56 | extends_documentation_fragment: f5 57 | requirements: 58 | - f5-sdk >= 2.2.3 59 | author: 60 | - Tim Rupp (@caphrim007) 61 | ''' 62 | 63 | EXAMPLES = ''' 64 | ''' 65 | 66 | RETURN = ''' 67 | ''' 68 | 69 | from ansible.module_utils.basic import BOOLEANS 70 | from ansible.module_utils.f5_utils import ( 71 | AnsibleF5Client, 72 | AnsibleF5Parameters, 73 | HAS_F5SDK, 74 | F5ModuleError, 75 | iControlUnexpectedHTTPError 76 | ) 77 | 78 | 79 | class Parameters(AnsibleF5Parameters): 80 | api_map = { 81 | 'autoCheck': 'auto_check' 82 | } 83 | 84 | updatables = [ 85 | 'auto_check', 'frequency' 86 | ] 87 | 88 | returnables = [ 89 | 'auto_check', 'frequency' 90 | ] 91 | 92 | @property 93 | def auto_check(self): 94 | if self._values['auto_check'] is None: 95 | return None 96 | elif self._values['auto_check'] in [True, 'enabled']: 97 | return 'enabled' 98 | else: 99 | return 'disabled' 100 | 101 | def api_params(self): 102 | result = {} 103 | for api_attribute in self.api_attributes: 104 | if self.network == 'default': 105 | result['network'] = None 106 | elif self.api_map is not None and api_attribute in self.api_map: 107 | result[api_attribute] = getattr(self, self.api_map[api_attribute]) 108 | else: 109 | result[api_attribute] = getattr(self, api_attribute) 110 | result = self._filter_params(result) 111 | return result 112 | 113 | 114 | class ModuleManager(object): 115 | def __init__(self, client): 116 | self.client = client 117 | self.have = None 118 | self.want = Parameters(self.client.module.params) 119 | self.changes = Parameters() 120 | 121 | def exec_module(self): 122 | result = dict() 123 | 124 | try: 125 | changed = self.update() 126 | except iControlUnexpectedHTTPError as e: 127 | raise F5ModuleError(str(e)) 128 | 129 | changes = self.changes.to_return() 130 | result.update(**changes) 131 | result.update(dict(changed=changed)) 132 | return result 133 | 134 | def _update_changed_options(self): 135 | changed = {} 136 | for key in Parameters.updatables: 137 | if getattr(self.want, key) is not None: 138 | attr1 = getattr(self.want, key) 139 | attr2 = getattr(self.have, key) 140 | if attr1 != attr2: 141 | changed[key] = attr1 142 | if changed: 143 | self.changes = Parameters(changed) 144 | return True 145 | return False 146 | 147 | def should_update(self): 148 | result = self._update_changed_options() 149 | if result: 150 | return True 151 | return False 152 | 153 | def update(self): 154 | self.have = self.read_current_from_device() 155 | if not self.should_update(): 156 | return False 157 | if self.client.check_mode: 158 | return True 159 | self.update_on_device() 160 | return True 161 | 162 | def update_on_device(self): 163 | params = self.want.api_params() 164 | result = self.client.api.tm.sys.software.update.load() 165 | result.modify(**params) 166 | 167 | def read_current_from_device(self): 168 | resource = self.client.api.tm.sys.software.update.load() 169 | result = resource.attrs 170 | return Parameters(result) 171 | 172 | 173 | class ArgumentSpec(object): 174 | def __init__(self): 175 | self.supports_check_mode = True 176 | self.argument_spec = dict( 177 | auto_check=dict( 178 | required=False, 179 | default=None, 180 | choices=BOOLEANS, 181 | type='bool' 182 | ), 183 | frequency=dict( 184 | required=False, 185 | default=None, 186 | choices=['daily', 'monthly', 'weekly'] 187 | ) 188 | ) 189 | self.f5_product_name = 'bigip' 190 | 191 | 192 | def main(): 193 | if not HAS_F5SDK: 194 | raise F5ModuleError("The python f5-sdk module is required") 195 | 196 | spec = ArgumentSpec() 197 | 198 | client = AnsibleF5Client( 199 | argument_spec=spec.argument_spec, 200 | supports_check_mode=spec.supports_check_mode, 201 | f5_product_name=spec.f5_product_name 202 | ) 203 | 204 | mm = ModuleManager(client) 205 | results = mm.exec_module() 206 | client.module.exit_json(**results) 207 | 208 | if __name__ == '__main__': 209 | main() 210 | -------------------------------------------------------------------------------- /library_old/bigip_user_facts.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | # 4 | # Copyright 2016 F5 Networks Inc. 5 | # 6 | # This file is part of Ansible 7 | # 8 | # Ansible is free software: you can redistribute it and/or modify 9 | # it under the terms of the GNU General Public License as published by 10 | # the Free Software Foundation, either version 3 of the License, or 11 | # (at your option) any later version. 12 | # 13 | # Ansible is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | # GNU General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU General Public License 19 | # along with Ansible. If not, see . 20 | 21 | ANSIBLE_METADATA = { 22 | 'status': ['preview'], 23 | 'supported_by': 'community', 24 | 'metadata_version': '1.0' 25 | } 26 | 27 | DOCUMENTATION = ''' 28 | --- 29 | module: bigip_user_facts 30 | short_description: Retrieve user account attributes from a BIG-IP 31 | description: 32 | - Retrieve user account attributes from a BIG-IP 33 | version_added: "2.2" 34 | options: 35 | username_credential: 36 | description: 37 | - Name of the user to retrieve facts for 38 | required: true 39 | notes: 40 | - Requires the f5-sdk Python package on the host. This is as easy as pip 41 | install f5-sdk 42 | - Facts are placed in the C(bigip) variable 43 | extends_documentation_fragment: f5 44 | requirements: 45 | - f5-sdk 46 | author: 47 | - Tim Rupp (@caphrim007) 48 | ''' 49 | 50 | EXAMPLES = ''' 51 | - name: Gather facts about user 'johnd' 52 | bigip_user_facts: 53 | name: "johnd" 54 | password: "secret" 55 | server: "lb.mydomain.com" 56 | user: "admin" 57 | validate_certs: "no" 58 | delegate_to: localhost 59 | 60 | - name: Display the user facts 61 | debug: 62 | var: bigip 63 | ''' 64 | 65 | RETURN = ''' 66 | description: 67 | description: The description of the user 68 | returned: changed 69 | type: string 70 | sample: "John Doe" 71 | username_credential: 72 | description: The username beign searched for 73 | returned: changed 74 | type: string 75 | sample: "jdoe" 76 | encrypted_password: 77 | description: The encrypted value of the password 78 | returned: changed 79 | type: string 80 | sample: "$6$/cgtFz0....yzv465uAJ/" 81 | partition_access: 82 | description: Access permissions for the account 83 | returned: changed 84 | type: list 85 | sample: 86 | - name: "all-partitions" 87 | role: "admin" 88 | ''' 89 | 90 | try: 91 | from f5.bigip import ManagementRoot 92 | HAS_F5SDK = True 93 | except ImportError: 94 | HAS_F5SDK = False 95 | 96 | 97 | class BigIpUserFacts(object): 98 | def __init__(self, *args, **kwargs): 99 | if not HAS_F5SDK: 100 | raise F5ModuleError("The python f5-sdk module is required") 101 | 102 | self.params = kwargs 103 | self.api = ManagementRoot(kwargs['server'], 104 | kwargs['user'], 105 | kwargs['password'], 106 | port=kwargs['server_port']) 107 | 108 | def exists(self): 109 | username_credential = self.params['username_credential'] 110 | if self.api.tm.auth.users.user.exists(name=username_credential): 111 | return True 112 | else: 113 | return False 114 | 115 | def flush(self): 116 | if self.exists: 117 | result = dict( 118 | changed=True, 119 | ansible_facts=dict( 120 | bigip=self.read() 121 | ) 122 | ) 123 | else: 124 | result = dict( 125 | changed=False 126 | ) 127 | return result 128 | 129 | def read(self): 130 | result = {} 131 | 132 | username_credential = self.params['username_credential'] 133 | user = self.api.tm.auth.users.user.load(name=username_credential) 134 | 135 | result['username_credential'] = username_credential 136 | 137 | if hasattr(user, 'description'): 138 | result['description'] = user.description 139 | 140 | if hasattr(user, 'encryptedPassword'): 141 | result['encrypted_password'] = user.encryptedPassword 142 | 143 | if hasattr(user, 'shell'): 144 | result['shell'] = user.shell 145 | 146 | if hasattr(user, 'partitionAccess'): 147 | result['partition_access'] = user.partitionAccess 148 | 149 | return result 150 | 151 | 152 | def main(): 153 | argument_spec = f5_argument_spec() 154 | 155 | meta_args = dict( 156 | username_credential=dict(required=True, aliases=['name'], no_log=False) 157 | ) 158 | argument_spec.update(meta_args) 159 | 160 | module = AnsibleModule( 161 | argument_spec=argument_spec, 162 | supports_check_mode=True 163 | ) 164 | 165 | try: 166 | result = dict() 167 | obj = BigIpUserFacts(check_mode=module.check_mode, **module.params) 168 | result = obj.flush() 169 | 170 | module.exit_json(**result) 171 | except F5ModuleError as e: 172 | module.fail_json(msg=str(e)) 173 | 174 | from ansible.module_utils.basic import * 175 | from ansible.module_utils.f5_utils import * 176 | 177 | if __name__ == '__main__': 178 | main() 179 | -------------------------------------------------------------------------------- /library_old/bigiq_license_pool.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | # 4 | # Copyright 2016 F5 Networks Inc. 5 | # 6 | # This file is part of Ansible 7 | # 8 | # Ansible is free software: you can redistribute it and/or modify 9 | # it under the terms of the GNU General Public License as published by 10 | # the Free Software Foundation, either version 3 of the License, or 11 | # (at your option) any later version. 12 | # 13 | # Ansible is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | # GNU General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU General Public License 19 | # along with Ansible. If not, see . 20 | 21 | ANSIBLE_METADATA = { 22 | 'status': ['preview'], 23 | 'supported_by': 'community', 24 | 'metadata_version': '1.0' 25 | } 26 | 27 | DOCUMENTATION = ''' 28 | --- 29 | module: bigiq_license_pool 30 | short_description: foo 31 | description: 32 | - foo 33 | version_added: "2.2" 34 | options: 35 | server: 36 | description: 37 | - BIG-IP host 38 | required: true 39 | user: 40 | description: 41 | - BIG-IP username 42 | required: true 43 | aliases: 44 | - username 45 | password: 46 | description: 47 | - BIG-IP password 48 | required: true 49 | notes: 50 | - Requires the f5-sdk Python package on the remote host. This is as easy as 51 | pip install f5-sdk 52 | - https://localhost:10443/mgmt/shared/iapp/global-installed-packages/ 53 | requirements: 54 | - f5-sdk 55 | author: 56 | - Tim Rupp (@caphrim007) 57 | ''' 58 | 59 | EXAMPLES = ''' 60 | 61 | ''' 62 | 63 | RETURN = ''' 64 | 65 | ''' 66 | 67 | from ansible.module_utils.basic import * 68 | from ansible.module_utils.f5_utils import * 69 | 70 | if __name__ == '__main__': 71 | main() 72 | 73 | 74 | -------------------------------------------------------------------------------- /library_old/bigiq_license_pool_member.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | # 4 | # Copyright 2016 F5 Networks Inc. 5 | # 6 | # This file is part of Ansible 7 | # 8 | # Ansible is free software: you can redistribute it and/or modify 9 | # it under the terms of the GNU General Public License as published by 10 | # the Free Software Foundation, either version 3 of the License, or 11 | # (at your option) any later version. 12 | # 13 | # Ansible is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | # GNU General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU General Public License 19 | # along with Ansible. If not, see . 20 | 21 | ANSIBLE_METADATA = { 22 | 'status': ['preview'], 23 | 'supported_by': 'community', 24 | 'metadata_version': '1.0' 25 | } 26 | 27 | DOCUMENTATION = ''' 28 | --- 29 | module: bigiq_license_pool_member 30 | short_description: foo 31 | description: 32 | - foo 33 | version_added: "2.2" 34 | options: 35 | server: 36 | description: 37 | - BIG-IP host 38 | required: true 39 | user: 40 | description: 41 | - BIG-IP username 42 | required: true 43 | aliases: 44 | - username 45 | password: 46 | description: 47 | - BIG-IP password 48 | required: true 49 | notes: 50 | - Requires the f5-sdk Python package on the remote host. This is as easy as 51 | pip install f5-sdk 52 | - https://localhost:10443/mgmt/shared/iapp/global-installed-packages/ 53 | requirements: 54 | - f5-sdk 55 | author: 56 | - Tim Rupp (@caphrim007) 57 | ''' 58 | 59 | EXAMPLES = ''' 60 | 61 | ''' 62 | 63 | RETURN = ''' 64 | 65 | ''' 66 | 67 | from ansible.module_utils.basic import * 68 | from ansible.module_utils.f5_utils import * 69 | 70 | if __name__ == '__main__': 71 | main() 72 | 73 | 74 | -------------------------------------------------------------------------------- /library_old/f5_support_upload.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | # 4 | # Copyright 2016 F5 Networks Inc. 5 | # 6 | # This file is part of Ansible 7 | # 8 | # Ansible is free software: you can redistribute it and/or modify 9 | # it under the terms of the GNU General Public License as published by 10 | # the Free Software Foundation, either version 3 of the License, or 11 | # (at your option) any later version. 12 | # 13 | # Ansible is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | # GNU General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU General Public License 19 | # along with Ansible. If not, see . 20 | 21 | ANSIBLE_METADATA = { 22 | 'status': ['preview'], 23 | 'supported_by': 'community', 24 | 'metadata_version': '1.0' 25 | } 26 | 27 | DOCUMENTATION = ''' 28 | --- 29 | module: bigip_partition 30 | short_description: Manage BIG-IP partitions 31 | description: 32 | - Manage BIG-IP partitions 33 | version_added: "2.3" 34 | options: 35 | description: 36 | description: 37 | - The description to attach to the Partition 38 | required: False 39 | default: None 40 | route_domain: 41 | description: 42 | - The default Route Domain to assign to the Partition. If no route domain 43 | is specified, then the default route domain for the system (typically 44 | zero) will be used only when creating a new partition. C(route_domain) 45 | and C(route_domain_id) are mutually exclusive. 46 | required: False 47 | default: None 48 | notes: 49 | - Requires the bigsuds Python package on the host if using the iControl 50 | interface. This is as easy as pip install bigsuds 51 | requirements: 52 | - bigsuds 53 | - requests 54 | extends_documentation_fragment: f5 55 | author: 56 | - Tim Rupp (@caphrim007) 57 | ''' 58 | 59 | EXAMPLES = ''' 60 | 61 | ''' 62 | 63 | -------------------------------------------------------------------------------- /library_old/iworkflow_license.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | # 4 | # Copyright 2016 F5 Networks Inc. 5 | # 6 | # This file is part of Ansible 7 | # 8 | # Ansible is free software: you can redistribute it and/or modify 9 | # it under the terms of the GNU General Public License as published by 10 | # the Free Software Foundation, either version 3 of the License, or 11 | # (at your option) any later version. 12 | # 13 | # Ansible is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | # GNU General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU General Public License 19 | # along with Ansible. If not, see . 20 | 21 | ANSIBLE_METADATA = { 22 | 'status': ['preview'], 23 | 'supported_by': 'community', 24 | 'metadata_version': '1.0' 25 | } 26 | 27 | DOCUMENTATION = ''' 28 | --- 29 | module: bigip_partition 30 | short_description: Manage BIG-IP partitions 31 | description: 32 | - Manage BIG-IP partitions 33 | version_added: "2.3" 34 | options: 35 | description: 36 | description: 37 | - The description to attach to the Partition 38 | required: False 39 | default: None 40 | route_domain: 41 | description: 42 | - The default Route Domain to assign to the Partition. If no route domain 43 | is specified, then the default route domain for the system (typically 44 | zero) will be used only when creating a new partition. C(route_domain) 45 | and C(route_domain_id) are mutually exclusive. 46 | required: False 47 | notes: 48 | - Requires the bigsuds Python package on the host if using the iControl 49 | interface. This is as easy as pip install bigsuds 50 | requirements: 51 | - bigsuds 52 | - requests 53 | extends_documentation_fragment: f5 54 | author: 55 | - Tim Rupp (@caphrim007) 56 | ''' 57 | 58 | EXAMPLES = ''' 59 | 60 | ''' 61 | 62 | -------------------------------------------------------------------------------- /library_old/iworkflow_user.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | # 4 | # Copyright 2017 F5 Networks Inc. 5 | # 6 | # This file is part of Ansible 7 | # 8 | # Ansible is free software: you can redistribute it and/or modify 9 | # it under the terms of the GNU General Public License as published by 10 | # the Free Software Foundation, either version 3 of the License, or 11 | # (at your option) any later version. 12 | # 13 | # Ansible is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | # GNU General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU General Public License 19 | # along with Ansible. If not, see . 20 | 21 | ANSIBLE_METADATA = { 22 | 'status': ['preview'], 23 | 'supported_by': 'community', 24 | 'metadata_version': '1.0' 25 | } 26 | 27 | DOCUMENTATION = ''' 28 | module: iworkflow_user 29 | short_description: Manage users in iWorkflow. 30 | description: 31 | - Manage users in iWorkflow. 32 | version_added: 2.4 33 | options: 34 | name: 35 | description: 36 | - Name of the user that you want to manage. 37 | required: True 38 | description: 39 | description: 40 | - An optional description for the user. 41 | required: False 42 | default: None 43 | state: 44 | description: 45 | - When C(state) is C(present), ensures that the user exists. When 46 | C(state) is C(absent), ensures that the user is removed. 47 | required: False 48 | default: present 49 | choices: 50 | - present 51 | - absent 52 | notes: 53 | - Requires the f5-sdk Python package on the host. This is as easy as pip 54 | install f5-sdk. 55 | extends_documentation_fragment: f5 56 | requirements: 57 | - f5-sdk >= 2.3.0 58 | - iWorkflow >= 2.1.0 59 | author: 60 | - Tim Rupp (@caphrim007) 61 | ''' 62 | 63 | EXAMPLES = ''' 64 | 65 | ''' 66 | 67 | RETURN = ''' 68 | 69 | ''' 70 | 71 | 72 | from ansible.module_utils.f5_utils import ( 73 | AnsibleF5Client, 74 | AnsibleF5Parameters, 75 | F5ModuleError, 76 | HAS_F5SDK, 77 | iControlUnexpectedHTTPError 78 | ) 79 | 80 | 81 | class Parameters(AnsibleF5Parameters): 82 | api_map = { 83 | 'displayName': 'description' 84 | } 85 | returnables = [] 86 | 87 | api_attributes = [ 88 | 'description', 89 | ] 90 | 91 | updatables = [] 92 | 93 | def to_return(self): 94 | result = {} 95 | try: 96 | for returnable in self.returnables: 97 | result[returnable] = getattr(self, returnable) 98 | result = self._filter_params(result) 99 | except Exception: 100 | pass 101 | return result 102 | 103 | def api_params(self): 104 | result = {} 105 | for api_attribute in self.api_attributes: 106 | if self.api_map is not None and api_attribute in self.api_map: 107 | result[api_attribute] = getattr(self, self.api_map[api_attribute]) 108 | else: 109 | result[api_attribute] = getattr(self, api_attribute) 110 | result = self._filter_params(result) 111 | return result 112 | 113 | 114 | class ModuleManager(object): 115 | def __init__(self, client): 116 | self.client = client 117 | self.have = None 118 | self.want = Parameters(self.client.module.params) 119 | self.changes = Parameters() 120 | 121 | def _set_changed_options(self): 122 | changed = {} 123 | for key in Parameters.returnables: 124 | if getattr(self.want, key) is not None: 125 | changed[key] = getattr(self.want, key) 126 | if changed: 127 | self.changes = Parameters(changed) 128 | 129 | def _update_changed_options(self): 130 | changed = {} 131 | for key in Parameters.updatables: 132 | if getattr(self.want, key) is not None: 133 | attr1 = getattr(self.want, key) 134 | attr2 = getattr(self.have, key) 135 | if attr1 != attr2: 136 | changed[key] = attr1 137 | if changed: 138 | self.changes = Parameters(changed) 139 | return True 140 | return False 141 | 142 | def exec_module(self): 143 | changed = False 144 | result = dict() 145 | state = self.want.state 146 | 147 | try: 148 | if state == "present": 149 | changed = self.present() 150 | elif state == "absent": 151 | changed = self.absent() 152 | except iControlUnexpectedHTTPError as e: 153 | raise F5ModuleError(str(e)) 154 | 155 | changes = self.changes.to_return() 156 | result.update(**changes) 157 | result.update(dict(changed=changed)) 158 | return result 159 | 160 | def exists(self): 161 | return self.client.api.shared.authz.users.user.exists( 162 | name=self.want.name 163 | ) 164 | 165 | def present(self): 166 | if self.exists(): 167 | return self.update() 168 | else: 169 | return self.create() 170 | 171 | def create(self): 172 | if self.client.check_mode: 173 | return True 174 | self.create_on_device() 175 | return True 176 | 177 | def update(self): 178 | pass 179 | 180 | def read_current_from_device(self): 181 | collection = self.client.api.cm.cloud.tenants_s.get_collection( 182 | requests_params=dict( 183 | params="$filter=name+eq+'{0}'".format(self.want.name) 184 | ) 185 | ) 186 | resource = collection.pop() 187 | result = resource.attrs 188 | return Parameters(result) 189 | 190 | def create_on_device(self): 191 | params = self.want.api_params() 192 | self.client.api.cm.cloud.tenants_s.tenant.create( 193 | name=self.want.name, 194 | **params 195 | ) 196 | return True 197 | 198 | def absent(self): 199 | if self.exists(): 200 | return self.remove() 201 | return False 202 | 203 | def remove(self): 204 | if self.client.check_mode: 205 | return True 206 | self.remove_from_device() 207 | if self.exists(): 208 | raise F5ModuleError("Failed to delete the tenant") 209 | return True 210 | 211 | def remove_from_device(self): 212 | collection = self.client.api.cm.cloud.tenants_s.get_collection( 213 | requests_params=dict( 214 | params="$filter=name+eq+'{0}'".format(self.want.name) 215 | ) 216 | ) 217 | resource = collection.pop() 218 | resource.delete() 219 | 220 | 221 | class ArgumentSpec(object): 222 | def __init__(self): 223 | self.supports_check_mode = True 224 | self.argument_spec = dict( 225 | name=dict(required=True), 226 | description=dict(type='str'), 227 | contact_address=dict(type='str'), 228 | contact_phone=dict(type='str'), 229 | contact_email=dict(type='str'), 230 | state=dict( 231 | required=False, 232 | default='present', 233 | choices=['absent', 'present'] 234 | ) 235 | ) 236 | self.f5_product_name = 'iworkflow' 237 | 238 | 239 | def main(): 240 | if not HAS_F5SDK: 241 | raise F5ModuleError("The python f5-sdk module is required") 242 | 243 | spec = ArgumentSpec() 244 | 245 | client = AnsibleF5Client( 246 | argument_spec=spec.argument_spec, 247 | supports_check_mode=spec.supports_check_mode, 248 | f5_product_name=spec.f5_product_name 249 | ) 250 | 251 | try: 252 | mm = ModuleManager(client) 253 | results = mm.exec_module() 254 | client.module.exit_json(**results) 255 | except F5ModuleError as e: 256 | client.module.fail_json(msg=str(e)) 257 | 258 | 259 | if __name__ == '__main__': 260 | main() 261 | -------------------------------------------------------------------------------- /library_old/wait_for_bigip.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | # 4 | # Copyright 2016 F5 Networks Inc. 5 | # 6 | # This file is part of Ansible 7 | # 8 | # Ansible is free software: you can redistribute it and/or modify 9 | # it under the terms of the GNU General Public License as published by 10 | # the Free Software Foundation, either version 3 of the License, or 11 | # (at your option) any later version. 12 | # 13 | # Ansible is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | # GNU General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU General Public License 19 | # along with Ansible. If not, see . 20 | 21 | ANSIBLE_METADATA = { 22 | 'status': ['preview'], 23 | 'supported_by': 'community', 24 | 'metadata_version': '1.0' 25 | } 26 | 27 | DOCUMENTATION = ''' 28 | --- 29 | module: bigip_partition 30 | short_description: Manage BIG-IP partitions 31 | description: 32 | - Manage BIG-IP partitions 33 | version_added: "2.3" 34 | options: 35 | description: 36 | description: 37 | - The description to attach to the Partition 38 | required: False 39 | default: None 40 | route_domain: 41 | description: 42 | - The default Route Domain to assign to the Partition. If no route domain 43 | is specified, then the default route domain for the system (typically 44 | zero) will be used only when creating a new partition. C(route_domain) 45 | and C(route_domain_id) are mutually exclusive. 46 | required: False 47 | notes: 48 | - Requires the bigsuds Python package on the host if using the iControl 49 | interface. This is as easy as pip install bigsuds 50 | requirements: 51 | - bigsuds 52 | - requests 53 | extends_documentation_fragment: f5 54 | author: 55 | - Tim Rupp (@caphrim007) 56 | ''' 57 | 58 | EXAMPLES = ''' 59 | 60 | ''' 61 | 62 | -------------------------------------------------------------------------------- /misc/user_repos.json: -------------------------------------------------------------------------------- 1 | { 2 | "repos": [ 3 | { 4 | "name":"mcgonagle-ansible_f5", 5 | "repo":"https://github.com/mcgonagle/ansible_f5.git", 6 | "branch":"master", 7 | "skip":false, 8 | "skipinstall":true 9 | } 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /password.yml: -------------------------------------------------------------------------------- 1 | $ANSIBLE_VAULT;1.1;AES256 2 | 63323737613865613139353862373036633563353164616362646532336438626234396461373937 3 | 3731653032366438636539323230376233336131653334390a643930356161386235353462646630 4 | 38323738633462333263623433613534643839663230393434393239323632336535373637313939 5 | 6435636131656465620a376361393066313936383731363131343639636261373634326339653636 6 | 61376466356362623262623530626136643363356366343163643863616535393435386131396663 7 | 6235336366373764646561333963396236613731626632656361 8 | -------------------------------------------------------------------------------- /playbooks/custom_facts.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: custom facts 3 | hosts: all 4 | roles: 5 | - custom_facts 6 | ... 7 | -------------------------------------------------------------------------------- /playbooks/onboarding.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: all 3 | gather_facts: False 4 | roles: 5 | - onboarding 6 | ... 7 | -------------------------------------------------------------------------------- /playbooks/operations.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: all 3 | gather_facts: False 4 | roles: 5 | - operations 6 | ... 7 | -------------------------------------------------------------------------------- /roles/custom_facts/README.md: -------------------------------------------------------------------------------- 1 | Role Name 2 | ========= 3 | 4 | A brief description of the role goes here. 5 | 6 | Requirements 7 | ------------ 8 | 9 | Any pre-requisites that may not be covered by Ansible itself or the role should be mentioned here. For instance, if the role uses the EC2 module, it may be a good idea to mention in this section that the boto package is required. 10 | 11 | Role Variables 12 | -------------- 13 | 14 | A description of the settable variables for this role should go here, including any variables that are in defaults/main.yml, vars/main.yml, and any variables that can/should be set via parameters to the role. Any variables that are read from other roles and/or the global scope (ie. hostvars, group vars, etc.) should be mentioned here as well. 15 | 16 | Dependencies 17 | ------------ 18 | 19 | A list of other roles hosted on Galaxy should go here, plus any details in regards to parameters that may need to be set for other roles, or variables that are used from other roles. 20 | 21 | Example Playbook 22 | ---------------- 23 | 24 | Including an example of how to use your role (for instance, with variables passed in as parameters) is always nice for users too: 25 | 26 | - hosts: servers 27 | roles: 28 | - { role: username.rolename, x: 42 } 29 | 30 | License 31 | ------- 32 | 33 | BSD 34 | 35 | Author Information 36 | ------------------ 37 | 38 | An optional section for the role authors to include contact information, or a website (HTML is not allowed). 39 | -------------------------------------------------------------------------------- /roles/custom_facts/defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # defaults file for custom_facts -------------------------------------------------------------------------------- /roles/custom_facts/files/datacenter.fact: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | AVAILABILTY_ZONE=$(curl -s http://169.254.169.254/latest/meta-data/placement/availability-zone) 4 | cat <