diff --git a/TODO.txt b/TODO.txt new file mode 100644 index 0000000..a758463 --- /dev/null +++ b/TODO.txt @@ -0,0 +1 @@ +- Replace alvaroaleman.freeipa-client with https://galaxy.ansible.com/freeipa/ansible_freeipa \ No newline at end of file diff --git a/collections/ansible_collections/davidban77/gns3/.gitignore b/collections/ansible_collections/davidban77/gns3/.gitignore new file mode 100644 index 0000000..9b9bbd1 --- /dev/null +++ b/collections/ansible_collections/davidban77/gns3/.gitignore @@ -0,0 +1,93 @@ +# Compiled source # +################### +*.com +*.class +*.dll +*.exe +*.o +*.so +__pycache__/ +*.py[cod] +*$py.class + +# Packages # +############ +# it's better to unpack these files and commit the raw source +# git has its own built in compression methods +*.7z +*.dmg +*.gz +*.iso +*.jar +*.rar +*.tar +*.zip +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +pip-wheel-metadata/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# Logs and databases # +###################### +*.log +*.sql +*.sqlite + +# OS generated files # +###################### +.DS_Store +.DS_Store? +._* +.Spotlight-V100 +.Trashes +ehthumbs.db +Thumbs.db +*.retry +.vscode +.mypy_cache +.pytest_cache +__pycache__ +prof +.envFile +.env +.eapi.conf +.idea + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +.hypothesis/ +.pytest_cache/ + +# Sphinx documentation +docs/_build/ + +# MkDocs +site/ + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json diff --git a/collections/ansible_collections/davidban77/gns3/CHANGELOG.md b/collections/ansible_collections/davidban77/gns3/CHANGELOG.md new file mode 100644 index 0000000..80731d4 --- /dev/null +++ b/collections/ansible_collections/davidban77/gns3/CHANGELOG.md @@ -0,0 +1,69 @@ +# Releases + +## 1.5.0 + +**Enhancements:** + +- Added `gns3_facts` to retrieve the compute information like: console ports, server version, available emulators, available images, etc.. +- Added `gns3_snapshot` to manipulate the snapshot creation/deletion and restoration of a project. + +**Fixes:** + +- Added the needed `user` and `password` arguments to all the modules, when interacting with a GNS3 server with authentication. +- Refactored the modules a little to be more standard with each other. + +## 1.4.0 + +**Enhacements:** + +- Added `gns3_node` to interact with the node inside a project. Provides the following: + - `start/stop/suspend/reload`: Actions to be applied on the node. These are idempotent with the exception of `reload`. + - Special flags like `retry` for an action to be applied a second time just in case... And a `force_project_open` to interact with a device if the project is closed +- Refactored `gns3_project` to be more pythonic + +## 1.3.0 + +**Enhancements:** + +- Added `gns3_node_file` and `gns3_project_file` modules. +- Improved the Makefile +- Added alpine node to the tests + +## 1.2.2. + +**Fixes:** + +- Upgrading to `gns3fy ^0.4.0` + +## 1.2.1 + +**Enhancements:** + +- No more `node_type` needed when creating nodes in a project. + +## 1.2.0 + +**Enhancements:** + +- Modules: + - `gns3_nodes_inventory`: Returns inventory-style dictionary of the nodes. + +**Fixes:** + +- Modules: + - Error when using the `gns3_version` module when `gns3fy` is not installed + +- Tests: + - Added check for `gns3_version` + +## 1.1.0 + +**Enhancements:** + +- Roles: + - `create_lab`: Create a GNS3 Lab by creating a project and starting up the nodes + - `delete_lab`: Deletes a GNS3 Lab by stopping nodes and deleting the project + +## 1.0.1 + +Initial push of the ansible collections. Released focused on the `gns3` module diff --git a/collections/ansible_collections/davidban77/gns3/FILES.json b/collections/ansible_collections/davidban77/gns3/FILES.json new file mode 100644 index 0000000..af5dc35 --- /dev/null +++ b/collections/ansible_collections/davidban77/gns3/FILES.json @@ -0,0 +1,299 @@ +{ + "files": [ + { + "name": ".", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "plugins", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "roles", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": ".DS_Store", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "07d2bba37d01224569c017d4c7a1279b25034e29466d550ed965f82ed0aaa357", + "format": 1 + }, + { + "name": "LICENSE", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "ecec1ee81897773f92976da30c1fbb4414107ef182511644e86945d74e1a986f", + "format": 1 + }, + { + "name": "requirements.txt", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "59e53d1f4cae821cf5701a9d35babccae916321df53376fa3aa9aaced4134071", + "format": 1 + }, + { + "name": "CHANGELOG.md", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "8274d3baedce15723f01977a4bbf351b5b3d0773fdecb31e67fd33f4a219d866", + "format": 1 + }, + { + "name": "dev-requirements.txt", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "c1f58a2e2e6ad1c44048e835ebc329fb1d8b4e3e65da997defeeac119c22f44c", + "format": 1 + }, + { + "name": "Makefile", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "293c346df21e6637e8bc604cdd5dc7757acdace716eec4a8917be922d821e4aa", + "format": 1 + }, + { + "name": "README.md", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "b2b255969f71c789635f478015538bad0da15af127521fb5d98580617ae5f368", + "format": 1 + }, + { + "name": ".gitignore", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "2282d3966f03871ec05c50da914155bf8d715beebb8027b559a8870116fc5651", + "format": 1 + }, + { + "name": "galaxy.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "11fdd35c3e074f92599a16e94a4425db14b0c2a741020c41cac4b15538a717f5", + "format": 1 + }, + { + "name": "test/playbooks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "test/playbooks/group_vars", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "test/playbooks/create_files.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "633a5a2b3c11c27c7264a5444da7249843490349bc9704e73828e58c75822bc4", + "format": 1 + }, + { + "name": "test/playbooks/node_interaction.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "4d30f6988337e9be5777106bd65357b7064dcfe2345e9672fb184b909c831dff", + "format": 1 + }, + { + "name": "test/playbooks/delete_files.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "2cc8b222450116e3ac24c959a7e9c36f4ad36073c3f9213bf81dbca769080da5", + "format": 1 + }, + { + "name": "test/playbooks/snapshots.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "4d659f0381a8ae4130081b62ce11f25518a3881cf1f164dd7c078dc70a284d00", + "format": 1 + }, + { + "name": "test/playbooks/ansible.cfg", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "27762b4172718c13f2abb4b8180678875717a465e497eeae3f546e2f24556421", + "format": 1 + }, + { + "name": "test/playbooks/facts.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "781170433cc129bb49ec0b215f280f73f35634afac0d397dda3da38bcd03da4c", + "format": 1 + }, + { + "name": "test/playbooks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "e66b08210468e91df3c15ef46169a2064bc26b18bf28465f1f42d464321b05a1", + "format": 1 + }, + { + "name": "test/playbooks/group_vars/all.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "fa9871fb705af3de74be241428233020ff7d02322f5b58c0b32d05df17990e6a", + "format": 1 + }, + { + "name": "plugins/modules", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "plugins/modules/gns3_facts.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "b47b546f9bcbd38128dbb7d4d24a4f1ec4a329a52cd0b2cb6acd37797bbb944a", + "format": 1 + }, + { + "name": "plugins/modules/gns3_project.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "857080b1b5f6b9c1e04aa6e51501f2edae3a9d4fd63a1eecbffb214cc57e12c4", + "format": 1 + }, + { + "name": "plugins/modules/gns3_node_file.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "83eb69764b268fee6d67decdb1fc01f915f47882b4dfcb885599d6d475ce5e47", + "format": 1 + }, + { + "name": "plugins/modules/gns3_node.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "03d49fac0ef8191c620929deb82d1ef2b2dcb0fe28e78d5ab1ff868b516d4e44", + "format": 1 + }, + { + "name": "plugins/modules/gns3_snapshot.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "f25e7a9bfdd07abea77971dbf6126238c8d870036cb9beb8668aa74698accdb4", + "format": 1 + }, + { + "name": "plugins/modules/gns3_version.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "470c19c7e60aed0fc7b318fa8b4433e87c0b66f5f5c6ddda0050e27e85b4abb9", + "format": 1 + }, + { + "name": "plugins/modules/gns3_nodes_inventory.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "7b021e9ef803a03dfe4b975a47d27bfb558b910feee4e31249bf4a8f702846ba", + "format": 1 + }, + { + "name": "plugins/modules/gns3_project_file.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "e85dac29bd330c67214038eb1a9098e67ce3e3e16ae62ffb447dfdaea14c7ef3", + "format": 1 + }, + { + "name": "roles/delete_lab", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "roles/create_lab", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "roles/delete_lab/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "roles/delete_lab/meta", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "roles/delete_lab/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "95ac2ba013e97795a2e86623b6cbce9d5e432d9a6b58216be475d1d92ebe56b4", + "format": 1 + }, + { + "name": "roles/delete_lab/meta/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "9d92ea65373c0af69fd88e95f63fec9f4001e04128277f340a75932e0500eade", + "format": 1 + }, + { + "name": "roles/create_lab/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "roles/create_lab/meta", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "roles/create_lab/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "ed0bd1a5303442348d549b2aa5cc046abdc675be5d4dc8f4fa1d87f3fe44b621", + "format": 1 + }, + { + "name": "roles/create_lab/meta/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "14579b38e8cee8b07fe7b2cd337ee0611e949864ff84b1d8a1bc61ffb54e06c4", + "format": 1 + }, + { + "name": ".vscode/settings.json", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "4d5e35cc829fff24f9d120ef957b2ce72fbcc854577ae11ae7534f79bc21ad10", + "format": 1 + } + ], + "format": 1 +} \ No newline at end of file diff --git a/collections/ansible_collections/davidban77/gns3/LICENSE b/collections/ansible_collections/davidban77/gns3/LICENSE new file mode 100644 index 0000000..2732caa --- /dev/null +++ b/collections/ansible_collections/davidban77/gns3/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2019 David Flores + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/collections/ansible_collections/davidban77/gns3/MANIFEST.json b/collections/ansible_collections/davidban77/gns3/MANIFEST.json new file mode 100644 index 0000000..8abaf27 --- /dev/null +++ b/collections/ansible_collections/davidban77/gns3/MANIFEST.json @@ -0,0 +1,37 @@ +{ + "collection_info": { + "namespace": "davidban77", + "name": "gns3", + "version": "1.5.0", + "license": [ + "MIT" + ], + "description": "Module to interact with GNS3 server REST API based on gns3fy", + "repository": "https://github.com/davidban77/ansible-collection-gns3", + "documentation": "https://github.com/davidban77/ansible-collection-gns3/blob/master/README.md", + "homepage": "https://github.com/davidban77/ansible-collection-gns3", + "issues": "https://github.com/davidban77/ansible-collection-gns3/issues", + "authors": [ + "David Flores " + ], + "tags": [ + "gns3", + "gns3fy", + "networking", + "rest", + "system", + "netops" + ], + "license_file": null, + "readme": "README.md", + "dependencies": {} + }, + "file_manifest_file": { + "name": "FILES.json", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "f4608d42f56cf93d10743fa414e9a358810137998c8a7129f0aa9a378344aa50", + "format": 1 + }, + "format": 1 +} \ No newline at end of file diff --git a/collections/ansible_collections/davidban77/gns3/Makefile b/collections/ansible_collections/davidban77/gns3/Makefile new file mode 100644 index 0000000..a856985 --- /dev/null +++ b/collections/ansible_collections/davidban77/gns3/Makefile @@ -0,0 +1,30 @@ +VERSION=1.5.0 + +build: + rm -rf releases/ + mazer build + +publish: build + mazer publish releases/davidban77-gns3-${VERSION}.tar.gz + +test-create-lab: + cd test/playbooks; ansible-playbook main.yml -e execute=create + +test-node-interaction: + cd test/playbooks; ansible-playbook node_interaction.yml + +test-create-files: + cd test/playbooks; ansible-playbook create_files.yml + +test-snapshots: + cd test/playbooks; ansible-playbook snapshots.yml + +test-delete-files: + cd test/playbooks; ansible-playbook delete_files.yml + +test-delete-lab: + cd test/playbooks; ansible-playbook main.yml -e execute=delete + +test-create-all: test-create-lab test-create-files test-node-interaction test-snapshots + +test-delete-all: test-delete-files test-delete-lab diff --git a/collections/ansible_collections/davidban77/gns3/README.md b/collections/ansible_collections/davidban77/gns3/README.md new file mode 100644 index 0000000..d4b2d24 --- /dev/null +++ b/collections/ansible_collections/davidban77/gns3/README.md @@ -0,0 +1,207 @@ +# Ansible Module for GNS3 +[Ansible-Galaxy collections](https://galaxy.ansible.com/davidban77/gns3) repository for GNS3 Server REST API using [gns3fy - see the docs](https://davidban77.github.io/gns3fy/). + +## Installation + +For the module to be used you need to have installed [gns3fy](https://github.com/davidban77/gns3fy) + +``` +pip install gns3fy +``` + +This collections is packaged under ansible-galaxy, so to install it you need [mazer from Ansible Projects](https://galaxy.ansible.com/docs/mazer/index.html): + +``` +mazer install davidban77.gns3 +``` + +## Features + +- Open/closes projects. +- Starts/stops all nodes inside a project, or it can be done sequentially with a delay factor. +- Creates/Updates projects with nodes and links specified as variables in a playbook. +- Deletes projects safely by stopping nodes, if there are any, then closing the project and finally deleting it. +- Creates/Deletes/Restores snapshots of projects. +- Retrieves information about available emulators on the GNS3 server compute, as well as available images, console ports, version, etc.. +- Idempotency is present in all actions. An example could be reflected in a playbook that creates a project with nodes and links, these settings will not be executed again on a rerun (and by settings I mean projects settings, nodes and links)/ + + +## Modules + +These are the modules provided with this collection: + +- `gns3_version`: Retrieves GNS3 server version. (**TO BE DEPRECATED** with the `gns3_facts` module) +- `gns3_facts`: Retrieves the compute(s) information of a GNS3 server +- `gns3_project`: Module to interact with GNS3 server projects + - It opens/closes projects and performs basic turnup/teradown operations on nodes. + - It creates/updates or deletes projects, with the respective nodes and links specified +- `gns3_project_file`: Updates/creates a file on a project directory. +- `gns3_snapshot`: Module that interacts with snapshots of a project on GNS3 server. +- `gns3_node`: Module to operate a node in a GNS3 server project. +- `gns3_node_file`: Updates/creates a file on a node directory. +- `gns3_nodes_inventory`: Retrieves GNS3 a project nodes console information. + +## Examples: using the module + +Here are some examples of how to use the module. + +#### Get server version + +```yaml +--- +- host: localhost + # Call the collections to use the respective modules + collections: + - davidban77.gns3 + vars: + gns3_url: http://localhost + tasks: + - name: Get the server facts + gns3_facts: + url: "{{ gns3_url }}" + port: 3080 + get_images: all + get_compute_ports: yes + register: result + + - debug: var=result +``` +#### Get nodes_inventory information from a project + +```yaml +--- +- host: localhost + # Call the collections to use the respective modules + collections: + - davidban77.gns3 + vars: + gns3_url: http://localhost + tasks: + - name: Get the server version + gns3_nodes_inventory: + url: "{{ gns3_url }}" + project_name: lab_example + register: result + + - debug: var=result +``` + +#### Manipulate GNS3 projects + +```yaml +--- +# Open a GNS3 project +- name: Start lab + gns3_project: + url: "{{ gns3_url }}" + state: opened + project_name: lab_example + +# Stop all nodes inside an open project +- name: Stop nodes + gns3_project: + url: "{{ gns3_url }}" + state: opened + project_name: lab_example + nodes_state: stopped + nodes_strategy: all + poll_wait_time: 5 + +# Open a GNS3 project and start nodes one by one with a delay of 10sec between them +- name: Start nodes one by one + gns3_project: + url: "{{ gns3_url }}" + state: opened + project_name: lab_example + nodes_state: started + nodes_strategy: one_by_one + nodes_delay: 10 + +# Close a GNS3 project +- name: Stop lab + gns3_project: + url: "{{ gns3_url }}" + state: closed + project_id: "UUID-SOMETHING-1234567" +``` + +#### Create and delete projects + +```yaml +--- +# Create a GNS3 project given nodes and links specifications +- name: Create a project + gns3_project: + url: "{{ gns3_url }}" + state: present + project_name: new_lab + nodes_spec: + - name: alpine-1 + template: alpine + - name: alpine-2 + template: alpine + links_spec: + - ['alpine-1', 'eth0', 'alpine-2', 'eth1'] + +# Delete a GNS3 project +- name: Delete project + gns3_project: + url: "{{ gns3_url }}" + state: absent + project_name: new_lab +``` + +## Examples: using the roles + +There are also some convinient roles that you can use to manage your labs. Here is an example playbook: + +`main.yml` +```yaml +- hosts: localhost + tasks: + - import_role: + name: create_lab + when: execute == "create" + - import_role: + name: delete_lab + when: execute == "delete" +``` + +This way you can call and switch the behaviour of the playbook: + +**Create the lab** +``` +ansible-playbook main.yml -e execute=create +``` + +Or **delete the lab** +``` +ansible-playbook main.yml -e execute=delete +``` + +Here is the example variable file which specifies the naming convention used. You can see that the variable names come from the module itself with only `gns3_` + +```yaml +--- +gns3_url: "http://dev_gns3server" +gns3_project_name: test_ansible +gns3_nodes_spec: + - name: veos-1 + template: "vEOS-4.21.5F" + - name: veos-2 + template: "vEOS-4.21.5F" + - name: ios-1 + template: "IOU-15.4" + - name: ios-2 + template: "IOU-15.4" +gns3_nodes_strategy: one_by_one +gns3_links_spec: + - ["veos-1", "Ethernet1", "veos-2", "Ethernet1"] + - ["veos-1", "Ethernet2", "ios-1", "Ethernet1/0"] + - ["veos-2", "Ethernet2", "ios-2", "Ethernet1/0"] + - ["ios-1", "Ethernet1/2", "ios-2", "Ethernet1/2"] +``` + +### More examples + +For more examples like create an `/etc/network/interfaces` file for an `alpine` docker node to configure its network interfaces, or restore a project to an specific snapshot, you can go to the `test/playbooks` directory. diff --git a/collections/ansible_collections/davidban77/gns3/dev-requirements.txt b/collections/ansible_collections/davidban77/gns3/dev-requirements.txt new file mode 100644 index 0000000..54b944b --- /dev/null +++ b/collections/ansible_collections/davidban77/gns3/dev-requirements.txt @@ -0,0 +1,4 @@ +-r requirements.txt + +flake8 +black diff --git a/collections/ansible_collections/davidban77/gns3/galaxy.yml b/collections/ansible_collections/davidban77/gns3/galaxy.yml new file mode 100644 index 0000000..7b81ef3 --- /dev/null +++ b/collections/ansible_collections/davidban77/gns3/galaxy.yml @@ -0,0 +1,21 @@ +namespace: "davidban77" +name: "gns3" +version: "1.5.0" +readme: "README.md" +description: "Module to interact with GNS3 server REST API based on gns3fy" +authors: + - "David Flores " +dependencies: +license: + - "MIT" +tags: + - gns3 + - gns3fy + - networking + - rest + - system + - netops +repository: "https://github.com/davidban77/ansible-collection-gns3" +documentation: "https://github.com/davidban77/ansible-collection-gns3/blob/master/README.md" +homepage: "https://github.com/davidban77/ansible-collection-gns3" +issues: "https://github.com/davidban77/ansible-collection-gns3/issues" diff --git a/collections/ansible_collections/davidban77/gns3/plugins/modules/gns3_facts.py b/collections/ansible_collections/davidban77/gns3/plugins/modules/gns3_facts.py new file mode 100644 index 0000000..d3581e7 --- /dev/null +++ b/collections/ansible_collections/davidban77/gns3/plugins/modules/gns3_facts.py @@ -0,0 +1,187 @@ +#!/usr/bin/env python + +ANSIBLE_METADATA = { + "metadata_version": "1.1", + "status": ["preview"], + "supported_by": "community", +} + +DOCUMENTATION = """ +--- +module: gns3_facts +short_description: Module that retrieves the compute(s) information of a GNS3 server +version_added: '2.8' +description: + - Module that retrieves the compute(s) information of a GNS3 server +requirements: [ gns3fy ] +author: + - David Flores (@davidban77) +options: + url: + description: + - URL target of the GNS3 server + required: true + type: str + port: + description: + - TCP port to connect to server REST API + type: int + default: 3080 + user: + description: + - User to connect to GNS3 server + type: str + password: + description: + - Password to connect to GNS3 server + type: str + get_images: + description: + - If set it will also retrieve the images of the specified emulator unless + - is set to 'all', in which case will retrieve from all emulators. For a + - list of available emulators, visit the GNS3 API information + type: str + get_compute_ports: + description: + - If set it will retrieve the console_ports and udp_ports of the compute + type: bool +""" + +EXAMPLES = """ +# Retrieves all the information from the computes of GNS3 server +- name: Retrieve all the facts of a GNS3 server computes + gns3_facts: + url: http://localhost + get_images: all + get_compute_ports: yes + register: computes_info + +- debug: var=computes_info + +# Retrieves only basic facts data of the GNS3 server computes +- gns3_facts: + url: http://localhost + register: computes_info + +- debug: var=computes_info +""" + +RETURN = """ +compute_id: + description: Server identifier + type: str +name: + description: Server name + type: str +host: + description: Server host + type: str +capabilities: + description: Object that describes what the server supports + type: dict +connected: + description: Whether the controller is connected to the compute or not + type: bool +cpu_usage_percent: + description: CPU usage of the compute + type: float +memory_usage_percent: + description: RAM usage of the compute + type: int +port: + description: Server port + type: int +protocol: + description: Protocol used (http, https) + type: str +user: + description: User for authentication + type: str +last_error: + description: Last error on the compute + type: str +images: + description: Images configured on the compute depending on the emulator (optional) + type: dict +compute_ports: + description: Ports used by the compute (console and udp ports) (optional) + type: dict +""" + +import traceback +from ansible.module_utils.basic import AnsibleModule, missing_required_lib + +GNS3FY_IMP_ERR = None +try: + from gns3fy import Gns3Connector + + HAS_GNS3FY = True +except Exception: + HAS_GNS3FY = False + GNS3FY_IMP_ERR = traceback.format_exc() + + +def main(): + module = AnsibleModule( + argument_spec=dict( + url=dict(type="str", required=True), + port=dict(type="int", default=3080), + user=dict(type="str", default=None), + password=dict(type="str", default=None, no_log=True), + get_images=dict(type="str", default=None), + get_compute_ports=dict(type="bool", default=False), + ) + ) + result = dict(changed=False) + if not HAS_GNS3FY: + module.fail_json(msg=missing_required_lib("gns3fy"), exception=GNS3FY_IMP_ERR) + + server_url = module.params["url"] + server_port = module.params["port"] + server_user = module.params["user"] + server_password = module.params["password"] + get_images = module.params["get_images"] + get_compute_ports = module.params["get_compute_ports"] + + try: + # Create server session + server = Gns3Connector( + url=f"{server_url}:{server_port}", user=server_user, cred=server_password + ) + + computes = server.get_computes() + for compute in computes: + + # Images + if get_images: + compute["images"] = dict() + + if get_images == "all": + for emulator in compute["capabilities"]["node_types"]: + try: + compute["images"][emulator] = server.get_compute_images( + emulator=emulator, compute_id=compute["compute_id"] + ) + except Exception as err: + if "404" in str(err): + # Contine if no image dir is set for that emulator + continue + else: + compute["images"][get_images] = server.get_compute_images( + emulator=get_images, compute_id=compute["compute_id"] + ) + + # Compute ports + if get_compute_ports: + compute["compute_ports"] = server.get_compute_ports( + compute_id=compute["compute_id"] + ) + + result["facts"] = computes + module.exit_json(**result) + except Exception as err: + module.fail_json(msg=str(err), **result) + + +if __name__ == "__main__": + main() diff --git a/collections/ansible_collections/davidban77/gns3/plugins/modules/gns3_node.py b/collections/ansible_collections/davidban77/gns3/plugins/modules/gns3_node.py new file mode 100644 index 0000000..5b9e882 --- /dev/null +++ b/collections/ansible_collections/davidban77/gns3/plugins/modules/gns3_node.py @@ -0,0 +1,272 @@ +#!/usr/bin/env python + +ANSIBLE_METADATA = { + "metadata_version": "1.2", + "status": ["preview"], + "supported_by": "community", +} + +DOCUMENTATION = """ +--- +module: gns3_node +short_description: Module to operate a node in a GNS3 server project +version_added: '2.8' +description: + - Module to operate a node in a GNS3 server project. + - It starts/stops/suspend/reloads a node. +requirements: [ gns3fy ] +author: + - David Flores (@davidban77) +options: + url: + description: + - URL target of the GNS3 server + required: true + type: str + port: + description: + - TCP port to connect to server REST API + type: int + default: 3080 + user: + description: + - User to connect to GNS3 server + type: str + password: + description: + - Password to connect to GNS3 server + type: str + project_name: + description: + - Project name + type: str + project_id: + description: + - Project ID + type: str + node_name: + description: + - Node name + type: str + node_id: + description: + - Node ID + type: str + state: + description: + - State of the node, it can be: + - '- C(started): Starts a node' + - '- C(stopped): Stops a node' + - '- C(suspended): Suspends a node' + - '- C(reload): Special non-idempotent action that reloads a node' + type: str + choices: ['started', 'stopped', 'suspended', 'reload'] + retry: + description: + - Retries an action based on the state, if true and state is set to reload + - it will reload the device and try to start it again if the status was not + - changed + type: bool + default: false + poll_wait_time: + description: + - Delay in seconds to wait to poll nodes when they are started/stopped. + - Used when I(nodes_state) is C(started)/C(stopped) + type: int + default: 5 + force_project_open: + description: + - It will open the project (if closed) to interact with the device. + - Otherwise it will throw out an error + type: bool + default: false +""" + +EXAMPLES = """ +# Open a GNS3 project and start router01 node +- name: Start node + gns3_node: + url: http://localhost + project_name: lab_example + node_name: router01 + node_state: started + force_project_open: true + +# Stop a node and wait 10 seconds to poll for status +- name: Stop node + gns3_node: + url: http://localhost + project_name: lab_example + node_name: router01 + state: stopped + +# Suspend a node based on UUID +- name: Suspend node + gns3_node: + url: http://localhost + project_name: lab_example + node_id: 'ROUTER-UUID-SOMETHING-1234567' + state: suspended + +# Reload a node and apply a retry to start if needed +- name: Stop lab + gns3_node: + url: http://localhost + project_id: 'PROJECT-UUID-SOMETHING-1234567' + node_name: router01 + state: reload + retry: true + poll_wait_time: 30 +""" + +RETURN = """ +name: + description: Project name + type: str +project_id: + description: Project UUID + type: str +node_id: + description: Node UUID + type: str +status: + description: Project status. Possible values: opened, closed + type: str +node_directory: + description: Path of the node on the server (works only with compute=local) + type: str +node_type: + description: Network node type + type: str +""" +import time +import traceback +from ansible.module_utils.basic import AnsibleModule, missing_required_lib + +GNS3FY_IMP_ERR = None +try: + from gns3fy import Gns3Connector, Project + + HAS_GNS3FY = True +except Exception: + HAS_GNS3FY = False + GNS3FY_IMP_ERR = traceback.format_exc() + + +def return_node_data(node): + "Returns the node main attributes" + return dict( + name=node.name, + project_id=node.project_id, + node_id=node.node_id, + status=node.status, + node_directory=node.node_directory, + node_type=node.node_type, + ) + + +def state_verification(expected_state, node, retry=False, poll_wait_time=5): + "Verifies node state and returns a changed attribute" + if expected_state == "started" and node.status != "started": + node.start() + if node.status != "started" and retry: + node.start() + return True + elif expected_state == "stopped" and node.status != "stopped": + node.stop() + if node.status != "stopped" and retry: + node.stop() + return True + elif expected_state == "suspended" and node.status != "suspended": + node.suspend() + if node.status != "suspended" and retry: + node.suspend() + return True + elif expected_state == "reload": + node.reload() + time.sleep(poll_wait_time) + node.get() + if node.status != "started" and retry: + node.start() + return True + return False + + +def main(): + module = AnsibleModule( + argument_spec=dict( + url=dict(type="str", required=True), + port=dict(type="int", default=3080), + user=dict(type="str", default=None), + password=dict(type="str", default=None, no_log=True), + state=dict( + type="str", + required=True, + choices=["started", "stopped", "suspended", "reload"], + ), + project_name=dict(type="str", default=None), + project_id=dict(type="str", default=None), + node_name=dict(type="str", default=None), + node_id=dict(type="str", default=None), + retry=dict(type="bool", default=False), + poll_wait_time=dict(type="int", default=5), + force_project_open=dict(type="bool", default=False), + ), + required_one_of=[["project_name", "project_id"], ["node_name", "node_id"]], + ) + result = dict(changed=False) + if not HAS_GNS3FY: + module.fail_json(msg=missing_required_lib("gns3fy"), exception=GNS3FY_IMP_ERR) + + server_url = module.params["url"] + server_port = module.params["port"] + server_user = module.params["user"] + server_password = module.params["password"] + state = module.params["state"] + project_name = module.params["project_name"] + project_id = module.params["project_id"] + node_name = module.params["node_name"] + node_id = module.params["node_id"] + retry = module.params["retry"] + poll_wait_time = module.params["poll_wait_time"] + force_project_open = module.params["force_project_open"] + + try: + # Create server session + server = Gns3Connector( + url=f"{server_url}:{server_port}", user=server_user, cred=server_password + ) + # Define the project + if project_name is not None: + project = Project(name=project_name, connector=server) + elif project_id is not None: + project = Project(project_id=project_id, connector=server) + if project is None: + module.fail_json(msg="Could not retrieve project. Check name", **result) + + project.get() + if project.status != "opened" and force_project_open: + project.open() + + # Retrieve node + if node_name is not None: + node = project.get_node(name=node_name) + elif node_id is not None: + node = project.get_node(node_id=node_id) + if node is None: + module.fail_json(msg="Could not retrieve node. Check name", **result) + except Exception as err: + module.fail_json(msg=str(err), **result) + + # Apply state change + result["changed"] = state_verification( + expected_state=state, node=node, retry=retry, poll_wait_time=poll_wait_time + ) + + # Return the node data + result["node"] = return_node_data(node) + module.exit_json(**result) + + +if __name__ == "__main__": + main() diff --git a/collections/ansible_collections/davidban77/gns3/plugins/modules/gns3_node_file.py b/collections/ansible_collections/davidban77/gns3/plugins/modules/gns3_node_file.py new file mode 100644 index 0000000..6d0c305 --- /dev/null +++ b/collections/ansible_collections/davidban77/gns3/plugins/modules/gns3_node_file.py @@ -0,0 +1,192 @@ +#!/usr/bin/env python + +ANSIBLE_METADATA = { + "metadata_version": "1.2", + "status": ["preview"], + "supported_by": "community", +} + +DOCUMENTATION = """ +--- +module: gns3_node_file +short_description: Updates/creates a file on a node directory +version_added: '2.8' +description: + - "Updates/creates a file on a node directory of a GNS3 project" +requirements: [ gns3fy ] +author: + - David Flores (@davidban77) +options: + url: + description: + - URL target of the GNS3 server + required: true + type: str + port: + description: + - TCP port to connect to server REST API + type: int + default: 3080 + user: + description: + - User to connect to GNS3 server + type: str + password: + description: + - Password to connect to GNS3 server + type: str + project_name: + description: + - Project name + type: str + project_id: + description: + - Project ID + type: str + node_name: + description: + - Node name + type: str + node_id: + description: + - Node ID + type: str + data: + description: + - The text to insert. + type: str + dest: + description: + - Node destination path. Like 'etc/network/interfaces' + type: str + required: true + state: + description: + - If the file should present or absent + type: str + choices: ['present', 'absent'] + default: present +""" + +EXAMPLES = """ +# Retrieve the GNS3 server version +- name: Get the server version + gns3_node_file: + url: http://localhost + port: 3080 + project_name: test_lab + node_name: alpine-1 + data: | + auto eth0 + iface eth0 inet dhcp + dest: /etc/network/interfaces +""" +import traceback + +GNS3FY_IMP_ERR = None +try: + from gns3fy import Gns3Connector, Project + + HAS_GNS3FY = True +except ImportError: + GNS3FY_IMP_ERR = traceback.format_exc() + HAS_GNS3FY = False + +from ansible.module_utils.basic import AnsibleModule, missing_required_lib + + +def node_write_file(module, node, path, data): + "Writes text data into specified path of the node" + try: + node.write_file(path=path, data=data) + except Exception as err: + module.fail_json(msg=str(err), exception=traceback.format_exc()) + + +def main(): + module = AnsibleModule( + argument_spec=dict( + url=dict(type="str", required=True), + port=dict(type="int", default=3080), + user=dict(type="str", default=None), + password=dict(type="str", default=None, no_log=True), + project_name=dict(type="str", default=None), + project_id=dict(type="str", default=None), + node_name=dict(type="str", default=None), + node_id=dict(type="str", default=None), + data=dict(type="str", default=None), + dest=dict(type="str", required=True), + state=dict(type="str", choices=["present", "absent"], default="present"), + ), + required_one_of=[["project_name", "project_id"], ["node_name", "node_id"]], + ) + if not HAS_GNS3FY: + module.fail_json(msg=missing_required_lib("gns3fy"), exception=GNS3FY_IMP_ERR) + result = dict(changed=False) + + server_url = module.params["url"] + server_port = module.params["port"] + server_user = module.params["user"] + server_password = module.params["password"] + project_name = module.params["project_name"] + project_id = module.params["project_id"] + node_name = module.params["node_name"] + node_id = module.params["node_id"] + data = module.params["data"] + dest = module.params["dest"] + state = module.params["state"] + if state == "present" and data is None: + module.fail_json(msg="Parameter needs to be passed: data", **result) + + # Create server session + server = Gns3Connector( + url=f"{server_url}:{server_port}", user=server_user, cred=server_password + ) + # Define the project + if project_name is not None: + project = Project(name=project_name, connector=server) + elif project_id is not None: + project = Project(project_id=project_id, connector=server) + if project is None: + module.fail_json(msg="Could not retrieve project. Check name", **result) + + # Retrieve project info + project.get() + + # Define the Node + if node_name is not None: + node = project.get_node(name=node_name) + elif node_id is not None: + node = project.get_node(node_id=node_id) + if node is None: + module.fail_json(msg="Could not retrieve node. Check name", **result) + + # Try to get file data + try: + file_data = node.get_file(path=dest) + except Exception as err: + if "not found" in str(err): + file_data = None + else: + module.fail_json(msg=str(err), exception=traceback.format_exc()) + + if state == "absent": + if file_data is None or file_data == "": + result.update(changed=False) + else: + # Delete node file data + # As of now (GNS3 v2.2.rc5) the DELETE method is not allowed + node_write_file(module, node, dest, "") + result.update(changed=True) + elif state == "present": + if file_data == data: + result.update(changed=False) + else: + node_write_file(module, node, dest, data) + result.update(changed=True) + + module.exit_json(**result) + + +if __name__ == "__main__": + main() diff --git a/collections/ansible_collections/davidban77/gns3/plugins/modules/gns3_nodes_inventory.py b/collections/ansible_collections/davidban77/gns3/plugins/modules/gns3_nodes_inventory.py new file mode 100644 index 0000000..5cd2ebe --- /dev/null +++ b/collections/ansible_collections/davidban77/gns3/plugins/modules/gns3_nodes_inventory.py @@ -0,0 +1,128 @@ +#!/usr/bin/env python + +ANSIBLE_METADATA = { + "metadata_version": "1.2", + "status": ["preview"], + "supported_by": "community", +} + +DOCUMENTATION = """ +--- +module: gns3_nodes_inventory +short_description: Retrieves GNS3 a project nodes console information +version_added: '2.8' +description: + - "Retrieves nodes inventory information from a GNS3 project" +requirements: [ gns3fy ] +author: + - David Flores (@davidban77) +options: + url: + description: + - URL target of the GNS3 server + required: true + type: str + port: + description: + - TCP port to connect to server REST API + type: int + default: 3080 + user: + description: + - User to connect to GNS3 server + type: str + password: + description: + - Password to connect to GNS3 server + type: str + project_name: + description: + - Project name + type: str + project_id: + description: + - Project ID + type: str +""" + +EXAMPLES = """ +# Retrieve the GNS3 server version +- name: Get the server version + gns3_nodes_inventory: + url: http://localhost + port: 3080 + project_name: test_lab + register: nodes_inventory + +- debug: var=nodes_inventory +""" + +RETURN = """ +nodes_inventory: + description: Dictionary that contain: name, server, console_port, console_type, + type and template of each node + type: dict +total_nodes: + description: Total number of nodes + type: int +""" +import traceback + +GNS3FY_IMP_ERR = None +try: + from gns3fy import Gns3Connector, Project + + HAS_GNS3FY = True +except ImportError: + GNS3FY_IMP_ERR = traceback.format_exc() + HAS_GNS3FY = False + +from ansible.module_utils.basic import AnsibleModule, missing_required_lib + + +def main(): + module = AnsibleModule( + argument_spec=dict( + url=dict(type="str", required=True), + port=dict(type="int", default=3080), + user=dict(type="str", default=None), + password=dict(type="str", default=None, no_log=True), + project_name=dict(type="str", default=None), + project_id=dict(type="str", default=None), + ), + required_one_of=[["project_name", "project_id"]], + ) + if not HAS_GNS3FY: + module.fail_json(msg=missing_required_lib("gns3fy"), exception=GNS3FY_IMP_ERR) + result = dict(changed=False, nodes_inventory=None, total_nodes=None) + + server_url = module.params["url"] + server_port = module.params["port"] + server_user = module.params["user"] + server_password = module.params["password"] + project_name = module.params["project_name"] + project_id = module.params["project_id"] + + # Create server session + server = Gns3Connector( + url=f"{server_url}:{server_port}", user=server_user, cred=server_password + ) + # Define the project + if project_name is not None: + project = Project(name=project_name, connector=server) + elif project_id is not None: + project = Project(project_id=project_id, connector=server) + + # Retrieve project info + project.get() + + nodes_inventory = project.nodes_inventory() + result.update( + nodes_inventory=nodes_inventory, total_nodes=len(nodes_inventory.keys()) + ) + + module.exit_json(**result) + + +if __name__ == "__main__": + main() diff --git a/collections/ansible_collections/davidban77/gns3/plugins/modules/gns3_project.py b/collections/ansible_collections/davidban77/gns3/plugins/modules/gns3_project.py new file mode 100644 index 0000000..405248a --- /dev/null +++ b/collections/ansible_collections/davidban77/gns3/plugins/modules/gns3_project.py @@ -0,0 +1,434 @@ +#!/usr/bin/env python + +ANSIBLE_METADATA = { + "metadata_version": "1.4", + "status": ["preview"], + "supported_by": "community", +} + +DOCUMENTATION = """ +--- +module: gns3_project +short_description: Module to interact with GNS3 server projects +version_added: '2.8' +description: + - 'Module to interact with GNS3 server projects. + - It is using the L(gns3fy library,https://davidban77.github.io/gns3fy/)' + - It opens/closes projects and performs basic turnup/teradown operations on nodes. + - It creates/updates or deletes projects. +requirements: [ gns3fy ] +author: + - David Flores (@davidban77) +options: + url: + description: + - URL target of the GNS3 server + required: true + type: str + port: + description: + - TCP port to connect to server REST API + type: int + default: 3080 + user: + description: + - User to connect to GNS3 server + type: str + password: + description: + - Password to connect to GNS3 server + type: str + state: + description: + - State of the project to be on the GNS3 server + - '- C(opened): Opens a project and turns up nodes' + - '- C(closed): Closes a project and turns down nodes' + - '- C(present): Creates/update a project on the server' + - '- C(absent): Deletes a project on the server' + type: str + choices: ['opened', 'closed', 'present', 'absent'] + project_name: + description: + - Project name + type: str + project_id: + description: + - Project ID + type: str + nodes_state: + description: + - Starts/stops nodes on the project. + - Used when I(state) is C(opened)/C(closed) + type: str + choices: ['started', 'stopped'] + nodes_strategy: + description: + - Start/stop strategy of the devices defined on the project. + - '- C(all): It starts/stops all nodes at once' + - '- C(one_by_one): It starts/stops nodes serialy using I(nodes_delay) time + between each action' + - Used when I(state) is C(opened)/C(closed) + type: str + choices: ['all', 'one_by_one'] + default: 'all' + nodes_delay: + description: + - Delay time in seconds to wait between nodes start/stop + - Used when I(nodes_strategy) is C(one_by_one) + type: int + default: 10 + poll_wait_time: + description: + - Delay in seconds to wait to poll nodes when they are started/stopped. + - Used when I(nodes_state) is C(started)/C(stopped) + type: int + default: 5 + nodes_spec: + description: + - List of dictionaries specifying the nodes properties. + - '- Mandatory attributes: C(name), C(node_type) and C(template).' + - '- Optional attributes: C(compute_id). It defaults to C(local)' + type: list + links_spec: + description: + - 'List of lists specifying the links endpoints. Example: C(- ["alpine-1", + "eth0", "alpine-2", "eth0"])' + - 'Mandatory attributes: C(node_a), C(port_a), C(node_b) and C(port_b)' + type: list +""" + +EXAMPLES = """ +# Open a GNS3 project +- name: Start lab + gns3_project: + url: http://localhost + state: opened + project_name: lab_example + +# Stop all nodes inside an open project +- name: Stop nodes + gns3_project: + url: http://localhost + state: opened + project_name: lab_example + nodes_state: stopped + nodes_strategy: all + poll_wait_time: 5 + +# Open a GNS3 project and start nodes one by one with a delay of 10sec between them +- name: Start nodes one by one + gns3_project: + url: http://localhost + state: opened + project_name: lab_example + nodes_state: started + nodes_strategy: one_by_one + nodes_delay: 10 + +# Close a GNS3 project +- name: Stop lab + gns3_project: + url: http://localhost + state: closed + project_id: 'UUID-SOMETHING-1234567' + +# Create a GNS3 project +- name: Create a project given nodes and links specs + gns3_project: + url: http://localhost + state: present + project_name: new_lab + nodes_spec: + - name: alpine-1 + node_type: docker + template: alpine + - name: alpine-2 + node_type: docker + template: alpine + links_spec: + - ('alpine-1', 'eth0', 'alpine-2', 'eth1') + +# Delete a GNS3 project +- name: Delete project + gns3_project: + url: http://localhost + state: absent + project_name: new_lab +""" + +RETURN = """ +name: + description: Project name + type: str +project_id: + description: Project UUID + type: str +status: + description: Project status. Possible values: opened, closed + type: str +path: + description: Path of the project on the server (works only with compute=local) + type: str +auto_close: + description: Project auto close when client cut off the notifications feed + type: bool +auto_open: + description: Project open when GNS3 start + type: bool +auto_start: + description: Project start when opened + type: bool +filename: + description: Project filename + type: str +""" + +import time +import traceback +from ansible.module_utils.basic import AnsibleModule, missing_required_lib + +GNS3FY_IMP_ERR = None +try: + from gns3fy import Gns3Connector, Project + + HAS_GNS3FY = True +except Exception: + HAS_GNS3FY = False + GNS3FY_IMP_ERR = traceback.format_exc() + + +def return_project_data(project): + "Returns the project main attributes" + return dict( + name=project.name, + project_id=project.project_id, + status=project.status, + path=project.path, + auto_close=project.auto_close, + auto_open=project.auto_open, + auto_start=project.auto_start, + filename=project.filename, + ) + + +# def nodes_state_verification(module, project, result): +def nodes_state_verification( + expected_nodes_state, nodes_strategy, nodes_delay, poll_wait_time, project +): + "Verifies each node state and returns a changed attribute" + nodes_statuses = [node.status for node in project.nodes] + + # Verify if nodes do not match expected state + if expected_nodes_state == "started" and any( + status == "stopped" for status in nodes_statuses + ): + # Turnup the nodes based on strategy + if nodes_strategy == "all": + project.start_nodes(poll_wait_time=poll_wait_time) + elif nodes_strategy == "one_by_one": + for node in project.nodes: + if node.status != "started": + node.start() + time.sleep(nodes_delay) + return True + elif expected_nodes_state == "stopped" and any( + status == "started" for status in nodes_statuses + ): + # Shutdown nodes based on strategy + if nodes_strategy == "all": + project.stop_nodes(poll_wait_time=poll_wait_time) + elif nodes_strategy == "one_by_one": + for node in project.nodes: + if node.status != "stopped": + node.stop() + time.sleep(nodes_delay) + return True + return False + + +def create_node(node_spec, project, module): + "Creates the node specified in nodes_spec" + # If exceptions occur then print them out in ansible format + try: + project.create_node(**node_spec) + except Exception as err: + module.fail_json(msg=str(err), exception=traceback.format_exc()) + + +def create_link(link_spec, project, module): + "Creates the node specified in nodes_spec" + # If exceptions occur then print them out in ansible format + try: + project.create_link(*link_spec) + except ValueError as err: + if "At least one port is used" in str(err): + return False + else: + module.fail_json(msg=str(err), exception=traceback.format_exc()) + except Exception as err: + module.fail_json(msg=str(err), exception=traceback.format_exc()) + return True + + +def main(): + module = AnsibleModule( + argument_spec=dict( + url=dict(type="str", required=True), + port=dict(type="int", default=3080), + user=dict(type="str", default=None), + password=dict(type="str", default=None, no_log=True), + state=dict( + type="str", + required=True, + choices=["opened", "closed", "present", "absent"], + ), + project_name=dict(type="str", default=None), + project_id=dict(type="str", default=None), + nodes_state=dict(type="str", choices=["started", "stopped"]), + nodes_strategy=dict( + type="str", choices=["all", "one_by_one"], default="all" + ), + nodes_delay=dict(type="int", default=10), + poll_wait_time=dict(type="int", default=5), + nodes_spec=dict(type="list"), + links_spec=dict(type="list"), + ), + supports_check_mode=True, + required_one_of=[["project_name", "project_id"]], + required_if=[["nodes_strategy", "one_by_one", ["nodes_delay"]]], + ) + result = dict(changed=False) + if not HAS_GNS3FY: + module.fail_json(msg=missing_required_lib("gns3fy"), exception=GNS3FY_IMP_ERR) + if module.check_mode: + module.exit_json(**result) + + server_url = module.params["url"] + server_port = module.params["port"] + server_user = module.params["user"] + server_password = module.params["password"] + state = module.params["state"] + project_name = module.params["project_name"] + project_id = module.params["project_id"] + nodes_state = module.params["nodes_state"] + nodes_strategy = module.params["nodes_strategy"] + nodes_delay = module.params["nodes_delay"] + poll_wait_time = module.params["poll_wait_time"] + nodes_spec = module.params["nodes_spec"] + links_spec = module.params["links_spec"] + + try: + # Create server session + server = Gns3Connector( + url=f"{server_url}:{server_port}", user=server_user, cred=server_password + ) + # Define the project + if project_name is not None: + project = Project(name=project_name, connector=server) + elif project_id is not None: + project = Project(project_id=project_id, connector=server) + except Exception as err: + module.fail_json(msg=str(err), **result) + + #  Retrieve project information + try: + project.get() + pr_exists = True + except Exception as err: + pr_exists = False + reason = str(err) + + if state == "opened": + if pr_exists: + if project.status != "opened": + # Open project + project.open() + + # Now verify nodes + if nodes_state is not None: + + # Change flag based on the nodes state + result["changed"] = nodes_state_verification( + expected_nodes_state=nodes_state, + nodes_strategy=nodes_strategy, + nodes_delay=nodes_delay, + poll_wait_time=poll_wait_time, + project=project, + ) + else: + # Means that nodes are not taken into account for idempotency + result["changed"] = True + # Even if the project is open if nodes_state has been set, check it + else: + if nodes_state is not None: + result["changed"] = nodes_state_verification( + expected_nodes_state=nodes_state, + nodes_strategy=nodes_strategy, + nodes_delay=nodes_delay, + poll_wait_time=poll_wait_time, + project=project, + ) + + else: + module.fail_json(msg=reason, **result) + + elif state == "closed": + if pr_exists: + if project.status != "closed": + # Close project + project.close() + result["changed"] = True + else: + module.fail_json(msg=reason, **result) + + elif state == "present": + if pr_exists: + if nodes_spec is not None: + # Need to verify if nodes exist + _nodes_already_created = [node.name for node in project.nodes] + for node_spec in nodes_spec: + if node_spec["name"] not in _nodes_already_created: + # Open the project in case it was closed + project.open() + create_node(node_spec, project, module) + result["changed"] = True + if links_spec is not None: + for link_spec in links_spec: + project.open() + # Trigger another get to refresh nodes attributes + project.get() + # Link verification is already built in the library + created = create_link(link_spec, project, module) + if created: + result["changed"] = True + else: + # Create project + project.create() + # Nodes section + if nodes_spec is not None: + for node_spec in nodes_spec: + create_node(node_spec, project, module) + # Links section + if links_spec is not None: + for link_spec in links_spec: + create_link(link_spec, project, module) + result["changed"] = True + elif state == "absent": + if pr_exists: + # Stop nodes and close project to perform delete gracefully + if project.status != "opened": + # Project needs to be opened in order to be deleted... + project.open() + project.stop_nodes(poll_wait_time=0) + project.delete() + result["changed"] = True + else: + module.exit_json(**result) + + # Return the project data + result["project"] = return_project_data(project) + module.exit_json(**result) + + +if __name__ == "__main__": + main() diff --git a/collections/ansible_collections/davidban77/gns3/plugins/modules/gns3_project_file.py b/collections/ansible_collections/davidban77/gns3/plugins/modules/gns3_project_file.py new file mode 100644 index 0000000..f636a8a --- /dev/null +++ b/collections/ansible_collections/davidban77/gns3/plugins/modules/gns3_project_file.py @@ -0,0 +1,170 @@ +#!/usr/bin/env python + +ANSIBLE_METADATA = { + "metadata_version": "1.2", + "status": ["preview"], + "supported_by": "community", +} + +DOCUMENTATION = """ +--- +module: gns3_project_file +short_description: Updates/creates a file on a project directory +version_added: '2.8' +description: + - "Updates/creates a file on a project directory on the GNS3 server" +requirements: [ gns3fy ] +author: + - David Flores (@davidban77) +options: + url: + description: + - URL target of the GNS3 server + required: true + type: str + port: + description: + - TCP port to connect to server REST API + type: int + default: 3080 + user: + description: + - User to connect to GNS3 server + type: str + password: + description: + - Password to connect to GNS3 server + type: str + project_name: + description: + - Project name + type: str + project_id: + description: + - Project ID + type: str + data: + description: + - The text to insert. + type: str + dest: + description: + - Node destination path. Like 'etc/network/interfaces' + type: str + required: true + state: + description: + - If the file should present or absent + type: str + choices: ['present', 'absent'] + default: present +""" + +EXAMPLES = """ +# Retrieve the GNS3 server version +- name: Get the server version + gns3_project_file: + url: http://localhost + port: 3080 + project_name: test_lab + data: | + Hello this is a README! + dest: README.txt +""" +import traceback + +GNS3FY_IMP_ERR = None +try: + from gns3fy import Gns3Connector, Project + + HAS_GNS3FY = True +except ImportError: + GNS3FY_IMP_ERR = traceback.format_exc() + HAS_GNS3FY = False + +from ansible.module_utils.basic import AnsibleModule, missing_required_lib + + +def project_write_file(module, project, path, data): + "Writes text data into specified path of the project" + try: + project.write_file(path=path, data=data) + except Exception as err: + module.fail_json(msg=str(err), exception=traceback.format_exc()) + + +def main(): + module = AnsibleModule( + argument_spec=dict( + url=dict(type="str", required=True), + port=dict(type="int", default=3080), + user=dict(type="str", default=None), + password=dict(type="str", default=None, no_log=True), + project_name=dict(type="str", default=None), + project_id=dict(type="str", default=None), + data=dict(type="str", default=None), + dest=dict(type="str", required=True), + state=dict(type="str", choices=["present", "absent"], default="present"), + ), + required_one_of=[["project_name", "project_id"]], + ) + if not HAS_GNS3FY: + module.fail_json(msg=missing_required_lib("gns3fy"), exception=GNS3FY_IMP_ERR) + result = dict(changed=False) + + server_url = module.params["url"] + server_port = module.params["port"] + server_user = module.params["user"] + server_password = module.params["password"] + project_name = module.params["project_name"] + project_id = module.params["project_id"] + data = module.params["data"] + dest = module.params["dest"] + state = module.params["state"] + if state == "present" and data is None: + module.fail_json(msg="Parameter needs to be passed: data", **result) + + # Create server session + server = Gns3Connector( + url=f"{server_url}:{server_port}", user=server_user, cred=server_password + ) + # Define the project + if project_name is not None: + project = Project(name=project_name, connector=server) + elif project_id is not None: + project = Project(project_id=project_id, connector=server) + if project is None: + module.fail_json(msg="Could not retrieve project. Check name", **result) + + # Retrieve project info + project.get() + + # Try to get file data + try: + file_data = project.get_file(path=dest) + except Exception as err: + if "Not Found" in str(err): + file_data = None + else: + module.fail_json(msg=str(err), exception=traceback.format_exc()) + + if state == "absent": + if file_data is None or file_data == "": + result.update(changed=False) + else: + # Delete project file data + # As of now (GNS3 v2.2.rc5) the DELETE method is not allowed + project_write_file(module, project, dest, "") + result.update(changed=True) + elif state == "present": + if file_data == data: + result.update(changed=False) + else: + project_write_file(module, project, dest, data) + result.update(changed=True) + + module.exit_json(**result) + + +if __name__ == "__main__": + main() diff --git a/collections/ansible_collections/davidban77/gns3/plugins/modules/gns3_snapshot.py b/collections/ansible_collections/davidban77/gns3/plugins/modules/gns3_snapshot.py new file mode 100644 index 0000000..75d9895 --- /dev/null +++ b/collections/ansible_collections/davidban77/gns3/plugins/modules/gns3_snapshot.py @@ -0,0 +1,203 @@ +#!/usr/bin/env python + +ANSIBLE_METADATA = { + "metadata_version": "1.1", + "status": ["preview"], + "supported_by": "community", +} + +DOCUMENTATION = """ +--- +module: gns3_snapshot +short_description: Module that interacts with snapshots of a project on GNS3 server +version_added: '2.8' +description: + - Module that interacts with snapshots of a project on GNS3 server +requirements: [ gns3fy ] +author: + - David Flores (@davidban77) +options: + url: + description: + - URL target of the GNS3 server + required: true + type: str + port: + description: + - TCP port to connect to server REST API + type: int + default: 3080 + user: + description: + - User to connect to GNS3 server + type: str + password: + description: + - Password to connect to GNS3 server + type: str + project_name: + description: + - Project name + type: str + project_id: + description: + - Project ID + type: str + snapshot_name: + description: + - Snapshot name + type: str + snapshot_id: + description: + - Snapshot ID + type: str + state: + description: + - Creates/deletes/restores a project snapshot. + - NOTE: The restore is not an idempotent task + type: str + choices: ['present', 'absent', 'restore'] + required: true +""" + +EXAMPLES = """ +# Retrieves all the information from the computes of GNS3 server +- name: Retrieve all the facts of a GNS3 server computes + gns3_snapshot: + url: http://localhost + project_name: demo_lab + snapshot_name: snap1 + state: present + register: result + +- debug: var=result + +# Retrieves only basic facts data of the GNS3 server computes +- gns3_snapshot: + url: http://localhost + project_name: demo_lab + snapshot_id: "SOME_UUID" + state: absent + +# Restores the project from a specific snapshot. This is NOT idempotent +- gns3_snapshot: + url: http://localhost + project_name: demo_lab + snapshot_name: snap1 + state: restore +""" + +RETURN = """ +created_at: + description: Unix format datetime + type: int +name: + description: Snapshot name + type: str +project_id: + description: Project UUID + type: str +snapshot_id: + description: Snapshot UUID + type: dict +""" + +import traceback +from ansible.module_utils.basic import AnsibleModule, missing_required_lib + +GNS3FY_IMP_ERR = None +try: + from gns3fy import Gns3Connector, Project + + HAS_GNS3FY = True +except Exception: + HAS_GNS3FY = False + GNS3FY_IMP_ERR = traceback.format_exc() + + +def main(): + module = AnsibleModule( + argument_spec=dict( + url=dict(type="str", required=True), + user=dict(type="str", default=None), + password=dict(type="str", default=None, no_log=True), + port=dict(type="int", default=3080), + state=dict( + type="str", required=True, choices=["present", "absent", "restore"] + ), + project_name=dict(type="str", default=None), + project_id=dict(type="str", default=None), + snapshot_name=dict(type="str", default=None), + snapshot_id=dict(type="str", default=None), + ), + required_one_of=[ + ["project_name", "project_id"], + ["snapshot_name", "snapshot_id"], + ], + ) + result = dict(changed=False) + if not HAS_GNS3FY: + module.fail_json(msg=missing_required_lib("gns3fy"), exception=GNS3FY_IMP_ERR) + + server_url = module.params["url"] + server_port = module.params["port"] + server_user = module.params["user"] + server_password = module.params["password"] + project_name = module.params["project_name"] + project_id = module.params["project_id"] + snapshot_name = module.params["snapshot_name"] + snapshot_id = module.params["snapshot_id"] + state = module.params["state"] + + try: + # Create server session + server = Gns3Connector( + url=f"{server_url}:{server_port}", user=server_user, cred=server_password + ) + + # Define the project + if project_name is not None: + project = Project(name=project_name, connector=server) + elif project_id is not None: + project = Project(project_id=project_id, connector=server) + + # Collect project and snapshots data + project.get() + snapshot = project.get_snapshot(name=snapshot_name, snapshot_id=snapshot_id) + + if state == "present": + if snapshot is None: + # Create the snapshot + if not snapshot_name: + module.fail_json( + msg="Need to specify snapshot name for creation", **result + ) + project.create_snapshot(name=snapshot_name) + result["changed"] = True + result["snapshot"] = project.get_snapshot( + name=snapshot_name, snapshot_id=snapshot_id + ) + else: + result["snapshot"] = snapshot + + elif state == "absent": + if snapshot: + #  Delete snapshot + project.delete_snapshot(name=snapshot_name, snapshot_id=snapshot_id) + result["changed"] = True + + elif state == "restore": + if not snapshot: + module.fail_json(msg="Snapshot not found", **result) + # Restore snapshot + project.restore_snapshot(name=snapshot_name, snapshot_id=snapshot_id) + result["changed"] = True + result["snapshot"] = snapshot + + module.exit_json(**result) + except Exception as err: + module.fail_json(msg=str(err), **result) + + +if __name__ == "__main__": + main() diff --git a/collections/ansible_collections/davidban77/gns3/plugins/modules/gns3_version.py b/collections/ansible_collections/davidban77/gns3/plugins/modules/gns3_version.py new file mode 100644 index 0000000..6ac8f99 --- /dev/null +++ b/collections/ansible_collections/davidban77/gns3/plugins/modules/gns3_version.py @@ -0,0 +1,100 @@ +#!/usr/bin/env python + +ANSIBLE_METADATA = { + "metadata_version": "1.3", + "status": ["preview"], + "supported_by": "community", +} + +DOCUMENTATION = """ +--- +module: gns3_version +short_description: Retrieves GNS3 server version +version_added: '2.8' +description: + - 'Retrieves GNS3 server version using gns3fy' +requirements: [ gns3fy ] +author: + - David Flores (@davidban77) +options: + url: + description: + - URL target of the GNS3 server + required: true + type: str + port: + description: + - TCP port to connect to server REST API + type: int + default: 3080 + user: + description: + - User to connect to GNS3 server + type: str + password: + description: + - Password to connect to GNS3 server + type: str +""" + +EXAMPLES = """ +# Retrieve the GNS3 server version +- name: Get the server version + gns3_version: + url: http://localhost + port: 3080 + register: result + +- debug: var=result +""" + +RETURN = """ +local_compute: + description: Whether this is a local server or not + type: bool + returned: always +version: + description: Version number of the server + type: str + returned: always +""" +import traceback +from ansible.module_utils.basic import AnsibleModule, missing_required_lib + +GNS3FY_IMP_ERR = None +try: + from gns3fy import Gns3Connector + + HAS_GNS3FY = True +except Exception: + HAS_GNS3FY = False + GNS3FY_IMP_ERR = traceback.format_exc() + + +def main(): + module = AnsibleModule( + argument_spec=dict( + url=dict(type="str", required=True), + port=dict(type="int", default=3080), + user=dict(type="str", default=None), + password=dict(type="str", default=None, no_log=True), + ) + ) + if not HAS_GNS3FY: + module.fail_json(msg=missing_required_lib("gns3fy"), exception=GNS3FY_IMP_ERR) + result = dict(changed=False, local_compute=None, version=None) + server_url = module.params["url"] + server_port = module.params["port"] + server_user = module.params["user"] + server_password = module.params["password"] + + server = Gns3Connector( + url=f"{server_url}:{server_port}", user=server_user, cred=server_password + ) + _version = server.get_version() + result.update(local_compute=_version["local"], version=_version["version"]) + module.exit_json(**result) + + +if __name__ == "__main__": + main() diff --git a/collections/ansible_collections/davidban77/gns3/requirements.txt b/collections/ansible_collections/davidban77/gns3/requirements.txt new file mode 100644 index 0000000..5cd2c06 --- /dev/null +++ b/collections/ansible_collections/davidban77/gns3/requirements.txt @@ -0,0 +1,2 @@ +ansible>=2.8.0 +gns3fy>=0.5.2 diff --git a/collections/ansible_collections/davidban77/gns3/test/playbooks/ansible.cfg b/collections/ansible_collections/davidban77/gns3/test/playbooks/ansible.cfg new file mode 100644 index 0000000..d65a64c --- /dev/null +++ b/collections/ansible_collections/davidban77/gns3/test/playbooks/ansible.cfg @@ -0,0 +1,6 @@ +[defaults] +library = ../../plugins/modules +roles_path = ../../roles +nocows = 1 +retry_files_enabled = False +display_skipped_hosts = no diff --git a/collections/ansible_collections/davidban77/gns3/test/playbooks/create_files.yml b/collections/ansible_collections/davidban77/gns3/test/playbooks/create_files.yml new file mode 100644 index 0000000..f7ff5ce --- /dev/null +++ b/collections/ansible_collections/davidban77/gns3/test/playbooks/create_files.yml @@ -0,0 +1,22 @@ +- hosts: localhost + tasks: + - name: Play with a dummy file to node + gns3_node_file: + url: "{{ gns3_url }}" + project_name: "{{ gns3_project_name }}" + node_name: alpine-1 + state: present + dest: /etc/network/dummy_file + data: | + # Some data to insert on the file + auto eth0 + iface eth0 inect dhcp + + - name: Play with a dummy file on project + gns3_project_file: + url: "{{ gns3_url }}" + project_name: "{{ gns3_project_name }}" + state: present + dest: README.txt + data: | + Hello! this is a README diff --git a/collections/ansible_collections/davidban77/gns3/test/playbooks/delete_files.yml b/collections/ansible_collections/davidban77/gns3/test/playbooks/delete_files.yml new file mode 100644 index 0000000..0b51a33 --- /dev/null +++ b/collections/ansible_collections/davidban77/gns3/test/playbooks/delete_files.yml @@ -0,0 +1,16 @@ +- hosts: localhost + tasks: + - name: Play with a dummy file to node + gns3_node_file: + url: "{{ gns3_url }}" + project_name: "{{ gns3_project_name }}" + node_name: alpine-1 + state: absent + dest: /etc/network/dummy_file + + - name: Play with a dummy file on project + gns3_project_file: + url: "{{ gns3_url }}" + project_name: "{{ gns3_project_name }}" + state: absent + dest: README.txt diff --git a/collections/ansible_collections/davidban77/gns3/test/playbooks/facts.yml b/collections/ansible_collections/davidban77/gns3/test/playbooks/facts.yml new file mode 100644 index 0000000..c8c0fa0 --- /dev/null +++ b/collections/ansible_collections/davidban77/gns3/test/playbooks/facts.yml @@ -0,0 +1,18 @@ +- hosts: localhost + gather_facts: no + tasks: + - name: Retrieve computes info all + gns3_facts: + url: "{{ gns3_url }}" + get_images: iou + get_compute_ports: no + register: resultado + + - debug: var=resultado + + # - name: Retrieves basic facts + # gns3_facts: + # url: "{{ gns3_url }}" + # register: resultado + + # - debug: var=resultado diff --git a/collections/ansible_collections/davidban77/gns3/test/playbooks/group_vars/all.yml b/collections/ansible_collections/davidban77/gns3/test/playbooks/group_vars/all.yml new file mode 100644 index 0000000..7ffbb25 --- /dev/null +++ b/collections/ansible_collections/davidban77/gns3/test/playbooks/group_vars/all.yml @@ -0,0 +1,21 @@ +--- +gns3_url: "http://dev_gns3server" +gns3_project_name: test_ansible +gns3_nodes_spec: + - name: veos-1 + template: "vEOS-4.21.5F" + - name: veos-2 + template: "vEOS-4.21.5F" + - name: ios-1 + template: "IOU-L2-15.1" + - name: ios-2 + template: "IOU-L3-15.4" + - name: alpine-1 + template: "alpine" +gns3_nodes_strategy: one_by_one +gns3_links_spec: + - ["veos-1", "Ethernet1", "veos-2", "Ethernet1"] + - ["veos-1", "Ethernet2", "ios-1", "Ethernet1/0"] + - ["veos-2", "Ethernet2", "ios-2", "Ethernet1/0"] + - ["ios-1", "Ethernet1/2", "ios-2", "Ethernet1/2"] + - ["ios-1", "Ethernet1/3", "alpine-1", "eth0"] diff --git a/collections/ansible_collections/davidban77/gns3/test/playbooks/main.yml b/collections/ansible_collections/davidban77/gns3/test/playbooks/main.yml new file mode 100644 index 0000000..48c0ac3 --- /dev/null +++ b/collections/ansible_collections/davidban77/gns3/test/playbooks/main.yml @@ -0,0 +1,28 @@ +- hosts: localhost + tasks: + - name: Get server version + gns3_facts: + url: "{{ gns3_url }}" + get_images: all + get_compute_ports: yes + register: resultado + + - debug: var=resultado + + - name: Creation/Active section + when: execute == "create" + block: + - import_role: + name: create_lab + + - name: Get nodes inventory + gns3_nodes_inventory: + url: "{{ gns3_url }}" + project_name: "{{ gns3_project_name }}" + register: nodes_inventory + + - debug: var=nodes_inventory + + - import_role: + name: delete_lab + when: execute == "delete" diff --git a/collections/ansible_collections/davidban77/gns3/test/playbooks/node_interaction.yml b/collections/ansible_collections/davidban77/gns3/test/playbooks/node_interaction.yml new file mode 100644 index 0000000..20828bd --- /dev/null +++ b/collections/ansible_collections/davidban77/gns3/test/playbooks/node_interaction.yml @@ -0,0 +1,28 @@ +- hosts: localhost + gather_facts: no + tasks: + - name: Reload a node alpine node which requires a special reload + gns3_node: + url: "{{ gns3_url }}" + project_name: "{{ gns3_project_name }}" + node_name: alpine-1 + state: reload + retry: yes + poll_wait_time: 30 + + - name: Stop ios-1 + gns3_node: + url: "{{ gns3_url }}" + project_name: "{{ gns3_project_name }}" + node_name: ios-1 + state: stopped + + - name: Start ios-1 + gns3_node: + url: "{{ gns3_url }}" + project_name: "{{ gns3_project_name }}" + node_name: ios-1 + state: started + register: node + + - debug: var=node diff --git a/collections/ansible_collections/davidban77/gns3/test/playbooks/snapshots.yml b/collections/ansible_collections/davidban77/gns3/test/playbooks/snapshots.yml new file mode 100644 index 0000000..7949a03 --- /dev/null +++ b/collections/ansible_collections/davidban77/gns3/test/playbooks/snapshots.yml @@ -0,0 +1,39 @@ +- hosts: localhost + gather_facts: no + tasks: + - name: Stop nodes on the project + gns3_project: + url: "{{ gns3_url }}" + project_name: "{{ gns3_project_name }}" + state: opened + nodes_state: stopped + + - name: Create snapshot + gns3_snapshot: + url: "{{ gns3_url }}" + project_name: "{{ gns3_project_name }}" + snapshot_name: snap + state: present + register: resultado + + - debug: var=resultado + + - pause: + minutes: 1 + + - name: Restore snapshot + gns3_snapshot: + url: "{{ gns3_url }}" + project_name: "{{ gns3_project_name }}" + snapshot_name: snap + state: restore + + - pause: + minutes: 1 + + - name: Delete snapshot + gns3_snapshot: + url: "{{ gns3_url }}" + project_name: "{{ gns3_project_name }}" + snapshot_name: snap + state: absent diff --git a/collections/requirements.yml b/collections/requirements.yml new file mode 100644 index 0000000..dcfd652 --- /dev/null +++ b/collections/requirements.yml @@ -0,0 +1,4 @@ +--- +collections: + - name: davidban77.gns3 + source: https://galaxy.ansible.com diff --git a/gitlab.yml b/gitlab.yml new file mode 100644 index 0000000..aca4194 --- /dev/null +++ b/gitlab.yml @@ -0,0 +1,39 @@ +- name: Ensure GitLab is installed + hosts: gitlab.lab.toal.ca + become: true + vars: + gitlab_external_url: "http://gitlab.lab.toal.ca/" + gitlab_git_data_dir: "/var/opt/gitlab/git-data" + # gitlab_edition: "gitlab-ce" + # gitlab_redirect_http_to_https: "false" + # # LDAP Configuration. + # gitlab_ldap_enabled: "true" + # gitlab_ldap_host: "idm1.mgmt.toal.ca" + # gitlab_ldap_port: "389" + # gitlab_ldap_uid: "ldapauth" + # gitlab_ldap_method: "start_tls" + # gitlab_ldap_bind_dn: "uid=ldapauth,cn=sysaccounts,cn=etc,dc=idm,dc=toal,dc=ca" + # gitlab_ldap_password: "growwaternapkin" + # gitlab_ldap_base: "cn=users,cn=accounts,dc=idm,dc=toal,dc=ca" + # # Email configuration. + # gitlab_email_enabled: "true" + # gitlab_email_from: "gitlab@takeflight.ca" + # gitlab_email_display_name: "Gitlab" + # gitlab_email_reply_to: "ptoal@takeflight.ca" + # # SMTP Configuration + # gitlab_smtp_enable: "true" + # gitlab_smtp_address: "smtp.gmail.com" + # gitlab_smtp_port: "587" + # gitlab_smtp_user_name: "server" + # gitlab_smtp_password: "ReJ3n_Dj9EB-j3b" + # gitlab_smtp_domain: "takeflight.ca" + # gitlab_smtp_authentication: "login" + # gitlab_smtp_enable_starttls_auto: "true" + # # gitlab_smtp_tls: "false" + # gitlab_smtp_openssl_verify_mode: "none" + # # gitlab_smtp_ca_path: "/etc/ssl/certs" + # # gitlab_smtp_ca_file: "/etc/ssl/certs/ca-certificates.crt" + # gitlab_nginx_listen_https: "false" + + roles: + - { role: geerlingguy.gitlab } diff --git a/site.yml b/site.yml index 28ab8b8..27406c5 100644 --- a/site.yml +++ b/site.yml @@ -23,7 +23,7 @@ - toallab.infrastructure - name: Include Minecraft tasks - include_tasks: minecraft.yml + include: minecraft.yml - name: Include Gitea tasks - include_tasks: gitea.yml + include: gitea.yml diff --git a/windows.yml b/windows.yml index d9cdd77..b5734b3 100644 --- a/windows.yml +++ b/windows.yml @@ -1,4 +1,4 @@ -- name: create a ovirt rhel template +- name: create an ovirt rhel template hosts: localhost gather_facts: False connection: local