-
Notifications
You must be signed in to change notification settings - Fork 20
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #13 from davidban77/develop
Adding gns3_node
- Loading branch information
Showing
6 changed files
with
399 additions
and
72 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,258 @@ | ||
#!/usr/bin/env python | ||
|
||
ANSIBLE_METADATA = { | ||
"metadata_version": "1.1", | ||
"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 (@netpanda) | ||
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 | ||
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), | ||
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"] | ||
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}") | ||
# 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() |
Oops, something went wrong.