1#!/usr/local/bin/python3.8
2from __future__ import (absolute_import, division, print_function)
3# Copyright 2019-2020 Fortinet, Inc.
4#
5# This program 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# This program 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 this program.  If not, see <https://www.gnu.org/licenses/>.
17
18__metaclass__ = type
19
20ANSIBLE_METADATA = {'status': ['preview'],
21                    'supported_by': 'community',
22                    'metadata_version': '1.1'}
23
24DOCUMENTATION = '''
25---
26module: fortios_system_mem_mgr
27short_description: Configure memory manager in Fortinet's FortiOS and FortiGate.
28description:
29    - This module is able to configure a FortiGate or FortiOS (FOS) device by allowing the
30      user to set and modify system feature and mem_mgr category.
31      Examples include all parameters and values need to be adjusted to datasources before usage.
32      Tested with FOS v6.0.0
33version_added: "2.10"
34author:
35    - Link Zheng (@chillancezen)
36    - Jie Xue (@JieX19)
37    - Hongbin Lu (@fgtdev-hblu)
38    - Frank Shen (@frankshen01)
39    - Miguel Angel Munoz (@mamunozgonzalez)
40    - Nicolas Thomas (@thomnico)
41notes:
42    - Legacy fortiosapi has been deprecated, httpapi is the preferred way to run playbooks
43
44requirements:
45    - ansible>=2.9.0
46options:
47    access_token:
48        description:
49            - Token-based authentication.
50              Generated from GUI of Fortigate.
51        type: str
52        required: false
53    enable_log:
54        description:
55            - Enable/Disable logging for task.
56        type: bool
57        required: false
58        default: false
59    vdom:
60        description:
61            - Virtual domain, among those defined previously. A vdom is a
62              virtual instance of the FortiGate that can be configured and
63              used as a different unit.
64        type: str
65        default: root
66
67    system_mem_mgr:
68        description:
69            - Configure memory manager.
70        default: null
71        type: dict
72        suboptions:
73            mass_mmsd:
74                description:
75                    - memory limit for Mass MMS Daemon (% of free memory)
76                type: int
77'''
78
79EXAMPLES = '''
80- hosts: fortigates
81  collections:
82    - fortinet.fortios
83  connection: httpapi
84  vars:
85   vdom: "root"
86   ansible_httpapi_use_ssl: yes
87   ansible_httpapi_validate_certs: no
88   ansible_httpapi_port: 443
89  tasks:
90  - name: Configure memory manager.
91    fortios_system_mem_mgr:
92      vdom:  "{{ vdom }}"
93      system_mem_mgr:
94        mass_mmsd: "3"
95
96'''
97
98RETURN = '''
99build:
100  description: Build number of the fortigate image
101  returned: always
102  type: str
103  sample: '1547'
104http_method:
105  description: Last method used to provision the content into FortiGate
106  returned: always
107  type: str
108  sample: 'PUT'
109http_status:
110  description: Last result given by FortiGate on last operation applied
111  returned: always
112  type: str
113  sample: "200"
114mkey:
115  description: Master key (id) used in the last call to FortiGate
116  returned: success
117  type: str
118  sample: "id"
119name:
120  description: Name of the table used to fulfill the request
121  returned: always
122  type: str
123  sample: "urlfilter"
124path:
125  description: Path of the table used to fulfill the request
126  returned: always
127  type: str
128  sample: "webfilter"
129revision:
130  description: Internal revision number
131  returned: always
132  type: str
133  sample: "17.0.2.10658"
134serial:
135  description: Serial number of the unit
136  returned: always
137  type: str
138  sample: "FGVMEVYYQT3AB5352"
139status:
140  description: Indication of the operation's result
141  returned: always
142  type: str
143  sample: "success"
144vdom:
145  description: Virtual domain used
146  returned: always
147  type: str
148  sample: "root"
149version:
150  description: Version of the FortiGate
151  returned: always
152  type: str
153  sample: "v5.6.3"
154
155'''
156from ansible.module_utils.basic import AnsibleModule
157from ansible.module_utils.connection import Connection
158from ansible_collections.fortinet.fortios.plugins.module_utils.fortios.fortios import FortiOSHandler
159from ansible_collections.fortinet.fortios.plugins.module_utils.fortios.fortios import check_legacy_fortiosapi
160from ansible_collections.fortinet.fortios.plugins.module_utils.fortios.fortios import schema_to_module_spec
161from ansible_collections.fortinet.fortios.plugins.module_utils.fortios.fortios import check_schema_versioning
162from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FAIL_SOCKET_MSG
163from ansible_collections.fortinet.fortios.plugins.module_utils.fortios.comparison import is_same_comparison
164from ansible_collections.fortinet.fortios.plugins.module_utils.fortios.comparison import serialize
165
166
167def filter_system_mem_mgr_data(json):
168    option_list = ['mass_mmsd']
169    dictionary = {}
170
171    for attribute in option_list:
172        if attribute in json and json[attribute] is not None:
173            dictionary[attribute] = json[attribute]
174
175    return dictionary
176
177
178def underscore_to_hyphen(data):
179    if isinstance(data, list):
180        for i, elem in enumerate(data):
181            data[i] = underscore_to_hyphen(elem)
182    elif isinstance(data, dict):
183        new_data = {}
184        for k, v in data.items():
185            new_data[k.replace('_', '-')] = underscore_to_hyphen(v)
186        data = new_data
187
188    return data
189
190
191def system_mem_mgr(data, fos):
192    vdom = data['vdom']
193    system_mem_mgr_data = data['system_mem_mgr']
194    filtered_data = underscore_to_hyphen(filter_system_mem_mgr_data(system_mem_mgr_data))
195
196    return fos.set('system',
197                   'mem-mgr',
198                   data=filtered_data,
199                   vdom=vdom)
200
201
202def is_successful_status(status):
203    return status['status'] == "success" or \
204        status['http_method'] == "DELETE" and status['http_status'] == 404
205
206
207def fortios_system(data, fos):
208
209    if data['system_mem_mgr']:
210        resp = system_mem_mgr(data, fos)
211    else:
212        fos._module.fail_json(msg='missing task body: %s' % ('system_mem_mgr'))
213
214    return not is_successful_status(resp), \
215        resp['status'] == "success" and \
216        (resp['revision_changed'] if 'revision_changed' in resp else True), \
217        resp
218
219
220versioned_schema = {
221    "type": "dict",
222    "children": {
223        "mass_mmsd": {
224            "type": "integer",
225            "revisions": {
226                "v6.0.0": True,
227                "v6.0.5": True,
228                "v6.2.0": True,
229                "v6.2.3": True,
230                "v6.2.5": True,
231                "v6.2.7": True,
232                "v6.0.11": True
233            }
234        }
235    },
236    "revisions": {
237        "v6.0.0": True,
238        "v6.0.5": True,
239        "v6.2.0": True,
240        "v6.2.3": True,
241        "v6.2.5": True,
242        "v6.2.7": True,
243        "v6.0.11": True
244    }
245}
246
247
248def main():
249    module_spec = schema_to_module_spec(versioned_schema)
250    mkeyname = None
251    fields = {
252        "access_token": {"required": False, "type": "str", "no_log": True},
253        "enable_log": {"required": False, "type": bool},
254        "vdom": {"required": False, "type": "str", "default": "root"},
255        "system_mem_mgr": {
256            "required": False, "type": "dict", "default": None,
257            "options": {
258            }
259        }
260    }
261    for attribute_name in module_spec['options']:
262        fields["system_mem_mgr"]['options'][attribute_name] = module_spec['options'][attribute_name]
263        if mkeyname and mkeyname == attribute_name:
264            fields["system_mem_mgr"]['options'][attribute_name]['required'] = True
265
266    check_legacy_fortiosapi()
267    module = AnsibleModule(argument_spec=fields,
268                           supports_check_mode=False)
269
270    versions_check_result = None
271    if module._socket_path:
272        connection = Connection(module._socket_path)
273        if 'access_token' in module.params:
274            connection.set_option('access_token', module.params['access_token'])
275
276        if 'enable_log' in module.params:
277            connection.set_option('enable_log', module.params['enable_log'])
278        else:
279            connection.set_option('enable_log', False)
280        fos = FortiOSHandler(connection, module, mkeyname)
281        versions_check_result = check_schema_versioning(fos, versioned_schema, "system_mem_mgr")
282
283        is_error, has_changed, result = fortios_system(module.params, fos)
284
285    else:
286        module.fail_json(**FAIL_SOCKET_MSG)
287
288    if versions_check_result and versions_check_result['matched'] is False:
289        module.warn("Ansible has detected version mismatch between FortOS system and your playbook, see more details by specifying option -vvv")
290
291    if not is_error:
292        if versions_check_result and versions_check_result['matched'] is False:
293            module.exit_json(changed=has_changed, version_check_warning=versions_check_result, meta=result)
294        else:
295            module.exit_json(changed=has_changed, meta=result)
296    else:
297        if versions_check_result and versions_check_result['matched'] is False:
298            module.fail_json(msg="Error in repo", version_check_warning=versions_check_result, meta=result)
299        else:
300            module.fail_json(msg="Error in repo", meta=result)
301
302
303if __name__ == '__main__':
304    main()
305