Passed
Pull Request — master (#370)
by Jaspar
01:48
created

create-monthly-report.gmp.main()   A

Complexity

Conditions 3

Size

Total Lines 37
Code Lines 21

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 21
nop 2
dl 0
loc 37
rs 9.376
c 0
b 0
f 0
1
# -*- coding: utf-8 -*-
2
# Copyright (C) 2021 Greenbone Networks GmbH
3
#
4
# SPDX-License-Identifier: GPL-3.0-or-later
5
#
6
# This program is free software: you can redistribute it and/or modify
7
# it under the terms of the GNU General Public License as published by
8
# the Free Software Foundation, either version 3 of the License, or
9
# (at your option) any later version.
10
#
11
# This program is distributed in the hope that it will be useful,
12
# but WITHOUT ANY WARRANTY; without even the implied warranty of
13
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
# GNU General Public License for more details.
15
#
16
# You should have received a copy of the GNU General Public License
17
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
18
19
from uuid import UUID
20
from typing import List
21
from datetime import date, timedelta
22
from argparse import ArgumentParser, RawTextHelpFormatter
23
24
from gvmtools.helper import generate_uuid, error_and_exit
25
26
from lxml import etree as e
27
28
from gvm.xml import pretty_print
29
30
HELP_TEXT = ''
31
32
33
def get_last_reports_from_tasks(gmp, from_date, to_date, tags: List):
34
    """ Get the last reports from the tasks in the given time period """
35
36
    task_filter = 'rows=-1 '
37
    period_filter = 'created>{0} and created<{1}'.format(
38
        from_date.isoformat(), to_date.isoformat()
39
    )
40
    filter_parts = []
41
    if tags:
42
        for tag in tags:
43
            filter_parts.append('{} and {}'.format(period_filter, tag))
44
45
        tags_filter = ' or '.join(filter_parts)
46
        task_filter += tags_filter
47
    else:
48
        task_filter += period_filter
49
50
    print('Filtering the task with the filter term [{}]'.format(task_filter))
51
52
    tasks_xml = gmp.get_tasks(filter=task_filter)
53
    reports = []
54
    for report in tasks_xml.xpath('task/last_report/report/@id'):
55
        reports.append(str(report))
56
57
    # remove duplicates ... just in case
58
    reports = list(dict.fromkeys(reports))
59
60
    return reports
61
62
63
def combine_reports(gmp, reports: List, filter_term: str):
64
    """ Combining the filtered ports, results and hosts of the given report ids into one new report."""
65
    new_uuid = generate_uuid()
66
    combined_report = e.Element(
67
        'report',
68
        {
69
            'id': new_uuid,
70
            'format_id': 'd5da9f67-8551-4e51-807b-b6a873d70e34',
71
            'extension': 'xml',
72
            'content_type': 'text/xml',
73
        },
74
    )
75
    report_elem = e.Element('report', {'id': new_uuid})
76
77
    ports_elem = e.Element('ports', {'start': '1', 'max': '-1'})
78
    results_elem = e.Element('results', {'start': '1', 'max': '-1'})
79
    combined_report.append(report_elem)
80
    report_elem.append(results_elem)
81
82
    hosts = []
83
    for report in reports:
84
        current_report = gmp.get_report(
85
            report, filter=filter_term, details=True
86
        )[0]
87
        pretty_print(current_report.find('report').find('result_count'))
88
        for port in current_report.xpath('report/ports/port'):
89
            ports_elem.append(port)
90
        for result in current_report.xpath('report/results/result'):
91
            results_elem.append(result)
92
        for host in current_report.xpath('report/host'):
93
            report_elem.append(host)
94
95
    return combined_report
96
97
98
def send_report(gmp, combined_report, period_start, period_end):
99
    """Creating a container task and sending the combined report to the GSM
100
101
    gmp: the GMP object
102
    combined_report: the combined report xml object
103
    period_start: the start date
104
    period_end: the end date
105
    """
106
107
    task_name = 'Consolidated Report [{} - {}]'.format(period_start, period_end)
108
109
    res = gmp.create_container_task(
110
        name=task_name, comment='Created with gvm-tools.'
111
    )
112
113
    task_id = res.xpath('//@id')[0]
114
115
    combined_report = e.tostring(combined_report)
116
117
    res = gmp.import_report(combined_report, task_id=task_id)
118
119
    return res.xpath('//@id')[0]
120
121
122
def parse_tags(tags: List):
123
    """Parsing and validating the given tags
124
125
    tags (List): A list containing tags:
126
                 name, tag-id, name=value
127
128
    Returns a list containing tag="name", tag_id="id" ...
129
    """
130
    filter_tags = []
131
    for tag in tags:
132
        try:
133
            UUID(tag, version=4)
134
            filter_tags.append('tag_id="{}"'.format(tag))
135
        except ValueError:
136
            filter_tags.append('tag="{}"'.format(tag))
137
138
    return filter_tags
139
140
141
def parse_period(period: List):
142
    """Parsing and validating the given time period
143
144
    period (List): A list with two entries containing
145
                   dates in the format yyyy/mm/dd
146
147
    Returns two date-objects containing the passed dates
148
    """
149
    try:
150
        s_year, s_month, s_day = map(int, period[0].split('/'))
151
    except ValueError as e:
152
        error_and_exit(
153
            'Start date [{}] is not a correct date format:\n{}'.format(
154
                period[0], e.args[0]
155
            )
156
        )
157
    try:
158
        e_year, e_month, e_day = map(int, period[1].split('/'))
159
    except ValueError as e:
160
        error_and_exit(
161
            'End date [{}] is not a correct date format:\n{}'.format(
162
                period[1], e.args[0]
163
            )
164
        )
165
166
    try:
167
        period_start = date(s_year, s_month, s_day)
168
    except ValueError as e:
169
        error_and_exit('Start date: {}'.format(e.args[0]))
170
171
    try:
172
        period_end = date(e_year, e_month, e_day)
173
    except ValueError as e:
174
        error_and_exit('End date: {}'.format(e.args[0]))
175
176
    if period_end < period_start:
177
        error_and_exit('The start date seems to after the end date.')
178
179
    return period_start, period_end
180
181
182
def parse_args(args):  # pylint: disable=unused-argument
183
    """ Parsing args ... """
184
185
    parser = ArgumentParser(
186
        prefix_chars='+',
187
        add_help=False,
188
        formatter_class=RawTextHelpFormatter,
189
        description=HELP_TEXT,
190
    )
191
192
    parser.add_argument(
193
        '+h',
194
        '++help',
195
        action='help',
196
        help='Show this help message and exit.',
197
    )
198
199
    parser.add_argument(
200
        '+p',
201
        '++period',
202
        nargs=2,
203
        type=str,
204
        required=True,
205
        dest='period',
206
        help='Choose a time period that is filtering the tasks. Use the date format YYYY/MM/DD.',
207
    )
208
209
    parser.add_argument(
210
        '+t',
211
        '++tags',
212
        nargs='+',
213
        type=str,
214
        dest='tags',
215
        help=(
216
            'Filter the tasks by given tag(s).\n'
217
            'If you pass more than on tag, they will be concatenated with '
218
            or '\n'
219
            'You can pass tag names, tag ids or tag name=value to this argument'
220
        ),
221
    )
222
223
    parser.add_argument(
224
        '+f',
225
        '++filter',
226
        nargs='+',
227
        type=str,
228
        dest='filter',
229
        help='Filter the results by given filter(s).',
230
    )
231
232
    script_args, _ = parser.parse_known_args()
233
    return script_args
234
235
236
def main(gmp, args):
237
    # pylint: disable=undefined-variable
238
239
    parsed_args = parse_args(args)
240
241
    period_start, period_end = parse_period(parsed_args.period)
242
243
    print(
244
        'Combining reports from tasks within the time period [{}, {}]'.format(
245
            period_start, period_end
246
        )
247
    )
248
249
    filter_tags = None
250
    if parsed_args.tags:
251
        filter_tags = parse_tags(parsed_args.tags)
252
253
    reports = get_last_reports_from_tasks(
254
        gmp, period_start, period_end, filter_tags
255
    )
256
257
    print("Combining {} found reports.".format(len(reports)))
258
259
    filter_term = ''
260
    if parsed_args.filter:
261
        filter_term = ' '.join(parsed_args.filter)
262
        print(
263
            'Filtering the results by the following filter term [{}]'.format(
264
                filter_term
265
            )
266
        )
267
    else:
268
        print('No result filter given.')
269
270
    combined_report = combine_reports(gmp, reports, filter_term)
271
272
    send_report(gmp, combined_report, period_start, period_end)
273
274
275
if __name__ == '__gmp__':
276
    main(gmp, args)
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable gmp does not seem to be defined.
Loading history...
Comprehensibility Best Practice introduced by
The variable args does not seem to be defined.
Loading history...
277