Add api versioning
This commit is contained in:
parent
eb3b446a9f
commit
f40fe7372c
209
api/v1.py
209
api/v1.py
@ -1,105 +1,140 @@
|
||||
|
||||
# Copyright (c) 2013 Mirantis, Inc.
|
||||
# Copyright (c) 2013 Mirantis, Inc.
|
||||
#
|
||||
# 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
|
||||
# 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
|
||||
# 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.
|
||||
# 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.
|
||||
|
||||
from flask import Flask
|
||||
from flask.ext.restful import reqparse, abort, Api, Resource
|
||||
import os
|
||||
from flask import Blueprint, make_response, send_file
|
||||
from flask import jsonify, request, abort
|
||||
from flask import current_app
|
||||
from werkzeug import secure_filename
|
||||
|
||||
app = Flask(__name__)
|
||||
api = Api(app)
|
||||
from parser import ManifestParser
|
||||
from archiver import Archiver
|
||||
|
||||
TODOS = {
|
||||
'todo1': {'task': 'build an API'},
|
||||
'todo2': {'task': '?????'},
|
||||
'todo3': {'task': 'profit!'},
|
||||
}
|
||||
v1_api = Blueprint('v1', __name__)
|
||||
|
||||
|
||||
def abort_if_todo_doesnt_exist(todo_id):
|
||||
if todo_id not in TODOS:
|
||||
abort(404, message="Todo {} doesn't exist".format(todo_id))
|
||||
@v1_api.route('/client/ui')
|
||||
def get_ui_data():
|
||||
parser = ManifestParser(current_app.config["ROOT_DIRECTORY"])
|
||||
manifests = parser.parse()
|
||||
archive_name = Archiver().create(manifests, "ui_forms")
|
||||
|
||||
parser = reqparse.RequestParser()
|
||||
parser.add_argument('task', type=str)
|
||||
return send_file(archive_name)
|
||||
|
||||
|
||||
# Todo
|
||||
# show a single todo item and lets you delete them
|
||||
class Todo(Resource):
|
||||
def get(self, todo_id):
|
||||
abort_if_todo_doesnt_exist(todo_id)
|
||||
return TODOS[todo_id]
|
||||
@v1_api.route('/client/conductor')
|
||||
def get_conductor_data():
|
||||
parser = ManifestParser(current_app.config["ROOT_DIRECTORY"])
|
||||
manifests = parser.parse()
|
||||
archive_name = Archiver().create(manifests,
|
||||
"heat_templates",
|
||||
"agent_templates",
|
||||
"scripts")
|
||||
|
||||
def delete(self, todo_id):
|
||||
abort_if_todo_doesnt_exist(todo_id)
|
||||
del TODOS[todo_id]
|
||||
return '', 204
|
||||
|
||||
def put(self, todo_id):
|
||||
args = parser.parse_args()
|
||||
task = {'task': args['task']}
|
||||
TODOS[todo_id] = task
|
||||
return task, 201
|
||||
return send_file(archive_name)
|
||||
|
||||
|
||||
# TodoList
|
||||
# shows a list of all todos, and lets you POST to add new tasks
|
||||
class TodoList(Resource):
|
||||
def get(self):
|
||||
return TODOS
|
||||
@v1_api.route('/admin/<data_type>', methods=['GET', 'POST'])
|
||||
def get_data_type_locations(data_type):
|
||||
####### validation ########
|
||||
if data_type not in current_app.config['DATA_TYPES']:
|
||||
abort(404)
|
||||
result_path = os.path.join(current_app.config["DIRECTORIES_BY_TYPE"][
|
||||
data_type])
|
||||
####### end validation ########
|
||||
if request.method == 'GET':
|
||||
locations = []
|
||||
|
||||
def post(self):
|
||||
args = parser.parse_args()
|
||||
todo_id = 'todo%d' % (len(TODOS) + 1)
|
||||
TODOS[todo_id] = {'task': args['task']}
|
||||
return TODOS[todo_id], 201
|
||||
for path, subdirs, files in os.walk(result_path):
|
||||
for name in files:
|
||||
locations.append(os.path.join(path, name))
|
||||
result = {data_type: locations}
|
||||
return jsonify(result)
|
||||
|
||||
##
|
||||
## Actually setup the Api resource routing here
|
||||
##
|
||||
api.add_resource(TodoList, '/todos')
|
||||
api.add_resource(Todo, '/todos/<string:todo_id>')
|
||||
if request.method == 'POST':
|
||||
file_to_upload = request.files.get('file')
|
||||
if file_to_upload:
|
||||
filename = secure_filename(file_to_upload.filename)
|
||||
file_to_upload.save(os.path.join(result_path, filename))
|
||||
return jsonify(result="success")
|
||||
else:
|
||||
abort(503)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
app.run(debug=True)
|
||||
#
|
||||
# @app.route('/client/ui')
|
||||
# def ui_data():
|
||||
# #type - application/z-gzip
|
||||
# pass
|
||||
#
|
||||
# @app.route('/client/ui')
|
||||
# def conductor_data():
|
||||
# #type - application/z-gzip
|
||||
# pass
|
||||
#
|
||||
# @app.route('/client/ui')
|
||||
# def conductor_data():
|
||||
# #type - application/json
|
||||
# pass
|
||||
#
|
||||
# @app.route('/client/<data_type>/<path>')
|
||||
# def conductor_data():
|
||||
# #type - application/json
|
||||
# pass
|
||||
#
|
||||
# @app.route('/client/<data_type>/<file_name>')
|
||||
# def conductor_data():
|
||||
# #type - application/json
|
||||
# pass
|
||||
#
|
||||
#
|
||||
# if __name__ == '__main__':
|
||||
# app.run()
|
||||
@v1_api.route('/admin/<data_type>/<path:path>', methods=['GET', 'POST'])
|
||||
def get_data_type_locations_by_path_or_get_file(data_type, path):
|
||||
####### validation ########
|
||||
if data_type not in current_app.config['DATA_TYPES']:
|
||||
abort(404)
|
||||
result_path = os.path.join(current_app.config["DIRECTORIES_BY_TYPE"][
|
||||
data_type],
|
||||
path)
|
||||
if not os.path.exists(result_path):
|
||||
abort(404)
|
||||
####### end validation ########
|
||||
if request.method == 'GET':
|
||||
locations = []
|
||||
#return file content or directory content
|
||||
if os.path.isfile(result_path):
|
||||
return send_file(result_path)
|
||||
else:
|
||||
for file in os.listdir(result_path):
|
||||
locations.append(os.path.join(path, file))
|
||||
result = {data_type: locations}
|
||||
return jsonify(result)
|
||||
|
||||
if request.method == 'POST':
|
||||
file_to_upload = request.files.get('file')
|
||||
if file_to_upload:
|
||||
filename = secure_filename(file_to_upload.filename)
|
||||
file_to_upload.save(os.path.join(result_path, filename))
|
||||
return jsonify(result="success")
|
||||
else:
|
||||
abort(403)
|
||||
|
||||
|
||||
@v1_api.route('/admin/<data_type>/<path:path>', methods=['PUT', 'DELETE'])
|
||||
def create_dirs(data_type, path):
|
||||
if data_type not in current_app.config['DATA_TYPES']:
|
||||
abort(404)
|
||||
result_path = os.path.join(current_app.config["DIRECTORIES_BY_TYPE"][
|
||||
data_type],
|
||||
path)
|
||||
if request.method == 'PUT':
|
||||
resp = make_response()
|
||||
if os.path.exists(result_path):
|
||||
return resp
|
||||
if data_type == current_app.config['MANIFESTS']:
|
||||
abort(403)
|
||||
try:
|
||||
os.makedirs(result_path)
|
||||
except Exception as e:
|
||||
abort(403)
|
||||
return resp
|
||||
|
||||
if request.method == 'DELETE':
|
||||
if not os.path.exists(result_path):
|
||||
abort(404)
|
||||
if os.path.isfile(result_path):
|
||||
try:
|
||||
os.remove(result_path)
|
||||
except Exception as e:
|
||||
abort(404)
|
||||
else:
|
||||
try:
|
||||
os.rmdir(result_path)
|
||||
except Exception as e:
|
||||
abort(403)
|
||||
resp = make_response()
|
||||
return resp
|
||||
|
@ -87,7 +87,7 @@ class Archiver(object):
|
||||
shutil.rmtree(temp_dir, ignore_errors=True)
|
||||
except Exception as e:
|
||||
log.error("Unable to delete temp directory: {0}".format(e))
|
||||
return target_archeve
|
||||
return os.path.abspath(target_archeve)
|
||||
|
||||
|
||||
|
||||
|
@ -1,13 +0,0 @@
|
||||
# Copyright (c) 2013 Mirantis, Inc.
|
||||
#
|
||||
# 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.
|
@ -11,18 +11,16 @@
|
||||
# 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 os
|
||||
from parser import ManifestParser
|
||||
from archiver import Archiver
|
||||
import flask
|
||||
from keystoneclient.middleware import auth_token
|
||||
from api.v1 import v1_api
|
||||
|
||||
|
||||
def main():
|
||||
parser = ManifestParser(os.path.join(os.path.dirname(__file__), os.pardir,
|
||||
'Services'))
|
||||
manifests = parser.parse()
|
||||
Archiver().create(manifests, "ui_forms", "heat_templates", "agent_templates")
|
||||
|
||||
app = flask.Flask(__name__)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
app.register_blueprint(v1_api, url_prefix='/v1')
|
||||
app.config.from_pyfile('consts.py')
|
||||
|
||||
if __name__ == '__main__':
|
||||
app.run(debug=True)
|
145
test.py
145
test.py
@ -1,145 +0,0 @@
|
||||
# Copyright (c) 2013 Mirantis, Inc.
|
||||
#
|
||||
# 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 os
|
||||
from flask import Flask, make_response, send_from_directory, send_file, \
|
||||
jsonify, request, abort
|
||||
from flask.ext.restful import Api, Resource
|
||||
from werkzeug import secure_filename
|
||||
|
||||
from parser import ManifestParser
|
||||
from archiver import Archiver
|
||||
|
||||
app = Flask(__name__)
|
||||
app.config.from_pyfile('consts.py')
|
||||
api = Api(app)
|
||||
|
||||
@app.route('/client/ui')
|
||||
def get_ui_data():
|
||||
parser = ManifestParser(app.config["ROOT_DIRECTORY"])
|
||||
manifests = parser.parse()
|
||||
archive_name = Archiver().create(manifests, "ui_forms")
|
||||
|
||||
return send_from_directory(os.path.dirname(__file__), archive_name)
|
||||
|
||||
|
||||
@app.route('/client/conductor')
|
||||
def get_conductor_data():
|
||||
parser = ManifestParser(app.config["ROOT_DIRECTORY"])
|
||||
manifests = parser.parse()
|
||||
archive_name = Archiver().create(manifests,
|
||||
"heat_templates",
|
||||
"agent_templates",
|
||||
"scripts")
|
||||
|
||||
return send_from_directory(os.path.dirname(__file__), archive_name)
|
||||
|
||||
|
||||
@app.route('/admin/<data_type>', methods=['GET', 'POST'])
|
||||
def get_data_type_locations(data_type):
|
||||
####### validation ########
|
||||
if data_type not in app.config['DATA_TYPES']:
|
||||
abort(404)
|
||||
result_path = os.path.join(app.config["DIRECTORIES_BY_TYPE"][
|
||||
data_type])
|
||||
####### end validation ########
|
||||
if request.method == 'GET':
|
||||
locations = []
|
||||
|
||||
for path, subdirs, files in os.walk(result_path):
|
||||
for name in files:
|
||||
locations.append(os.path.join(path, name))
|
||||
result = {data_type: locations}
|
||||
return jsonify(result)
|
||||
|
||||
if request.method == 'POST':
|
||||
file_to_upload = request.files.get('file')
|
||||
if file_to_upload:
|
||||
filename = secure_filename(file_to_upload.filename)
|
||||
file_to_upload.save(os.path.join(result_path, filename))
|
||||
return jsonify(result="success")
|
||||
else:
|
||||
abort(503)
|
||||
|
||||
|
||||
@app.route('/admin/<data_type>/<path:path>', methods=['GET', 'POST'])
|
||||
def get_data_type_locations_by_path_or_get_file(data_type, path):
|
||||
####### validation ########
|
||||
if data_type not in app.config['DATA_TYPES']:
|
||||
abort(404)
|
||||
result_path = os.path.join(app.config["DIRECTORIES_BY_TYPE"][
|
||||
data_type],
|
||||
path)
|
||||
if not os.path.exists(result_path):
|
||||
abort(404)
|
||||
####### end validation ########
|
||||
if request.method == 'GET':
|
||||
locations = []
|
||||
#return file content or directory content
|
||||
if os.path.isfile(result_path):
|
||||
return send_file(result_path)
|
||||
else:
|
||||
for file in os.listdir(result_path):
|
||||
locations.append(os.path.join(path, file))
|
||||
result = {data_type: locations}
|
||||
return jsonify(result)
|
||||
|
||||
if request.method == 'POST':
|
||||
file_to_upload = request.files.get('file')
|
||||
if file_to_upload:
|
||||
filename = secure_filename(file_to_upload.filename)
|
||||
file_to_upload.save(os.path.join(result_path, filename))
|
||||
return jsonify(result="success")
|
||||
else:
|
||||
abort(403)
|
||||
|
||||
|
||||
@app.route('/admin/<data_type>/<path:path>', methods=['PUT', 'DELETE'])
|
||||
def create_dirs(data_type, path):
|
||||
if data_type not in app.config['DATA_TYPES']:
|
||||
abort(404)
|
||||
result_path = os.path.join(app.config["DIRECTORIES_BY_TYPE"][
|
||||
data_type],
|
||||
path)
|
||||
if request.method == 'PUT':
|
||||
resp = make_response()
|
||||
if os.path.exists(result_path):
|
||||
return resp
|
||||
if data_type == app.config['MANIFESTS']:
|
||||
abort(403)
|
||||
try:
|
||||
os.makedirs(result_path)
|
||||
except Exception as e:
|
||||
abort(403)
|
||||
return resp
|
||||
|
||||
if request.method == 'DELETE':
|
||||
if not os.path.exists(result_path):
|
||||
abort(404)
|
||||
if os.path.isfile(result_path):
|
||||
try:
|
||||
os.remove(result_path)
|
||||
except Exception as e:
|
||||
abort(404)
|
||||
else:
|
||||
try:
|
||||
os.rmdir(result_path)
|
||||
except Exception as e:
|
||||
abort(403)
|
||||
resp = make_response()
|
||||
return resp
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
app.run(debug=True)
|
||||
#by default server running on localhost:5000
|
Loading…
x
Reference in New Issue
Block a user