Skip to content

Commit 02acd27

Browse files
Zuulopenstack-gerrit
authored andcommitted
Merge "Add port ranges on floating ip portforwardings cli"
2 parents 3478873 + bced485 commit 02acd27

File tree

4 files changed

+318
-57
lines changed

4 files changed

+318
-57
lines changed

openstackclient/network/v2/floating_ip_port_forwarding.py

Lines changed: 70 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,61 @@
2525
LOG = logging.getLogger(__name__)
2626

2727

28+
def validate_ports_diff(ports):
29+
if len(ports) == 0:
30+
return 0
31+
32+
ports_diff = ports[-1] - ports[0]
33+
if ports_diff < 0:
34+
msg = _("The last number in port range must be"
35+
" greater or equal to the first")
36+
raise exceptions.CommandError(msg)
37+
return ports_diff
38+
39+
40+
def validate_ports_match(internal_ports, external_ports):
41+
internal_ports_diff = validate_ports_diff(internal_ports)
42+
external_ports_diff = validate_ports_diff(external_ports)
43+
44+
if internal_ports_diff != 0 and internal_ports_diff != external_ports_diff:
45+
msg = _("The relation between internal and external ports does not "
46+
"match the pattern 1:N and N:N")
47+
raise exceptions.CommandError(msg)
48+
49+
50+
def validate_and_assign_port_ranges(parsed_args, attrs):
51+
internal_port_range = parsed_args.internal_protocol_port
52+
external_port_range = parsed_args.external_protocol_port
53+
external_ports = internal_ports = []
54+
if external_port_range:
55+
external_ports = list(map(int, str(external_port_range).split(':')))
56+
if internal_port_range:
57+
internal_ports = list(map(int, str(internal_port_range).split(':')))
58+
59+
validate_ports_match(internal_ports, external_ports)
60+
61+
for port in external_ports + internal_ports:
62+
validate_port(port)
63+
64+
if internal_port_range:
65+
if ':' in internal_port_range:
66+
attrs['internal_port_range'] = internal_port_range
67+
else:
68+
attrs['internal_port'] = int(internal_port_range)
69+
70+
if external_port_range:
71+
if ':' in external_port_range:
72+
attrs['external_port_range'] = external_port_range
73+
else:
74+
attrs['external_port'] = int(external_port_range)
75+
76+
77+
def validate_port(port):
78+
if port <= 0 or port > 65535:
79+
msg = _("The port number range is <1-65535>")
80+
raise exceptions.CommandError(msg)
81+
82+
2883
def _get_columns(item):
2984
column_map = {}
3085
hidden_columns = ['location', 'tenant_id']
@@ -58,7 +113,6 @@ def get_parser(self, prog_name):
58113
)
59114
parser.add_argument(
60115
'--internal-protocol-port',
61-
type=int,
62116
metavar='<port-number>',
63117
required=True,
64118
help=_("The protocol port number "
@@ -67,7 +121,6 @@ def get_parser(self, prog_name):
67121
)
68122
parser.add_argument(
69123
'--external-protocol-port',
70-
type=int,
71124
metavar='<port-number>',
72125
required=True,
73126
help=_("The protocol port number of "
@@ -92,6 +145,7 @@ def get_parser(self, prog_name):
92145
help=_("Floating IP that the port forwarding belongs to "
93146
"(IP address or ID)")
94147
)
148+
95149
return parser
96150

97151
def take_action(self, parsed_args):
@@ -102,19 +156,7 @@ def take_action(self, parsed_args):
102156
ignore_missing=False,
103157
)
104158

105-
if parsed_args.internal_protocol_port is not None:
106-
if (parsed_args.internal_protocol_port <= 0 or
107-
parsed_args.internal_protocol_port > 65535):
108-
msg = _("The port number range is <1-65535>")
109-
raise exceptions.CommandError(msg)
110-
attrs['internal_port'] = parsed_args.internal_protocol_port
111-
112-
if parsed_args.external_protocol_port is not None:
113-
if (parsed_args.external_protocol_port <= 0 or
114-
parsed_args.external_protocol_port > 65535):
115-
msg = _("The port number range is <1-65535>")
116-
raise exceptions.CommandError(msg)
117-
attrs['external_port'] = parsed_args.external_protocol_port
159+
validate_and_assign_port_ranges(parsed_args, attrs)
118160

119161
if parsed_args.port:
120162
port = client.find_port(parsed_args.port,
@@ -226,7 +268,9 @@ def take_action(self, parsed_args):
226268
'internal_port_id',
227269
'internal_ip_address',
228270
'internal_port',
271+
'internal_port_range',
229272
'external_port',
273+
'external_port_range',
230274
'protocol',
231275
'description',
232276
)
@@ -235,7 +279,9 @@ def take_action(self, parsed_args):
235279
'Internal Port ID',
236280
'Internal IP Address',
237281
'Internal Port',
282+
'Internal Port Range',
238283
'External Port',
284+
'External Port Range',
239285
'Protocol',
240286
'Description',
241287
)
@@ -246,8 +292,13 @@ def take_action(self, parsed_args):
246292
port = client.find_port(parsed_args.port,
247293
ignore_missing=False)
248294
query['internal_port_id'] = port.id
249-
if parsed_args.external_protocol_port is not None:
250-
query['external_port'] = parsed_args.external_protocol_port
295+
external_port = parsed_args.external_protocol_port
296+
if external_port:
297+
if ':' in external_port:
298+
query['external_port_range'] = external_port
299+
else:
300+
query['external_port'] = int(
301+
parsed_args.external_protocol_port)
251302
if parsed_args.protocol is not None:
252303
query['protocol'] = parsed_args.protocol
253304

