Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 83 additions & 5 deletions plugins/modules/cml_node.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,9 @@
type: str

config:
description: The day0 configuration of this node
description: The day0 configuration of this node. Can be of type string, list or dictionary.
required: false
type: str
type: raw

x:
description: X coordinate on topology canvas
Expand Down Expand Up @@ -102,16 +102,25 @@
day0_config: "{{ lookup('template', cml_config_template) }}"
when: cml_config_template is defined

- name: Start Node
- name: Create Node
cisco.cml.cml_node:
name: "{{ inventory_hostname }}"
host: "{{ cml_host }}"
user: "{{ cml_username }}"
password: "{{ cml_password }}"
lab: "{{ cml_lab }}"
state: started
state: present
image_definition: "{{ cml_image_definition | default(omit) }}"
config: "{{ day0_config | default(omit) }}"

- name: Start Node
cisco.cml.cml_node:
name: "{{ inventory_hostname }}"
host: "{{ cml_host }}"
user: "{{ cml_username }}"
password: "{{ cml_password }}"
lab: "{{ cml_lab }}"
state: started
"""

from ansible.module_utils.basic import AnsibleModule, env_fallback
Expand All @@ -127,7 +136,7 @@ def run_module():
lab=dict(type='str', required=True, fallback=(env_fallback, ['CML_LAB'])),
node_definition=dict(type='str'),
image_definition=dict(type='str'),
config=dict(type='str'),
config=dict(type='raw'),
tags=dict(type='list', elements='str'),
x=dict(type='int'),
y=dict(type='int'),
Expand All @@ -144,6 +153,29 @@ def run_module():
)
cml = cmlModule(module)

# Validate provided configuration format
if "config" in cml.params and cml.params["config"] is not None:
if (
not isinstance(cml.params["config"], (str, list, dict))
or (
isinstance(cml.params["config"], list)
and not all(
isinstance(cf, dict) and "name" in cf and "content" in cf
for cf in cml.params["config"]
)
)
or (
isinstance(cml.params["config"], dict)
and (
"name" not in cml.params["config"]
or "content" not in cml.params["config"]
)
)
):
cml.fail_json(
"Configuration must be a string, dictionary with 'name' and 'content' keys or list of such dictionaries"
)

labs = cml.client.find_labs_by_title(cml.params['lab'])
if len(labs) > 0:
lab = labs[0]
Expand All @@ -155,6 +187,52 @@ def run_module():
if node is None:
node = lab.create_node(label=cml.params['name'], node_definition=cml.params['node_definition'])
cml.result['changed'] = True
# set optional parameters when defined
if cml.params['config'] is not None:
node.configuration = cml.params['config']
else:
# check configuration of existing node when defined
if cml.params["config"] is not None:
config_change_needed = False
# Compare provided string with single config
# We are checking only content of main configuration
if isinstance(cml.params["config"], str):
if cml.params["config"] != node.configuration:
config_change_needed = True
else:
# Transform configuration files to dictionary
# From: [{'name': 'name1', 'content': 'content1...'}, ...]
# To: {'name1': 'content1...', ...}
cf_dict = {
cf["name"]: cf["content"] for cf in node.configuration_files
}
# Compare provided list of configs - [{'name': '...', 'content': '...'}, ...]
# We are checking existence and content of all provided config files
if isinstance(cml.params["config"], list):
if not all(
cf["name"] in cf_dict
and cf["content"] == cf_dict[cf["name"]]
for cf in cml.params["config"]
):
config_change_needed = True
# Compare provided dictionary with single config - {'name': '...', 'content': '...'}
# We are checking only existence and content of the provided config file
elif isinstance(cml.params["config"], dict):
if (
cml.params["config"]["name"] not in cf_dict
or cml.params["config"]["content"]
!= cf_dict[cml.params["config"]["name"]]
):
config_change_needed = True
if config_change_needed:
if node.state != "DEFINED_ON_CORE":
cml.fail_json(
"Configuration change detected, but node must be wiped and stopped before it can be updated"
)
cml.result["changed"] = True
if module.check_mode:
cml.exit_json()
node.configuration = cml.params["config"]
elif cml.params['state'] == 'started':
if node is None:
cml.fail_json("Node must be created before it is started")
Expand Down