1#!/usr/local/bin/python3.8
2# -*- coding: utf-8 -*-
3
4# (c) 2017, Ansible by Red Hat, inc
5# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
6
7from __future__ import absolute_import, division, print_function
8
9__metaclass__ = type
10
11
12DOCUMENTATION = """
13module: junos_system
14author: Ganesh Nalawade (@ganeshrn)
15short_description: Manage the system attributes on Juniper JUNOS devices
16description:
17- This module provides declarative management of node system attributes on Juniper
18  JUNOS devices.  It provides an option to configure host system parameters or remove
19  those parameters from the device active configuration.
20version_added: 1.0.0
21options:
22  hostname:
23    description:
24    - Configure the device hostname parameter. This option takes an ASCII string value.
25    type: str
26  domain_name:
27    description:
28    - Configure the IP domain name on the remote device to the provided value. Value
29      should be in the dotted name form and will be appended to the C(hostname) to
30      create a fully-qualified domain name.
31    type: str
32  domain_search:
33    description:
34    - Provides the list of domain suffixes to append to the hostname for the purpose
35      of doing name resolution. This argument accepts a list of names and will be
36      reconciled with the current active configuration on the running node.
37    type: list
38    elements: str
39  name_servers:
40    description:
41    - List of DNS name servers by IP address to use to perform name resolution lookups.  This
42      argument accepts either a list of DNS servers See examples.
43    type: list
44    elements: str
45  state:
46    description:
47    - State of the configuration values in the device's current active configuration.  When
48      set to I(present), the values should be configured in the device active configuration
49      and when set to I(absent) the values should not be in the device active configuration
50    type: str
51    default: present
52    choices:
53    - present
54    - absent
55  active:
56    description:
57    - Specifies whether or not the configuration is active or deactivated
58    default: true
59    type: bool
60requirements:
61- ncclient (>=v0.5.2)
62notes:
63- This module requires the netconf system service be enabled on the remote device
64  being managed.
65- Tested against vSRX JUNOS version 15.1X49-D15.4, vqfx-10000 JUNOS Version 15.1X53-D60.4.
66- Recommended connection is C(netconf). See L(the Junos OS Platform Options,../network/user_guide/platform_junos.html).
67- This module also works with C(local) connections for legacy playbooks.
68extends_documentation_fragment:
69- junipernetworks.junos.junos
70"""
71
72EXAMPLES = """
73- name: configure hostname and domain name
74  junipernetworks.junos.junos_system:
75    hostname: junos01
76    domain_name: test.example.com
77    domain-search:
78    - ansible.com
79    - redhat.com
80    - juniper.net
81
82- name: remove configuration
83  junipernetworks.junos.junos_system:
84    state: absent
85
86- name: configure name servers
87  junipernetworks.junos.junos_system:
88    name_servers:
89    - 8.8.8.8
90    - 8.8.4.4
91"""
92
93RETURN = """
94diff.prepared:
95  description: Configuration difference before and after applying change.
96  returned: when configuration is changed and diff option is enabled.
97  type: str
98  sample: >
99          [edit system]
100          +  host-name test;
101          +  domain-name ansible.com;
102          +  domain-search redhat.com;
103          [edit system name-server]
104              172.26.1.1 { ... }
105          +   8.8.8.8;
106"""
107import collections
108
109from ansible.module_utils.basic import AnsibleModule
110from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.junos import (
111    junos_argument_spec,
112    tostring,
113)
114from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.junos import (
115    load_config,
116    map_params_to_obj,
117    map_obj_to_ele,
118)
119from ansible_collections.junipernetworks.junos.plugins.module_utils.network.junos.junos import (
120    commit_configuration,
121    discard_changes,
122    locked_config,
123)
124
125USE_PERSISTENT_CONNECTION = True
126
127
128def validate_param_values(module, obj):
129    for key in obj:
130        # validate the param value (if validator func exists)
131        validator = globals().get("validate_%s" % key)
132        if callable(validator):
133            validator(module.params.get(key), module)
134
135
136def main():
137    """ main entry point for module execution
138    """
139    argument_spec = dict(
140        hostname=dict(),
141        domain_name=dict(),
142        domain_search=dict(type="list", elements="str"),
143        name_servers=dict(type="list", elements="str"),
144        state=dict(choices=["present", "absent"], default="present"),
145        active=dict(default=True, type="bool"),
146    )
147
148    argument_spec.update(junos_argument_spec)
149
150    params = ["hostname", "domain_name", "domain_search", "name_servers"]
151    required_if = [
152        ("state", "present", params, True),
153        ("state", "absent", params, True),
154        ("state", "active", params, True),
155        ("state", "suspend", params, True),
156    ]
157
158    module = AnsibleModule(
159        argument_spec=argument_spec,
160        required_if=required_if,
161        supports_check_mode=True,
162    )
163
164    warnings = list()
165    result = {"changed": False}
166
167    if warnings:
168        result["warnings"] = warnings
169
170    top = "system"
171
172    param_to_xpath_map = collections.OrderedDict()
173    param_to_xpath_map.update(
174        [
175            ("hostname", {"xpath": "host-name", "leaf_only": True}),
176            ("domain_name", {"xpath": "domain-name", "leaf_only": True}),
177            (
178                "domain_search",
179                {
180                    "xpath": "domain-search",
181                    "leaf_only": True,
182                    "value_req": True,
183                },
184            ),
185            ("name_servers", {"xpath": "name-server/name", "is_key": True}),
186        ]
187    )
188
189    validate_param_values(module, param_to_xpath_map)
190
191    want = map_params_to_obj(module, param_to_xpath_map)
192    ele = map_obj_to_ele(module, want, top)
193
194    with locked_config(module):
195        diff = load_config(module, tostring(ele), warnings, action="merge")
196
197        commit = not module.check_mode
198        if diff:
199            if commit:
200                commit_configuration(module)
201            else:
202                discard_changes(module)
203            result["changed"] = True
204
205            if module._diff:
206                result["diff"] = {"prepared": diff}
207
208    module.exit_json(**result)
209
210
211if __name__ == "__main__":
212    main()
213