Completed
Push — master ( 52721c...da306e )
by Jaspar
18s queued 14s
created

TargetsMixin.modify_target()   F

Complexity

Conditions 18

Size

Total Lines 108
Code Lines 62

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 18
eloc 62
nop 17
dl 0
loc 108
rs 1.2
c 0
b 0
f 0

How to fix   Long Method    Complexity    Many Parameters   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Complexity

Complex classes like gvm.protocols.gmpv214.entities.targets.TargetsMixin.modify_target() often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

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
# pylint: disable=arguments-differ, unused-import
20
21
from typing import Any, List, Optional
22
23
from gvm.errors import RequiredArgument, InvalidArgumentType
24
from gvm.protocols.gmpv208.entities.targets import (
25
    get_alive_test_from_string,
26
    TargetsMixin as Gmp208TargetsMixin,
27
    AliveTest,
28
)
29
from gvm.utils import to_bool, to_comma_list
30
from gvm.xml import XmlCommand
31
32
33
class TargetsMixin(Gmp208TargetsMixin):
34
    def create_target(
35
        self,
36
        name: str,
37
        *,
38
        asset_hosts_filter: Optional[str] = None,
39
        hosts: Optional[List[str]] = None,
40
        comment: Optional[str] = None,
41
        exclude_hosts: Optional[List[str]] = None,
42
        ssh_credential_id: Optional[str] = None,
43
        ssh_credential_port: Optional[int] = None,
44
        smb_credential_id: Optional[str] = None,
45
        esxi_credential_id: Optional[str] = None,
46
        snmp_credential_id: Optional[str] = None,
47
        alive_test: Optional[AliveTest] = None,
48
        allow_simultaneous_ips: Optional[bool] = None,
49
        reverse_lookup_only: Optional[bool] = None,
50
        reverse_lookup_unify: Optional[bool] = None,
51
        port_range: Optional[str] = None,
52
        port_list_id: Optional[str] = None,
53
    ) -> Any:
54
        """Create a new target
55
56
        Arguments:
57
            name: Name of the target
58
            asset_hosts_filter: Filter to select target host from assets hosts
59
            hosts: List of hosts addresses to scan
60
            exclude_hosts: List of hosts addresses to exclude from scan
61
            comment: Comment for the target
62
            ssh_credential_id: UUID of a ssh credential to use on target
63
            ssh_credential_port: The port to use for ssh credential
64
            smb_credential_id: UUID of a smb credential to use on target
65
            snmp_credential_id: UUID of a snmp credential to use on target
66
            esxi_credential_id: UUID of a esxi credential to use on target
67
            alive_test: Which alive test to use
68
            allow_simultaneous_ips: Whether to scan multiple IPs of the
69
                same host simultaneously
70
            reverse_lookup_only: Whether to scan only hosts that have names
71
            reverse_lookup_unify: Whether to scan only one IP when multiple IPs
72
                have the same name.
73
            port_range: Port range for the target
74
            port_list_id: UUID of the port list to use on target
75
76
        Returns:
77
            The response. See :py:meth:`send_command` for details.
78
        """
79
        if not name:
80
            raise RequiredArgument(
81
                function=self.create_target.__name__, argument='name'
82
            )
83
84
        cmd = XmlCommand("create_target")
85
        _xmlname = cmd.add_element("name", name)
86
87
        if asset_hosts_filter:
88
            cmd.add_element(
89
                "asset_hosts", attrs={"filter": str(asset_hosts_filter)}
90
            )
91
        elif hosts:
92
            cmd.add_element("hosts", to_comma_list(hosts))
93
        else:
94
            raise RequiredArgument(
95
                function=self.create_target.__name__,
96
                argument='hosts or asset_hosts_filter',
97
            )
98
99
        if comment:
100
            cmd.add_element("comment", comment)
101
102
        if exclude_hosts:
103
            cmd.add_element("exclude_hosts", to_comma_list(exclude_hosts))
104
105
        if ssh_credential_id:
106
            _xmlssh = cmd.add_element(
107
                "ssh_credential", attrs={"id": ssh_credential_id}
108
            )
109
            if ssh_credential_port:
110
                _xmlssh.add_element("port", str(ssh_credential_port))
111
112
        if smb_credential_id:
113
            cmd.add_element("smb_credential", attrs={"id": smb_credential_id})
114
115
        if esxi_credential_id:
116
            cmd.add_element("esxi_credential", attrs={"id": esxi_credential_id})
117
118
        if snmp_credential_id:
119
            cmd.add_element("snmp_credential", attrs={"id": snmp_credential_id})
120
121
        if alive_test:
122
            if not isinstance(alive_test, AliveTest):
123
                raise InvalidArgumentType(
124
                    function=self.create_target.__name__,
125
                    argument='alive_test',
126
                    arg_type=AliveTest.__name__,
127
                )
128
129
            cmd.add_element("alive_tests", alive_test.value)
130
131
        if allow_simultaneous_ips is not None:
