From 707ed651fb8276b40abea452d6e513d4fdace4a5 Mon Sep 17 00:00:00 2001 From: vanzhiganov Date: Thu, 9 Jun 2016 02:49:22 +0300 Subject: [PATCH] 66 API --- SWSCloudAPI/API/__init__.py | 313 ++++++++++++++++++++++++++++++++++++ SWSCloudAPI/__init__.py | 3 + SWSCloudAPI/application.py | 65 ++++++++ 3 files changed, 381 insertions(+) create mode 100644 SWSCloudAPI/API/__init__.py create mode 100644 SWSCloudAPI/__init__.py create mode 100644 SWSCloudAPI/application.py diff --git a/SWSCloudAPI/API/__init__.py b/SWSCloudAPI/API/__init__.py new file mode 100644 index 0000000..e7468d7 --- /dev/null +++ b/SWSCloudAPI/API/__init__.py @@ -0,0 +1,313 @@ +# coding: utf-8 + +from uuid import uuid4 +from flask import Blueprint, jsonify, request, g +from flask_httpauth import HTTPBasicAuth +from SWSCloudCore.controllers.datacenters import ControllerDataCenters +from SWSCloudCore.controllers.ips import ControllerIps +from SWSCloudCore.controllers.plans import ControllerPlans +from SWSCloudCore.controllers.containers import ControllerContainers +from SWSCloudCore.controllers.vms import ControllerVMS +from SWSCloudCore.controllers.users import ControllerAPI +from SWSCloudCore.controllers.users import ControllerUsers +from SWSCloudCore.controllers.users import ControllerSSHKey +from SWSCloudCore.controllers.billing import ControllerBilling +from SWSCloudCore.controllers.common import ControllerCommon, ControllerMessagesEmail +from SWSCloudCore.controllers.containers import ControllerContainersStatisticsState, ControllerContainersStatistics +from SWSCloudCore.controllers.tasks import ControllerTasks + + +api = Blueprint('api', __name__, url_prefix='/api/v1') +auth = HTTPBasicAuth() + +""" +TODO: Реализовать Процесс авторизации в версии API 2.0 +- получаем емейл и секретный ключ +- создаём временный токен +- выдаём токен +""" + + +@auth.verify_password +def verify_password(username, password): + if not ControllerAPI().auth(username, password): + return False + g.user_id = ControllerUsers().get_id_by_email(username) + return True + + +@api.route('/') +@auth.login_required +def index(): + """ + curl -X POST http://localhost:5000/api/v1/ -u : + :return: + """ + return jsonify(user_id=g.user_id) + + +@api.route('/datacenters/') +@auth.login_required +def datacenters_index(): + """ + get containers list + curl -X http://localhost:5000/api/v1/datacenters/ -u : + :return: + """ + dc_list = ControllerDataCenters().get() + return jsonify(total=dc_list.get('total'), items=dc_list.get('items')) + + +@api.route('/pricing/vms/') +@auth.login_required +def pricing_vms(): + """ + get pricing list + curl -X http://localhost:5000/api/v1/pricing/vms/ -u : + :return: + """ + return jsonify(pricing=ControllerPlans().get_plans(status='active')) + + +@api.route('/pricing/containers/') +@auth.login_required +def pricing_containers(): + """ + get pricing list + curl -X GET http://localhost:5000/api/v1/pricing/containers/ -u : + :return: + """ + return jsonify(pricing=100) + + +@api.route('/containers/', methods=['GET']) +@auth.login_required +def containers_list(): + """ + curl -X GET http://localhost:5000/api/v1/containers/ -u : + :return: + """ + # get containers list + containers = ControllerContainers(g.user_id).get_items() + # + return jsonify(total=containers['total'], items=containers['items']) + + +@api.route('/containers/', methods=['POST']) +@auth.login_required +def container_create(): + """ + curl -X POST http://localhost:5000/api/v1/containers/ -u : -d "datacenter_id=123" + :return: + """ + # Check exists data center + if not ControllerDataCenters().exists(request.form.get('datacenter')): + return jsonify(message='datacenter not exists') + # Check money + if ControllerBilling().get(g.user_id) <= 0: + return jsonify(message='no money') + + # select server from selected region with available ip-addresses + # select IP + select_ip = ControllerIps().getfree(request.form.get('datacenter')) + # mark ip as busy (taken) + ControllerIps().setbusy(select_ip.id) + # generate password for container user + password = ControllerCommon().generate_password(size=14) + + user_ssh = ControllerSSHKey(g.user_id) + + new_container = dict( + container_id=str(uuid4()), + datacenter_id=str(select_ip.datacenter.id), + server_id=str(select_ip.server.id), + ipv4=select_ip.ipv4, + ipv6=select_ip.ipv6, + ipv4_gateway=select_ip.ipv4_gateway, + ipv6_gateway=select_ip.ipv6_gateway, + username='ubuntu', + password=password, + ssh_key='', + ) + + # sshkey + if user_ssh.check(): + new_container['ssh_key'] = user_ssh.get() + + # create container record in database + # status 4: creation + status = 4 + container_create = ControllerContainers(g.user_id).create( + new_container['container_id'], + new_container['datacenter_id'], + new_container['server_id'], + new_container['ipv4'], + new_container['ipv6'], + status + ) + # create default state data + ControllerContainersStatisticsState().set(new_container['container_id'], dict()) + if container_create: + # create task for create new container + ControllerTasks(g.user_id).create( + new_container['datacenter_id'], + new_container['server_id'], + 'container_create', + 0, + container_id=new_container['container_id'], + ipv4=new_container['ipv4'], + ipv6=new_container['ipv6'], + ipv4_gateway=new_container['ipv4_gateway'], + ipv6_gateway=new_container['ipv6_gateway'], + username=new_container['username'], + password=new_container['password'], + ssh_key=new_container['ssh_key'] + ) + + # send mail message with recovery code + message_parts = [] + + if new_container['ipv4']: + message_parts.append(u"IPv4: %s" % new_container['ipv4']) + if new_container['ipv6']: + message_parts.append(u"IPv6: %s" % new_container['ipv6']) + message_parts.append(u"Пользователь: %s" % new_container['username']) + message_parts.append(u"Пароль: %s" % new_container['password']) + if new_container['ssh_key']: + message_parts.append(u"SSH ключ: добавлен") + + message = '
\n'.join(message_parts) + subject = u'GoCloud.ru: Новый контейнер' + lead = u"""Поздравляем с новым контейнером.""" + callout = u""" + Для входа в личный кабинет воспользуйтесь + страницей авторизации. + """ + + user_data = ControllerUsers(g.user_id).get() + + email = ControllerMessagesEmail() + email.send(title=subject, to=user_data.email, lead=lead, message=message, callout=callout) + + # + return jsonify(message='ok') + + +@api.route('/container/', methods=['DELETE']) +@auth.login_required +def container_delete(container_id): + """ + curl -X DELETE http://localhost:5000/api/v1/container/ -u : -d "container_id=" + :return: + """ + containers = ControllerContainers(g.user_id) + # check the user have a selected rule + # if user not have a container then redirect to the container list + if not containers.check_exists_item(container_id): + return jsonify(message='container_not_exists') + + # get container details + container_details = ControllerContainers(g.user_id).get_item(container_id) + + # Обновляем статус "5" для правила + containers.set_status(container_id, 5) + # Создание задания + ControllerTasks(g.user_id).create( + container_details.datacenter.id, + container_details.server.id, + 'container_delete', + 0, + container_id=container_id + ) + # TODO: send email container was deleted about + return jsonify(status=0, message='container has been deleted') + + +@api.route('/container/', methods=['GET']) +@auth.login_required +def container_info(container_id): + """ + curl -X GET http://localhost:5000/api/v1/container/ -u : + :return: + """ + # init + containers = ControllerContainers(g.user_id) + # check the user have a selected rule + # if user not have a container then redirect to the container list + if not containers.check_exists_item(container_id): + return jsonify(message='container_not_found') + # get container details + container_details = containers.get_item(container_id) + # print ControllerContainersStatisticsState().get(container_id) + + statistics = [] + for s in ControllerContainersStatistics(container_id).size_get(1): + created = s.created + statistics.append({ + 'year': created.strftime('%Y'), + 'month': created.strftime('%m'), + 'day': created.strftime('%d'), + 'hour': created.strftime('%H'), + 'minute': created.strftime('%M'), + 'data': s.memory + }) + # return + return jsonify(container=container_details, stats_memory=statistics) + + +@api.route('/container/', methods=['POST']) +@auth.login_required +def container_actions(container_id): + """ + curl -X POST http://localhost:5000/api/v1/container/ -u : -d "status=inactive" + curl -X POST http://localhost:5000/api/v1/container/ -u : -d "action=active" + :return: + """ + containers = ControllerContainers(g.user_id) + # check the user have a selected rule + # if user not have a container then redirect to the container list + if not containers.check_exists_item(container_id): + return jsonify(message='container_not_found') + + # get container details + container_details = containers.get_item(container_id) + + if request.form.get('status') == "inactive": + containers.set_status(container_id, 3) + # Создание задания + ControllerTasks(g.user_id).create( + container_details.datacenter.id, + container_details.server.id, + 'container_stop', + 0, + container_id=container_id + ) + elif request.form.get('status') == 'active': + balance = ControllerBilling().get(g.user_id) + + if balance <= 0: + return jsonify(message='no money') + + containers.set_status(container_id, 2) + # Создание задания + ControllerTasks(g.user_id).create( + container_details.datacenter.id, + container_details.server.id, + 'container_start', + 0, + container_id=container_details.id + ) + return jsonify(message='ok') + else: + return jsonify(status=1, message='require action') + + +@api.route('/vms/') +@auth.login_required +def vms_list(): + """ + get virtual servers list + curl -X POST http://localhost:5000/api/v1/vms/ -u : + :return: + """ + return jsonify(vms=ControllerVMS(g.user_id).get_items()) diff --git a/SWSCloudAPI/__init__.py b/SWSCloudAPI/__init__.py new file mode 100644 index 0000000..326e243 --- /dev/null +++ b/SWSCloudAPI/__init__.py @@ -0,0 +1,3 @@ +# coding: utf-8 + +from application import app diff --git a/SWSCloudAPI/application.py b/SWSCloudAPI/application.py new file mode 100644 index 0000000..57c3839 --- /dev/null +++ b/SWSCloudAPI/application.py @@ -0,0 +1,65 @@ +# coding: utf-8 + +from flask import Flask, g, jsonify +from SWSCloudAPI.API import api +from SWSCloudCore import models +from SWSCloudCore.models import database +from SWSCloudCore.config import config + +app = Flask(__name__) +# app.config['SERVER_NAME'] = settings.get('Application', 'SERVER_NAME') +app.config['DEBUG'] = config.getboolean('Application', 'DEBUG') +app.config['SECRET_KEY'] = config.get("Application", "SECRET_KEY") + +app.register_blueprint(api) + + +@app.errorhandler(404) +def page_not_found(e): + app.logger.error(e) + return jsonify(dict(message='resource not found')), 404 + + +@app.errorhandler(403) +def access_deny(e): + app.logger.error(e) + return jsonify(dict(message='access deny')), 403 + + +@app.errorhandler(410) +def page_not_found(e): + app.logger.error(e) + return jsonify(dict()), 410 + + +@app.errorhandler(500) +def page_not_found(e): + app.logger.error(e) + return jsonify(dict(message='maintenance')), 500 + + +@app.before_request +def before_request(): + g.settings = dict() + # извлекаем настройки и определяем их в глобальную переменную + for setting in models.Settings.select(models.Settings.key, models.Settings.val).execute(): + g.settings[setting.key] = setting.val + + +@app.before_first_request +def before_first_request(): + try: + database.connect() + except Exception as e: + app.logger.error(e) + return jsonify({}), 500 + + +@app.after_request +def after_request(response): + # TODO: report about access + return response + + +if __name__ == '__main__': + app.run(host='0.0.0.0', port=5001, debug=True)