1#!/usr/bin/python
2#
3# This file is part of Ansible
4#
5# Ansible is free software: you can redistribute it and/or modify
6# it under the terms of the GNU General Public License as published by
7# the Free Software Foundation, either version 3 of the License, or
8# (at your option) any later version.
9#
10# Ansible is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13# GNU General Public License for more details.
14#
15# You should have received a copy of the GNU General Public License
16# along with Ansible.  If not, see <http://www.gnu.org/licenses/>.
17#
18
19from __future__ import absolute_import, division, print_function
20
21__metaclass__ = type
22
23ANSIBLE_METADATA = {'status': ['preview'],
24                    'supported_by': 'community',
25                    'metadata_version': '1.1'}
26
27DOCUMENTATION = '''
28---
29module: fmgr_script
30version_added: "2.5"
31notes:
32    - Full Documentation at U(https://ftnt-ansible-docs.readthedocs.io/en/latest/).
33author: Andrew Welsh (@Ghilli3)
34short_description: Add/Edit/Delete and execute scripts
35description: Create/edit/delete scripts and execute the scripts on the FortiManager using jsonrpc API
36
37options:
38  adom:
39    description:
40      - The administrative domain (admon) the configuration belongs to
41    required: true
42
43  vdom:
44    description:
45      - The virtual domain (vdom) the configuration belongs to
46
47  mode:
48    description:
49      - The desired mode of the specified object. Execute will run the script.
50    required: false
51    default: "add"
52    choices: ["add", "delete", "execute", "set"]
53    version_added: "2.8"
54
55  script_name:
56    description:
57      - The name of the script.
58    required: True
59
60  script_type:
61    description:
62      - The type of script (CLI or TCL).
63    required: false
64
65  script_target:
66    description:
67      - The target of the script to be run.
68    required: false
69
70  script_description:
71    description:
72      - The description of the script.
73    required: false
74
75  script_content:
76    description:
77      - The script content that will be executed.
78    required: false
79
80  script_scope:
81    description:
82      - (datasource) The devices that the script will run on, can have both device member and device group member.
83    required: false
84
85  script_package:
86    description:
87      - (datasource) Policy package object to run the script against
88    required: false
89'''
90
91EXAMPLES = '''
92- name: CREATE SCRIPT
93  fmgr_script:
94    adom: "root"
95    script_name: "TestScript"
96    script_type: "cli"
97    script_target: "remote_device"
98    script_description: "Create by Ansible"
99    script_content: "get system status"
100
101- name: EXECUTE SCRIPT
102  fmgr_script:
103    adom: "root"
104    script_name: "TestScript"
105    mode: "execute"
106    script_scope: "FGT1,FGT2"
107
108- name: DELETE SCRIPT
109  fmgr_script:
110    adom: "root"
111    script_name: "TestScript"
112    mode: "delete"
113'''
114
115RETURN = """
116api_result:
117  description: full API response, includes status code and message
118  returned: always
119  type: str
120"""
121
122from ansible.module_utils.basic import AnsibleModule, env_fallback
123from ansible.module_utils.connection import Connection
124from ansible.module_utils.network.fortimanager.fortimanager import FortiManagerHandler
125from ansible.module_utils.network.fortimanager.common import FMGBaseException
126from ansible.module_utils.network.fortimanager.common import FMGRCommon
127from ansible.module_utils.network.fortimanager.common import FMGRMethods
128from ansible.module_utils.network.fortimanager.common import DEFAULT_RESULT_OBJ
129from ansible.module_utils.network.fortimanager.common import FAIL_SOCKET_MSG
130
131
132def set_script(fmgr, paramgram):
133    """
134    :param fmgr: The fmgr object instance from fortimanager.py
135    :type fmgr: class object
136    :param paramgram: The formatted dictionary of options to process
137    :type paramgram: dict
138    :return: The response from the FortiManager
139    :rtype: dict
140    """
141
142    datagram = {
143        'content': paramgram["script_content"],
144        'desc': paramgram["script_description"],
145        'name': paramgram["script_name"],
146        'target': paramgram["script_target"],
147        'type': paramgram["script_type"],
148    }
149
150    url = '/dvmdb/adom/{adom}/script/'.format(adom=paramgram["adom"])
151    response = fmgr.process_request(url, datagram, FMGRMethods.SET)
152    return response
153
154
155def delete_script(fmgr, paramgram):
156    """
157    :param fmgr: The fmgr object instance from fortimanager.py
158    :type fmgr: class object
159    :param paramgram: The formatted dictionary of options to process
160    :type paramgram: dict
161    :return: The response from the FortiManager
162    :rtype: dict
163    """
164
165    datagram = {
166        'name': paramgram["script_name"],
167    }
168
169    url = '/dvmdb/adom/{adom}/script/{script_name}'.format(adom=paramgram["adom"], script_name=paramgram["script_name"])
170    response = fmgr.process_request(url, datagram, FMGRMethods.DELETE)
171    return response
172
173
174def execute_script(fmgr, paramgram):
175    """
176    :param fmgr: The fmgr object instance from fortimanager.py
177    :type fmgr: class object
178    :param paramgram: The formatted dictionary of options to process
179    :type paramgram: dict
180    :return: The response from the FortiManager
181    :rtype: dict
182    """
183
184    scope_list = list()
185    scope = paramgram["script_scope"].replace(' ', '')
186    scope = scope.split(',')
187    for dev_name in scope:
188        scope_list.append({'name': dev_name, 'vdom': paramgram["vdom"]})
189
190    datagram = {
191        'adom': paramgram["adom"],
192        'script': paramgram["script_name"],
193        'package': paramgram["script_package"],
194        'scope': scope_list,
195    }
196
197    url = '/dvmdb/adom/{adom}/script/execute'.format(adom=paramgram["adom"])
198    response = fmgr.process_request(url, datagram, FMGRMethods.EXEC)
199    return response
200
201
202def main():
203    argument_spec = dict(
204        adom=dict(required=False, type="str", default="root"),
205        vdom=dict(required=False, type="str", default="root"),
206        mode=dict(choices=["add", "execute", "set", "delete"], type="str", default="add"),
207        script_name=dict(required=True, type="str"),
208        script_type=dict(required=False, type="str"),
209        script_target=dict(required=False, type="str"),
210        script_description=dict(required=False, type="str"),
211        script_content=dict(required=False, type="str"),
212        script_scope=dict(required=False, type="str"),
213        script_package=dict(required=False, type="str"),
214    )
215
216    module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=False, )
217    paramgram = {
218        "script_name": module.params["script_name"],
219        "script_type": module.params["script_type"],
220        "script_target": module.params["script_target"],
221        "script_description": module.params["script_description"],
222        "script_content": module.params["script_content"],
223        "script_scope": module.params["script_scope"],
224        "script_package": module.params["script_package"],
225        "adom": module.params["adom"],
226        "vdom": module.params["vdom"],
227        "mode": module.params["mode"],
228    }
229    module.paramgram = paramgram
230    fmgr = None
231    if module._socket_path:
232        connection = Connection(module._socket_path)
233        fmgr = FortiManagerHandler(connection, module)
234        fmgr.tools = FMGRCommon()
235    else:
236        module.fail_json(**FAIL_SOCKET_MSG)
237
238    results = DEFAULT_RESULT_OBJ
239
240    try:
241        if paramgram["mode"] in ['add', 'set']:
242            results = set_script(fmgr, paramgram)
243            fmgr.govern_response(module=module, results=results, msg="Operation Finished",
244                                 ansible_facts=fmgr.construct_ansible_facts(results, module.params, module.params))
245    except Exception as err:
246        raise FMGBaseException(err)
247
248    try:
249        if paramgram["mode"] == "execute":
250            results = execute_script(fmgr, paramgram)
251            fmgr.govern_response(module=module, results=results, msg="Operation Finished",
252                                 ansible_facts=fmgr.construct_ansible_facts(results, module.params, module.params))
253    except Exception as err:
254        raise FMGBaseException(err)
255
256    try:
257        if paramgram["mode"] == "delete":
258            results = delete_script(fmgr, paramgram)
259            fmgr.govern_response(module=module, results=results, msg="Operation Finished",
260                                 ansible_facts=fmgr.construct_ansible_facts(results, module.params, module.params))
261    except Exception as err:
262        raise FMGBaseException(err)
263
264    return module.exit_json(**results[1])
265
266
267if __name__ == "__main__":
268    main()
269