1"""
2NAPALM NTP
3==========
4
5Manages NTP on network devices.
6
7:codeauthor: Mircea Ulinic <ping@mirceaulinic.net> & Jerome Fleury <jf@cloudflare.com>
8:maturity:   new
9:depends:    napalm
10:platform:   unix
11
12Dependencies
13------------
14- :mod:`NAPALM proxy minion <salt.proxy.napalm>`
15- :mod:`NET basic features <salt.modules.napalm_network>`
16
17.. seealso::
18    :mod:`NTP peers management state <salt.states.netntp>`
19
20.. versionadded:: 2016.11.0
21"""
22
23
24import logging
25
26# import NAPALM utils
27import salt.utils.napalm
28from salt.utils.napalm import proxy_napalm_wrap
29
30log = logging.getLogger(__file__)
31
32
33# ----------------------------------------------------------------------------------------------------------------------
34# module properties
35# ----------------------------------------------------------------------------------------------------------------------
36
37__virtualname__ = "ntp"
38__proxyenabled__ = ["napalm"]
39__virtual_aliases__ = ("napalm_ntp",)
40# uses NAPALM-based proxy to interact with network devices
41
42# ----------------------------------------------------------------------------------------------------------------------
43# property functions
44# ----------------------------------------------------------------------------------------------------------------------
45
46
47def __virtual__():
48    """
49    NAPALM library must be installed for this module to work and run in a (proxy) minion.
50    """
51    return salt.utils.napalm.virtual(__opts__, __virtualname__, __file__)
52
53
54# ----------------------------------------------------------------------------------------------------------------------
55# helper functions -- will not be exported
56# ----------------------------------------------------------------------------------------------------------------------
57
58# ----------------------------------------------------------------------------------------------------------------------
59# callable functions
60# ----------------------------------------------------------------------------------------------------------------------
61
62
63@proxy_napalm_wrap
64def peers(**kwargs):  # pylint: disable=unused-argument
65
66    """
67    Returns a list the NTP peers configured on the network device.
68
69    :return: configured NTP peers as list.
70
71    CLI Example:
72
73    .. code-block:: bash
74
75        salt '*' ntp.peers
76
77    Example output:
78
79    .. code-block:: python
80
81        [
82            '192.168.0.1',
83            '172.17.17.1',
84            '172.17.17.2',
85            '2400:cb00:6:1024::c71b:840a'
86        ]
87
88    """
89
90    ntp_peers = salt.utils.napalm.call(
91        napalm_device, "get_ntp_peers", **{}  # pylint: disable=undefined-variable
92    )
93
94    if not ntp_peers.get("result"):
95        return ntp_peers
96
97    ntp_peers_list = list(ntp_peers.get("out", {}).keys())
98
99    ntp_peers["out"] = ntp_peers_list
100
101    return ntp_peers
102
103
104@proxy_napalm_wrap
105def servers(**kwargs):  # pylint: disable=unused-argument
106
107    """
108    Returns a list of the configured NTP servers on the device.
109
110    CLI Example:
111
112    .. code-block:: bash
113
114        salt '*' ntp.servers
115
116    Example output:
117
118    .. code-block:: python
119
120        [
121            '192.168.0.1',
122            '172.17.17.1',
123            '172.17.17.2',
124            '2400:cb00:6:1024::c71b:840a'
125        ]
126    """
127
128    ntp_servers = salt.utils.napalm.call(
129        napalm_device, "get_ntp_servers", **{}  # pylint: disable=undefined-variable
130    )
131
132    if not ntp_servers.get("result"):
133        return ntp_servers
134
135    ntp_servers_list = list(ntp_servers.get("out", {}).keys())
136
137    ntp_servers["out"] = ntp_servers_list
138
139    return ntp_servers
140
141
142@proxy_napalm_wrap
143def stats(peer=None, **kwargs):  # pylint: disable=unused-argument
144
145    """
146    Returns a dictionary containing synchronization details of the NTP peers.
147
148    :param peer: Returns only the details of a specific NTP peer.
149    :return: a list of dictionaries, with the following keys:
150
151        * remote
152        * referenceid
153        * synchronized
154        * stratum
155        * type
156        * when
157        * hostpoll
158        * reachability
159        * delay
160        * offset
161        * jitter
162
163    CLI Example:
164
165    .. code-block:: bash
166
167        salt '*' ntp.stats
168
169    Example output:
170
171    .. code-block:: python
172
173        [
174            {
175                'remote'        : '188.114.101.4',
176                'referenceid'   : '188.114.100.1',
177                'synchronized'  : True,
178                'stratum'       : 4,
179                'type'          : '-',
180                'when'          : '107',
181                'hostpoll'      : 256,
182                'reachability'  : 377,
183                'delay'         : 164.228,
184                'offset'        : -13.866,
185                'jitter'        : 2.695
186            }
187        ]
188    """
189
190    proxy_output = salt.utils.napalm.call(
191        napalm_device, "get_ntp_stats", **{}  # pylint: disable=undefined-variable
192    )
193
194    if not proxy_output.get("result"):
195        return proxy_output
196
197    ntp_peers = proxy_output.get("out")
198
199    if peer:
200        ntp_peers = [
201            ntp_peer for ntp_peer in ntp_peers if ntp_peer.get("remote", "") == peer
202        ]
203
204    proxy_output.update({"out": ntp_peers})
205
206    return proxy_output
207
208
209@proxy_napalm_wrap
210def set_peers(*peers, **options):
211
212    """
213    Configures a list of NTP peers on the device.
214
215    :param peers: list of IP Addresses/Domain Names
216    :param test (bool): discard loaded config. By default ``test`` is False
217        (will not dicard the changes)
218    :commit commit (bool): commit loaded config. By default ``commit`` is True
219        (will commit the changes). Useful when the user does not want to commit
220        after each change, but after a couple.
221
222    By default this function will commit the config changes (if any). To load without committing, use the `commit`
223    option. For dry run use the `test` argument.
224
225    CLI Example:
226
227    .. code-block:: bash
228
229        salt '*' ntp.set_peers 192.168.0.1 172.17.17.1 time.apple.com
230        salt '*' ntp.set_peers 172.17.17.1 test=True  # only displays the diff
231        salt '*' ntp.set_peers 192.168.0.1 commit=False  # preserves the changes, but does not commit
232    """
233
234    test = options.pop("test", False)
235    commit = options.pop("commit", True)
236
237    # pylint: disable=undefined-variable
238    return __salt__["net.load_template"](
239        "set_ntp_peers",
240        peers=peers,
241        test=test,
242        commit=commit,
243        inherit_napalm_device=napalm_device,
244    )
245    # pylint: enable=undefined-variable
246
247
248@proxy_napalm_wrap
249def set_servers(*servers, **options):
250    """
251    Configures a list of NTP servers on the device.
252
253    :param servers: list of IP Addresses/Domain Names
254    :param test (bool): discard loaded config. By default ``test`` is False
255        (will not dicard the changes)
256    :commit commit (bool): commit loaded config. By default ``commit`` is True
257        (will commit the changes). Useful when the user does not want to commit
258        after each change, but after a couple.
259
260    By default this function will commit the config changes (if any). To load without committing, use the `commit`
261    option. For dry run use the `test` argument.
262
263    CLI Example:
264
265    .. code-block:: bash
266
267        salt '*' ntp.set_servers 192.168.0.1 172.17.17.1 time.apple.com
268        salt '*' ntp.set_servers 172.17.17.1 test=True  # only displays the diff
269        salt '*' ntp.set_servers 192.168.0.1 commit=False  # preserves the changes, but does not commit
270    """
271
272    test = options.pop("test", False)
273    commit = options.pop("commit", True)
274
275    # pylint: disable=undefined-variable
276    return __salt__["net.load_template"](
277        "set_ntp_servers",
278        servers=servers,
279        test=test,
280        commit=commit,
281        inherit_napalm_device=napalm_device,
282    )
283    # pylint: enable=undefined-variable
284
285
286@proxy_napalm_wrap
287def delete_peers(*peers, **options):
288
289    """
290    Removes NTP peers configured on the device.
291
292    :param peers: list of IP Addresses/Domain Names to be removed as NTP peers
293    :param test (bool): discard loaded config. By default ``test`` is False
294        (will not dicard the changes)
295    :param commit (bool): commit loaded config. By default ``commit`` is True
296        (will commit the changes). Useful when the user does not want to commit
297        after each change, but after a couple.
298
299    By default this function will commit the config changes (if any). To load
300    without committing, use the ``commit`` option. For a dry run, use the
301    ``test`` argument.
302
303    CLI Example:
304
305    .. code-block:: bash
306
307        salt '*' ntp.delete_peers 8.8.8.8 time.apple.com
308        salt '*' ntp.delete_peers 172.17.17.1 test=True  # only displays the diff
309        salt '*' ntp.delete_peers 192.168.0.1 commit=False  # preserves the changes, but does not commit
310    """
311
312    test = options.pop("test", False)
313    commit = options.pop("commit", True)
314
315    # pylint: disable=undefined-variable
316    return __salt__["net.load_template"](
317        "delete_ntp_peers",
318        peers=peers,
319        test=test,
320        commit=commit,
321        inherit_napalm_device=napalm_device,
322    )
323    # pylint: enable=undefined-variable
324
325
326@proxy_napalm_wrap
327def delete_servers(*servers, **options):
328
329    """
330    Removes NTP servers configured on the device.
331
332    :param servers: list of IP Addresses/Domain Names to be removed as NTP
333        servers
334    :param test (bool): discard loaded config. By default ``test`` is False
335        (will not dicard the changes)
336    :param commit (bool): commit loaded config. By default ``commit`` is True
337        (will commit the changes). Useful when the user does not want to commit
338        after each change, but after a couple.
339
340    By default this function will commit the config changes (if any). To load
341    without committing, use the ``commit`` option. For dry run use the ``test``
342    argument.
343
344    CLI Example:
345
346    .. code-block:: bash
347
348        salt '*' ntp.delete_servers 8.8.8.8 time.apple.com
349        salt '*' ntp.delete_servers 172.17.17.1 test=True  # only displays the diff
350        salt '*' ntp.delete_servers 192.168.0.1 commit=False  # preserves the changes, but does not commit
351    """
352
353    test = options.pop("test", False)
354    commit = options.pop("commit", True)
355
356    # pylint: disable=undefined-variable
357    return __salt__["net.load_template"](
358        "delete_ntp_servers",
359        servers=servers,
360        test=test,
361        commit=commit,
362        inherit_napalm_device=napalm_device,
363    )
364    # pylint: enable=undefined-variable
365