@@ -297,14 +348,12 @@ def get_parser(self, prog_name):
297348
parser.add_argument(
298349
'--internal-protocol-port',
299350
metavar='<port-number>',
300-
type=int,
301351
help=_("The TCP/UDP/other protocol port number of the "
302352
"network port fixed IPv4 address associated to "
303353
"the floating IP port forwarding")
304354
)
305355
parser.add_argument(
306356
'--external-protocol-port',
307-
type=int,
308357
metavar='<port-number>',
309358
help=_("The TCP/UDP/other protocol port number of the "
310359
"port forwarding's floating IP address")
@@ -339,19 +388,8 @@ def take_action(self, parsed_args):
339388

340389
if parsed_args.internal_ip_address:
341390
attrs['internal_ip_address'] = parsed_args.internal_ip_address
342-
if parsed_args.internal_protocol_port is not None:
343-
if (parsed_args.internal_protocol_port <= 0 or
344-
parsed_args.internal_protocol_port > 65535):
345-
msg = _("The port number range is <1-65535>")
346-
raise exceptions.CommandError(msg)
347-
attrs['internal_port'] = parsed_args.internal_protocol_port
348-
349-
if parsed_args.external_protocol_port is not None:
350-
if (parsed_args.external_protocol_port <= 0 or
351-
parsed_args.external_protocol_port > 65535):
352-
msg = _("The port number range is <1-65535>")
353-
raise exceptions.CommandError(msg)
354-
attrs['external_port'] = parsed_args.external_protocol_port
391+
392+
validate_and_assign_port_ranges(parsed_args, attrs)
355393

356394
if parsed_args.protocol:
357395
attrs['protocol'] = parsed_args.protocol

openstackclient/tests/unit/network/v2/fakes.py

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1066,11 +1066,13 @@ class FakeFloatingIPPortForwarding(object):
10661066
""""Fake one or more Port forwarding"""
10671067

10681068
@staticmethod
1069-
def create_one_port_forwarding(attrs=None):
1069+
def create_one_port_forwarding(attrs=None, use_range=False):
10701070
"""Create a fake Port Forwarding.
10711071
10721072
:param Dictionary attrs:
10731073
A dictionary with all attributes
1074+
:param Boolean use_range:
1075+
A boolean which defines if we will use ranges or not
10741076
:return:
10751077
A FakeResource object with name, id, etc.
10761078
"""
@@ -1084,13 +1086,29 @@ def create_one_port_forwarding(attrs=None):
10841086
'floatingip_id': floatingip_id,
10851087
'internal_port_id': 'internal-port-id-' + uuid.uuid4().hex,
10861088
'internal_ip_address': '192.168.1.2',
1087-
'internal_port': randint(1, 65535),
1088-
'external_port': randint(1, 65535),
10891089
'protocol': 'tcp',
10901090
'description': 'some description',
10911091
'location': 'MUNCHMUNCHMUNCH',
10921092
}
10931093

