Passed
Pull Request — master (#370)
by Jaspar
02:10
created

create-monthly-report.gmp.parse_period()   B

Complexity

Conditions 6

Size

Total Lines 33
Code Lines 24

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
eloc 24
nop 1
dl 0
loc 33
rs 8.3706
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 typing import List
20
from datetime import date, timedelta
21
from argparse import ArgumentParser, RawTextHelpFormatter
22
23
from gvmtools.helper import generate_uuid, error_and_exit
24
25
from lxml import etree as e
26
27
from gvm.xml import pretty_print
28
29
HELP_TEXT = ""
30
31
32
def get_last_reports_from_tasks(gmp, from_date, to_date):
33
    """ Get the last reports from the tasks in the given time period """
34
35
    task_filter = "rows=-1 and created>{0} and created<{1}".format(
36
        from_date.isoformat(), to_date.isoformat()
37
    )
38
39
    tasks_xml = gmp.get_tasks(filter=task_filter)
40
    reports = []
41
    for report in tasks_xml.xpath('task/last_report/report/@id'):
42
        reports.append(str(report))
43
44
    print(reports)
45
    return reports
46
47
48
def create_filter(gmp, filter_term, date):
49
    filter_name = "Filter for Monthly Report ({})".format(date)
50
51
    res = gmp.create_filter(term=filter_term, name=filter_name)
52
    return res.xpath('//@id')[0]
53
54
55
def combine_reports(gmp, reports: List, filter_term: str):
56
    """ Combining the filtered ports, results and hosts of the given report ids into one new report."""
57
    new_uuid = generate_uuid()
58
    combined_report = e.Element(
59
        'report',
60
        {
61
            'id': new_uuid,
62
            'format_id': 'd5da9f67-8551-4e51-807b-b6a873d70e34',
63
            'extension': 'xml',
64
            'content_type': 'text/xml',
65
        },
66
    )
67
    report_elem = e.Element('report', {'id': new_uuid})
68
69
    ports_elem = e.Element('ports', {'start': '1', 'max': '-1'})
70
    results_elem = e.Element('results', {'start': '1', 'max': '-1'})
71
    combined_report.append(report_elem)
72
    report_elem.append(results_elem)
73
74
    hosts = []
75
    for report in reports:
76
        current_report = gmp.get_report(
77
            report, filter=filter_term, details=True
78
        )[0]
79
        pretty_print(current_report.find('report').find('result_count'))
80
        for port in current_report.xpath('report/ports/port'):
81
            ports_elem.append(port)
82
        for result in current_report.xpath('report/results/result'):
83
            results_elem.append(result)
84
        for host in current_report.xpath('report/host'):
85
            report_elem.append(host)
86
87
    return combined_report
88
89
90
def send_report(gmp, combined_report, period_start, period_end):
91
    """ Creating a container task and sending the combined report to the GSM """
92
93
    task_name = "Consolidated Report [{} - {}]".format(period_start, period_end)
94
95
    res = gmp.create_container_task(
96
        name=task_name, comment="Created with gvm-tools."
97
    )
98
99
    task_id = res.xpath('//@id')[0]
100
101
    combined_report = e.tostring(combined_report)
102
103
    res = gmp.import_report(combined_report, task_id=task_id)
104
105
    return res.xpath('//@id')[0]
106
107
108
def parse_period(period: List):
109
    """ Parsing and validating the given time period """
110
    try:
111
        s_year, s_month, s_day = map(int, period[0].split('/'))
112
    except ValueError as e:
113
        error_and_exit(
114
            "Start date [{}] is not a correct date format:\n{}".format(
115
                period[0], e.args[0]
116
            )
117
        )
118
    try:
119
        e_year, e_month, e_day = map(int, period[1].split('/'))
120
    except ValueError as e:
121
        error_and_exit(
122
            "End date [{}] is not a correct date format:\n{}".format(
123
                period[1], e.args[0]
124
            )
125
        )
126
127
    try:
128
        period_start = date(s_year, s_month, s_day)
129
    except ValueError as e:
130
        error_and_exit("Start date: {}".format(e.args[0]))
131
132
    try:
133
        period_end = date(e_year, e_month, e_day)
134
    except ValueError as e:
135
        error_and_exit("End date: {}".format(e.args[0]))
136
137
    if period_end < period_start:
138
        error_and_exit("The start date seems to after the end date.")
139
140
    return period_start, period_end
141
142
143
def parse_args(args):  # pylint: disable=unused-argument
144
    parser = ArgumentParser(
145
        prefix_chars="+",
146
        add_help=False,
147
        formatter_class=RawTextHelpFormatter,
148
        description=HELP_TEXT,
149
    )
150
151
    parser.add_argument(
152
        "+h",
153
        "++help",
154
        action="help",
155
        help="Show this help message and exit.",
156
    )
157
158
    parser.add_argument(
159
        "+p",
160
        "++period",
161
        nargs=2,
162
        type=str,
163
        required=True,
164
        dest="period",
165
        help="Choose a time period that is filtering the tasks. Use the date format YYYY/MM/DD.",
166
    )
167
168
    parser.add_argument(
169
        "+t",
170
        "++tags",
171
        nargs='+',
172
        type=str,
173
        dest="tags",
174
        help="Filter the tasks by given tag(s).",
175
    )
176
177
    parser.add_argument(
178
        "+f",
179
        "++filter",
180
        nargs='+',
181
        type=str,
182
        dest="filter",
183
        help="Filter the results by given filter(s).",
184
    )
185
186
    script_args, _ = parser.parse_known_args()
187
    return script_args
188
189
190
def main(gmp, args):
191
    # pylint: disable=undefined-variable
192
193
    parsed_args = parse_args(args)
194
195
    period_start, period_end = parse_period(parsed_args.period)
196
197
    print(
198
        "Combining reports from tasks within the time period [{}, {}]".format(
199
            period_start, period_end
200
        )
201
    )
202
203
    filter_term = ""
204
    if parsed_args.filter:
205
        filter_term = ' '.join(parsed_args.filter)
206
        print(
207
            "Filtering the results by the following filter term [{}]".format(
208
                filter_term
209
            )
210
        )
211
    else:
212
        print("No result filter given.")
213
214
    reports = get_last_reports_from_tasks(gmp, period_start, period_end)
215
216
    combined_report = combine_reports(gmp, reports, filter_term)
217
218
    send_report(gmp, combined_report, period_start, period_end)
219
220
221
if __name__ == '__gmp__':
222
    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...
223