Initial Sketch of REST driver for ONOS
Intents function - returns all intents
Intent fucntion - returns a single intent
Change-Id: I718bedfd60603d0930f5c69a6664c92bbf8a74ba
diff --git a/TestON/drivers/common/api/controller/onosrestdriver.py b/TestON/drivers/common/api/controller/onosrestdriver.py
new file mode 100644
index 0000000..a38b073
--- /dev/null
+++ b/TestON/drivers/common/api/controller/onosrestdriver.py
@@ -0,0 +1,199 @@
+#!/usr/bin/env python
+"""
+Created on 07-08-2015
+
+ TestON is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 2 of the License, or
+ ( at your option ) any later version.
+
+ TestON is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with TestON. If not, see <http://www.gnu.org/licenses/>.
+
+"""
+import json
+import os
+import requests
+import sys
+
+sys.path.append( "../" )
+from drivers.common.api.controllerdriver import Controller
+
+
+class OnosRestDriver( Controller ):
+
+ def __init__( self ):
+ super( Controller, self ).__init__()
+ self.ip_address = "localhost"
+ self.port = "8080"
+ self.user_name = "user"
+ self.password = "CHANGEME"
+
+ def connect( self, **connectargs ):
+ try:
+ for key in connectargs:
+ vars( self )[ key ] = connectargs[ key ]
+ self.name = self.options[ 'name' ]
+ except Exception as e:
+ main.log.exception( e )
+ try:
+ if os.getenv( str( self.ip_address ) ) != None:
+ self.ip_address = os.getenv( str( self.ip_address ) )
+ else:
+ main.log.info( self.name + ": ip set to" + self.ip_address )
+ except KeyError:
+ main.log.info( "Invalid host name," +
+ "defaulting to 'localhost' instead" )
+ self.ip_address = 'localhost'
+ except Exception as inst:
+ main.log.error( "Uncaught exception: " + str( inst ) )
+
+ self.handle = super( OnosRestDriver, self ).connect()
+ return self.handle
+
+ def send( self, ip, port, url, base="/onos/v1", method="GET",
+ query=None, data=None ):
+ """
+ Arguments:
+ str ip: ONOS IP Address
+ str port: ONOS REST Port
+ str url: ONOS REST url path.
+ NOTE that this is is only the relative path. IE "/devices"
+ str base: The base url for the given REST api. Applications could
+ potentially have their own base url
+ str method: HTTP method type
+ dict params: Dictionary to be sent in the query string for
+ the request
+ dict data: Dictionary to be sent in the body of the request
+ """
+ # TODO: Authentication - simple http (user,pass) tuple
+ # TODO: should we maybe just pass kwargs straight to response?
+ # TODO: Do we need to allow for other protocols besides http?
+ # ANSWER: Not yet, but potentially https with certificates
+ try:
+ path = "http://" + str( ip ) + ":" + str( port ) + base + url
+ main.log.info( "Sending request " + path + " using " +
+ method.upper() + " method." )
+ response = requests.request( method.upper(),
+ path,
+ params=query,
+ data=data )
+ return ( response.status_code, response.text.encode( 'utf8' ) )
+ except requests.exceptions:
+ main.log.exception( "Error sending request." )
+ return None
+ except Exception as e:
+ main.log.exception( e )
+ return None
+ # FIXME: add other exceptions
+
+ def intents( self, ip="DEFAULT", port="DEFAULT" ):
+ """
+ """
+ try:
+ output = None
+ if ip == "DEFAULT":
+ main.log.warn( "No ip given, reverting to ip from topo file" )
+ ip = self.ip_address
+ if port == "DEFAULT":
+ main.log.warn( "No port given, reverting to port from topo file" )
+ port = self.port
+ response = self.send( ip, port, url="/intents" )
+ if response:
+ main.log.debug( response )
+ # We can do some verification on the return code
+ # NOTE: Not all requests return 200 on success, usually it will be a 2XX code
+ # 3XX is a redirction, which may be given on a post to show where the new resource can be found
+ # 4XX is usually a bad request on our side
+ # 5XX will usually mean an ONOS bug
+ if response[0] == 200:
+ main.log.debug("all ok")
+ else:
+ main.log.error( "Error with REST request, response was: " +
+ str( response ) )
+ # return main.FALSE
+ output = response[1]
+
+ # NOTE: The output is slightly differen from the cli.
+ # if data = cli's json output
+ # then rest output is dict( 'intents' : data )
+
+ # We have some options here:
+ # 1) we can return the whole thing as a string as we do with cli,
+ # then change our tests to correctly parse the data
+ #
+ # 2) We could return just the data of the response, but we would
+ # have to decide if we return:
+ # 2a) the data as a dictionary or
+ # 2b) as a json string.
+ #
+ # If we return the dict, we probably want to change the
+ # cli drivers to match.
+
+ # Ideally, we would be able to switch between using the api driver
+ # and the cli driver by simply changing the .topo file. I don't
+ # know if we will achive that right away, but we should try to plan
+ # for that.
+
+
+ # 1)
+ '''
+ return output
+ '''
+
+ # 2a)
+ '''
+ import json
+ a = json.loads( output )
+ return a.get( 'intents' )
+ '''
+
+ # 2b)
+ import json
+ a = json.loads( output ).get( 'intents' )
+ b = json.dumps(a)
+ main.log.debug( b )
+ return b
+ except Exception as e:
+ main.log.exception( e )
+ return None
+
+ def intent( self, appId, intentId, ip="DEFAULT", port="DEFAULT" ):
+ """
+ Returns a single intent in dictionary form
+ """
+ try:
+ output = None
+ if ip == "DEFAULT":
+ main.log.warn( "No ip given, reverting to ip from topo file" )
+ ip = self.ip_address
+ if port == "DEFAULT":
+ main.log.warn( "No port given, reverting to port from topo file" )
+ port = self.port
+ # NOTE: REST url requires the intent id to be in decimal form
+ query = "/" + str( appId ) + "/" + str( int( intentId, 16 ) )
+ response = self.send( ip, port, url="/intents" + query )
+ if response:
+ main.log.debug( response )
+ # We can do some verification on the return code
+ # NOTE: Not all requests return 200 on success, usually it will be a 2XX code
+ # 3XX is a redirction, which may be given on a post to show where the new resource can be found
+ # 4XX is usually a bad request on our side
+ # 5XX will usually mean an ONOS bug
+ if response[0] == 200:
+ main.log.debug("all ok")
+ else:
+ main.log.error( "Error with REST request, response was: " +
+ str( response ) )
+ # return main.FALSE
+ output = response[1]
+ a = json.loads( output )
+ return a
+ except Exception as e:
+ main.log.exception( e )
+ return None