1094+
if use_range:
1095+
port_range = randint(0, 100)
1096+
internal_start = randint(1, 65535 - port_range)
1097+
internal_end = internal_start + port_range
1098+
internal_range = ':'.join(map(str, [internal_start, internal_end]))
1099+
external_start = randint(1, 65535 - port_range)
1100+
external_end = external_start + port_range
1101+
external_range = ':'.join(map(str, [external_start, external_end]))
1102+
port_forwarding_attrs['internal_port_range'] = internal_range
1103+
port_forwarding_attrs['external_port_range'] = external_range
1104+
port_forwarding_attrs['internal_port'] = None
1105+
port_forwarding_attrs['external_port'] = None
1106+
else:
1107+
port_forwarding_attrs['internal_port'] = randint(1, 65535)
1108+
port_forwarding_attrs['external_port'] = randint(1, 65535)
1109+
port_forwarding_attrs['internal_port_range'] = ''
1110+
port_forwarding_attrs['external_port_range'] = ''
1111+
10941112
# Overwrite default attributes.
10951113
port_forwarding_attrs.update(attrs)
10961114

@@ -1101,25 +1119,28 @@ def create_one_port_forwarding(attrs=None):
11011119
return port_forwarding
11021120

11031121
@staticmethod
1104-
def create_port_forwardings(attrs=None, count=2):
1122+
def create_port_forwardings(attrs=None, count=2, use_range=False):
11051123
"""Create multiple fake Port Forwarding.
11061124
11071125
:param Dictionary attrs:
11081126
A dictionary with all attributes
11091127
:param int count:
11101128
The number of Port Forwarding rule to fake
1129+
:param Boolean use_range:
1130+
A boolean which defines if we will use ranges or not
11111131
:return:
11121132
A list of FakeResource objects faking the Port Forwardings
11131133
"""
11141134
port_forwardings = []
11151135
for i in range(0, count):
11161136
port_forwardings.append(
1117-
FakeFloatingIPPortForwarding.create_one_port_forwarding(attrs)
1137+
FakeFloatingIPPortForwarding.create_one_port_forwarding(
1138+
attrs, use_range=use_range)
11181139
)
11191140
return port_forwardings
11201141

11211142
@staticmethod
1122-
def get_port_forwardings(port_forwardings=None, count=2):
1143+
def get_port_forwardings(port_forwardings=None, count=2, use_range=False):
11231144
"""Get a list of faked Port Forwardings.
11241145
11251146
If port forwardings list is provided, then initialize the Mock object
@@ -1129,13 +1150,16 @@ def get_port_forwardings(port_forwardings=None, count=2):
11291150
A list of FakeResource objects faking port forwardings
11301151
:param int count:
11311152
The number of Port Forwardings to fake
1153+
:param Boolean use_range:
1154+
A boolean which defines if we will use ranges or not
11321155
:return:
11331156
An iterable Mock object with side_effect set to a list of faked
11341157
Port Forwardings
11351158
"""
11361159
if port_forwardings is None:
11371160
port_forwardings = (
1138-
FakeFloatingIPPortForwarding.create_port_forwardings(count)
1161+
FakeFloatingIPPortForwarding.create_port_forwardings(
1162+
count, use_range=use_range)
11391163
)
11401164

11411165
return mock.Mock(side_effect=port_forwardings)

0 commit comments

Comments
 (0)