Add REST API service
Usage documentation will follow. Partially implements, since authentication is not yet supported. Co-Authored-By: Shachar Snapiri <shachar.snapiri@toganetworks.com> Change-Id: Ic9a69baf33d5bed4c35f89d45c8acfd3129e5d03 Partially-Implements: blueprint add-dragonflow-api
This commit is contained in:
parent
0b07ac529b
commit
bd037320f2
|
@ -0,0 +1,126 @@
|
|||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import argparse
|
||||
|
||||
import bottle
|
||||
from http import HTTPStatus # Only from Python 3.5
|
||||
from oslo_serialization import jsonutils
|
||||
|
||||
import dragonflow.common.exceptions as df_exceptions
|
||||
from dragonflow.common import utils
|
||||
from dragonflow.db import api_nb
|
||||
from dragonflow.db import model_framework as mf
|
||||
from dragonflow.db.models import all # noqa
|
||||
|
||||
|
||||
def nbapi_decorator(f):
|
||||
# f(nbapi, ...) -> f(...)
|
||||
def wrapper(*args, **kwargs):
|
||||
# REVISIT(oanson) We might get away with using functools, but we
|
||||
# need nbapi to be instantiated after argument parsing.
|
||||
nbapi = api_nb.NbApi.get_instance()
|
||||
return f(nbapi, *args, **kwargs)
|
||||
return wrapper
|
||||
|
||||
|
||||
def model_decorator(f):
|
||||
def wrapper(*args, **kwargs):
|
||||
name = kwargs['name']
|
||||
try:
|
||||
model = mf.get_model(name)
|
||||
except KeyError:
|
||||
bottle.abort(HTTPStatus.NOT_FOUND.value,
|
||||
"Model '%s' not found" % (name,))
|
||||
return f(model, *args, **kwargs)
|
||||
return wrapper
|
||||
|
||||
|
||||
@bottle.get('/<name>')
|
||||
@model_decorator
|
||||
@nbapi_decorator
|
||||
def get_all(nbapi, model, name):
|
||||
instances = nbapi.get_all(model)
|
||||
result = [i.to_struct() for i in instances]
|
||||
bottle.response.content_type = 'application/json'
|
||||
return jsonutils.dumps(result)
|
||||
|
||||
|
||||
@bottle.post('/<name>')
|
||||
@model_decorator
|
||||
@nbapi_decorator
|
||||
def create(nbapi, model, name):
|
||||
"""POST is create! Create a new instance"""
|
||||
json_data_dict = bottle.json
|
||||
if not json_data_dict:
|
||||
bottle.abort(HTTPStatus.PRECONDITION_FAILED.value,
|
||||
"JSON content required")
|
||||
instance = model(**json_data_dict)
|
||||
nbapi.create(instance)
|
||||
bottle.response.status = HTTPStatus.CREATED.value
|
||||
|
||||
|
||||
@bottle.put('/<name>')
|
||||
@model_decorator
|
||||
@nbapi_decorator
|
||||
def update(nbapi, model, name):
|
||||
"""PUT is update! Update an existing instance"""
|
||||
json_data_dict = bottle.json
|
||||
if not json_data_dict:
|
||||
bottle.abort(HTTPStatus.PRECONDITION_FAILED.value,
|
||||
"JSON content required")
|
||||
instance = model(**json_data_dict)
|
||||
try:
|
||||
nbapi.update(instance)
|
||||
except df_exceptions.DBKeyNotFound:
|
||||
bottle.abort(HTTPStatus.NOT_FOUND.value,
|
||||
"Model instance '%s/%s' not found" % (name, instance.id))
|
||||
bottle.response.status = HTTPStatus.NO_CONTENT.value
|
||||
|
||||
|
||||
@bottle.get('/<name>/<id_>')
|
||||
@model_decorator
|
||||
@nbapi_decorator
|
||||
def get(nbapi, model, name, id_):
|
||||
instance = nbapi.get(model(id=id_))
|
||||
if not instance:
|
||||
bottle.abort(HTTPStatus.NOT_FOUND.value,
|
||||
"Model instance '%s/%s' not found" % (name, id_))
|
||||
bottle.response.content_type = 'application/json'
|
||||
return instance.to_json()
|
||||
|
||||
|
||||
@bottle.delete('/<name>/<id_>')
|
||||
@model_decorator
|
||||
@nbapi_decorator
|
||||
def delete(nbapi, model, name, id_):
|
||||
instance = nbapi.get(model(id=id_))
|
||||
if not instance:
|
||||
bottle.abort(HTTPStatus.NOT_FOUND.value,
|
||||
"Model instance '%s/%s' not found" % (name, id_))
|
||||
nbapi.delete(instance)
|
||||
bottle.response.status = HTTPStatus.NO_CONTENT.value
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description='Dragonflow REST server')
|
||||
parser.add_argument('--host', type=str, default='127.0.0.1',
|
||||
help='Host to listen on (127.0.0.1)')
|
||||
parser.add_argument('--port', type=int, default=8080,
|
||||
help='Port to listen on (8080)')
|
||||
parser.add_argument('--config', type=str,
|
||||
default='/etc/dragonflow/dragonflow.ini',
|
||||
help=('Dragonflow config file '
|
||||
'(/etc/dragonflow/dragonflow.ini)'))
|
||||
args = parser.parse_args()
|
||||
utils.config_init(None, [args.config])
|
||||
bottle.run(host=args.host, port=args.port)
|
|
@ -53,10 +53,15 @@ def etcdir(*p):
|
|||
|
||||
|
||||
def config_parse(conf=None, args=None, **kwargs):
|
||||
config_files = [etcdir('neutron.conf'), etcdir('dragonflow.ini')]
|
||||
config_init(conf, config_files, args, **kwargs)
|
||||
|
||||
|
||||
def config_init(conf, config_files, args=None, **kwargs):
|
||||
if args is None:
|
||||
args = []
|
||||
args += ['--config-file', etcdir('neutron.conf')]
|
||||
args += ['--config-file', etcdir('dragonflow.ini')]
|
||||
for conf_file in config_files:
|
||||
args.extend(['--config-file', conf_file])
|
||||
if conf is None:
|
||||
release = version.version_info.release_string()
|
||||
cfg.CONF(args=args, project='dragonflow',
|
||||
|
|
|
@ -60,6 +60,7 @@ console_scripts =
|
|||
df-bgp-service = dragonflow.cmd.eventlet.df_bgp_service:main
|
||||
df-skydive-service = dragonflow.cmd.df_skydive_service:service_main
|
||||
dragonflow-status = dragonflow.cmd.status:main
|
||||
df-rest-service = dragonflow.cmd.eventlet.df_rest_service:main
|
||||
dragonflow.pubsub_driver =
|
||||
zmq_pubsub_driver = dragonflow.db.pubsub_drivers.zmq_pubsub_driver:ZMQPubSubConnect
|
||||
zmq_bind_pubsub_driver = dragonflow.db.pubsub_drivers.zmq_pubsub_driver:ZMQPubSubBind
|
||||
|
|
Loading…
Reference in New Issue