blob: a38b073ef212620deb34def4a17a9e85fab3794a [file] [log] [blame]
Jon Hallfc915882015-07-14 13:33:17 -07001#!/usr/bin/env python
2"""
3Created on 07-08-2015
4
5 TestON is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 2 of the License, or
8 ( at your option ) any later version.
9
10 TestON is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with TestON. If not, see <http://www.gnu.org/licenses/>.
17
18"""
19import json
20import os
21import requests
22import sys
23
24sys.path.append( "../" )
25from drivers.common.api.controllerdriver import Controller
26
27
28class OnosRestDriver( Controller ):
29
30 def __init__( self ):
31 super( Controller, self ).__init__()
32 self.ip_address = "localhost"
33 self.port = "8080"
34 self.user_name = "user"
35 self.password = "CHANGEME"
36
37 def connect( self, **connectargs ):
38 try:
39 for key in connectargs:
40 vars( self )[ key ] = connectargs[ key ]
41 self.name = self.options[ 'name' ]
42 except Exception as e:
43 main.log.exception( e )
44 try:
45 if os.getenv( str( self.ip_address ) ) != None:
46 self.ip_address = os.getenv( str( self.ip_address ) )
47 else:
48 main.log.info( self.name + ": ip set to" + self.ip_address )
49 except KeyError:
50 main.log.info( "Invalid host name," +
51 "defaulting to 'localhost' instead" )
52 self.ip_address = 'localhost'
53 except Exception as inst:
54 main.log.error( "Uncaught exception: " + str( inst ) )
55
56 self.handle = super( OnosRestDriver, self ).connect()
57 return self.handle
58
59 def send( self, ip, port, url, base="/onos/v1", method="GET",
60 query=None, data=None ):
61 """
62 Arguments:
63 str ip: ONOS IP Address
64 str port: ONOS REST Port
65 str url: ONOS REST url path.
66 NOTE that this is is only the relative path. IE "/devices"
67 str base: The base url for the given REST api. Applications could
68 potentially have their own base url
69 str method: HTTP method type
70 dict params: Dictionary to be sent in the query string for
71 the request
72 dict data: Dictionary to be sent in the body of the request
73 """
74 # TODO: Authentication - simple http (user,pass) tuple
75 # TODO: should we maybe just pass kwargs straight to response?
76 # TODO: Do we need to allow for other protocols besides http?
77 # ANSWER: Not yet, but potentially https with certificates
78 try:
79 path = "http://" + str( ip ) + ":" + str( port ) + base + url
80 main.log.info( "Sending request " + path + " using " +
81 method.upper() + " method." )
82 response = requests.request( method.upper(),
83 path,
84 params=query,
85 data=data )
86 return ( response.status_code, response.text.encode( 'utf8' ) )
87 except requests.exceptions:
88 main.log.exception( "Error sending request." )
89 return None
90 except Exception as e:
91 main.log.exception( e )
92 return None
93 # FIXME: add other exceptions
94
95 def intents( self, ip="DEFAULT", port="DEFAULT" ):
96 """
97 """
98 try:
99 output = None
100 if ip == "DEFAULT":
101 main.log.warn( "No ip given, reverting to ip from topo file" )
102 ip = self.ip_address
103 if port == "DEFAULT":
104 main.log.warn( "No port given, reverting to port from topo file" )
105 port = self.port
106 response = self.send( ip, port, url="/intents" )
107 if response:
108 main.log.debug( response )
109 # We can do some verification on the return code
110 # NOTE: Not all requests return 200 on success, usually it will be a 2XX code
111 # 3XX is a redirction, which may be given on a post to show where the new resource can be found
112 # 4XX is usually a bad request on our side
113 # 5XX will usually mean an ONOS bug
114 if response[0] == 200:
115 main.log.debug("all ok")
116 else:
117 main.log.error( "Error with REST request, response was: " +
118 str( response ) )
119 # return main.FALSE
120 output = response[1]
121
122 # NOTE: The output is slightly differen from the cli.
123 # if data = cli's json output
124 # then rest output is dict( 'intents' : data )
125
126 # We have some options here:
127 # 1) we can return the whole thing as a string as we do with cli,
128 # then change our tests to correctly parse the data
129 #
130 # 2) We could return just the data of the response, but we would
131 # have to decide if we return:
132 # 2a) the data as a dictionary or
133 # 2b) as a json string.
134 #
135 # If we return the dict, we probably want to change the
136 # cli drivers to match.
137
138 # Ideally, we would be able to switch between using the api driver
139 # and the cli driver by simply changing the .topo file. I don't
140 # know if we will achive that right away, but we should try to plan
141 # for that.
142
143
144 # 1)
145 '''
146 return output
147 '''
148
149 # 2a)
150 '''
151 import json
152 a = json.loads( output )
153 return a.get( 'intents' )
154 '''
155
156 # 2b)
157 import json
158 a = json.loads( output ).get( 'intents' )
159 b = json.dumps(a)
160 main.log.debug( b )
161 return b
162 except Exception as e:
163 main.log.exception( e )
164 return None
165
166 def intent( self, appId, intentId, ip="DEFAULT", port="DEFAULT" ):
167 """
168 Returns a single intent in dictionary form
169 """
170 try:
171 output = None
172 if ip == "DEFAULT":
173 main.log.warn( "No ip given, reverting to ip from topo file" )
174 ip = self.ip_address
175 if port == "DEFAULT":
176 main.log.warn( "No port given, reverting to port from topo file" )
177 port = self.port
178 # NOTE: REST url requires the intent id to be in decimal form
179 query = "/" + str( appId ) + "/" + str( int( intentId, 16 ) )
180 response = self.send( ip, port, url="/intents" + query )
181 if response:
182 main.log.debug( response )
183 # We can do some verification on the return code
184 # NOTE: Not all requests return 200 on success, usually it will be a 2XX code
185 # 3XX is a redirction, which may be given on a post to show where the new resource can be found
186 # 4XX is usually a bad request on our side
187 # 5XX will usually mean an ONOS bug
188 if response[0] == 200:
189 main.log.debug("all ok")
190 else:
191 main.log.error( "Error with REST request, response was: " +
192 str( response ) )
193 # return main.FALSE
194 output = response[1]
195 a = json.loads( output )
196 return a
197 except Exception as e:
198 main.log.exception( e )
199 return None