132
            cmd.add_element(
133
                "allow_simultaneous_ips", to_bool(allow_simultaneous_ips)
134
            )
135
136
        if reverse_lookup_only is not None:
137
            cmd.add_element("reverse_lookup_only", to_bool(reverse_lookup_only))
138
139
        if reverse_lookup_unify is not None:
140
            cmd.add_element(
141
                "reverse_lookup_unify", to_bool(reverse_lookup_unify)
142
            )
143
144
        if port_range:
145
            cmd.add_element("port_range", port_range)
146
147
        if port_list_id:
148
            cmd.add_element("port_list", attrs={"id": port_list_id})
149
150
        return self._send_xml_command(cmd)
151
152
    def modify_target(
153
        self,
154
        target_id: str,
155
        *,
156
        name: Optional[str] = None,
157
        comment: Optional[str] = None,
158
        hosts: Optional[List[str]] = None,
159
        exclude_hosts: Optional[List[str]] = None,
160
        ssh_credential_id: Optional[str] = None,
161
        ssh_credential_port: Optional[bool] = None,
162
        smb_credential_id: Optional[str] = None,
163
        esxi_credential_id: Optional[str] = None,
164
        snmp_credential_id: Optional[str] = None,
165
        alive_test: Optional[AliveTest] = None,
166
        allow_simultaneous_ips: Optional[bool] = None,
167
        reverse_lookup_only: Optional[bool] = None,
168
        reverse_lookup_unify: Optional[bool] = None,
169
        port_list_id: Optional[str] = None,
170
    ) -> Any:
171
        """Modifies an existing target.
172
173
        Arguments:
174
            target_id: ID of target to modify.
175
            comment: Comment on target.
176
            name: Name of target.
177
            hosts: List of target hosts.
178
            exclude_hosts: A list of hosts to exclude.
179
            ssh_credential_id: UUID of SSH credential to use on target.
180
            ssh_credential_port: The port to use for ssh credential
181
            smb_credential_id: UUID of SMB credential to use on target.
182
            esxi_credential_id: UUID of ESXi credential to use on target.
183
            snmp_credential_id: UUID of SNMP credential to use on target.
184
            port_list_id: UUID of port list describing ports to scan.
185
            alive_test: Which alive tests to use.
186
            allow_simultaneous_ips: Whether to scan multiple IPs of the
187
                same host simultaneously
188
            reverse_lookup_only: Whether to scan only hosts that have names.
189
            reverse_lookup_unify: Whether to scan only one IP when multiple IPs
190
                have the same name.
191
192
        Returns:
193
            The response. See :py:meth:`send_command` for details.
194
        """
195
        if not target_id:
196
            raise RequiredArgument(
197
                function=self.modify_target.__name__, argument='target_id'
198
            )
199
200
        cmd = XmlCommand("modify_target")
201
        cmd.set_attribute("target_id", target_id)
202
203
        if comment:
204
            cmd.add_element("comment", comment)
205
206
        if name:
207
            cmd.add_element("name", name)
208
209
        if hosts:
210
            cmd.add_element("hosts", to_comma_list(hosts))
211
            if exclude_hosts is None:
212
                exclude_hosts = ['']
213
214
        if exclude_hosts:
215
            cmd.add_element("exclude_hosts", to_comma_list(exclude_hosts))
216
217
        if alive_test:
218
            if not isinstance(alive_test, AliveTest):
219
                raise InvalidArgumentType(
220
                    function=self.modify_target.__name__,
221
                    argument='alive_test',
222
                    arg_type=AliveTest.__name__,
223
                )
224
            cmd.add_element("alive_tests", alive_test.value)
225
226
        if ssh_credential_id:
227
            _xmlssh = cmd.add_element(
228
                "ssh_credential", attrs={"id": ssh_credential_id}
229
            )
230
231
            if ssh_credential_port:
232
                _xmlssh.add_element("port", str(ssh_credential_port))
233
234
        if smb_credential_id:
235
            cmd.add_element("smb_credential", attrs={"id": smb_credential_id})
236
237
        if esxi_credential_id:
238
            cmd.add_element("esxi_credential", attrs={"id": esxi_credential_id})
239
240
        if snmp_credential_id:
241
            cmd.add_element("snmp_credential", attrs={"id": snmp_credential_id})
242
243
        if allow_simultaneous_ips is not None:
244
            cmd.add_element(
245
                "allow_simultaneous_ips", to_bool(allow_simultaneous_ips)
246
            )
247
248
        if reverse_lookup_only is not None:
249
            cmd.add_element("reverse_lookup_only", to_bool(reverse_lookup_only))
250
251
        if reverse_lookup_unify is not None:
252
            cmd.add_element(
253
                "reverse_lookup_unify", to_bool(reverse_lookup_unify)
254
            )
255
256
        if port_list_id:
257
            cmd.add_element("port_list", attrs={"id": port_list_id})
258
259
        return self._send_xml_command(cmd)
260