1#!/usr/bin/python
2from __future__ import (absolute_import, division, print_function)
3# Copyright 2019 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_report_layout
27short_description: Report layout configuration 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 report feature and layout category.
31      Examples include all parameters and values need to be adjusted to datasources before usage.
32      Tested with FOS v6.0.5
33version_added: "2.8"
34author:
35    - Miguel Angel Munoz (@mamunozgonzalez)
36    - Nicolas Thomas (@thomnico)
37notes:
38    - Requires fortiosapi library developed by Fortinet
39    - Run as a local_action in your playbook
40requirements:
41    - fortiosapi>=0.9.8
42options:
43    host:
44        description:
45            - FortiOS or FortiGate IP address.
46        type: str
47        required: false
48    username:
49        description:
50            - FortiOS or FortiGate username.
51        type: str
52        required: false
53    password:
54        description:
55            - FortiOS or FortiGate password.
56        type: str
57        default: ""
58    vdom:
59        description:
60            - Virtual domain, among those defined previously. A vdom is a
61              virtual instance of the FortiGate that can be configured and
62              used as a different unit.
63        type: str
64        default: root
65    https:
66        description:
67            - Indicates if the requests towards FortiGate must use HTTPS protocol.
68        type: bool
69        default: true
70    ssl_verify:
71        description:
72            - Ensures FortiGate certificate must be verified by a proper CA.
73        type: bool
74        default: true
75        version_added: 2.9
76    state:
77        description:
78            - Indicates whether to create or remove the object.
79              This attribute was present already in previous version in a deeper level.
80              It has been moved out to this outer level.
81        type: str
82        required: false
83        choices:
84            - present
85            - absent
86        version_added: 2.9
87    report_layout:
88        description:
89            - Report layout configuration.
90        default: null
91        type: dict
92        suboptions:
93            state:
94                description:
95                    - B(Deprecated)
96                    - Starting with Ansible 2.9 we recommend using the top-level 'state' parameter.
97                    - HORIZONTALLINE
98                    - Indicates whether to create or remove the object.
99                type: str
100                required: false
101                choices:
102                    - present
103                    - absent
104            body_item:
105                description:
106                    - Configure report body item.
107                type: list
108                suboptions:
109                    chart:
110                        description:
111                            - Report item chart name.
112                        type: str
113                    chart_options:
114                        description:
115                            - Report chart options.
116                        type: str
117                        choices:
118                            - include-no-data
119                            - hide-title
120                            - show-caption
121                    column:
122                        description:
123                            - Report section column number.
124                        type: int
125                    content:
126                        description:
127                            - Report item text content.
128                        type: str
129                    description:
130                        description:
131                            - Description.
132                        type: str
133                    drill_down_items:
134                        description:
135                            - Control how drill down charts are shown.
136                        type: str
137                    drill_down_types:
138                        description:
139                            - Control whether keys from the parent being combined or not.
140                        type: str
141                    hide:
142                        description:
143                            - Enable/disable hide item in report.
144                        type: str
145                        choices:
146                            - enable
147                            - disable
148                    id:
149                        description:
150                            - Report item ID.
151                        required: true
152                        type: int
153                    img_src:
154                        description:
155                            - Report item image file name.
156                        type: str
157                    list:
158                        description:
159                            - Configure report list item.
160                        type: list
161                        suboptions:
162                            content:
163                                description:
164                                    - List entry content.
165                                type: str
166                            id:
167                                description:
168                                    - List entry ID.
169                                required: true
170                                type: int
171                    list_component:
172                        description:
173                            - Report item list component.
174                        type: str
175                        choices:
176                            - bullet
177                            - numbered
178                    misc_component:
179                        description:
180                            - Report item miscellaneous component.
181                        type: str
182                        choices:
183                            - hline
184                            - page-break
185                            - column-break
186                            - section-start
187                    parameters:
188                        description:
189                            - Parameters.
190                        type: list
191                        suboptions:
192                            id:
193                                description:
194                                    - ID.
195                                required: true
196                                type: int
197                            name:
198                                description:
199                                    - Field name that match field of parameters defined in dataset.
200                                type: str
201                            value:
202                                description:
203                                    - Value to replace corresponding field of parameters defined in dataset.
204                                type: str
205                    style:
206                        description:
207                            - Report item style.
208                        type: str
209                    table_caption_style:
210                        description:
211                            - Table chart caption style.
212                        type: str
213                    table_column_widths:
214                        description:
215                            - Report item table column widths.
216                        type: str
217                    table_even_row_style:
218                        description:
219                            - Table chart even row style.
220                        type: str
221                    table_head_style:
222                        description:
223                            - Table chart head style.
224                        type: str
225                    table_odd_row_style:
226                        description:
227                            - Table chart odd row style.
228                        type: str
229                    text_component:
230                        description:
231                            - Report item text component.
232                        type: str
233                        choices:
234                            - text
235                            - heading1
236                            - heading2
237                            - heading3
238                    title:
239                        description:
240                            - Report section title.
241                        type: str
242                    top_n:
243                        description:
244                            - Value of top.
245                        type: int
246                    type:
247                        description:
248                            - Report item type.
249                        type: str
250                        choices:
251                            - text
252                            - image
253                            - chart
254                            - misc
255            cutoff_option:
256                description:
257                    - Cutoff-option is either run-time or custom.
258                type: str
259                choices:
260                    - run-time
261                    - custom
262            cutoff_time:
263                description:
264                    - "Custom cutoff time to generate report [hh:mm]."
265                type: str
266            day:
267                description:
268                    - Schedule days of week to generate report.
269                type: str
270                choices:
271                    - sunday
272                    - monday
273                    - tuesday
274                    - wednesday
275                    - thursday
276                    - friday
277                    - saturday
278            description:
279                description:
280                    - Description.
281                type: str
282            email_recipients:
283                description:
284                    - Email recipients for generated reports.
285                type: str
286            email_send:
287                description:
288                    - Enable/disable sending emails after reports are generated.
289                type: str
290                choices:
291                    - enable
292                    - disable
293            format:
294                description:
295                    - Report format.
296                type: str
297                choices:
298                    - pdf
299            max_pdf_report:
300                description:
301                    - Maximum number of PDF reports to keep at one time (oldest report is overwritten).
302                type: int
303            name:
304                description:
305                    - Report layout name.
306                required: true
307                type: str
308            options:
309                description:
310                    - Report layout options.
311                type: str
312                choices:
313                    - include-table-of-content
314                    - auto-numbering-heading
315                    - view-chart-as-heading
316                    - show-html-navbar-before-heading
317                    - dummy-option
318            page:
319                description:
320                    - Configure report page.
321                type: dict
322                suboptions:
323                    column_break_before:
324                        description:
325                            - Report page auto column break before heading.
326                        type: str
327                        choices:
328                            - heading1
329                            - heading2
330                            - heading3
331                    footer:
332                        description:
333                            - Configure report page footer.
334                        type: dict
335                        suboptions:
336                            footer_item:
337                                description:
338                                    - Configure report footer item.
339                                type: list
340                                suboptions:
341                                    content:
342                                        description:
343                                            - Report item text content.
344                                        type: str
345                                    description:
346                                        description:
347                                            - Description.
348                                        type: str
349                                    id:
350                                        description:
351                                            - Report item ID.
352                                        required: true
353                                        type: int
354                                    img_src:
355                                        description:
356                                            - Report item image file name.
357                                        type: str
358                                    style:
359                                        description:
360                                            - Report item style.
361                                        type: str
362                                    type:
363                                        description:
364                                            - Report item type.
365                                        type: str
366                                        choices:
367                                            - text
368                                            - image
369                            style:
370                                description:
371                                    - Report footer style.
372                                type: str
373                    header:
374                        description:
375                            - Configure report page header.
376                        type: dict
377                        suboptions:
378                            header_item:
379                                description:
380                                    - Configure report header item.
381                                type: list
382                                suboptions:
383                                    content:
384                                        description:
385                                            - Report item text content.
386                                        type: str
387                                    description:
388                                        description:
389                                            - Description.
390                                        type: str
391                                    id:
392                                        description:
393                                            - Report item ID.
394                                        required: true
395                                        type: int
396                                    img_src:
397                                        description:
398                                            - Report item image file name.
399                                        type: str
400                                    style:
401                                        description:
402                                            - Report item style.
403                                        type: str
404                                    type:
405                                        description:
406                                            - Report item type.
407                                        type: str
408                                        choices:
409                                            - text
410                                            - image
411                            style:
412                                description:
413                                    - Report header style.
414                                type: str
415                    options:
416                        description:
417                            - Report page options.
418                        type: str
419                        choices:
420                            - header-on-first-page
421                            - footer-on-first-page
422                    page_break_before:
423                        description:
424                            - Report page auto page break before heading.
425                        type: str
426                        choices:
427                            - heading1
428                            - heading2
429                            - heading3
430                    paper:
431                        description:
432                            - Report page paper.
433                        type: str
434                        choices:
435                            - a4
436                            - letter
437            schedule_type:
438                description:
439                    - Report schedule type.
440                type: str
441                choices:
442                    - demand
443                    - daily
444                    - weekly
445            style_theme:
446                description:
447                    - Report style theme.
448                type: str
449            subtitle:
450                description:
451                    - Report subtitle.
452                type: str
453            time:
454                description:
455                    - "Schedule time to generate report [hh:mm]."
456                type: str
457            title:
458                description:
459                    - Report title.
460                type: str
461'''
462
463EXAMPLES = '''
464- hosts: localhost
465  vars:
466   host: "192.168.122.40"
467   username: "admin"
468   password: ""
469   vdom: "root"
470   ssl_verify: "False"
471  tasks:
472  - name: Report layout configuration.
473    fortios_report_layout:
474      host:  "{{ host }}"
475      username: "{{ username }}"
476      password: "{{ password }}"
477      vdom:  "{{ vdom }}"
478      https: "False"
479      state: "present"
480      report_layout:
481        body_item:
482         -
483            chart: "<your_own_value>"
484            chart_options: "include-no-data"
485            column: "6"
486            content: "<your_own_value>"
487            description: "<your_own_value>"
488            drill_down_items: "<your_own_value>"
489            drill_down_types: "<your_own_value>"
490            hide: "enable"
491            id:  "12"
492            img_src: "<your_own_value>"
493            list:
494             -
495                content: "<your_own_value>"
496                id:  "16"
497            list_component: "bullet"
498            misc_component: "hline"
499            parameters:
500             -
501                id:  "20"
502                name: "default_name_21"
503                value: "<your_own_value>"
504            style: "<your_own_value>"
505            table_caption_style: "<your_own_value>"
506            table_column_widths: "<your_own_value>"
507            table_even_row_style: "<your_own_value>"
508            table_head_style: "<your_own_value>"
509            table_odd_row_style: "<your_own_value>"
510            text_component: "text"
511            title: "<your_own_value>"
512            top_n: "31"
513            type: "text"
514        cutoff_option: "run-time"
515        cutoff_time: "<your_own_value>"
516        day: "sunday"
517        description: "<your_own_value>"
518        email_recipients: "<your_own_value>"
519        email_send: "enable"
520        format: "pdf"
521        max_pdf_report: "40"
522        name: "default_name_41"
523        options: "include-table-of-content"
524        page:
525            column_break_before: "heading1"
526            footer:
527                footer_item:
528                 -
529                    content: "<your_own_value>"
530                    description: "<your_own_value>"
531                    id:  "49"
532                    img_src: "<your_own_value>"
533                    style: "<your_own_value>"
534                    type: "text"
535                style: "<your_own_value>"
536            header:
537                header_item:
538                 -
539                    content: "<your_own_value>"
540                    description: "<your_own_value>"
541                    id:  "58"
542                    img_src: "<your_own_value>"
543                    style: "<your_own_value>"
544                    type: "text"
545                style: "<your_own_value>"
546            options: "header-on-first-page"
547            page_break_before: "heading1"
548            paper: "a4"
549        schedule_type: "demand"
550        style_theme: "<your_own_value>"
551        subtitle: "<your_own_value>"
552        time: "<your_own_value>"
553        title: "<your_own_value>"
554'''
555
556RETURN = '''
557build:
558  description: Build number of the fortigate image
559  returned: always
560  type: str
561  sample: '1547'
562http_method:
563  description: Last method used to provision the content into FortiGate
564  returned: always
565  type: str
566  sample: 'PUT'
567http_status:
568  description: Last result given by FortiGate on last operation applied
569  returned: always
570  type: str
571  sample: "200"
572mkey:
573  description: Master key (id) used in the last call to FortiGate
574  returned: success
575  type: str
576  sample: "id"
577name:
578  description: Name of the table used to fulfill the request
579  returned: always
580  type: str
581  sample: "urlfilter"
582path:
583  description: Path of the table used to fulfill the request
584  returned: always
585  type: str
586  sample: "webfilter"
587revision:
588  description: Internal revision number
589  returned: always
590  type: str
591  sample: "17.0.2.10658"
592serial:
593  description: Serial number of the unit
594  returned: always
595  type: str
596  sample: "FGVMEVYYQT3AB5352"
597status:
598  description: Indication of the operation's result
599  returned: always
600  type: str
601  sample: "success"
602vdom:
603  description: Virtual domain used
604  returned: always
605  type: str
606  sample: "root"
607version:
608  description: Version of the FortiGate
609  returned: always
610  type: str
611  sample: "v5.6.3"
612
613'''
614
615from ansible.module_utils.basic import AnsibleModule
616from ansible.module_utils.connection import Connection
617from ansible.module_utils.network.fortios.fortios import FortiOSHandler
618from ansible.module_utils.network.fortimanager.common import FAIL_SOCKET_MSG
619
620
621def login(data, fos):
622    host = data['host']
623    username = data['username']
624    password = data['password']
625    ssl_verify = data['ssl_verify']
626
627    fos.debug('on')
628    if 'https' in data and not data['https']:
629        fos.https('off')
630    else:
631        fos.https('on')
632
633    fos.login(host, username, password, verify=ssl_verify)
634
635
636def filter_report_layout_data(json):
637    option_list = ['body_item', 'cutoff_option', 'cutoff_time',
638                   'day', 'description', 'email_recipients',
639                   'email_send', 'format', 'max_pdf_report',
640                   'name', 'options', 'page',
641                   'schedule_type', 'style_theme', 'subtitle',
642                   'time', 'title']
643    dictionary = {}
644
645    for attribute in option_list:
646        if attribute in json and json[attribute] is not None:
647            dictionary[attribute] = json[attribute]
648
649    return dictionary
650
651
652def underscore_to_hyphen(data):
653    if isinstance(data, list):
654        for elem in data:
655            elem = underscore_to_hyphen(elem)
656    elif isinstance(data, dict):
657        new_data = {}
658        for k, v in data.items():
659            new_data[k.replace('_', '-')] = underscore_to_hyphen(v)
660        data = new_data
661
662    return data
663
664
665def report_layout(data, fos):
666    vdom = data['vdom']
667    if 'state' in data and data['state']:
668        state = data['state']
669    elif 'state' in data['report_layout'] and data['report_layout']:
670        state = data['report_layout']['state']
671    else:
672        state = True
673    report_layout_data = data['report_layout']
674    filtered_data = underscore_to_hyphen(filter_report_layout_data(report_layout_data))
675
676    if state == "present":
677        return fos.set('report',
678                       'layout',
679                       data=filtered_data,
680                       vdom=vdom)
681
682    elif state == "absent":
683        return fos.delete('report',
684                          'layout',
685                          mkey=filtered_data['name'],
686                          vdom=vdom)
687
688
689def is_successful_status(status):
690    return status['status'] == "success" or \
691        status['http_method'] == "DELETE" and status['http_status'] == 404
692
693
694def fortios_report(data, fos):
695
696    if data['report_layout']:
697        resp = report_layout(data, fos)
698
699    return not is_successful_status(resp), \
700        resp['status'] == "success", \
701        resp
702
703
704def main():
705    fields = {
706        "host": {"required": False, "type": "str"},
707        "username": {"required": False, "type": "str"},
708        "password": {"required": False, "type": "str", "default": "", "no_log": True},
709        "vdom": {"required": False, "type": "str", "default": "root"},
710        "https": {"required": False, "type": "bool", "default": True},
711        "ssl_verify": {"required": False, "type": "bool", "default": True},
712        "state": {"required": False, "type": "str",
713                  "choices": ["present", "absent"]},
714        "report_layout": {
715            "required": False, "type": "dict", "default": None,
716            "options": {
717                "state": {"required": False, "type": "str",
718                          "choices": ["present", "absent"]},
719                "body_item": {"required": False, "type": "list",
720                              "options": {
721                                  "chart": {"required": False, "type": "str"},
722                                  "chart_options": {"required": False, "type": "str",
723                                                    "choices": ["include-no-data", "hide-title", "show-caption"]},
724                                  "column": {"required": False, "type": "int"},
725                                  "content": {"required": False, "type": "str"},
726                                  "description": {"required": False, "type": "str"},
727                                  "drill_down_items": {"required": False, "type": "str"},
728                                  "drill_down_types": {"required": False, "type": "str"},
729                                  "hide": {"required": False, "type": "str",
730                                           "choices": ["enable", "disable"]},
731                                  "id": {"required": True, "type": "int"},
732                                  "img_src": {"required": False, "type": "str"},
733                                  "list": {"required": False, "type": "list",
734                                           "options": {
735                                               "content": {"required": False, "type": "str"},
736                                               "id": {"required": True, "type": "int"}
737                                           }},
738                                  "list_component": {"required": False, "type": "str",
739                                                     "choices": ["bullet", "numbered"]},
740                                  "misc_component": {"required": False, "type": "str",
741                                                     "choices": ["hline", "page-break", "column-break",
742                                                                 "section-start"]},
743                                  "parameters": {"required": False, "type": "list",
744                                                 "options": {
745                                                     "id": {"required": True, "type": "int"},
746                                                     "name": {"required": False, "type": "str"},
747                                                     "value": {"required": False, "type": "str"}
748                                                 }},
749                                  "style": {"required": False, "type": "str"},
750                                  "table_caption_style": {"required": False, "type": "str"},
751                                  "table_column_widths": {"required": False, "type": "str"},
752                                  "table_even_row_style": {"required": False, "type": "str"},
753                                  "table_head_style": {"required": False, "type": "str"},
754                                  "table_odd_row_style": {"required": False, "type": "str"},
755                                  "text_component": {"required": False, "type": "str",
756                                                     "choices": ["text", "heading1", "heading2",
757                                                                 "heading3"]},
758                                  "title": {"required": False, "type": "str"},
759                                  "top_n": {"required": False, "type": "int"},
760                                  "type": {"required": False, "type": "str",
761                                           "choices": ["text", "image", "chart",
762                                                       "misc"]}
763                              }},
764                "cutoff_option": {"required": False, "type": "str",
765                                  "choices": ["run-time", "custom"]},
766                "cutoff_time": {"required": False, "type": "str"},
767                "day": {"required": False, "type": "str",
768                        "choices": ["sunday", "monday", "tuesday",
769                                    "wednesday", "thursday", "friday",
770                                    "saturday"]},
771                "description": {"required": False, "type": "str"},
772                "email_recipients": {"required": False, "type": "str"},
773                "email_send": {"required": False, "type": "str",
774                               "choices": ["enable", "disable"]},
775                "format": {"required": False, "type": "str",
776                           "choices": ["pdf"]},
777                "max_pdf_report": {"required": False, "type": "int"},
778                "name": {"required": True, "type": "str"},
779                "options": {"required": False, "type": "str",
780                            "choices": ["include-table-of-content", "auto-numbering-heading", "view-chart-as-heading",
781                                        "show-html-navbar-before-heading", "dummy-option"]},
782                "page": {"required": False, "type": "dict",
783                         "options": {
784                             "column_break_before": {"required": False, "type": "str",
785                                                     "choices": ["heading1", "heading2", "heading3"]},
786                             "footer": {"required": False, "type": "dict",
787                                        "options": {
788                                            "footer_item": {"required": False, "type": "list",
789                                                            "options": {
790                                                                "content": {"required": False, "type": "str"},
791                                                                "description": {"required": False, "type": "str"},
792                                                                "id": {"required": True, "type": "int"},
793                                                                "img_src": {"required": False, "type": "str"},
794                                                                "style": {"required": False, "type": "str"},
795                                                                "type": {"required": False, "type": "str",
796                                                                         "choices": ["text", "image"]}
797                                                            }},
798                                            "style": {"required": False, "type": "str"}
799                                        }},
800                             "header": {"required": False, "type": "dict",
801                                        "options": {
802                                            "header_item": {"required": False, "type": "list",
803                                                            "options": {
804                                                                "content": {"required": False, "type": "str"},
805                                                                "description": {"required": False, "type": "str"},
806                                                                "id": {"required": True, "type": "int"},
807                                                                "img_src": {"required": False, "type": "str"},
808                                                                "style": {"required": False, "type": "str"},
809                                                                "type": {"required": False, "type": "str",
810                                                                         "choices": ["text", "image"]}
811                                                            }},
812                                            "style": {"required": False, "type": "str"}
813                                        }},
814                             "options": {"required": False, "type": "str",
815                                         "choices": ["header-on-first-page", "footer-on-first-page"]},
816                             "page_break_before": {"required": False, "type": "str",
817                                                   "choices": ["heading1", "heading2", "heading3"]},
818                             "paper": {"required": False, "type": "str",
819                                       "choices": ["a4", "letter"]}
820                         }},
821                "schedule_type": {"required": False, "type": "str",
822                                  "choices": ["demand", "daily", "weekly"]},
823                "style_theme": {"required": False, "type": "str"},
824                "subtitle": {"required": False, "type": "str"},
825                "time": {"required": False, "type": "str"},
826                "title": {"required": False, "type": "str"}
827
828            }
829        }
830    }
831
832    module = AnsibleModule(argument_spec=fields,
833                           supports_check_mode=False)
834
835    # legacy_mode refers to using fortiosapi instead of HTTPAPI
836    legacy_mode = 'host' in module.params and module.params['host'] is not None and \
837                  'username' in module.params and module.params['username'] is not None and \
838                  'password' in module.params and module.params['password'] is not None
839
840    if not legacy_mode:
841        if module._socket_path:
842            connection = Connection(module._socket_path)
843            fos = FortiOSHandler(connection)
844
845            is_error, has_changed, result = fortios_report(module.params, fos)
846        else:
847            module.fail_json(**FAIL_SOCKET_MSG)
848    else:
849        try:
850            from fortiosapi import FortiOSAPI
851        except ImportError:
852            module.fail_json(msg="fortiosapi module is required")
853
854        fos = FortiOSAPI()
855
856        login(module.params, fos)
857        is_error, has_changed, result = fortios_report(module.params, fos)
858        fos.logout()
859
860    if not is_error:
861        module.exit_json(changed=has_changed, meta=result)
862    else:
863        module.fail_json(msg="Error in repo", meta=result)
864
865
866if __name__ == '__main__':
867    main()
868