Skip to content

Commit 1bf6706

Browse files
author
Dean Troyer
committed
Low-level Compute v2 API: security group rules
api.compute.APIv2 security group rule functions. novaclient 8.0 is now released without support for the previously deprecated nova-net functions, so include a new low-level REST implementation of the removed APIs. Change-Id: Ieabd61113bc6d3562738686f52bb06aa84fca765
1 parent 4289ddd commit 1bf6706

6 files changed

Lines changed: 301 additions & 118 deletions

File tree

openstackclient/api/compute_v2.py

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,12 @@
1919
from osc_lib.i18n import _
2020

2121

22+
# TODO(dtroyer): Mingrate this to osc-lib
23+
class InvalidValue(Exception):
24+
"""An argument value is not valid: wrong type, out of range, etc"""
25+
message = "Supplied value is not valid"
26+
27+
2228
class APIv2(api.BaseAPI):
2329
"""Compute v2 API"""
2430

@@ -27,6 +33,29 @@ def __init__(self, **kwargs):
2733

2834
# Overrides
2935

36+
def _check_integer(self, value, msg=None):
37+
"""Attempt to convert value to an integer
38+
39+
Raises InvalidValue on failure
40+
41+
:param value:
42+
Convert this to an integer. None is converted to 0 (zero).
43+
:param msg:
44+
An alternate message for the exception, must include exactly
45+
one substitution to receive the attempted value.
46+
"""
47+
48+
if value is None:
49+
return 0
50+
51+
try:
52+
value = int(value)
53+
except (TypeError, ValueError):
54+
if not msg:
55+
msg = "%s is not an integer" % value
56+
raise InvalidValue(msg)
57+
return value
58+
3059
# TODO(dtroyer): Override find() until these fixes get into an osc-lib
3160
# minimum release
3261
def find(
@@ -209,3 +238,71 @@ def security_group_set(
209238
json={'security_group': security_group},
210239
).json()['security_group']
211240
return None
241+
242+
# Security Group Rules
243+
244+
def security_group_rule_create(
245+
self,
246+
security_group_id=None,
247+
ip_protocol=None,
248+
from_port=None,
249+
to_port=None,
250+
remote_ip=None,
251+
remote_group=None,
252+
):
253+
"""Create a new security group rule
254+
255+
https://developer.openstack.org/api-ref/compute/#create-security-group-rule
256+
257+
:param string security_group_id:
258+
Security group ID
259+
:param ip_protocol:
260+
IP protocol, 'tcp', 'udp' or 'icmp'
261+
:param from_port:
262+
Source port
263+
:param to_port:
264+
Destination port
265+
:param remote_ip:
266+
Source IP address in CIDR notation
267+
:param remote_group:
268+
Remote security group
269+
"""
270+
271+
url = "/os-security-group-rules"
272+
273+
if ip_protocol.lower() not in ['icmp', 'tcp', 'udp']:
274+
raise InvalidValue(
275+
"%(s) is not one of 'icmp', 'tcp', or 'udp'" % ip_protocol
276+
)
277+
278+
params = {
279+
'parent_group_id': security_group_id,
280+
'ip_protocol': ip_protocol,
281+
'from_port': self._check_integer(from_port),
282+
'to_port': self._check_integer(to_port),
283+
'cidr': remote_ip,
284+
'group_id': remote_group,
285+
}
286+
287+
return self.create(
288+
url,
289+
json={'security_group_rule': params},
290+
)['security_group_rule']
291+
292+
def security_group_rule_delete(
293+
self,
294+
security_group_rule_id=None,
295+
):
296+
"""Delete a security group rule
297+
298+
https://developer.openstack.org/api-ref/compute/#delete-security-group-rule
299+
300+
:param string security_group_rule_id:
301+
Security group rule ID
302+
"""
303+
304+
url = "/os-security-group-rules"
305+
if security_group_rule_id is not None:
306+
return self.delete('/%s/%s' % (url, security_group_rule_id))
307+
308+
return None

openstackclient/network/v2/security_group_rule.py

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -376,15 +376,15 @@ def take_action_compute(self, client, parsed_args):
376376
else:
377377
remote_ip = '0.0.0.0/0'
378378

379-
obj = client.security_group_rules.create(
380-
group['id'],
381-
protocol,
382-
from_port,
383-
to_port,
384-
remote_ip,
385-
parsed_args.remote_group,
379+
obj = client.api.security_group_rule_create(
380+
security_group_id=group['id'],
381+
ip_protocol=protocol,
382+
from_port=from_port,
383+
to_port=to_port,
384+
remote_ip=remote_ip,
385+
remote_group=parsed_args.remote_group,
386386
)
387-
return _format_security_group_rule_show(obj._info)
387+
return _format_security_group_rule_show(obj)
388388

389389

390390
class DeleteSecurityGroupRule(common.NetworkAndComputeDelete):
@@ -409,7 +409,7 @@ def take_action_network(self, client, parsed_args):
409409
client.delete_security_group_rule(obj)
410410

411411
def take_action_compute(self, client, parsed_args):
412-
client.security_group_rules.delete(self.r)
412+
client.api.security_group_rule_delete(self.r)
413413

414414

415415
class ListSecurityGroupRule(common.NetworkAndComputeLister):

openstackclient/tests/unit/api/test_compute_v2.py

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,3 +226,84 @@ def test_security_group_set_options_name(self):
226226
security_group='sg2',
227227
description='desc2')
228228
self.assertEqual(self.FAKE_SECURITY_GROUP_RESP_2, ret)
229+
230+
231+
class TestSecurityGroupRule(TestComputeAPIv2):
232+
233+
FAKE_SECURITY_GROUP_RULE_RESP = {
234+
'id': '1',
235+
'name': 'sgr1',
236+
'tenant_id': 'proj-1',
237+
'ip_protocol': 'TCP',
238+
'from_port': 1,
239+
'to_port': 22,
240+
'group': {},
241+
# 'ip_range': ,
242+
# 'cidr': ,
243+
# 'parent_group_id': ,
244+
}
245+
246+
def test_security_group_create_no_options(self):
247+
self.requests_mock.register_uri(
248+
'POST',
249+
FAKE_URL + '/os-security-group-rules',
250+
json={'security_group_rule': self.FAKE_SECURITY_GROUP_RULE_RESP},
251+
status_code=200,
252+
)
253+
ret = self.api.security_group_rule_create(
254+
security_group_id='1',
255+
ip_protocol='tcp',
256+
)
257+
self.assertEqual(self.FAKE_SECURITY_GROUP_RULE_RESP, ret)
258+
259+
def test_security_group_create_options(self):
260+
self.requests_mock.register_uri(
261+
'POST',
262+
FAKE_URL + '/os-security-group-rules',
263+
json={'security_group_rule': self.FAKE_SECURITY_GROUP_RULE_RESP},
264+
status_code=200,
265+
)
266+
ret = self.api.security_group_rule_create(
267+
security_group_id='1',
268+
ip_protocol='tcp',
269+
from_port=22,
270+
to_port=22,
271+
remote_ip='1.2.3.4/24',
272+
)
273+
self.assertEqual(self.FAKE_SECURITY_GROUP_RULE_RESP, ret)
274+
275+
def test_security_group_create_port_errors(self):
276+
self.requests_mock.register_uri(
277+
'POST',
278+
FAKE_URL + '/os-security-group-rules',
279+
json={'security_group_rule': self.FAKE_SECURITY_GROUP_RULE_RESP},
280+
status_code=200,
281+
)
282+
self.assertRaises(
283+
compute.InvalidValue,
284+
self.api.security_group_rule_create,
285+
security_group_id='1',
286+
ip_protocol='tcp',
287+
from_port='',
288+
to_port=22,
289+
remote_ip='1.2.3.4/24',
290+
)
291+
self.assertRaises(
292+
compute.InvalidValue,
293+
self.api.security_group_rule_create,
294+
security_group_id='1',
295+
ip_protocol='tcp',
296+
from_port=0,
297+
to_port=[],
298+
remote_ip='1.2.3.4/24',
299+
)
300+
301+
def test_security_group_rule_delete(self):
302+
self.requests_mock.register_uri(
303+
'DELETE',
304+
FAKE_URL + '/os-security-group-rules/1',
305+
status_code=202,
306+
)
307+
ret = self.api.security_group_rule_delete('1')
308+
self.assertEqual(202, ret.status_code)
309+
self.assertEqual("", ret.text)

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

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -556,10 +556,7 @@ def create_one_security_group_rule(attrs=None):
556556
# Overwrite default attributes.
557557
security_group_rule_attrs.update(attrs)
558558

559-
security_group_rule = fakes.FakeResource(
560-
info=copy.deepcopy(security_group_rule_attrs),
561-
loaded=True)
562-
return security_group_rule
559+
return security_group_rule_attrs
563560

564561
@staticmethod
565562
def create_security_group_rules(attrs=None, count=2):

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -356,7 +356,7 @@ class TestShowSecurityGroupCompute(TestSecurityGroupCompute):
356356
# The security group to be shown.
357357
_security_group = \
358358
compute_fakes.FakeSecurityGroup.create_one_security_group(
359-
attrs={'rules': [_security_group_rule._info]}
359+
attrs={'rules': [_security_group_rule]}
360360
)
361361

362362
columns = (
@@ -373,7 +373,7 @@ class TestShowSecurityGroupCompute(TestSecurityGroupCompute):
373373
_security_group['name'],
374374
_security_group['tenant_id'],
375375
security_group._format_compute_security_group_rules(
376-
[_security_group_rule._info]),
376+
[_security_group_rule]),
377377
)
378378

379379
def setUp(self):

0 commit comments

Comments
 (0)