Satellite installer
This commit is contained in:
@@ -23,6 +23,10 @@
|
|||||||
name: "{{ inventory_hostname }}_disk0"
|
name: "{{ inventory_hostname }}_disk0"
|
||||||
state: present
|
state: present
|
||||||
|
|
||||||
|
- name: VM Created
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
- name: Add NIC to VM
|
- name: Add NIC to VM
|
||||||
ovirt_nic:
|
ovirt_nic:
|
||||||
state: present
|
state: present
|
||||||
|
|||||||
@@ -1,93 +0,0 @@
|
|||||||
# 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
|
|
||||||
@@ -1,69 +0,0 @@
|
|||||||
# 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
|
|
||||||
@@ -1,299 +0,0 @@
|
|||||||
{
|
|
||||||
"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
|
|
||||||
}
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
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.
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
{
|
|
||||||
"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 <davidflores7_8@hotmail.com>"
|
|
||||||
],
|
|
||||||
"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
|
|
||||||
}
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
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
|
|
||||||
@@ -1,207 +0,0 @@
|
|||||||
# 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.
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
-r requirements.txt
|
|
||||||
|
|
||||||
flake8
|
|
||||||
black
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
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 <davidflores7_8@hotmail.com>"
|
|
||||||
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"
|
|
||||||
@@ -1,187 +0,0 @@
|
|||||||
#!/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()
|
|
||||||
@@ -1,272 +0,0 @@
|
|||||||
#!/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()
|
|
||||||
@@ -1,192 +0,0 @@
|
|||||||
#!/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()
|
|
||||||
@@ -1,128 +0,0 @@
|
|||||||
#!/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()
|
|
||||||
@@ -1,434 +0,0 @@
|
|||||||
#!/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()
|
|
||||||
@@ -1,170 +0,0 @@
|
|||||||
#!/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()
|
|
||||||
@@ -1,203 +0,0 @@
|
|||||||
#!/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()
|
|
||||||
@@ -1,100 +0,0 @@
|
|||||||
#!/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()
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
ansible>=2.8.0
|
|
||||||
gns3fy>=0.5.2
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
[defaults]
|
|
||||||
library = ../../plugins/modules
|
|
||||||
roles_path = ../../roles
|
|
||||||
nocows = 1
|
|
||||||
retry_files_enabled = False
|
|
||||||
display_skipped_hosts = no
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
- 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
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
- 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
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
- 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
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
---
|
|
||||||
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"]
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
- 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"
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
- 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
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
- 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
|
|
||||||
@@ -17,3 +17,6 @@ collections:
|
|||||||
|
|
||||||
- name: redhat.satellite
|
- name: redhat.satellite
|
||||||
source: https://cloud.redhat.com/api/automation-hub/
|
source: https://cloud.redhat.com/api/automation-hub/
|
||||||
|
|
||||||
|
- name: community.general
|
||||||
|
source: https://galaxy.ansible.com
|
||||||
|
|||||||
@@ -47,12 +47,3 @@
|
|||||||
name: insights-client
|
name: insights-client
|
||||||
state: present
|
state: present
|
||||||
when: ansible_distribution == "RedHat"
|
when: ansible_distribution == "RedHat"
|
||||||
|
|
||||||
- name: Performance Co-Pilot
|
|
||||||
yum:
|
|
||||||
name:
|
|
||||||
- pcp-system-tools
|
|
||||||
- pcp-zeroconf
|
|
||||||
- cockpit-pcp
|
|
||||||
- pcp-pmda-trace
|
|
||||||
- pcp-selinux
|
|
||||||
|
|||||||
318
satellite.yml
318
satellite.yml
@@ -1,34 +1,32 @@
|
|||||||
# Playbook to install Satellite server on RHV
|
# Playbook to install Satellite server on RHV
|
||||||
|
|
||||||
# TODO: Autocreate pxeboot environment on tftp server. This was a partial attempt to create the ks file
|
- name: Prepare RHV for Build
|
||||||
# and dump it on the NAS.
|
hosts: localhost
|
||||||
# Note for my future self: Don't bother trying to attach a VFD/ISO with the ks file. It will all
|
gather_facts: no
|
||||||
# end in tears, because RHV4.2 doesn't have the APIs / functionality.
|
tasks:
|
||||||
|
- name: Obtain SSO token from username / password credentials
|
||||||
|
redhat.rhv.ovirt_auth:
|
||||||
|
url: "{{ ovirt_url }}"
|
||||||
|
username: "{{ ovirt_username }}"
|
||||||
|
password: "{{ ovirt_password }}"
|
||||||
|
|
||||||
# - name: Prepare Kickstart Files
|
- name: ISO is uploaded to RHV
|
||||||
# hosts: vms
|
redhat.rhv.ovirt_disk:
|
||||||
# connection: local
|
name: "{{ rhel_iso_filename }}"
|
||||||
# gather_facts: no
|
upload_image_path: "{{ rhel_iso_path }}/{{ rhel_iso_filename }}"
|
||||||
|
storage_domain: ssdvdo0
|
||||||
# tasks:
|
size: 5 GiB
|
||||||
# - name: Get first nfs server
|
wait: true
|
||||||
# set_fact: ks_nfs_server="{{ groups['nfs_server'][0] }}"
|
bootable: true
|
||||||
# - set_fact: ks_file="{{ hostvars[ks_nfs_server]['nfs_dir'] }}/{{ inventory_hostname }}.cfg"
|
format: raw
|
||||||
|
content_type: iso
|
||||||
# - name: Copy ks file to builddir
|
register: iso_disk
|
||||||
# template:
|
|
||||||
# src: templates/ks.cfg
|
|
||||||
# dest: "{{ ks_file }}"
|
|
||||||
# delegate_to: "{{ ks_nfs_server }}"
|
|
||||||
|
|
||||||
- name: Create VMs
|
- name: Create VMs
|
||||||
hosts: vms
|
hosts: "{{ vm_name }}"
|
||||||
connection: local
|
connection: local
|
||||||
gather_facts: no
|
gather_facts: no
|
||||||
# Never run this, unless specifically enabled
|
# Never run this, unless specifically enabled
|
||||||
tags:
|
|
||||||
- never
|
|
||||||
- rebuild
|
|
||||||
vars:
|
vars:
|
||||||
# Hack to work around virtualenv python interpreter
|
# Hack to work around virtualenv python interpreter
|
||||||
ansible_python_interpreter: "{{ ansible_playbook_python }}"
|
ansible_python_interpreter: "{{ ansible_playbook_python }}"
|
||||||
@@ -36,184 +34,196 @@
|
|||||||
tasks:
|
tasks:
|
||||||
- name: Remove known_hosts entry
|
- name: Remove known_hosts entry
|
||||||
known_hosts:
|
known_hosts:
|
||||||
name: "{{ inventory_hostname }}"
|
name: "{{ vm_name }}"
|
||||||
state: absent
|
state: absent
|
||||||
|
|
||||||
- name: Create VM Disks
|
- name: Create VM disk
|
||||||
ovirt_disk:
|
ovirt_disk:
|
||||||
auth: "{{ ovirt_auth }}"
|
name: "{{ vm_name }}_Disk0"
|
||||||
name: '{{ item.name }}'
|
description: '{{ vm_name }} Primary Disk'
|
||||||
description: '{{ item.descr }}'
|
interface: 'virtio_scsi'
|
||||||
interface: '{{ item.interface }}'
|
size: '{{ disk }}GiB'
|
||||||
size: '{{ item.size }}'
|
state: attached
|
||||||
state: '{{ item.state }}'
|
sparse: yes
|
||||||
sparse: '{{ item.sparse }}'
|
|
||||||
wait: true
|
wait: true
|
||||||
storage_domain: "{{ item.storage_domain }}"
|
storage_domain: "ssdvdo0"
|
||||||
async: 300
|
async: 300
|
||||||
poll: 15
|
poll: 15
|
||||||
loop: "{{ vm_disks }}"
|
|
||||||
# If we change the disks, we will PXE Boot the Server for install
|
|
||||||
notify: PXE Boot
|
|
||||||
|
|
||||||
- name: Create Satellite VM in RHV
|
- name: Create Satellite VM in RHV
|
||||||
ovirt_vm:
|
ovirt_vm:
|
||||||
auth: "{{ ovirt_auth }}"
|
|
||||||
name: "{{ vm_name }}"
|
name: "{{ vm_name }}"
|
||||||
state: present
|
state: present
|
||||||
memory: "{{ vm_memory }}"
|
memory: "{{ memory}}GiB"
|
||||||
disks: "{{ vm_disks }}"
|
disks:
|
||||||
cpu_cores: "{{ vm_cpu_cores }}"
|
- name: "{{ vm_name }}_Disk0"
|
||||||
cluster: "{{ vm_cluster }}"
|
activate: yes
|
||||||
operating_system: "{{ vm_os }}"
|
bootable: yes
|
||||||
|
cpu_cores: "{{ vcpus }}"
|
||||||
|
cluster: "{{ cluster }}"
|
||||||
|
operating_system: "rhel_7x64"
|
||||||
type: server
|
type: server
|
||||||
graphical_console:
|
graphical_console:
|
||||||
protocol:
|
protocol:
|
||||||
- spice
|
|
||||||
- vnc
|
- vnc
|
||||||
boot_devices:
|
boot_devices:
|
||||||
- hd
|
- hd
|
||||||
async: 300
|
async: 300
|
||||||
poll: 15
|
poll: 15
|
||||||
|
register: vm_result
|
||||||
|
|
||||||
- name: Assign NIC
|
- name: Assign NIC
|
||||||
ovirt_nic:
|
ovirt_nic:
|
||||||
auth: "{{ ovirt_auth }}"
|
|
||||||
interface: virtio
|
interface: virtio
|
||||||
mac_address: "{{ vm_mac_address }}"
|
|
||||||
name: nic1
|
name: nic1
|
||||||
profile: ovirtmgmt
|
profile: ovirtmgmt
|
||||||
network: ovirtmgmt
|
network: ovirtmgmt
|
||||||
state: plugged
|
state: plugged
|
||||||
vm: "{{ vm_name }}"
|
vm: "{{ vm_name }}"
|
||||||
|
register: nic_result
|
||||||
|
|
||||||
handlers:
|
- name: Prepare First Boot Resources
|
||||||
- name: PXE Boot
|
hosts: "{{ vm_name }}"
|
||||||
ovirt_vm:
|
|
||||||
auth: "{{ ovirt_auth }}"
|
|
||||||
name: "{{ vm_name }}"
|
|
||||||
boot_devices:
|
|
||||||
- network
|
|
||||||
state: running
|
|
||||||
register: vm_build_result
|
|
||||||
|
|
||||||
- name: Ensure Satellite is running and reachable
|
|
||||||
hosts: satellite
|
|
||||||
gather_facts: no
|
|
||||||
connection: local
|
connection: local
|
||||||
|
gather_facts: no
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
- name: Create directory for initial boot files
|
||||||
|
tempfile:
|
||||||
|
state: directory
|
||||||
|
register: kstmpdir
|
||||||
|
|
||||||
|
- name: Extract ISO files
|
||||||
|
community.general.iso_extract:
|
||||||
|
image: "{{ rhel_iso_path }}/{{ rhel_iso_filename }}"
|
||||||
|
dest: "{{ kstmpdir.path }}"
|
||||||
|
files:
|
||||||
|
- isolinux/vmlinuz
|
||||||
|
- isolinux/initrd.img
|
||||||
|
|
||||||
|
# TODO Move out vars
|
||||||
|
- name: Copy Files to Webserver
|
||||||
|
hosts: webserver.mgmt.toal.ca
|
||||||
|
become: yes
|
||||||
|
tasks:
|
||||||
|
- name: Generate Kickstart File
|
||||||
|
template:
|
||||||
|
src: templates/ks.cfg
|
||||||
|
dest: "/var/www/ks/{{ vm_name }}.cfg"
|
||||||
|
|
||||||
|
- name: Prepare Hypervisor
|
||||||
|
hosts: "{{ vm_host }}"
|
||||||
|
tasks:
|
||||||
|
- name: Temporary Directory
|
||||||
|
file:
|
||||||
|
path: "/tmp/{{ vm_name }}"
|
||||||
|
state: directory
|
||||||
|
mode: 0755
|
||||||
|
|
||||||
|
- name: Transfer files to Hypervisor
|
||||||
|
copy:
|
||||||
|
src: "{{ hostvars[vm_name].kstmpdir.path }}/{{ item }}"
|
||||||
|
dest: "/tmp/{{ vm_name }}/{{ item }}"
|
||||||
|
loop:
|
||||||
|
- vmlinuz
|
||||||
|
- initrd.img
|
||||||
|
|
||||||
|
# NOTE: This is not idempotent
|
||||||
|
- name: First Boot
|
||||||
|
hosts: localhost
|
||||||
|
gather_facts: no
|
||||||
vars:
|
vars:
|
||||||
# Hack to work around virtualenv python interpreter
|
# Hack to work around virtualenv python interpreter
|
||||||
ansible_python_interpreter: "{{ ansible_playbook_python }}"
|
ansible_python_interpreter: "{{ ansible_playbook_python }}"
|
||||||
|
|
||||||
tasks:
|
tasks:
|
||||||
- name: VM is running
|
- block:
|
||||||
|
- name: Start VM with first-boot parameters
|
||||||
|
ovirt_vm:
|
||||||
|
name: "{{ vm_name }}"
|
||||||
|
host: "{{ vm_host }}"
|
||||||
|
kernel_params_persist: false
|
||||||
|
cd_iso: "{{ iso_disk.id }}"
|
||||||
|
kernel_path: "/tmp/{{ vm_name }}/vmlinuz"
|
||||||
|
kernel_params: "ks=http://192.168.1.199/ks/{{ vm_name }}.cfg inst.stage2=hd:LABEL=RHEL-7.9\\x20Server.x86_64"
|
||||||
|
initrd_path: "/tmp/{{ vm_name }}/initrd.img"
|
||||||
|
state: running
|
||||||
|
|
||||||
|
|
||||||
|
- name: Wait for system to shut down after installation
|
||||||
|
ovirt_vm_info:
|
||||||
|
pattern: "name={{ vm_name }}"
|
||||||
|
register: vm_info
|
||||||
|
until: vm_info['ovirt_vms'][0]['status'] == "down"
|
||||||
|
delay: 20
|
||||||
|
retries: 60
|
||||||
|
when: hostvars[vm_name].vm_result.vm.status != 'up'
|
||||||
|
|
||||||
|
- name: Power up VM
|
||||||
|
ovirt_vm:
|
||||||
|
name: "{{ vm_name }}"
|
||||||
|
state: running
|
||||||
|
|
||||||
|
- name: VM is running
|
||||||
|
connection: local
|
||||||
ovirt_vm:
|
ovirt_vm:
|
||||||
auth: "{{ ovirt_auth }}"
|
|
||||||
name: "{{ vm_name }}"
|
name: "{{ vm_name }}"
|
||||||
state: running
|
state: running
|
||||||
boot_devices:
|
boot_devices:
|
||||||
- hd
|
- hd
|
||||||
|
|
||||||
|
- name: Ensure Satellite is reachable
|
||||||
|
hosts: "{{ vm_name }}"
|
||||||
|
gather_facts: no
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
- name: Set authentication for bootstrap
|
||||||
|
no_log: True
|
||||||
|
set_fact:
|
||||||
|
ansible_ssh_user: "root"
|
||||||
|
ansible_ssh_pass: "{{ initial_root_pass }}"
|
||||||
|
|
||||||
- name: Wait for SSH to be ready
|
- name: Wait for SSH to be ready
|
||||||
wait_for_connection:
|
wait_for_connection:
|
||||||
timeout: 1800
|
timeout: 1800
|
||||||
sleep: 5
|
sleep: 5
|
||||||
|
|
||||||
- name: Set up ipa-client
|
- name: Register System to Red Hat
|
||||||
hosts: satellite
|
|
||||||
remote_user: root
|
|
||||||
vars:
|
|
||||||
ansible_ssh_pass: "{{ satellite_root_pass }}"
|
|
||||||
become: no
|
|
||||||
roles:
|
|
||||||
- alvaroaleman.freeipa-client
|
|
||||||
pre_tasks:
|
|
||||||
- name: Register to RHSM and connect to Satellite Subscription.
|
|
||||||
tags: rhsm
|
|
||||||
redhat_subscription:
|
redhat_subscription:
|
||||||
state: present
|
state: present
|
||||||
auto_attach: yes
|
|
||||||
username: "{{ rhn_username }}"
|
username: "{{ rhn_username }}"
|
||||||
password: "{{ rhn_password }}"
|
password: "{{ rhn_password }}"
|
||||||
pool: "^Red Hat Satellite Infrastructure Subscription$"
|
# TODO This shouldn't be hard-coded
|
||||||
|
pool_ids: 8a85f99c727637ad0172e1ba2856736d
|
||||||
|
|
||||||
|
- name: Set up IPA Client
|
||||||
|
hosts: "{{ vm_name }}"
|
||||||
|
become: yes
|
||||||
|
vars:
|
||||||
|
ipaclient_realm: IDM.TOAL.CA
|
||||||
|
ipaclient_mkhomedir: true
|
||||||
|
ipaclient_domain: "mgmt.toal.ca"
|
||||||
|
ipasssd_enable_dns_updates: true
|
||||||
|
collections:
|
||||||
|
- freeipa.ansible_freeipa
|
||||||
|
pre_tasks:
|
||||||
- name: Set hostname
|
- name: Set hostname
|
||||||
hostname:
|
hostname:
|
||||||
name: "{{ansible_host}}"
|
name: "{{ vm_name }}"
|
||||||
|
|
||||||
|
roles:
|
||||||
|
- role: debian-freeipa-client
|
||||||
|
when: ansible_os_family == "Debian"
|
||||||
|
- role: ipaclient
|
||||||
|
state: present
|
||||||
|
when: ansible_os_family == "RedHat"
|
||||||
|
|
||||||
|
- name: Set up Basic Lab Packages
|
||||||
|
hosts: "{{ vm_name }}"
|
||||||
|
become: yes
|
||||||
|
roles:
|
||||||
|
- role: toal-common
|
||||||
|
|
||||||
- name: Configure Satellite Servers
|
- name: Configure Satellite Servers
|
||||||
hosts: satellite
|
hosts: "{{ vm_name }}"
|
||||||
become: true
|
become: true
|
||||||
roles:
|
|
||||||
- ansible-role-redhat_satellite6_installation
|
|
||||||
pre_tasks:
|
|
||||||
# This could take a while, if we are creating the VM from scratch, and installing
|
|
||||||
# the base software
|
|
||||||
|
|
||||||
# - name: Required Satellite Repos
|
|
||||||
# tags: rhsm
|
|
||||||
# rhsm_repository:
|
|
||||||
# name: "{{ item }}"
|
|
||||||
# state: present
|
|
||||||
# with_items:
|
|
||||||
# - rhel-7-server-rpms
|
|
||||||
# - rhel-server-rhscl-7-rpms
|
|
||||||
# - rhel-7-server-satellite-6.4-rpms
|
|
||||||
# - rhel-7-server-satellite-maintenance-6-rpms
|
|
||||||
# - rhel-7-server-ansible-2.6-rpms
|
|
||||||
# - rhel-7-server-rh-common-rpms
|
|
||||||
|
|
||||||
- name: Ensure latest versions of packages
|
|
||||||
yum:
|
|
||||||
name: "*"
|
|
||||||
state: latest
|
|
||||||
|
|
||||||
- name: Chronyd Installed
|
|
||||||
yum:
|
|
||||||
name: chrony
|
|
||||||
state: latest
|
|
||||||
notify: Restart Chrony
|
|
||||||
|
|
||||||
- name: IdM Client
|
|
||||||
yum:
|
|
||||||
name: ipa-client
|
|
||||||
state: latest
|
|
||||||
|
|
||||||
- name: Latest Version of SOS
|
|
||||||
yum:
|
|
||||||
name: sos
|
|
||||||
state: latest
|
|
||||||
|
|
||||||
# TODO: set this in Administer -> Settings -> Puppet Puppet out of sync disabled = Yes
|
|
||||||
# Description: Disable host configuration status turning to out of sync for Puppet after report does not arrive within configured interval
|
|
||||||
|
|
||||||
# TODO: Make this work
|
|
||||||
# For now:
|
|
||||||
# hammer user-group create --admin yes --name satellite_admins
|
|
||||||
# hammer user-group external create --name satellite_admins --user-group satellite_admins --auth-source-id 3
|
|
||||||
|
|
||||||
# - name: Satellite configuration
|
|
||||||
# hosts: satellite
|
|
||||||
# gather_facts: no
|
|
||||||
# connection: local
|
|
||||||
# vars:
|
|
||||||
# # Hack to work around virtualenv python interpreter
|
|
||||||
# ansible_python_interpreter: "{{ ansible_playbook_python }}"
|
|
||||||
|
|
||||||
# tasks:
|
|
||||||
# - foreman:
|
|
||||||
# username: admin
|
|
||||||
# password: "{{satellite_deployment_admin_password}}"
|
|
||||||
# server_url: "https://{{satellite_deployment_hostname_full}}"
|
|
||||||
# entity: user-group
|
|
||||||
# params:
|
|
||||||
# name: satellite_admins
|
|
||||||
# admin: yes
|
|
||||||
|
|
||||||
# - foreman:
|
|
||||||
# username: admin
|
|
||||||
# password: "{{satellite_deployment_admin_password}}"
|
|
||||||
# server_url: "https://{{satellite_deployment_hostname_full}}"
|
|
||||||
# entity:
|
|
||||||
# params:
|
|
||||||
# name: satellite_admins
|
|
||||||
# admin: yes
|
|
||||||
|
|||||||
@@ -1,18 +1,20 @@
|
|||||||
lang en_CA
|
lang en_CA
|
||||||
keyboard us
|
keyboard us
|
||||||
timezone America/Toronto --isUtc
|
timezone America/Toronto --isUtc
|
||||||
rootpw $1$3Sx/AUYD$VOS6XPI5U5x3pW4CA6m1y0 --iscrypted
|
rootpw {{ initial_root_pass|password_hash('sha512') }} --iscrypted
|
||||||
sshpw --username=ptoal $1$3Sx/AUYD$VOS6XPI5U5x3pW4CA6m1y0 --iscrypted
|
sshpw --username=ptoal $1$3Sx/AUYD$VOS6XPI5U5x3pW4CA6m1y0 --iscrypted
|
||||||
#platform x86, AMD64, or Intel EM64T
|
#platform x86, AMD64, or Intel EM64T
|
||||||
reboot
|
poweroff
|
||||||
text
|
text
|
||||||
cdrom
|
cdrom
|
||||||
bootloader --location=mbr --append="rhgb quiet crashkernel=auto"
|
bootloader --location=mbr --append="rhgb quiet crashkernel=auto"
|
||||||
zerombr
|
zerombr
|
||||||
|
{% set ipaddr=hostvars[vm_name].interfaces[0]['ip_addresses'][0]['address']|ansible.netcommon.ipaddr('address') %}
|
||||||
|
{% set ipmask=hostvars[vm_name].interfaces[0]['ip_addresses'][0]['address']|ansible.netcommon.ipaddr('netmask') %}
|
||||||
|
network --bootproto=static --ip={{ ipaddr }} --netmask={{ ipmask }} --gateway=192.168.90.1 --nameserver=192.168.90.1
|
||||||
clearpart --none
|
clearpart --none
|
||||||
autopart
|
autopart
|
||||||
eula --agreed
|
eula --agreed
|
||||||
network --device=eth0 --bootproto=static --ip=192.168.90.2 --netmask=255.255.255.0 --gateway=192.168.90.1 --nameserver=192.168.90.1
|
|
||||||
auth --passalgo=sha512 --useshadow
|
auth --passalgo=sha512 --useshadow
|
||||||
selinux --enforcing
|
selinux --enforcing
|
||||||
firewall --enabled --ssh
|
firewall --enabled --ssh
|
||||||
|
|||||||
Reference in New Issue
Block a user