-
Notifications
You must be signed in to change notification settings - Fork 69
/
sgrule_res_handler.py
398 lines (341 loc) · 16.2 KB
/
sgrule_res_handler.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
# Copyright 2015. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import uuid
from cfgm_common import exceptions as vnc_exc
from neutron.common import constants
from vnc_api import vnc_api
import contrail_res_handler as res_handler
import sg_res_handler as sg_handler
class SecurityGroupRuleMixin(object):
def _security_group_rule_vnc_to_neutron(self, sg_id, sg_rule,
sg_obj=None, fields=None):
sgr_q_dict = {}
if sg_id is None:
return sgr_q_dict
if not sg_obj:
try:
sg_obj = sg_handler.SecurityGroupHandler(
self._vnc_lib).get_sg_obj(id=sg_id)
except vnc_exc.NoIdError:
self._raise_contrail_exception(
'SecurityGroupNotFound',
id=sg_id, resource='security_group_rule')
remote_cidr = None
remote_sg_uuid = None
saddr = sg_rule.get_src_addresses()[0]
daddr = sg_rule.get_dst_addresses()[0]
if saddr.get_security_group() == 'local':
direction = 'egress'
addr = daddr
elif daddr.get_security_group() == 'local':
direction = 'ingress'
addr = saddr
else:
self._raise_contrail_exception(
'SecurityGroupRuleNotFound',
id=sg_rule.get_rule_uuid(), resource='security_group_rule')
if addr.get_subnet():
remote_cidr = '%s/%s' % (addr.get_subnet().get_ip_prefix(),
addr.get_subnet().get_ip_prefix_len())
elif addr.get_security_group():
if addr.get_security_group() != 'any' and (
addr.get_security_group() != 'local'):
remote_sg = addr.get_security_group()
try:
if remote_sg != ':'.join(sg_obj.get_fq_name()):
remote_sg_obj = sg_handler.SecurityGroupHandler(
self._vnc_lib).get_sg_obj(fq_name_str=remote_sg)
else:
remote_sg_obj = sg_obj
remote_sg_uuid = remote_sg_obj.uuid
except vnc_exc.NoIdError:
pass
sgr_q_dict['id'] = sg_rule.get_rule_uuid()
sgr_q_dict['tenant_id'] = self._project_id_vnc_to_neutron(
sg_obj.parent_uuid)
sgr_q_dict['security_group_id'] = sg_obj.uuid
if hasattr(sg_rule, 'get_ethertype'):
sgr_q_dict['ethertype'] = sg_rule.get_ethertype()
else:
sgr_q_dict['ethertype'] = 'IPv4'
sgr_q_dict['direction'] = direction
proto = sg_rule.get_protocol()
sgr_q_dict['protocol'] = None if proto == 'any' else proto
port_min = sg_rule.get_dst_ports()[0].get_start_port()
if sgr_q_dict['protocol'] in (constants.PROTO_NAME_ICMP,
str(constants.PROTO_NUM_ICMP)):
sgr_q_dict['port_range_min'] = port_min
else:
sgr_q_dict['port_range_min'] = None if port_min == 0 else port_min
port_max = (sg_rule.get_dst_ports()[0].get_end_port())
sgr_q_dict['port_range_max'] = None if port_max == 65535 else port_max
if remote_cidr == '0.0.0.0/0' or remote_cidr == '::/0':
remote_cidr = None
sgr_q_dict['remote_ip_prefix'] = remote_cidr
sgr_q_dict['remote_group_id'] = remote_sg_uuid
if fields:
sgr_q_dict = self._filter_res_dict(sgr_q_dict, fields)
return sgr_q_dict
# end _security_group_rule_vnc_to_neutron
def _security_group_rule_find(self, sgr_id, project_uuid=None):
dom_projects = []
if not project_uuid:
dom_projects = self._project_list_domain(None)
else:
dom_projects = [{'uuid': project_uuid}]
for project in dom_projects:
proj_id = project['uuid']
project_sgs = sg_handler.SecurityGroupHandler(
self._vnc_lib).resource_list_by_project(proj_id)
for sg_obj in project_sgs:
sgr_entries = sg_obj.get_security_group_entries()
if sgr_entries is None:
continue
for sg_rule in sgr_entries.get_policy_rule():
if sg_rule.get_rule_uuid() == sgr_id:
return sg_obj, sg_rule
return None, None
# end _security_group_rule_find
class SecurityGroupRuleGetHandler(res_handler.ResourceGetHandler,
SecurityGroupRuleMixin):
def resource_get(self, context, sgr_id, fields=None):
project_uuid = None
if not context['is_admin']:
project_uuid = self._project_id_neutron_to_vnc(context['tenant'])
sg_obj, sg_rule = self._security_group_rule_find(sgr_id, project_uuid)
if sg_obj and sg_rule:
return self._security_group_rule_vnc_to_neutron(sg_obj.uuid,
sg_rule, sg_obj,
fields=fields)
self._raise_contrail_exception('SecurityGroupRuleNotFound', id=sgr_id,
resource='security_group_rule')
def security_group_rules_read(self, sg_obj, fields=None):
sgr_entries = sg_obj.get_security_group_entries()
sg_rules = []
if sgr_entries is None:
return
for sg_rule in sgr_entries.get_policy_rule():
sg_info = self._security_group_rule_vnc_to_neutron(sg_obj.uuid,
sg_rule,
sg_obj,
fields=fields)
sg_rules.append(sg_info)
return sg_rules
# end security_group_rules_read
def resource_list(self, context, filters=None, fields=None):
ret_list = []
# collect phase
all_sgs = []
if filters and 'tenant_id' in filters:
project_ids = self._validate_project_ids(context,
filters['tenant_id'])
for p_id in project_ids:
project_sgs = sg_handler.SecurityGroupHandler(
self._vnc_lib).resource_list_by_project(p_id)
all_sgs.append(project_sgs)
else: # no filters
p_id = None
if context and not context['is_admin']:
p_id = self._project_id_neutron_to_vnc(context['tenant'])
project_sgs = sg_handler.SecurityGroupHandler(
self._vnc_lib).resource_list_by_project(p_id)
all_sgs.append(project_sgs)
# prune phase
for project_sgs in all_sgs:
for sg_obj in project_sgs:
# TODO() implement same for name specified in filter
if not self._filters_is_present(filters, 'id', sg_obj.uuid):
continue
sgr_info = self.security_group_rules_read(sg_obj,
fields=fields)
if sgr_info:
ret_list.extend(sgr_info)
return ret_list
class SecurityGroupRuleDeleteHandler(res_handler.ResourceDeleteHandler,
SecurityGroupRuleMixin):
def _security_group_rule_delete(self, sg_obj, sg_rule):
rules = sg_obj.get_security_group_entries()
rules.get_policy_rule().remove(sg_rule)
sg_obj.set_security_group_entries(rules)
sg_handler.SecurityGroupHandler(
self._vnc_lib).resource_update_obj(sg_obj)
return
# end _security_group_rule_delete
def resource_delete(self, context, sgr_id):
project_uuid = None
if not context['is_admin']:
project_uuid = self._project_id_neutron_to_vnc(context['tenant'])
sg_obj, sg_rule = self._security_group_rule_find(sgr_id, project_uuid)
if sg_obj and sg_rule:
return self._security_group_rule_delete(sg_obj, sg_rule)
self._raise_contrail_exception('SecurityGroupRuleNotFound', id=sgr_id,
resource='security_group_rule')
class SecurityGroupRuleCreateHandler(res_handler.ResourceCreateHandler,
SecurityGroupRuleMixin):
resource_create_method = "security_group_rule_create"
def _convert_protocol(self, value):
IP_PROTOCOL_MAP = {constants.PROTO_NUM_TCP: constants.PROTO_NAME_TCP,
constants.PROTO_NUM_UDP: constants.PROTO_NAME_UDP,
constants.PROTO_NUM_ICMP: constants.PROTO_NAME_ICMP}
if value is None:
return
if isinstance(value, str) and value.lower() == 'any':
return 'any'
try:
val = int(value)
# TODO(ethuleau): support all protocol numbers
if val >= 0 and val <= 255:
return IP_PROTOCOL_MAP[val] if val in IP_PROTOCOL_MAP else (
str(val))
self._raise_contrail_exception(
'SecurityGroupRuleInvalidProtocol',
protocol=value, values=IP_PROTOCOL_MAP.values(),
resource='security_group_rule')
except (ValueError, TypeError):
if value.lower() in IP_PROTOCOL_MAP.values():
return value.lower()
self._raise_contrail_exception(
'SecurityGroupRuleInvalidProtocol',
protocol=value, values=IP_PROTOCOL_MAP.values(),
resource='security_group_rule')
def _validate_port_range(self, rule):
"""Check that port_range is valid."""
if (rule['port_range_min'] is None and
rule['port_range_max'] is None):
return
if not rule['protocol']:
self._raise_contrail_exception(
'SecurityGroupProtocolRequiredWithPorts',
resource='security_group_rule')
if rule['protocol'] in [constants.PROTO_NAME_TCP,
constants.PROTO_NAME_UDP]:
if (rule['port_range_min'] is not None and
rule['port_range_min'] <= rule['port_range_max']):
pass
else:
self._raise_contrail_exception(
'SecurityGroupInvalidPortRange',
resource='security_group_rule')
elif rule['protocol'] == constants.PROTO_NAME_ICMP:
for attr, field in [('port_range_min', 'type'),
('port_range_max', 'code')]:
if rule[attr] > 255:
self._raise_contrail_exception(
'SecurityGroupInvalidIcmpValue', field=field,
attr=attr, value=rule[attr],
resource='security_group_rule')
if (rule['port_range_min'] is None and
rule['port_range_max']):
self._raise_contrail_exception(
'SecurityGroupMissingIcmpType',
value=rule['port_range_max'],
resource='security_group_rule')
def _security_group_rule_neutron_to_vnc(self, sgr_q):
# default port values
if sgr_q['protocol'] in (constants.PROTO_NAME_ICMP,
str(constants.PROTO_NUM_ICMP)):
port_min = None
port_max = None
else:
port_min = 0
port_max = 65535
if sgr_q['port_range_min'] is not None:
port_min = sgr_q['port_range_min']
if sgr_q['port_range_max'] is not None:
port_max = sgr_q['port_range_max']
if sgr_q['remote_ip_prefix'] and sgr_q['remote_group_id']:
self._raise_contrail_exception("BadRequest",
msg="Can't set remote_ip_prefix with remote_group_id",
resource="security_group_rule")
endpt = [vnc_api.AddressType(security_group='any')]
if sgr_q['remote_ip_prefix']:
cidr = sgr_q['remote_ip_prefix'].split('/')
pfx = cidr[0]
pfx_len = int(cidr[1])
endpt = [vnc_api.AddressType(
subnet=vnc_api.SubnetType(pfx, pfx_len))]
elif sgr_q['remote_group_id']:
try:
sg_obj = sg_handler.SecurityGroupHandler(
self._vnc_lib).get_sg_obj(id=sgr_q['remote_group_id'])
except vnc_exc.NoIdError:
self._raise_contrail_exception('SecurityGroupNotFound',
id=sgr_q['remote_group_id'],
resource='security_group_rule')
if sgr_q.get('tenant_id') and (
sg_obj.parent_uuid != self._project_id_neutron_to_vnc(sgr_q['tenant_id'])):
self._raise_contrail_exception("NotFound")
endpt = [vnc_api.AddressType(
security_group=sg_obj.get_fq_name_str())]
if sgr_q['direction'] == 'ingress':
dir = '>'
local = endpt
remote = [vnc_api.AddressType(security_group='local')]
else:
dir = '>'
remote = endpt
local = [vnc_api.AddressType(security_group='local')]
if not sgr_q['protocol']:
sgr_q['protocol'] = 'any'
if not sgr_q['remote_ip_prefix'] and not sgr_q['remote_group_id']:
if not sgr_q['ethertype']:
sgr_q['ethertype'] = 'IPv4'
sgr_uuid = str(uuid.uuid4()) if 'id' not in sgr_q else sgr_q['id']
rule = vnc_api.PolicyRuleType(
rule_uuid=sgr_uuid, direction=dir,
protocol=sgr_q['protocol'],
src_addresses=local,
src_ports=[vnc_api.PortType(0, 65535)],
dst_addresses=remote,
dst_ports=[vnc_api.PortType(port_min, port_max)],
ethertype=sgr_q['ethertype'])
return rule
# end _security_group_rule_neutron_to_vnc
def _security_group_rule_create(self, sg_id, sg_rule, project_id):
sghandler = sg_handler.SecurityGroupHandler(self._vnc_lib)
try:
sg_vnc = sghandler.get_sg_obj(id=sg_id)
except vnc_exc.NoIdError:
self._raise_contrail_exception('SecurityGroupNotFound', id=sg_id,
resource='security_group')
if project_id and sg_vnc.parent_uuid != self._project_id_neutron_to_vnc(project_id):
self._raise_contrail_exception('NotFound')
rules = sg_vnc.get_security_group_entries()
if rules is None:
rules = vnc_api.PolicyEntriesType([sg_rule])
else:
rules.add_policy_rule(sg_rule)
sg_vnc.set_security_group_entries(rules)
try:
sghandler.resource_update_obj(sg_vnc)
except vnc_exc.PermissionDenied as e:
self._raise_contrail_exception(
'BadRequest',
resource='security_group_rule', msg=str(e))
return
# end _security_group_rule_create
def resource_create(self, context, sgr_q):
sgr_q['protocol'] = self._convert_protocol(sgr_q['protocol'])
self._validate_port_range(sgr_q)
sg_id = sgr_q['security_group_id']
sg_rule = self._security_group_rule_neutron_to_vnc(sgr_q)
self._security_group_rule_create(sg_id, sg_rule,
sgr_q.get('tenant_id', None))
ret_sg_rule_q = self._security_group_rule_vnc_to_neutron(sg_id,
sg_rule)
return ret_sg_rule_q
class SecurityGroupRuleHandler(SecurityGroupRuleGetHandler,
SecurityGroupRuleDeleteHandler,
SecurityGroupRuleCreateHandler):
pass