/
contrail_res_handler.py
306 lines (252 loc) · 11 KB
/
contrail_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
# 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 cfgm_common import SG_NO_RULE_NAME, SG_NO_RULE_FQ_NAME
from neutron_plugin_contrail.plugins.opencontrail import contrail_plugin_base
from vnc_api import vnc_api
from neutron_plugin_contrail.plugins.opencontrail.quota.driver import QuotaDriver
class ContrailResourceHandler(object):
def __init__(self, vnc_lib, **kwargs):
self._vnc_lib = vnc_lib
self._kwargs = kwargs
@staticmethod
def _filters_is_present(filters, key_name, match_value):
if not filters:
return True
if key_name in filters:
try:
if key_name == 'tenant_id':
filter_value = [t_id for t_id in filters[key_name]]
else:
filter_value = filters[key_name]
filter_value.index(match_value)
except ValueError: # not in requested list
return False
return True
@staticmethod
def _raise_contrail_exception(exc, **kwargs):
exc_info = {'exception': exc}
exc_info.update(kwargs)
contrail_plugin_base._raise_contrail_error(exc_info,
kwargs.get('resource'))
@staticmethod
def _validate_project_ids(context, project_ids=None):
if context and not context['is_admin']:
return [context['tenant']]
ids = []
for project_id in project_ids:
try:
ids.append(
ContrailResourceHandler._project_id_neutron_to_vnc(
project_id))
except ValueError:
pass
return ids
@staticmethod
def _project_id_vnc_to_neutron(proj_id):
return proj_id.replace("-", "")
@staticmethod
def _project_id_neutron_to_vnc(proj_id):
return str(uuid.UUID(proj_id))
@staticmethod
def _filter_res_dict(res_dict, fields):
new_res_dict = {}
for f in fields:
new_res_dict[f] = res_dict.get(f)
return new_res_dict
def _project_read(self, proj_id=None, fq_name=None):
if proj_id:
proj_id = self._project_id_neutron_to_vnc(proj_id)
return self._vnc_lib.project_read(id=proj_id, fq_name=fq_name)
def _project_list_domain(self, domain_id):
# TODO() till domain concept is not present in keystone
fq_name = ['default-domain']
resp_dict = self._vnc_lib.projects_list(parent_fq_name=fq_name)
return resp_dict['projects']
class ResourceCreateHandler(ContrailResourceHandler):
resource_create_method = None
def _resource_create(self, obj):
"""Create a new resource.
If the fq_name is already used, the object uuid is added to
the last fq_name element in order to generate a unique fq_name.
"""
create_method = getattr(self._vnc_lib, self.resource_create_method)
try:
try:
obj_uuid = create_method(obj)
# To allow several resources with an identical name
# but different uuids.
except vnc_exc.RefsExistError as e:
if obj.uuid is not None:
raise e
else:
# The fq_name is already used, a new one is generated
obj.uuid = str(uuid.uuid4())
obj.name += '-' + obj.uuid
obj.fq_name[-1] += '-' + obj.uuid
obj_uuid = create_method(obj)
except (vnc_exc.BadRequest, vnc_exc.PermissionDenied) as e:
res_type = obj.get_type()
self._raise_contrail_exception('BadRequest',
msg=str(e),
resource=res_type)
except vnc_exc.OverQuota as e:
res_type = obj.get_type()
for n, c in QuotaDriver.quota_neutron_to_contrail_type.items():
if c.replace("_", "-") == res_type:
res_type = n
self._raise_contrail_exception('OverQuota',
overs=[res_type],
msg=str(e))
return obj_uuid
class ResourceDeleteHandler(ContrailResourceHandler):
resource_delete_method = None
def _resource_delete(self, id=None, fq_name=None):
delete_method = getattr(self._vnc_lib, self.resource_delete_method)
delete_method(id=id, fq_name=fq_name)
class ResourceUpdateHandler(ContrailResourceHandler):
resource_update_method = None
def _resource_update(self, obj):
getattr(self._vnc_lib, self.resource_update_method)(obj)
class ResourceGetHandler(ContrailResourceHandler):
back_ref_fields = None
resource_list_method = None
resource_get_method = None
detail = True
def _resource_list(self, back_refs=False, **kwargs):
if back_refs:
kwargs['fields'] = list(set((kwargs.get('fields', [])) +
(self.back_ref_fields or [])))
if 'detail' not in kwargs:
kwargs['detail'] = self.detail
return getattr(self._vnc_lib, self.resource_list_method)(**kwargs)
def _resource_get(self, resource_get_method=None, back_refs=False,
**kwargs):
if back_refs:
kwargs['fields'] = list(set((kwargs.get('fields', [])) +
(self.back_ref_fields or [])))
if resource_get_method:
return getattr(self._vnc_lib, resource_get_method)(**kwargs)
return getattr(self._vnc_lib, self.resource_get_method)(**kwargs)
def _resource_count_optimized(self, filters):
if filters and ('tenant_id' not in filters or len(filters.keys()) > 1):
return None
project_ids = filters.get('tenant_id') if filters else None
if not isinstance(project_ids, list):
project_ids = [project_ids]
json_resource = self.resource_list_method.replace("_", "-")
json_resource = json_resource.replace('-list', '')
if self.resource_list_method == "floating_ips_list":
count = lambda pid: self._resource_list(
back_ref_id=pid, count=True, back_refs=False,
detail=False)[json_resource]['count']
else:
count = lambda pid: self._resource_list(
parent_id=pid, count=True, back_refs=False,
detail=False)[json_resource]['count']
ret = [count(self._project_id_neutron_to_vnc(pid) if pid else None)
for pid in project_ids] if project_ids else [count(None)]
return sum(ret)
class VMachineHandler(ResourceGetHandler, ResourceCreateHandler,
ResourceDeleteHandler):
resource_create_method = 'virtual_machine_create'
resource_list_method = 'virtual_machines_list'
resource_get_method = 'virtual_machine_read'
resource_delete_method = 'virtual_machine_delete'
def ensure_vm_instance(self, instance_id):
instance_name = instance_id
instance_obj = vnc_api.VirtualMachine(instance_name)
try:
try:
uuid.UUID(instance_id)
instance_obj.uuid = instance_id
except ValueError:
# if instance_id is not a valid uuid, let
# virtual_machine_create generate uuid for the vm
pass
self._resource_create(instance_obj)
except vnc_exc.RefsExistError:
instance_obj = self._resource_get(id=instance_obj.uuid)
return instance_obj
class SGHandler(ResourceGetHandler, ResourceCreateHandler,
ResourceDeleteHandler):
resource_create_method = 'security_group_create'
resource_list_method = 'security_groups_list'
resource_get_method = 'security_group_read'
resource_delete_method = 'security_group_delete'
_no_rule_sg_obj = None
def _create_no_rule_sg(self):
domain_obj = vnc_api.Domain(SG_NO_RULE_FQ_NAME[0])
proj_obj = vnc_api.Project(SG_NO_RULE_FQ_NAME[1],
domain_obj)
sg_rules = vnc_api.PolicyEntriesType()
id_perms = vnc_api.IdPermsType(
enable=True,
description="Security group with no rules",
user_visible=False)
sg_obj = vnc_api.SecurityGroup(
name=SG_NO_RULE_NAME,
parent_obj=proj_obj,
security_group_entries=sg_rules,
id_perms=id_perms)
self._resource_create(sg_obj)
return sg_obj
# end _create_no_rule_sg
def get_no_rule_security_group(self, create=True):
if SGHandler._no_rule_sg_obj:
return SGHandler._no_rule_sg_obj
try:
sg_obj = self._resource_get(
fq_name=SG_NO_RULE_FQ_NAME)
except vnc_api.NoIdError:
if create:
sg_obj = self._create_no_rule_sg()
else:
sg_obj = None
SGHandler._no_rule_sg_obj = sg_obj
return sg_obj
class InstanceIpHandler(ResourceGetHandler, ResourceCreateHandler,
ResourceDeleteHandler, ResourceUpdateHandler):
resource_create_method = 'instance_ip_create'
resource_list_method = 'instance_ips_list'
resource_get_method = 'instance_ip_read'
resource_delete_method = 'instance_ip_delete'
resource_update_method = 'instance_ip_update'
def is_ip_addr_in_net_id(self, ip_addr, net_id):
"""Checks if ip address is present in net-id."""
net_ip_list = [ipobj.get_instance_ip_address() for ipobj in
self._resource_list(back_ref_id=[net_id])]
return ip_addr in net_ip_list
def get_iip_obj(self, id):
return self._resource_get(id=id)
def get_iip_obj_list(self, **kwargs):
return self._resource_list(**kwargs)
def create_instance_ip(self, vn_obj, vmi_obj, ip_addr=None,
subnet_uuid=None, ip_family='v4'):
ip_name = str(uuid.uuid4())
ip_obj = vnc_api.InstanceIp(name=ip_name)
ip_obj.uuid = ip_name
if subnet_uuid:
ip_obj.set_subnet_uuid(subnet_uuid)
ip_obj.set_virtual_machine_interface(vmi_obj)
ip_obj.set_virtual_network(vn_obj)
if hasattr(ip_obj, 'set_instance_ip_family'):
ip_obj.set_instance_ip_family(ip_family)
if ip_addr:
ip_obj.set_instance_ip_address(ip_addr)
ip_id = self._resource_create(ip_obj)
return ip_id
def delete_iip_obj(self, iip_id):
self._resource_delete(id=iip_id)