CAL refactoring
[osm/SO.git] / rwcal / plugins / vala / rwcal_openstack / rift / rwcal / openstack / portchain / portchain_drv.py
1 #!/usr/bin/python
2
3 #
4 # Copyright 2017 RIFT.IO Inc
5 #
6 # Licensed under the Apache License, Version 2.0 (the "License");
7 # you may not use this file except in compliance with the License.
8 # You may obtain a copy of the License at
9 #
10 # http://www.apache.org/licenses/LICENSE-2.0
11 #
12 # Unless required by applicable law or agreed to in writing, software
13 # distributed under the License is distributed on an "AS IS" BASIS,
14 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 # See the License for the specific language governing permissions and
16 # limitations under the License.
17 #
18
19 import logging
20 import json
21 import requests
22
23
24 class L2PortChainDriver(object):
25 """
26 Driver for openstack neutron neutron-client v2
27 """
28 PORT_PAIRS_URL='/sfc/port_pairs'
29 PORT_PAIR_GROUPS_URL='/sfc/port_pair_groups'
30 PORT_CHAINS_URL='/sfc/port_chains'
31 FLOW_CLASSIFIERS_URL='/sfc/flow_classifiers'
32
33 def __init__(self, sess_handle, neutron_drv, logger = None):
34 """
35 Constructor for L2PortChainDriver class
36 Arguments:
37 sess_handle (instance of class SessionDriver)
38 neutron_drv
39 logger (instance of logging.Logger)
40 """
41 if logger is None:
42 self.log = logging.getLogger('rwcal.openstack.portchain')
43 self.log.setLevel(logging.DEBUG)
44 else:
45 self.log = logger
46
47 self._sess = sess_handle
48 self.neutron_drv = neutron_drv
49 self._neutron_base_url = neutron_drv.neutron_endpoint
50
51 @property
52 def neutron_base_url(self):
53 return self._neutron_base_url
54
55 @property
56 def tenant_id(self):
57 return self._sess.project_id
58
59 @property
60 def auth_token(self):
61 return self._sess.auth_token
62
63 def rest_api_handler(self,url,method,payload=None,refresh_token=True):
64 try:
65 if method == 'GET':
66 result=requests.get(self.neutron_base_url+url,
67 headers={"X-Auth-Token":self.auth_token,
68 "Content-Type": "application/json" })
69 elif method == 'POST':
70 self.log.debug("POST request being sent for url %s has payload %s",
71 self.neutron_base_url+url,payload)
72
73 result=requests.post(self.neutron_base_url+url,
74 headers={"X-Auth-Token":self.auth_token,
75 "Content-Type": "application/json"},
76 data=payload)
77 elif method == 'PUT':
78 result=requests.put(self.neutron_base_url+url,
79 headers={"X-Auth-Token":self.auth_token,
80 "Content-Type": "application/json"},
81 data=payload)
82 elif method == 'DELETE':
83 result=requests.delete(self.neutron_base_url+url,
84 headers={"X-Auth-Token": self.auth_token,
85 "Content-Type": "application/json"})
86 else:
87 raise("Invalid method name %s",method)
88
89 result.raise_for_status()
90
91 except requests.exceptions.HTTPError as e:
92 if result.status_code == 401 and refresh_token:
93 self._sess.invalidate_auth_token()
94 result = self.rest_api_handler(url,method,payload=payload,refresh_token=False)
95 else:
96 self.log.exception(e)
97 raise
98
99 return result
100
101 def create_port_pair(self,name,ingress_port,egress_port):
102 """
103 Create port pair
104 """
105 port_pair_dict = {}
106 port_pair = {}
107 port_pair_dict["name"] = name
108 port_pair_dict['tenant_id'] = self.tenant_id
109 port_pair_dict['ingress'] = ingress_port
110 port_pair_dict['egress'] = egress_port
111 port_pair["port_pair"] = port_pair_dict
112 port_pair_json = json.dumps(port_pair)
113
114 try:
115 result = self.rest_api_handler(L2PortChainDriver.PORT_PAIRS_URL, 'POST', port_pair_json)
116 result.raise_for_status()
117 except requests.exceptions.HTTPError as e:
118 if (result.status_code == 400 and 'NeutronError' in result.json()
119 and result.json()['NeutronError']['type'] == 'PortPairIngressEgressInUse'):
120 self.log.info("Port pair with same ingress and egress port already exists")
121 result = self.get_port_pair_list()
122 port_pair_list = result.json()['port_pairs']
123 port_pair_ids = [ pp['id'] for pp in port_pair_list if pp['ingress'] == ingress_port and pp['egress'] == egress_port]
124 return port_pair_ids[0]
125 else:
126 self.log.exception(e)
127 raise
128
129 self.log.debug("Port Pair response received is status code: %s, response: %s",
130 result.status_code, result.json())
131 return result.json()['port_pair']['id']
132
133 def delete_port_pair(self,port_pair_id):
134 try:
135 result = self.rest_api_handler(L2PortChainDriver.PORT_PAIRS_URL+'/{}'.format(port_pair_id), 'DELETE')
136 result.raise_for_status()
137 except requests.exceptions.HTTPError as e:
138 if (result.status_code == 409 and 'NeutronError' in result.json()
139 and result.json()['NeutronError']['type'] == 'PortPairInUse'):
140 self.log.info("Port pair is in use")
141 else:
142 self.log.exception(e)
143 raise
144 self.log.debug("Delete Port Pair response received is status code: %s", result.status_code)
145
146 def get_port_pair(self,port_pair_id):
147 result = self.rest_api_handler(L2PortChainDriver.PORT_PAIRS_URL+'/{}'.format(port_pair_id), 'GET')
148 result.raise_for_status()
149 self.log.debug("Get Port Pair response received is status code: %s, response: %s",
150 result.status_code,
151 result.json())
152 return result
153
154 def get_port_pair_list(self):
155 result = self.rest_api_handler(L2PortChainDriver.PORT_PAIRS_URL, 'GET')
156 result.raise_for_status()
157 self.log.debug("Get Port Pair list response received is status code: %s, response: %s",
158 result.status_code,
159 result.json())
160 return result
161
162 def create_port_pair_group(self,name,port_pairs):
163 """
164 Create port pair group
165 """
166 port_pair_group_dict = {}
167 port_pair_group_dict["name"] = name
168 port_pair_group_dict['tenant_id'] = self.tenant_id
169 port_pair_group_dict['port_pairs'] = list()
170 port_pair_group_dict['port_pairs'].extend(port_pairs)
171 port_pair_group = {}
172 port_pair_group["port_pair_group"] = port_pair_group_dict
173 port_pair_group_json = json.dumps(port_pair_group)
174
175 try:
176 result = self.rest_api_handler(L2PortChainDriver.PORT_PAIR_GROUPS_URL, 'POST', port_pair_group_json)
177 result.raise_for_status()
178 except requests.exceptions.HTTPError as e:
179 if (result.status_code == 409 and 'NeutronError' in result.json()
180 and result.json()['NeutronError']['type'] == 'PortPairInUse'):
181 self.log.info("Port pair group with same port pair already exists")
182 result = self.get_port_pair_group_list()
183 port_pair_group_list = result.json()['port_pair_groups']
184 port_pair_group_ids = [ppg['id'] for ppg in port_pair_group_list
185 if ppg['port_pairs'] == port_pairs]
186 return port_pair_group_ids[0]
187 else:
188 self.log.exception(e)
189 raise
190
191 self.log.debug("Create Port Pair group response received is status code: %s, response: %s",
192 result.status_code,
193 result.json())
194 return result.json()['port_pair_group']['id']
195
196 def delete_port_pair_group(self,port_pair_group_id):
197 try:
198 result = self.rest_api_handler(L2PortChainDriver.PORT_PAIR_GROUPS_URL+'/{}'.format(port_pair_group_id), 'DELETE')
199 result.raise_for_status()
200 except requests.exceptions.HTTPError as e:
201 if (result.status_code == 409 and 'NeutronError' in result.json()
202 and result.json()['NeutronError']['type'] == 'PortPairGroupInUse'):
203 self.log.info("Port pair group is in use")
204 else:
205 self.log.exception(e)
206 raise
207 self.log.debug("Delete Port Pair group response received is status code: %s",
208 result.status_code)
209
210 def get_port_pair_group(self,port_pair_group_id):
211 result = self.rest_api_handler(L2PortChainDriver.PORT_PAIR_GROUPS_URL+'/{}'.format(port_pair_group_id), 'GET')
212 result.raise_for_status()
213 self.log.debug("Get Port Pair group response received is status code: %s, response: %s",
214 result.status_code,
215 result.json())
216 return result
217
218 def get_port_pair_group_list(self):
219 result = self.rest_api_handler(L2PortChainDriver.PORT_PAIR_GROUPS_URL, 'GET')
220 result.raise_for_status()
221 self.log.debug("Get Port Pair group list response received is status code: %s, response: %s",
222 result.status_code,
223 result.json())
224 return result
225
226 def create_port_chain(self,name,port_pair_groups,flow_classifiers=None):
227 """
228 Create port chain
229 """
230 port_chain_dict = {}
231 port_chain_dict["name"]=name
232 port_chain_dict['tenant_id'] = self.tenant_id
233 port_chain_dict['port_pair_groups'] = list()
234 port_chain_dict['port_pair_groups'].extend(port_pair_groups)
235 if flow_classifiers:
236 port_chain_dict['flow_classifiers'] = list()
237 port_chain_dict['flow_classifiers'].extend(flow_classifiers)
238 port_chain = {}
239 port_chain["port_chain"] = port_chain_dict
240 port_chain_json = json.dumps(port_chain)
241
242 try:
243 result = self.rest_api_handler(L2PortChainDriver.PORT_CHAINS_URL, 'POST', port_chain_json)
244 result.raise_for_status()
245 except requests.exceptions.HTTPError as e:
246 if (result.status_code == 409 and 'NeutronError' in result.json()
247 and result.json()['NeutronError']['type'] == 'InvalidPortPairGroups'):
248 self.log.info("Port chain with same port pair group already exists")
249 result = self.get_port_chain_list()
250 port_chain_list = result.json()['port_chains']
251 port_chain_ids = [ pc['id'] for pc in port_chain_list
252 if pc['port_pair_groups'] == port_pair_groups ]
253 return port_chain_ids[0]
254 else:
255 self.log.exception(e)
256 raise()
257
258 self.log.debug("Create Port chain response received is status code: %s, response: %s",
259 result.status_code,
260 result.json())
261
262 return result.json()['port_chain']['id']
263
264 def delete_port_chain(self,port_chain_id):
265 result = self.rest_api_handler(L2PortChainDriver.PORT_CHAINS_URL+'/{}'.format(port_chain_id), 'DELETE')
266 result.raise_for_status()
267 self.log.debug("Delete Port chain response received is status code: %s", result.status_code)
268
269 def get_port_chain(self,port_chain_id):
270 result = self.rest_api_handler(L2PortChainDriver.PORT_CHAINS_URL+'/{}'.format(port_chain_id), 'GET')
271 result.raise_for_status()
272 self.log.debug("Get Port Chain response received is status code: %s, response: %s",
273 result.status_code,
274 result.json())
275 return result
276
277 def get_port_chain_list(self):
278 result = self.rest_api_handler(L2PortChainDriver.PORT_CHAINS_URL, 'GET')
279 result.raise_for_status()
280 self.log.debug("Get Port Chain list response received is status code: %s, response: %s",
281 result.status_code,
282 result.json())
283 return result
284
285 def update_port_chain(self,port_chain_id,port_pair_groups=None,flow_classifiers=None):
286 port_chain_dict = {}
287 if flow_classifiers:
288 port_chain_dict['flow_classifiers'] = list()
289 port_chain_dict['flow_classifiers'].extend(flow_classifiers)
290 if port_pair_groups:
291 port_chain_dict['port_pair_groups'] = list()
292 port_chain_dict['port_pair_groups'].extend(port_pair_groups)
293 port_chain = {}
294 port_chain["port_chain"] = port_chain_dict
295 port_chain_json = json.dumps(port_chain)
296
297 result = self.rest_api_handler(L2PortChainDriver.PORT_CHAINS_URL+'/{}'.format(port_chain_id), 'PUT', port_chain_json)
298 result.raise_for_status()
299 self.log.debug("Update Port chain response received is status code: %s, response: %s",
300 result.status_code,
301 result.json())
302 return result.json()['port_chain']['id']
303
304 def create_flow_classifier(self,name,classifier_dict):
305 """
306 Create flow classifier
307 """
308 classifier_fields = [ 'ethertype',
309 'protocol',
310 'source_port_range_min',
311 'source_port_range_max',
312 'destination_port_range_min',
313 'destination_port_range_max',
314 'source_ip_prefix',
315 'destination_ip_prefix',
316 'logical_source_port' ]
317
318 flow_classifier_dict = {}
319 flow_classifier_dict = {k: v for k, v in classifier_dict.items()
320 if k in classifier_fields}
321 flow_classifier_dict["name"]= name
322 flow_classifier_dict['tenant_id']= self.tenant_id
323
324 #flow_classifier_dict['ethertype']= 'IPv4'
325 #flow_classifier_dict['protocol']= 'TCP'
326 #flow_classifier_dict['source_port_range_min']= 80
327 #flow_classifier_dict['source_port_range_max']= 80
328 #flow_classifier_dict['destination_port_range_min']= 80
329 #flow_classifier_dict['destination_port_range_max']= 80
330 #flow_classifier_dict['source_ip_prefix']= '11.0.6.5/32'
331 #flow_classifier_dict['destination_ip_prefix']= '11.0.6.6/32'
332 #flow_classifier_dict['logical_source_port']= source_neutron_port
333 #flow_classifier_dict['logical_destination_port']= ''
334 flow_classifier = {}
335 flow_classifier["flow_classifier"] = flow_classifier_dict
336 flow_classifier_json = json.dumps(flow_classifier)
337
338 result = self.rest_api_handler(L2PortChainDriver.FLOW_CLASSIFIERS_URL, 'POST', flow_classifier_json)
339 result.raise_for_status()
340 self.log.debug("Create flow classifier response received is status code: %s, response: %s",
341 result.status_code,
342 result.json())
343 return result.json()['flow_classifier']['id']
344
345 def delete_flow_classifier(self,flow_classifier_id):
346 result = self.rest_api_handler(L2PortChainDriver.FLOW_CLASSIFIERS_URL+'/{}'.format(flow_classifier_id), 'DELETE')
347 result.raise_for_status()
348 self.log.debug("Delete flow classifier response received is status code: %s",
349 result.status_code)
350
351 def get_flow_classifier(self,flow_classifier_id):
352 result = self.rest_api_handler(L2PortChainDriver.FLOW_CLASSIFIERS_URL+'/{}'.format(flow_classifier_id), 'GET')
353 result.raise_for_status()
354 self.log.debug("Get flow classifier response received is status code: %s, response: %s",
355 result.status_code,
356 result.json())
357 return result