blob: 810275f376f5e2639e739ad5c7aa7b137d38f760 [file] [log] [blame]
rdudyalab086cf32016-08-11 00:07:45 -04001#
2# Copyright 2013 NEC Corporation. All rights reserved.
3#
4# Licensed under the Apache License, Version 2.0 (the "License"); you may
5# not use this file except in compliance with the License. You may obtain
6# a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13# License for the specific language governing permissions and limitations
14# under the License.
15from oslo_utils import timeutils
16import six
17from six import moves
18from six.moves.urllib import parse as urlparse
19
20from ceilometer.i18n import _
21from ceilometer.network.statistics import driver
22from ceilometer.network.statistics.onos import client
23from ceilometer.openstack.common import log
24from ceilometer import utils
25
26
27LOG = log.getLogger(__name__)
28
29
30def _get_properties(properties, prefix='properties'):
31 resource_meta = {}
32 if properties is not None:
33 for k, v in six.iteritems(properties):
34 value = v['value']
35 key = prefix + '_' + k
36 if 'name' in v:
37 key += '_' + v['name']
38 resource_meta[key] = value
39 return resource_meta
40
41
42def _get_int_sample(key, statistic, resource_id, resource_meta):
43 if key not in statistic:
44 return None
45 return int(statistic[key]), resource_id, resource_meta
46
47
48class ONOSDriver(driver.Driver):
49 """Driver of network info collector from ONOS.
50
51 This driver uses resources in "pipeline.yaml".
52 Resource requires below conditions:
53
54 * resource is url
55 * scheme is "onos"
56
57 This driver can be configured via query parameters.
58 Supported parameters:
59
60 * scheme:
61 The scheme of request url to ONOS REST API endpoint.
62 (default http)
63 * auth:
64 Auth strategy of http.
65 This parameter can be set basic and digest.(default None)
66 * user:
67 This is username that is used by auth.(default None)
68 * password:
69 This is password that is used by auth.(default None)
70 * container_name:
71 Name of container of ONOS.(default "default")
72 This parameter allows multi vaues.
73
74 e.g.::
75
76 onos://127.0.0.1:8181/onos/v1?auth=basic&user=admin&password=admin&scheme=http
77
78 In this case, the driver send request to below URLs:
79
80 http://127.0.0.1:8181/onos/v1/flows
81 """
82 @staticmethod
83 def _prepare_cache(endpoint, params, cache):
84
85 if 'network.statistics.onos' in cache:
86 return cache['network.statistics.onos']
87
88 data = {}
89
90 container_names = params.get('container_name', ['default'])
91
92 onos_params = {}
93 if 'auth' in params:
94 onos_params['auth'] = params['auth'][0]
95 if 'user' in params:
96 onos_params['user'] = params['user'][0]
97 if 'password' in params:
98 onos_params['password'] = params['password'][0]
99 cs = client.Client(endpoint, onos_params)
100
101 for container_name in container_names:
102 try:
103 container_data = {}
104
105 # get flow statistics
106 container_data['flow'] = cs.rest_client.get_flow_statistics(
107 container_name)
108
109 # get port statistics
110 container_data['port'] = cs.rest_client.get_port_statistics(
111 container_name)
112
113 # get table statistics
114 container_data['table'] = cs.rest_client.get_table_statistics(
115 container_name)
116
117 # get topology
118 #container_data['topology'] = cs.topology.get_topology(
119 # container_name)
120
121 # get switch informations
122 container_data['switch'] = cs.rest_client.get_devices(
123 container_name)
124
125 container_data['timestamp'] = timeutils.isotime()
126
127 data[container_name] = container_data
128 except Exception:
129 LOG.exception(_('Request failed to connect to ONOS'
130 ' with NorthBound REST API'))
131
132 cache['network.statistics.onos'] = data
133
134 return data
135
136 def get_sample_data(self, meter_name, parse_url, params, cache):
137
138 extractor = self._get_extractor(meter_name)
139 if extractor is None:
140 # The way to getting meter is not implemented in this driver or
141 # ONOS REST API has not api to getting meter.
142 return None
143
144 iter = self._get_iter(meter_name)
145 if iter is None:
146 # The way to getting meter is not implemented in this driver or
147 # ONOS REST API has not api to getting meter.
148 return None
149
150 parts = urlparse.ParseResult(params.get('scheme', ['http'])[0],
151 parse_url.netloc,
152 parse_url.path,
153 None,
154 None,
155 None)
156 endpoint = urlparse.urlunparse(parts)
157
158 data = self._prepare_cache(endpoint, params, cache)
159
160 samples = []
161 for name, value in six.iteritems(data):
162 timestamp = value['timestamp']
163 for sample in iter(extractor, value):
164 if sample is not None:
165 # set controller name and container name
166 # to resource_metadata
167 sample[2]['controller'] = 'ONOS'
168 sample[2]['container'] = name
169
170 samples.append(sample + (timestamp, ))
171
172 return samples
173
174 def _get_iter(self, meter_name):
175 if meter_name == 'switch':
176 return self._iter_switch
177 elif meter_name.startswith('switch.flow'):
178 return self._iter_flow
179 elif meter_name.startswith('switch.table'):
180 return self._iter_table
181 elif meter_name.startswith('switch.port'):
182 return self._iter_port
183
184 def _get_extractor(self, meter_name):
185 method_name = '_' + meter_name.replace('.', '_')
186 return getattr(self, method_name, None)
187
188 @staticmethod
189 def _iter_switch(extractor, data):
190 for switch in data['switch']['devices']:
191 yield extractor(switch, switch['id'], {})
192
193 @staticmethod
194 def _switch(statistic, resource_id, resource_meta):
195
196 for key in ['mfr','hw','sw','available']:
197 resource_meta[key] = statistic[key]
198 for key in ['protocol','channelId']:
199 resource_meta[key] = statistic['annotations'][key]
200
201 return 1, resource_id, resource_meta
202
203 @staticmethod
204 def _iter_port(extractor, data):
205 for statistic in data['port']['statistics']:
206 for port_statistic in statistic['ports']:
207 resource_meta = {'port': port_statistic['port']}
208 yield extractor(port_statistic, statistic['device'],
209 resource_meta, data)
210
211 @staticmethod
212 def _switch_port(statistic, resource_id, resource_meta, data):
213 return 1, resource_id, resource_meta
214
215 @staticmethod
216 def _switch_port_receive_packets(statistic, resource_id,
217 resource_meta, data):
218 return _get_int_sample('packetsReceived', statistic, resource_id,
219 resource_meta)
220
221 @staticmethod
222 def _switch_port_transmit_packets(statistic, resource_id,
223 resource_meta, data):
224 return _get_int_sample('packetsSent', statistic, resource_id,
225 resource_meta)
226
227 @staticmethod
228 def _switch_port_receive_bytes(statistic, resource_id,
229 resource_meta, data):
230 return _get_int_sample('bytesReceived', statistic, resource_id,
231 resource_meta)
232
233 @staticmethod
234 def _switch_port_transmit_bytes(statistic, resource_id,
235 resource_meta, data):
236 return _get_int_sample('bytesSent', statistic, resource_id,
237 resource_meta)
238
239 @staticmethod
240 def _switch_port_receive_drops(statistic, resource_id,
241 resource_meta, data):
242 return _get_int_sample('packetsRxDropped', statistic, resource_id,
243 resource_meta)
244
245 @staticmethod
246 def _switch_port_transmit_drops(statistic, resource_id,
247 resource_meta, data):
248 return _get_int_sample('packetsTxDropped', statistic, resource_id,
249 resource_meta)
250
251 @staticmethod
252 def _switch_port_receive_errors(statistic, resource_id,
253 resource_meta, data):
254 return _get_int_sample('packetsRxErrors', statistic, resource_id,
255 resource_meta)
256
257 @staticmethod
258 def _switch_port_transmit_errors(statistic, resource_id,
259 resource_meta, data):
260 return _get_int_sample('packetsTxErrors', statistic, resource_id,
261 resource_meta)
262
263 @staticmethod
264 def _switch_port_receive_frame_error(statistic, resource_id,
265 resource_meta, data):
266 #return _get_int_sample('receiveFrameError', statistic, resource_id,
267 # resource_meta)
268 return 0, resource_id, resource_meta
269
270 @staticmethod
271 def _switch_port_receive_overrun_error(statistic, resource_id,
272 resource_meta, data):
273 #return _get_int_sample('receiveOverRunError', statistic, resource_id,
274 # resource_meta)
275 return 0, resource_id, resource_meta
276
277 @staticmethod
278 def _switch_port_receive_crc_error(statistic, resource_id,
279 resource_meta, data):
280 #return _get_int_sample('receiveCrcError', statistic, resource_id,
281 # resource_meta)
282 return 0, resource_id, resource_meta
283
284 @staticmethod
285 def _switch_port_collision_count(statistic, resource_id,
286 resource_meta, data):
287 #return _get_int_sample('collisionCount', statistic, resource_id,
288 # resource_meta)
289 return 0, resource_id, resource_meta
290
291 @staticmethod
292 def _iter_table(extractor, data):
293 for statistic in data['table']['statistics']:
294 for table_statistic in statistic['table']:
295 resource_meta = {'table_id': table_statistic['tableId']}
296 yield extractor(table_statistic,
297 statistic['device'],
298 resource_meta)
299
300 @staticmethod
301 def _switch_table(statistic, resource_id, resource_meta):
302 return 1, resource_id, resource_meta
303
304 @staticmethod
305 def _switch_table_active_entries(statistic, resource_id,
306 resource_meta):
307 return _get_int_sample('activeEntries', statistic, resource_id,
308 resource_meta)
309
310 @staticmethod
311 def _switch_table_lookup_packets(statistic, resource_id,
312 resource_meta):
313 return _get_int_sample('packetsLookedUp', statistic, resource_id,
314 resource_meta)
315
316 @staticmethod
317 def _switch_table_matched_packets(statistic, resource_id,
318 resource_meta):
319 return _get_int_sample('packetsMathced', statistic, resource_id,
320 resource_meta)
321
322 @staticmethod
323 def _iter_flow(extractor, data):
324 for flow_statistic in data['flow']['flows']:
325 resource_meta = {'flow_id': flow_statistic['id'],
326 'table_id': flow_statistic['tableId'],
327 'priority': flow_statistic['priority'],
328 'state': flow_statistic['state']}
329 yield extractor(flow_statistic,
330 flow_statistic['deviceId'],
331 resource_meta)
332
333 @staticmethod
334 def _switch_flow(statistic, resource_id, resource_meta):
335 return 1, resource_id, resource_meta
336
337 @staticmethod
338 def _switch_flow_duration_seconds(statistic, resource_id,
339 resource_meta):
340 if 'life' not in statistic:
341 return None
342 return int(statistic['life']/1000), resource_id, resource_meta
343
344 @staticmethod
345 def _switch_flow_duration_nanoseconds(statistic, resource_id,
346 resource_meta):
347 if 'life' not in statistic:
348 return None
349 return int(statistic['life']*1000), resource_id, resource_meta
350
351 @staticmethod
352 def _switch_flow_packets(statistic, resource_id, resource_meta):
353 return _get_int_sample('packets', statistic, resource_id,
354 resource_meta)
355
356 @staticmethod
357 def _switch_flow_bytes(statistic, resource_id, resource_meta):
358 return _get_int_sample('bytes', statistic, resource_id,
359 resource_meta)