Cal refactor sync - Ver3
[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_base_url, logger = None):
34 """
35 Constructor for L2PortChainDriver class
36 Arguments:
37 sess_handle (instance of class SessionDriver)
38 neutron_base_url Neutron service endpoint
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_base_url = neutron_base_url
49
50 @property
51 def neutron_base_url(self):
52 return self._neutron_base_url
53
54 @property
55 def tenant_id(self):
56 return self._sess.project_id
57
58 @property
59 def auth_token(self):
60 return self._sess.auth_token
61
62 def rest_api_handler(self,url,method,payload=None,refresh_token=True):
63 try:
64 if method == 'GET':
65 result=requests.get(self.neutron_base_url+url,
66 headers={"X-Auth-Token":self.auth_token,
67 "Content-Type": "application/json" })
68 elif method == 'POST':
69 self.log.debug("POST request being sent for url %s has payload %s",
70 self.neutron_base_url+url,payload)
71
72 result=requests.post(self.neutron_base_url+url,
73 headers={"X-Auth-Token":self.auth_token,
74 "Content-Type": "application/json"},
75 data=payload)
76 elif method == 'PUT':
77 result=requests.put(self.neutron_base_url+url,
78 headers={"X-Auth-Token":self.auth_token,
79 "Content-Type": "application/json"},
80 data=payload)
81 elif method == 'DELETE':
82 result=requests.delete(self.neutron_base_url+url,
83 headers={"X-Auth-Token": self.auth_token,
84 "Content-Type": "application/json"})
85 else:
86 raise("Invalid method name %s",method)
87
88 result.raise_for_status()
89
90 except requests.exceptions.HTTPError as e:
91 if result.status_code == 401 and refresh_token:
92 self._sess.invalidate_auth_token()
93 result = self.rest_api_handler(url,method,payload=payload,refresh_token=False)
94 else:
95 self.log.exception(e)
96 raise
97
98 return result
99
100 def create_port_pair(self,name,ingress_port,egress_port):
101 """
102 Create port pair
103 """
104 port_pair_dict = {}
105 port_pair = {}
106 port_pair_dict["name"] = name
107 port_pair_dict['tenant_id'] = self.tenant_id
108 port_pair_dict['ingress'] = ingress_port
109 port_pair_dict['egress'] = egress_port
110 port_pair["port_pair"] = port_pair_dict
111 port_pair_json = json.dumps(port_pair)
112
113 try:
114 result = self.rest_api_handler(L2PortChainDriver.PORT_PAIRS_URL, 'POST', port_pair_json)
115 result.raise_for_status()
116 except requests.exceptions.HTTPError as e:
117 if (result.status_code == 400 and 'NeutronError' in result.json()
118 and result.json()['NeutronError']['type'] == 'PortPairIngressEgressInUse'):
119 self.log.info("Port pair with same ingress and egress port already exists")
120 result = self.get_port_pair_list()
121 port_pair_list = result.json()['port_pairs']
122 port_pair_ids = [ pp['id'] for pp in port_pair_list if pp['ingress'] == ingress_port and pp['egress'] == egress_port]
123 return port_pair_ids[0]
124 else:
125 self.log.exception(e)
126 raise
127
128 self.log.debug("Port Pair response received is status code: %s, response: %s",
129 result.status_code, result.json())
130 return result.json()['port_pair']['id']
131
132 def delete_port_pair(self,port_pair_id):
133 try:
134 result = self.rest_api_handler(L2PortChainDriver.PORT_PAIRS_URL+'/{}'.format(port_pair_id), 'DELETE')
135 result.raise_for_status()
136 except requests.exceptions.HTTPError as e:
137 if (result.status_code == 409 and 'NeutronError' in result.json()
138 and result.json()['NeutronError']['type'] == 'PortPairInUse'):
139 self.log.info("Port pair is in use")
140 else:
141 self.log.exception(e)
142 raise
143 self.log.debug("Delete Port Pair response received is status code: %s", result.status_code)
144
145 def get_port_pair(self,port_pair_id):
146 result = self.rest_api_handler(L2PortChainDriver.PORT_PAIRS_URL+'/{}'.format(port_pair_id), 'GET')
147 result.raise_for_status()
148 self.log.debug("Get Port Pair response received is status code: %s, response: %s",
149 result.status_code,
150 result.json())
151 return result
152
153 def get_port_pair_list(self):
154 result = self.rest_api_handler(L2PortChainDriver.PORT_PAIRS_URL, 'GET')
155 result.raise_for_status()
156 self.log.debug("Get Port Pair list response received is status code: %s, response: %s",
157 result.status_code,
158 result.json())
159 return result
160
161 def create_port_pair_group(self,name,port_pairs):
162 """
163 Create port pair group
164 """
165 port_pair_group_dict = {}
166 port_pair_group_dict["name"] = name
167 port_pair_group_dict['tenant_id'] = self.tenant_id
168 port_pair_group_dict['port_pairs'] = list()
169 port_pair_group_dict['port_pairs'].extend(port_pairs)
170 port_pair_group = {}
171 port_pair_group["port_pair_group"] = port_pair_group_dict
172 port_pair_group_json = json.dumps(port_pair_group)
173
174 try:
175 result = self.rest_api_handler(L2PortChainDriver.PORT_PAIR_GROUPS_URL, 'POST', port_pair_group_json)
176 result.raise_for_status()
177 except requests.exceptions.HTTPError as e:
178 if (result.status_code == 409 and 'NeutronError' in result.json()
179 and result.json()['NeutronError']['type'] == 'PortPairInUse'):
180 self.log.info("Port pair group with same port pair already exists")
181 result = self.get_port_pair_group_list()
182 port_pair_group_list = result.json()['port_pair_groups']
183 port_pair_group_ids = [ppg['id'] for ppg in port_pair_group_list
184 if ppg['port_pairs'] == port_pairs]
185 return port_pair_group_ids[0]
186 else:
187 self.log.exception(e)
188 raise
189
190 self.log.debug("Create Port Pair group response received is status code: %s, response: %s",
191 result.status_code,
192 result.json())
193 return result.json()['port_pair_group']['id']
194
195 def delete_port_pair_group(self,port_pair_group_id):
196 try:
197 result = self.rest_api_handler(L2PortChainDriver.PORT_PAIR_GROUPS_URL+'/{}'.format(port_pair_group_id), 'DELETE')
198 result.raise_for_status()
199 except requests.exceptions.HTTPError as e:
200 if (result.status_code == 409 and 'NeutronError' in result.json()
201 and result.json()['NeutronError']['type'] == 'PortPairGroupInUse'):
202 self.log.info("Port pair group is in use")
203 else:
204 self.log.exception(e)
205 raise
206 self.log.debug("Delete Port Pair group response received is status code: %s",
207 result.status_code)
208
209 def get_port_pair_group(self,port_pair_group_id):
210 result = self.rest_api_handler(L2PortChainDriver.PORT_PAIR_GROUPS_URL+'/{}'.format(port_pair_group_id), 'GET')
211 result.raise_for_status()
212 self.log.debug("Get Port Pair group response received is status code: %s, response: %s",
213 result.status_code,
214 result.json())
215 return result
216
217 def get_port_pair_group_list(self):
218 result = self.rest_api_handler(L2PortChainDriver.PORT_PAIR_GROUPS_URL, 'GET')
219 result.raise_for_status()
220 self.log.debug("Get Port Pair group list response received is status code: %s, response: %s",
221 result.status_code,
222 result.json())
223 return result
224
225 def create_port_chain(self,name,port_pair_groups,flow_classifiers=None):
226 """
227 Create port chain
228 """
229 port_chain_dict = {}
230 port_chain_dict["name"]=name
231 port_chain_dict['tenant_id'] = self.tenant_id
232 port_chain_dict['port_pair_groups'] = list()
233 port_chain_dict['port_pair_groups'].extend(port_pair_groups)
234 if flow_classifiers:
235 port_chain_dict['flow_classifiers'] = list()
236 port_chain_dict['flow_classifiers'].extend(flow_classifiers)
237 port_chain = {}
238 port_chain["port_chain"] = port_chain_dict
239 port_chain_json = json.dumps(port_chain)
240
241 try:
242 result = self.rest_api_handler(L2PortChainDriver.PORT_CHAINS_URL, 'POST', port_chain_json)
243 result.raise_for_status()
244 except requests.exceptions.HTTPError as e:
245 if (result.status_code == 409 and 'NeutronError' in result.json()
246 and result.json()['NeutronError']['type'] == 'InvalidPortPairGroups'):
247 self.log.info("Port chain with same port pair group already exists")
248 result = self.get_port_chain_list()
249 port_chain_list = result.json()['port_chains']
250 port_chain_ids = [ pc['id'] for pc in port_chain_list
251 if pc['port_pair_groups'] == port_pair_groups ]
252 return port_chain_ids[0]
253 else:
254 self.log.exception(e)
255 raise()
256
257 self.log.debug("Create Port chain response received is status code: %s, response: %s",
258 result.status_code,
259 result.json())
260
261 return result.json()['port_chain']['id']
262
263 def delete_port_chain(self,port_chain_id):
264 result = self.rest_api_handler(L2PortChainDriver.PORT_CHAINS_URL+'/{}'.format(port_chain_id), 'DELETE')
265 result.raise_for_status()
266 self.log.debug("Delete Port chain response received is status code: %s", result.status_code)
267
268 def get_port_chain(self,port_chain_id):
269 result = self.rest_api_handler(L2PortChainDriver.PORT_CHAINS_URL+'/{}'.format(port_chain_id), 'GET')
270 result.raise_for_status()
271 self.log.debug("Get Port Chain response received is status code: %s, response: %s",
272 result.status_code,
273 result.json())
274 return result
275
276 def get_port_chain_list(self):
277 result = self.rest_api_handler(L2PortChainDriver.PORT_CHAINS_URL, 'GET')
278 result.raise_for_status()
279 self.log.debug("Get Port Chain list response received is status code: %s, response: %s",
280 result.status_code,
281 result.json())
282 return result
283
284 def update_port_chain(self,port_chain_id,port_pair_groups=None,flow_classifiers=None):
285 port_chain_dict = {}
286 if flow_classifiers:
287 port_chain_dict['flow_classifiers'] = list()
288 port_chain_dict['flow_classifiers'].extend(flow_classifiers)
289 if port_pair_groups:
290 port_chain_dict['port_pair_groups'] = list()
291 port_chain_dict['port_pair_groups'].extend(port_pair_groups)
292 port_chain = {}
293 port_chain["port_chain"] = port_chain_dict
294 port_chain_json = json.dumps(port_chain)
295
296 result = self.rest_api_handler(L2PortChainDriver.PORT_CHAINS_URL+'/{}'.format(port_chain_id), 'PUT', port_chain_json)
297 result.raise_for_status()
298 self.log.debug("Update Port chain response received is status code: %s, response: %s",
299 result.status_code,
300 result.json())
301 return result.json()['port_chain']['id']
302
303 def create_flow_classifier(self,name,classifier_dict):
304 """
305 Create flow classifier
306 """
307 classifier_fields = [ 'ethertype',
308 'protocol',
309 'source_port_range_min',
310 'source_port_range_max',
311 'destination_port_range_min',
312 'destination_port_range_max',
313 'source_ip_prefix',
314 'destination_ip_prefix',
315 'logical_source_port' ]
316
317 flow_classifier_dict = {}
318 flow_classifier_dict = {k: v for k, v in classifier_dict.items()
319 if k in classifier_fields}
320 flow_classifier_dict["name"]= name
321 flow_classifier_dict['tenant_id']= self.tenant_id
322
323 #flow_classifier_dict['ethertype']= 'IPv4'
324 #flow_classifier_dict['protocol']= 'TCP'
325 #flow_classifier_dict['source_port_range_min']= 80
326 #flow_classifier_dict['source_port_range_max']= 80
327 #flow_classifier_dict['destination_port_range_min']= 80
328 #flow_classifier_dict['destination_port_range_max']= 80
329 #flow_classifier_dict['source_ip_prefix']= '11.0.6.5/32'
330 #flow_classifier_dict['destination_ip_prefix']= '11.0.6.6/32'
331 #flow_classifier_dict['logical_source_port']= source_neutron_port
332 #flow_classifier_dict['logical_destination_port']= ''
333 flow_classifier = {}
334 flow_classifier["flow_classifier"] = flow_classifier_dict
335 flow_classifier_json = json.dumps(flow_classifier)
336
337 result = self.rest_api_handler(L2PortChainDriver.FLOW_CLASSIFIERS_URL, 'POST', flow_classifier_json)
338 result.raise_for_status()
339 self.log.debug("Create flow classifier response received is status code: %s, response: %s",
340 result.status_code,
341 result.json())
342 return result.json()['flow_classifier']['id']
343
344 def delete_flow_classifier(self,flow_classifier_id):
345 result = self.rest_api_handler(L2PortChainDriver.FLOW_CLASSIFIERS_URL+'/{}'.format(flow_classifier_id), 'DELETE')
346 result.raise_for_status()
347 self.log.debug("Delete flow classifier response received is status code: %s",
348 result.status_code)
349
350 def get_flow_classifier(self,flow_classifier_id):
351 result = self.rest_api_handler(L2PortChainDriver.FLOW_CLASSIFIERS_URL+'/{}'.format(flow_classifier_id), 'GET')
352 result.raise_for_status()
353 self.log.debug("Get flow classifier response received is status code: %s, response: %s",
354 result.status_code,
355 result.json())
356 return result