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_dpdk_cpus 27short_description: Configure CPUs enabled to run engines in each DPDK stage 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 dpdk feature and cpus 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 dpdk_cpus: 68 description: 69 - Configure CPUs enabled to run engines in each DPDK stage. 70 default: null 71 type: dict 72 suboptions: 73 ips_cpus: 74 description: 75 - CPUs enabled to run DPDK IPS engines. 76 type: str 77 rx_cpus: 78 description: 79 - CPUs enabled to run DPDK RX engines. 80 type: str 81 tx_cpus: 82 description: 83 - CPUs enabled to run DPDK TX engines. 84 type: str 85 vnp_cpus: 86 description: 87 - CPUs enabled to run DPDK VNP engines. 88 type: str 89''' 90 91EXAMPLES = ''' 92- hosts: fortigates 93 collections: 94 - fortinet.fortios 95 connection: httpapi 96 vars: 97 vdom: "root" 98 ansible_httpapi_use_ssl: yes 99 ansible_httpapi_validate_certs: no 100 ansible_httpapi_port: 443 101 tasks: 102 - name: Configure CPUs enabled to run engines in each DPDK stage. 103 fortios_dpdk_cpus: 104 vdom: "{{ vdom }}" 105 dpdk_cpus: 106 ips_cpus: "<your_own_value>" 107 rx_cpus: "<your_own_value>" 108 tx_cpus: "<your_own_value>" 109 vnp_cpus: "<your_own_value>" 110 111''' 112 113RETURN = ''' 114build: 115 description: Build number of the fortigate image 116 returned: always 117 type: str 118 sample: '1547' 119http_method: 120 description: Last method used to provision the content into FortiGate 121 returned: always 122 type: str 123 sample: 'PUT' 124http_status: 125 description: Last result given by FortiGate on last operation applied 126 returned: always 127 type: str 128 sample: "200" 129mkey: 130 description: Master key (id) used in the last call to FortiGate 131 returned: success 132 type: str 133 sample: "id" 134name: 135 description: Name of the table used to fulfill the request 136 returned: always 137 type: str 138 sample: "urlfilter" 139path: 140 description: Path of the table used to fulfill the request 141 returned: always 142 type: str 143 sample: "webfilter" 144revision: 145 description: Internal revision number 146 returned: always 147 type: str 148 sample: "17.0.2.10658" 149serial: 150 description: Serial number of the unit 151 returned: always 152 type: str 153 sample: "FGVMEVYYQT3AB5352" 154status: 155 description: Indication of the operation's result 156 returned: always 157 type: str 158 sample: "success" 159vdom: 160 description: Virtual domain used 161 returned: always 162 type: str 163 sample: "root" 164version: 165 description: Version of the FortiGate 166 returned: always 167 type: str 168 sample: "v5.6.3" 169 170''' 171from ansible.module_utils.basic import AnsibleModule 172from ansible.module_utils.connection import Connection 173from ansible_collections.fortinet.fortios.plugins.module_utils.fortios.fortios import FortiOSHandler 174from ansible_collections.fortinet.fortios.plugins.module_utils.fortios.fortios import check_legacy_fortiosapi 175from ansible_collections.fortinet.fortios.plugins.module_utils.fortios.fortios import schema_to_module_spec 176from ansible_collections.fortinet.fortios.plugins.module_utils.fortios.fortios import check_schema_versioning 177from ansible_collections.fortinet.fortios.plugins.module_utils.fortimanager.common import FAIL_SOCKET_MSG 178from ansible_collections.fortinet.fortios.plugins.module_utils.fortios.comparison import is_same_comparison 179from ansible_collections.fortinet.fortios.plugins.module_utils.fortios.comparison import serialize 180 181 182def filter_dpdk_cpus_data(json): 183 option_list = ['ips_cpus', 'rx_cpus', 'tx_cpus', 184 'vnp_cpus'] 185 dictionary = {} 186 187 for attribute in option_list: 188 if attribute in json and json[attribute] is not None: 189 dictionary[attribute] = json[attribute] 190 191 return dictionary 192 193 194def underscore_to_hyphen(data): 195 if isinstance(data, list): 196 for i, elem in enumerate(data): 197 data[i] = underscore_to_hyphen(elem) 198 elif isinstance(data, dict): 199 new_data = {} 200 for k, v in data.items(): 201 new_data[k.replace('_', '-')] = underscore_to_hyphen(v) 202 data = new_data 203 204 return data 205 206 207def dpdk_cpus(data, fos): 208 vdom = data['vdom'] 209 dpdk_cpus_data = data['dpdk_cpus'] 210 filtered_data = underscore_to_hyphen(filter_dpdk_cpus_data(dpdk_cpus_data)) 211 212 return fos.set('dpdk', 213 'cpus', 214 data=filtered_data, 215 vdom=vdom) 216 217 218def is_successful_status(status): 219 return status['status'] == "success" or \ 220 status['http_method'] == "DELETE" and status['http_status'] == 404 221 222 223def fortios_dpdk(data, fos): 224 225 if data['dpdk_cpus']: 226 resp = dpdk_cpus(data, fos) 227 else: 228 fos._module.fail_json(msg='missing task body: %s' % ('dpdk_cpus')) 229 230 return not is_successful_status(resp), \ 231 resp['status'] == "success" and \ 232 (resp['revision_changed'] if 'revision_changed' in resp else True), \ 233 resp 234 235 236versioned_schema = { 237 "type": "dict", 238 "children": { 239 "tx_cpus": { 240 "type": "string", 241 "revisions": { 242 "v7.0.0": True 243 } 244 }, 245 "ips_cpus": { 246 "type": "string", 247 "revisions": { 248 "v7.0.0": True 249 } 250 }, 251 "vnp_cpus": { 252 "type": "string", 253 "revisions": { 254 "v7.0.0": True 255 } 256 }, 257 "rx_cpus": { 258 "type": "string", 259 "revisions": { 260 "v7.0.0": True 261 } 262 } 263 }, 264 "revisions": { 265 "v7.0.0": True 266 } 267} 268 269 270def main(): 271 module_spec = schema_to_module_spec(versioned_schema) 272 mkeyname = None 273 fields = { 274 "access_token": {"required": False, "type": "str", "no_log": True}, 275 "enable_log": {"required": False, "type": bool}, 276 "vdom": {"required": False, "type": "str", "default": "root"}, 277 "dpdk_cpus": { 278 "required": False, "type": "dict", "default": None, 279 "options": { 280 } 281 } 282 } 283 for attribute_name in module_spec['options']: 284 fields["dpdk_cpus"]['options'][attribute_name] = module_spec['options'][attribute_name] 285 if mkeyname and mkeyname == attribute_name: 286 fields["dpdk_cpus"]['options'][attribute_name]['required'] = True 287 288 check_legacy_fortiosapi() 289 module = AnsibleModule(argument_spec=fields, 290 supports_check_mode=False) 291 292 versions_check_result = None 293 if module._socket_path: 294 connection = Connection(module._socket_path) 295 if 'access_token' in module.params: 296 connection.set_option('access_token', module.params['access_token']) 297 298 if 'enable_log' in module.params: 299 connection.set_option('enable_log', module.params['enable_log']) 300 else: 301 connection.set_option('enable_log', False) 302 fos = FortiOSHandler(connection, module, mkeyname) 303 versions_check_result = check_schema_versioning(fos, versioned_schema, "dpdk_cpus") 304 305 is_error, has_changed, result = fortios_dpdk(module.params, fos) 306 307 else: 308 module.fail_json(**FAIL_SOCKET_MSG) 309 310 if versions_check_result and versions_check_result['matched'] is False: 311 module.warn("Ansible has detected version mismatch between FortOS system and your playbook, see more details by specifying option -vvv") 312 313 if not is_error: 314 if versions_check_result and versions_check_result['matched'] is False: 315 module.exit_json(changed=has_changed, version_check_warning=versions_check_result, meta=result) 316 else: 317 module.exit_json(changed=has_changed, meta=result) 318 else: 319 if versions_check_result and versions_check_result['matched'] is False: 320 module.fail_json(msg="Error in repo", version_check_warning=versions_check_result, meta=result) 321 else: 322 module.fail_json(msg="Error in repo", meta=result) 323 324 325if __name__ == '__main__': 326 main() 327