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