Skip to content

Commit 094c913

Browse files
committed
[minor_change] Add ndo_ntp_policy as a new module for managing NTP Policy objects.
1 parent 2638909 commit 094c913

File tree

3 files changed

+729
-0
lines changed

3 files changed

+729
-0
lines changed

plugins/modules/ndo_ntp_policy.py

Lines changed: 397 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,397 @@
1+
#!/usr/bin/python
2+
# -*- coding: utf-8 -*-
3+
4+
# Copyright: (c) 2025, Gaspard Micol (@gmicol) <gmicol@cisco.com>
5+
6+
# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt)
7+
8+
from __future__ import absolute_import, division, print_function
9+
10+
__metaclass__ = type
11+
12+
ANSIBLE_METADATA = {"metadata_version": "1.1", "status": ["preview"], "supported_by": "community"}
13+
14+
DOCUMENTATION = r"""
15+
---
16+
module: ndo_ntp_policy
17+
short_description: Manage NTP Policies in Fabric Policy Templates on Cisco Nexus Dashboard Orchestrator (NDO).
18+
description:
19+
- Manage NTP (NTP) Policies in Fabric Policy Templates on Cisco Nexus Dashboard Orchestrator (NDO).
20+
- This module is only supported on ND v3.1 (NDO v4.3) and later.
21+
author:
22+
- Gaspard Micol (@gmicol)
23+
options:
24+
template:
25+
description:
26+
- The name of the Fabric Policy template.
27+
type: str
28+
aliases: [ fabric_policy_template ]
29+
required: true
30+
name:
31+
description:
32+
- The name of the NTP Policy.
33+
type: str
34+
aliases: [ ntp_policy ]
35+
uuid:
36+
description:
37+
- The UUID of the NTP Policy.
38+
- This parameter is required when the NTP Policy O(name) needs to be updated.
39+
aliases: [ ntp_policy_uuid ]
40+
type: str
41+
description:
42+
description:
43+
- The description of the NTP Policy.
44+
- Providing an empty string will remove the O(description="") from the NTP Policy.
45+
type: str
46+
ntp_keys:
47+
description:
48+
- The List of NTP client authentication keys.
49+
- Providing a new list of O(ntp_keys) will completely replace an existing one from the NTP Policy.
50+
- Providing an empty list will remove the O(ntp_keys=[]) from the NTP Policy.
51+
type: list
52+
elements: dict
53+
suboptions:
54+
id:
55+
description:
56+
- The key's ID.
57+
type: int
58+
aliases: [ key_id ]
59+
key:
60+
description:
61+
- The key.
62+
type: str
63+
authentification_type:
64+
description:
65+
- the type of authentification.
66+
type: str
67+
choices: [ md5, sha1 ]
68+
trusted:
69+
description:
70+
- Set the NTP client authentification key to trusted.
71+
type: bool
72+
ntp_providers:
73+
description:
74+
- The list of NTP providers.
75+
- Providing a new list of O(ntp_providers) will completely replace an existing one from the NTP Policy.
76+
- Providing an empty list will remove the O(ntp_providers=[]) from the NTP Policy.
77+
type: list
78+
elements: dict
79+
suboptions:
80+
host:
81+
description:
82+
- The Hostname or IP address of the NTP provider.
83+
type: str
84+
minimum_poll_interval:
85+
description:
86+
- The Minimum Polling interval value.
87+
type: int
88+
aliases: [ min_poll ]
89+
maximum_poll_interval:
90+
description:
91+
- The Maximum Polling interval value.
92+
type: int
93+
aliases: [ max_poll ]
94+
management_epg_type:
95+
description:
96+
- The type of the management EPG.
97+
type: str
98+
choices: [ inb, oob ]
99+
aliases: [ epg_type ]
100+
management_epg:
101+
description:
102+
- The management EPG.
103+
type: str
104+
aliases: [ epg ]
105+
preferred:
106+
description:
107+
- Set the NTP provider to preferred.
108+
type: bool
109+
authentification_key_id:
110+
description:
111+
- The NTP authentification key ID.
112+
type: int
113+
aliases: [ key_id ]
114+
admin_state:
115+
description:
116+
- Enable admin state.
117+
type: str
118+
choices: [ enabled, disabled ]
119+
server_state:
120+
description:
121+
- Enable server state.
122+
type: str
123+
choices: [ enabled, disabled ]
124+
master_mode:
125+
description:
126+
- Enable master mode.
127+
type: str
128+
choices: [ enabled, disabled ]
129+
stratum:
130+
description:
131+
- The numerical value of the stratum.
132+
type: int
133+
authentification_state:
134+
description:
135+
- Enable authentification state.
136+
type: str
137+
choices: [ enabled, disabled ]
138+
state:
139+
description:
140+
- Use C(absent) for removing.
141+
- Use C(query) for listing an object or multiple objects.
142+
- Use C(present) for creating or updating.
143+
type: str
144+
choices: [ absent, query, present ]
145+
default: query
146+
notes:
147+
- The O(template) must exist before using this module in your playbook.
148+
Use M(cisco.mso.ndo_template) to create the Fabric Policy template.
149+
seealso:
150+
- module: cisco.mso.ndo_template
151+
extends_documentation_fragment: cisco.mso.modules
152+
"""
153+
154+
EXAMPLES = r"""
155+
- name: Create a new NTP Policy object
156+
cisco.mso.ndo_ntp_policy:
157+
host: mso_host
158+
username: admin
159+
password: SomeSecretPassword
160+
template: fabric_policy_template
161+
name: ntp_policy_1
162+
ntp_keys:
163+
- id: 1
164+
key: my_key
165+
authentification_type: md5
166+
trusted: true
167+
ntp_providers:
168+
- host: background
169+
minimum_poll_interval: 4
170+
maximum_poll_interval: 16
171+
management_epg_type: oob
172+
management_epg: default
173+
preferred: true
174+
authentification_key_id: 1
175+
admin_state: enabled
176+
server_state: enabled
177+
master_mode: enabled
178+
stratum: 4
179+
authentification_state: enabled
180+
state: present
181+
register: ntp_policy_1
182+
183+
- name: Update a NTP Policy object name with UUID
184+
cisco.mso.ndo_ntp_policy:
185+
host: mso_host
186+
username: admin
187+
password: SomeSecretPassword
188+
template: fabric_policy_template
189+
name: ntp_policy_2
190+
uuid: "{{ ntp_policy_1.current.uuid }}"
191+
state: present
192+
193+
- name: Query a NTP Policy object with name
194+
cisco.mso.ndo_ntp_policy:
195+
host: mso_host
196+
username: admin
197+
password: SomeSecretPassword
198+
template: fabric_policy_template
199+
name: ntp_policy_2
200+
state: query
201+
register: query_name
202+
203+
- name: Query a NTP Policy object with UUID
204+
cisco.mso.ndo_ntp_policy:
205+
host: mso_host
206+
username: admin
207+
password: SomeSecretPassword
208+
template: fabric_policy_template
209+
uuid: "{{ ntp_policy_1.current.uuid }}"
210+
state: query
211+
register: query_uuid
212+
213+
- name: Query all NTP Policy objects in a Fabric Policy Template
214+
cisco.mso.ndo_ntp_policy:
215+
host: mso_host
216+
username: admin
217+
password: SomeSecretPassword
218+
template: fabric_policy_template
219+
state: query
220+
register: query_all
221+
222+
- name: Delete a NTP Policy object with name
223+
cisco.mso.ndo_ntp_policy:
224+
host: mso_host
225+
username: admin
226+
password: SomeSecretPassword
227+
template: fabric_policy_template
228+
name: ntp_policy_2
229+
state: absent
230+
231+
- name: Delete a NTP Policy object with UUID
232+
cisco.mso.ndo_ntp_policy:
233+
host: mso_host
234+
username: admin
235+
password: SomeSecretPassword
236+
template: fabric_policy_template
237+
uuid: "{{ ntp_policy_1.current.uuid }}"
238+
state: absent
239+
"""
240+
241+
RETURN = r"""
242+
"""
243+
244+
import copy
245+
from ansible.module_utils.basic import AnsibleModule
246+
from ansible_collections.cisco.mso.plugins.module_utils.mso import MSOModule, mso_argument_spec
247+
from ansible_collections.cisco.mso.plugins.module_utils.template import MSOTemplate, KVPair
248+
from ansible_collections.cisco.mso.plugins.module_utils.utils import append_update_ops_data
249+
250+
251+
def main():
252+
argument_spec = mso_argument_spec()
253+
argument_spec.update(
254+
template=dict(type="str", required=True, aliases=["fabric_policy_template"]),
255+
name=dict(type="str", aliases=["ntp_policy"]),
256+
uuid=dict(type="str", aliases=["ntp_policy_uuid"]),
257+
description=dict(type="str"),
258+
ntp_keys=dict(
259+
type="list",
260+
elements="dict",
261+
options=dict(
262+
id=dict(type="int", aliases=["key_id"]),
263+
key=dict(type="str", no_log=True),
264+
authentification_type=dict(type="str", choices=["md5", "sha1"]),
265+
trusted=dict(type="bool"),
266+
),
267+
no_log=False,
268+
),
269+
ntp_providers=dict(
270+
type="list",
271+
elements="dict",
272+
options=dict(
273+
host=dict(type="str"),
274+
minimum_poll_interval=dict(type="int", aliases=["min_poll"]),
275+
maximum_poll_interval=dict(type="int", aliases=["max_poll"]),
276+
management_epg_type=dict(type="str", choices=["inb", "oob"], aliases=["epg_type"]),
277+
management_epg=dict(type="str", aliases=["epg"]),
278+
preferred=dict(type="bool"),
279+
authentification_key_id=dict(type="int", aliases=["key_id"]),
280+
),
281+
),
282+
admin_state=dict(type="str", choices=["enabled", "disabled"]),
283+
server_state=dict(type="str", choices=["enabled", "disabled"]),
284+
master_mode=dict(type="str", choices=["enabled", "disabled"]),
285+
stratum=dict(type="int"),
286+
authentification_state=dict(type="str", choices=["enabled", "disabled"]),
287+
state=dict(type="str", default="query", choices=["absent", "query", "present"]),
288+
)
289+
290+
module = AnsibleModule(
291+
argument_spec=argument_spec,
292+
supports_check_mode=True,
293+
required_if=[
294+
["state", "absent", ["name", "uuid"], True],
295+
["state", "present", ["name", "uuid"], True],
296+
],
297+
)
298+
299+
mso = MSOModule(module)
300+
301+
template = module.params.get("template")
302+
name = module.params.get("name")
303+
uuid = module.params.get("uuid")
304+
description = module.params.get("description")
305+
ntp_keys = module.params.get("ntp_keys")
306+
if ntp_keys:
307+
ntp_keys = [
308+
{
309+
"id": item.get("id"),
310+
"key": item.get("key"),
311+
"authType": item.get("authentification_type"),
312+
"trusted": item.get("trusted"),
313+
}
314+
for item in ntp_keys
315+
]
316+
ntp_providers = module.params.get("ntp_providers")
317+
if ntp_providers:
318+
ntp_providers = [
319+
{
320+
"host": item.get("host"),
321+
"minPollInterval": item.get("minimum_poll_interval"),
322+
"maxPollInterval": item.get("maximum_poll_interval"),
323+
"mgmtEpgType": item.get("management_epg_type"),
324+
"mgmtEpgName": item.get("management_epg"),
325+
"preferred": item.get("preferred"),
326+
"authKeyID": item.get("authentification_key_id"),
327+
}
328+
for item in ntp_providers
329+
]
330+
admin_state = module.params.get("admin_state")
331+
server_state = module.params.get("server_state")
332+
master_mode = module.params.get("master_mode")
333+
stratum = module.params.get("stratum")
334+
authentification_state = module.params.get("authentification_state")
335+
state = module.params.get("state")
336+
337+
template_object = MSOTemplate(mso, "tenant", template)
338+
template_object.validate_template("tenantPolicy")
339+
340+
ntp_policies = template_object.template.get("fabricPolicyTemplate", {}).get("template", {}).get("ntpPolicies", [])
341+
object_description = "NTP Policy"
342+
343+
if state in ["query", "absent"] and ntp_policies == []:
344+
mso.exit_json()
345+
elif state == "query" and not (name or uuid):
346+
mso.existing = ntp_policies
347+
elif ntp_policies and (name or uuid):
348+
match = template_object.get_object_by_key_value_pairs(object_description, ntp_policies, [KVPair("uuid", uuid) if uuid else KVPair("name", name)])
349+
if match:
350+
ntp_policy_attrs_path = "/fabricPolicyTemplate/template/ntpPolicies/{0}".format(match.index)
351+
mso.existing = mso.previous = copy.deepcopy(match.details)
352+
353+
ops = []
354+
355+
if state == "present":
356+
if uuid and not mso.existing:
357+
mso.fail_json(msg="{0} with the UUID: '{1}' not found".format(object_description, uuid))
358+
359+
mso_values = dict(
360+
name=name,
361+
description=description,
362+
ntpKeys=ntp_keys,
363+
ntpProviders=ntp_providers,
364+
adminState=admin_state,
365+
serverState=server_state,
366+
masterMode=master_mode,
367+
stratum=stratum,
368+
authState=authentification_state,
369+
)
370+
371+
if mso.existing:
372+
append_update_ops_data(ops, match.details, ntp_policy_attrs_path, mso_values)
373+
mso.sanitize(match.details, collate=True)
374+
else:
375+
mso.sanitize(mso_values)
376+
ops.append(dict(op="add", path="/fabricPolicyTemplate/template/ntpPolicies/-", value=mso.sent))
377+
378+
elif state == "absent":
379+
if mso.existing:
380+
ops.append(dict(op="remove", path=ntp_policy_attrs_path))
381+
382+
if not module.check_mode and ops:
383+
response_object = mso.request(template_object.template_path, method="PATCH", data=ops)
384+
ntp_policies = response_object.get("fabricPolicyTemplate", {}).get("template", {}).get("ntpPolicies", [])
385+
match = template_object.get_object_by_key_value_pairs(object_description, ntp_policies, [KVPair("uuid", uuid) if uuid else KVPair("name", name)])
386+
if match:
387+
mso.existing = match.details # When the state is present
388+
else:
389+
mso.existing = {} # When the state is absent
390+
elif module.check_mode and state != "query": # When the state is present/absent with check mode
391+
mso.existing = mso.proposed if state == "present" else {}
392+
393+
mso.exit_json()
394+
395+
396+
if __name__ == "__main__":
397+
main()

0 commit comments

Comments
 (0)