blob: 46b628528552b679ed43516013644d0bdef77e5d [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.
15
16import abc
17
18from oslo_config import cfg
19import requests
20from requests import auth
21import six
22import json
23
24from ceilometer.i18n import _
25from ceilometer.openstack.common import log
26
27
28CONF = cfg.CONF
29CONF.import_opt('http_timeout', 'ceilometer.service')
30
31
32LOG = log.getLogger(__name__)
33
34
35@six.add_metaclass(abc.ABCMeta)
36class _Base(object):
37 """Base class of ONOS REST APIs Clients."""
38
39 @abc.abstractproperty
40 def base_url(self):
41 """Returns base url for each REST API."""
42
43 def __init__(self, client):
44 self.client = client
45
46 def request(self, path, container_name):
47 return self.client.request(self.base_url + path, container_name)
48
49
50class ONOSRESTAPIFailed(Exception):
51 pass
52
53
54class ONOSRESTAPIClient(_Base):
55 """ONOS Statistics REST API Client
56
57 Base URL:
58 {endpoint}/onos/v1
59 """
60
61 base_url = '/onos/v1'
62
63 def get_devices(self, container_name):
64 """Get device informations
65
66 URL:
67 {Base URL}/devices
68 """
69 output = '{ "devices":[ \
70 { \
71 "id":"of:0000000000000001", \
72 "type":"SWITCH", \
73 "available":true, \
74 "role":"MASTER", \
75 "mfr":"Stanford University, Ericsson Research and CPqD Research", \
76 "hw":"OpenFlow 1.3 Reference Userspace Switch", \
77 "sw":"Apr 6 2015 16:10:53", \
78 "serial":"1", \
79 "chassisId":"1", \
80 "annotations":{"protocol":"OF_13","channelId":"192.168.10.50:39306"} \
81 }]}'
82
83 return self.request('/devices', container_name)
84 #LOG.info("SRIKANTH: Returning dummy ONOS devices output")
85 #outputJson = json.loads(output)
86 #return outputJson
87
88 def get_flow_statistics(self, container_name):
89 """Get flow statistics
90
91 URL:
92 {Base URL}/flows
93 """
94 output = '{"flows":[ \
95 { \
96 "deviceId":"of:0000000000000001", \
97 "id":"3377699721451393", \
98 "tableId":2, \
99 "appId":12, \
100 "groupId":0, \
101 "priority":100, \
102 "timeout":0, \
103 "isPermanent":true, \
104 "state":"PENDING_ADD", \
105 "life":0, \
106 "packets":0, \
107 "bytes":0, \
108 "lastSeen":1439355470576, \
109 "treatment":{"instructions":[],"deferred":[]}, \
110 "selector":{"criteria":[]} \
111 }]}'
112 return self.request('/flows', container_name)
113 #LOG.info("SRIKANTH: Returning dummy ONOS flow statistics output")
114 #outputJson = json.loads(output)
115 #return outputJson
116
117 def get_port_statistics(self, container_name):
118 """Get port statistics
119
120 URL:
121 {Base URL}/portstats
122 """
123 output = '{ "portstats": [ \
124 { \
125 "deviceId":"of:0000000000000001", \
126 "id":"3", \
127 "receivePackets": "182", \
128 "sentPackets": "173", \
129 "receiveBytes": "12740", \
130 "sentBytes": "12110", \
131 "receiveDrops": "740", \
132 "sentDrops": "110", \
133 "receiveErrors": "740", \
134 "sentErrors": "110", \
135 "receiveFrameError": "740", \
136 "receiveOverRunError": "740", \
137 "receiveCrcError": "740", \
138 "collisionCount": "110" \
139 }]}'
140 #TODO Add Portstats REST API to ONOS
141 return self.request('/statistics/ports', container_name)
142 #LOG.info("SRIKANTH: Returning dummy ONOS port statistics output")
143 #outputJson = json.loads(output)
144 #return outputJson
145
146 def get_table_statistics(self, container_name):
147 """Get table statistics
148
149 URL:
150 {Base URL}/table
151 """
152 output = '{ \
153 "tableStatistics": [ \
154 { \
155 "deviceId":"of:0000000000000001", \
156 "id":"4", \
157 "activeCount": "11", \
158 "lookupCount": "816", \
159 "matchedCount": "220", \
160 "maximumEntries": "1000" \
161 } \
162 ] \
163 }'
164 #TODO Add table statistics REST API to ONOS
165 return self.request('/statistics/flows/tables', container_name)
166 #LOG.info("SRIKANTH: Returning dummy ONOS table statistics output")
167 #outputJson = json.loads(output)
168 #return outputJson
169
170class Client(object):
171
172 def __init__(self, endpoint, params):
173 self.rest_client = ONOSRESTAPIClient(self)
174
175 self._endpoint = endpoint
176
177 self._req_params = self._get_req_params(params)
178
179 @staticmethod
180 def _get_req_params(params):
181 req_params = {
182 'headers': {
183 'Accept': 'application/json'
184 },
185 'timeout': CONF.http_timeout,
186 }
187
188 auth_way = params.get('auth')
189 if auth_way in ['basic', 'digest']:
190 user = params.get('user')
191 password = params.get('password')
192
193 if auth_way == 'basic':
194 auth_class = auth.HTTPBasicAuth
195 else:
196 auth_class = auth.HTTPDigestAuth
197
198 req_params['auth'] = auth_class(user, password)
199 return req_params
200
201 def _log_req(self, url):
202
203 curl_command = ['REQ: curl -i -X GET ', '"%s" ' % (url)]
204
205 if 'auth' in self._req_params:
206 auth_class = self._req_params['auth']
207 if isinstance(auth_class, auth.HTTPBasicAuth):
208 curl_command.append('--basic ')
209 else:
210 curl_command.append('--digest ')
211
212 curl_command.append('--user "%s":"%s" ' % (auth_class.username,
213 auth_class.password))
214
215 for name, value in six.iteritems(self._req_params['headers']):
216 curl_command.append('-H "%s: %s" ' % (name, value))
217
218 LOG.debug(''.join(curl_command))
219
220 @staticmethod
221 def _log_res(resp):
222
223 dump = ['RES: \n', 'HTTP %.1f %s %s\n' % (resp.raw.version,
224 resp.status_code,
225 resp.reason)]
226 dump.extend('%s: %s\n' % (k, v)
227 for k, v in six.iteritems(resp.headers))
228 dump.append('\n')
229 if resp.content:
230 dump.extend([resp.content, '\n'])
231
232 LOG.debug(''.join(dump))
233
234 def _http_request(self, url):
235 if CONF.debug:
236 self._log_req(url)
237 resp = requests.get(url, **self._req_params)
238 if CONF.debug:
239 self._log_res(resp)
240 if resp.status_code / 100 != 2:
241 raise ONOSRESTAPIFailed(
242 _('ONOS API returned %(status)s %(reason)s') %
243 {'status': resp.status_code, 'reason': resp.reason})
244
245 return resp.json()
246
247 def request(self, path, container_name):
248
249 url = self._endpoint + path % {'container_name': container_name}
250 return self._http_request(url)