refactoting and new apiv2
This commit is contained in:
parent
ef3933802e
commit
9261b24730
29 changed files with 563 additions and 166 deletions
BIN
FreeSans.ttf
BIN
FreeSans.ttf
Binary file not shown.
BIN
FreeSansBold.ttf
BIN
FreeSansBold.ttf
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -1,35 +0,0 @@
|
|||
# coding: utf-8
|
||||
|
||||
from flask import Blueprint, jsonify, g
|
||||
from flask_httpauth import HTTPBasicAuth
|
||||
from SWSCloudCore.controllers.users import ControllerAPI
|
||||
from SWSCloudCore.controllers.users import ControllerUsers
|
||||
|
||||
|
||||
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 <email>:<secret>
|
||||
:return:
|
||||
"""
|
||||
return jsonify(user_id=g.user_id)
|
0
SWSCloudAPI/API/compute/__init__.py
Normal file
0
SWSCloudAPI/API/compute/__init__.py
Normal file
1
SWSCloudAPI/API/compute/v1/__init__.py
Normal file
1
SWSCloudAPI/API/compute/v1/__init__.py
Normal file
|
@ -0,0 +1 @@
|
|||
# coding: utf-8
|
17
SWSCloudAPI/API/compute/v1/api.py
Normal file
17
SWSCloudAPI/API/compute/v1/api.py
Normal file
|
@ -0,0 +1,17 @@
|
|||
# coding: utf-8
|
||||
|
||||
from flask import Blueprint, jsonify, g
|
||||
|
||||
from SWSCloudAPI.API.compute.v1.common import auth
|
||||
|
||||
api_v1 = Blueprint('api', __name__, url_prefix='/api/compute/v1')
|
||||
|
||||
|
||||
@api_v1.route('/')
|
||||
@auth.login_required
|
||||
def index():
|
||||
"""
|
||||
curl -X POST http://localhost:5000/api/v1/ -u <email>:<secret>
|
||||
:return:
|
||||
"""
|
||||
return jsonify(user_id=g.user_id)
|
15
SWSCloudAPI/API/compute/v1/common.py
Normal file
15
SWSCloudAPI/API/compute/v1/common.py
Normal file
|
@ -0,0 +1,15 @@
|
|||
|
||||
from SWSCloudCore.controllers.users import ControllerAPI
|
||||
from SWSCloudCore.controllers.users import ControllerUsers
|
||||
|
||||
from flask_httpauth import HTTPBasicAuth
|
||||
|
||||
auth = HTTPBasicAuth()
|
||||
|
||||
|
||||
@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
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
from uuid import uuid4
|
||||
from flask import Blueprint, jsonify, request, g
|
||||
from SWSCloudAPI.API import auth
|
||||
from SWSCloudAPI.API.compute.v1.common import auth
|
||||
from SWSCloudCore.controllers.datacenters import ControllerDataCenters
|
||||
from SWSCloudCore.controllers.ips import ControllerIps
|
||||
from SWSCloudCore.controllers.users import ControllerUsers
|
||||
|
@ -13,7 +13,7 @@ from SWSCloudCore.controllers.tasks import ControllerTasks
|
|||
from SWSCloudCore.controllers.containers import (
|
||||
ControllerContainers, ControllerContainersStatistics, ControllerContainersStatisticsState)
|
||||
|
||||
api_v1_containers = Blueprint('containers', __name__, url_prefix='/api/v1/containers')
|
||||
api_v1_containers = Blueprint('containers', __name__, url_prefix='/api/compute/v1/containers')
|
||||
|
||||
|
||||
@api_v1_containers.route('/', methods=['GET'])
|
24
SWSCloudAPI/API/compute/v1/datacenters.py
Normal file
24
SWSCloudAPI/API/compute/v1/datacenters.py
Normal file
|
@ -0,0 +1,24 @@
|
|||
# coding: utf-8
|
||||
|
||||
from flask import Blueprint, jsonify
|
||||
from SWSCloudAPI.API.compute.v1.common import auth
|
||||
from SWSCloudCore.models import DataCenters
|
||||
|
||||
|
||||
api_v1_datacenters = Blueprint('datacenters', __name__, url_prefix='/api/compute/v1/datacenters')
|
||||
|
||||
|
||||
@api_v1_datacenters.route('/', methods=['GET'])
|
||||
@auth.login_required
|
||||
def index():
|
||||
"""
|
||||
get containers list
|
||||
curl -X http://localhost:5000/api/compute/v1/datacenters/ -u <email>:<secret>
|
||||
:return:
|
||||
"""
|
||||
# dc_list = ControllerDataCenters().get()
|
||||
dc_list = DataCenters.get_available()
|
||||
items = list()
|
||||
for x in dc_list:
|
||||
items.append(x)
|
||||
return jsonify(total=len(dc_list), items=items)
|
|
@ -1,13 +1,13 @@
|
|||
# coding: utf-8
|
||||
|
||||
from flask import Blueprint, jsonify
|
||||
from SWSCloudAPI.API import auth
|
||||
from SWSCloudAPI.API.compute.v1.common import auth
|
||||
from SWSCloudCore.controllers.plans import ControllerPlans
|
||||
|
||||
api_v1_pricing = Blueprint('pricing', __name__, url_prefix='/api/v1/pricing')
|
||||
api_v1_pricing = Blueprint('pricing', __name__, url_prefix='/api/compute/v1/pricing')
|
||||
|
||||
|
||||
@api_v1_pricing.route('/pricing/vms/')
|
||||
@api_v1_pricing.route('/vms')
|
||||
@auth.login_required
|
||||
def pricing_vms():
|
||||
"""
|
||||
|
@ -18,7 +18,7 @@ def pricing_vms():
|
|||
return jsonify(pricing=ControllerPlans().get_plans(status='active'))
|
||||
|
||||
|
||||
@api_v1_pricing.route('/pricing/containers/')
|
||||
@api_v1_pricing.route('/containers')
|
||||
@auth.login_required
|
||||
def pricing_containers():
|
||||
"""
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
from uuid import uuid4
|
||||
from flask import Blueprint, jsonify, request, g
|
||||
from SWSCloudAPI.API import auth
|
||||
from SWSCloudAPI.API.compute.v1.common import auth
|
||||
from SWSCloudCore.controllers.ips import ControllerIps
|
||||
from SWSCloudCore.controllers.plans import ControllerPlans
|
||||
from SWSCloudCore.controllers.users import ControllerUsers
|
||||
|
@ -12,7 +12,7 @@ from SWSCloudCore.controllers.common import ControllerCommon, ControllerMessages
|
|||
from SWSCloudCore.controllers.tasks import ControllerTasks
|
||||
from SWSCloudCore.controllers.vms import ControllerVMS
|
||||
|
||||
api_v1_vms = Blueprint('vms', __name__, url_prefix='/api/v1/vms')
|
||||
api_v1_vms = Blueprint('vms', __name__, url_prefix='/api/compute/v1/vms')
|
||||
|
||||
|
||||
@api_v1_vms.route('/', methods=['GET'])
|
0
SWSCloudAPI/API/compute/v2/__init__.py
Normal file
0
SWSCloudAPI/API/compute/v2/__init__.py
Normal file
3
SWSCloudAPI/API/compute/v2/common.py
Normal file
3
SWSCloudAPI/API/compute/v2/common.py
Normal file
|
@ -0,0 +1,3 @@
|
|||
|
||||
TOKEN_TTL = 1800
|
||||
TOKEN_PREFIX = 'token_'
|
33
SWSCloudAPI/API/compute/v2/datacenters.py
Normal file
33
SWSCloudAPI/API/compute/v2/datacenters.py
Normal file
|
@ -0,0 +1,33 @@
|
|||
# coding: utf-8
|
||||
|
||||
from flask import Blueprint, jsonify, request, g
|
||||
from SWSCloudAPI.API.compute.v2.common import *
|
||||
from SWSCloudCore.models import DataCenters
|
||||
|
||||
|
||||
api_v2_datacenters = Blueprint('v2datacenters', __name__, url_prefix='/api/compute/v2/datacenters')
|
||||
|
||||
|
||||
@api_v2_datacenters.route('/', methods=['GET'])
|
||||
def datacenter_list():
|
||||
"""
|
||||
get containers list
|
||||
curl -X http://localhost:5000/api/compute/v1/datacenters/ -u <email>:<secret>
|
||||
:return:
|
||||
"""
|
||||
if request.headers.get('Content-Type') != 'application/json':
|
||||
return jsonify(status='fail', message='content-type must be application/json')
|
||||
|
||||
# check exists token
|
||||
if not g.tokens.exists(TOKEN_PREFIX + request.headers.get('X-Auth-Token')):
|
||||
return jsonify(status='fail', message='token not exists')
|
||||
|
||||
# TODO: move to different endpoint
|
||||
g.tokens.expire(TOKEN_PREFIX + request.headers.get('X-Auth-Token'), TOKEN_TTL)
|
||||
|
||||
#
|
||||
dc_list = DataCenters.get_available()
|
||||
items = list()
|
||||
for x in dc_list:
|
||||
items.append(x)
|
||||
return jsonify(status='ok', payload=items, total=len(dc_list))
|
28
SWSCloudAPI/API/compute/v2/pricing.py
Normal file
28
SWSCloudAPI/API/compute/v2/pricing.py
Normal file
|
@ -0,0 +1,28 @@
|
|||
# coding: utf-8
|
||||
|
||||
from flask import Blueprint, jsonify, request, g
|
||||
from SWSCloudAPI.API.compute.v2.common import *
|
||||
from SWSCloudCore.controllers.plans import ControllerPlans
|
||||
|
||||
api_v2_pricing = Blueprint('v2pricing', __name__, url_prefix='/api/compute/v2/pricing')
|
||||
|
||||
|
||||
@api_v2_pricing.route('/')
|
||||
def pricing():
|
||||
"""get pricing list
|
||||
curl -XGET http://localhost:5001/api/compute/v2/pricing/ -H "X-Auth-Token: ad89abee-49bc-4434-98ee-c7598c2f0adc" -H "Content-Type: application/json"
|
||||
|
||||
:return:
|
||||
"""
|
||||
if request.headers.get('Content-Type') != 'application/json':
|
||||
return jsonify(status='fail', message='content-type must be application/json')
|
||||
|
||||
# check exists token
|
||||
if not g.tokens.exists(TOKEN_PREFIX + request.headers.get('X-Auth-Token')):
|
||||
return jsonify(status='fail', message='token not exists')
|
||||
|
||||
# TODO: move to different endpoint
|
||||
g.tokens.expire(TOKEN_PREFIX + request.headers.get('X-Auth-Token'), TOKEN_TTL)
|
||||
|
||||
payload = ControllerPlans().get_plans(status='active')
|
||||
return jsonify(status='ok', payload=payload)
|
65
SWSCloudAPI/API/compute/v2/token.py
Normal file
65
SWSCloudAPI/API/compute/v2/token.py
Normal file
|
@ -0,0 +1,65 @@
|
|||
# coding: utf-8
|
||||
|
||||
import json
|
||||
import validators
|
||||
from uuid import uuid4
|
||||
from flask import Blueprint, jsonify, g, request
|
||||
from SWSCloudCore.models import Users
|
||||
from SWSCloudAPI.API.compute.v2.common import *
|
||||
|
||||
api_v2_token = Blueprint('v2token', __name__, url_prefix='/api/compute/v2/token')
|
||||
|
||||
|
||||
@api_v2_token.route('/', methods=['POST'])
|
||||
def token_post():
|
||||
"""Get token
|
||||
|
||||
_Example_
|
||||
|
||||
curl -XPOST http://localhost:5001/api/compute/v2/token/ -d '{"email":"vanzhiganov@ya.ru","password":"qwepoi123"}' -H "Content-Type: application/json"
|
||||
|
||||
|
||||
{
|
||||
"status": "ok",
|
||||
"token": "422f45a4-eab9-4a79-9954-61c568bae0eb"
|
||||
}
|
||||
:return:
|
||||
"""
|
||||
#
|
||||
if request.headers.get('Content-Type') != 'application/json':
|
||||
return jsonify(status='fail', message='content-type must be application/json')
|
||||
# validate email
|
||||
if not validators.email(request.json.get('email')):
|
||||
return jsonify(status='fail', message='invalid email format')
|
||||
# verify email/password
|
||||
if not Users.auth(request.json.get('email'), request.json.get('password')):
|
||||
return jsonify(status='fail', message='invalid auth')
|
||||
# get user data
|
||||
user = Users.get_by_email(request.json.get('email'))
|
||||
token = str(uuid4())
|
||||
g.tokens.set(TOKEN_PREFIX + token, json.dumps(dict(user_id=str(user.id))), TOKEN_TTL)
|
||||
return jsonify(status='ok', payload=dict(token=token))
|
||||
|
||||
|
||||
@api_v2_token.route('/', methods=['GET'])
|
||||
def token_get():
|
||||
"""Get token data
|
||||
curl -XGET http://localhost:5001/api/compute/v2/token/ -H "X-Auth-Token: 422f45a4-eab9-4a79-9954-61c568bae0eb" -H "Content-Type: application/json"
|
||||
:return:
|
||||
"""
|
||||
if request.headers.get('Content-Type') != 'application/json':
|
||||
return jsonify(status='fail', message='content-type must be application/json')
|
||||
|
||||
# check exists token
|
||||
if not g.tokens.exists(TOKEN_PREFIX + request.headers.get('X-Auth-Token')):
|
||||
return jsonify(status='fail', message='token not exists')
|
||||
|
||||
# TODO: move to different endpoint
|
||||
g.tokens.expire(TOKEN_PREFIX + request.headers.get('X-Auth-Token'), TOKEN_TTL)
|
||||
|
||||
return jsonify(
|
||||
status='ok',
|
||||
# ttl=g.tokens.ttl('token_'+request.headers.get('X-Auth-Token')),
|
||||
# pttl=g.tokens.pttl('token_'+request.headers.get('X-Auth-Token')),
|
||||
payload=json.loads(g.tokens.get(TOKEN_PREFIX + request.headers.get('X-Auth-Token')))
|
||||
)
|
290
SWSCloudAPI/API/compute/v2/vms.py
Normal file
290
SWSCloudAPI/API/compute/v2/vms.py
Normal file
|
@ -0,0 +1,290 @@
|
|||
# coding: utf-8
|
||||
|
||||
import json
|
||||
from uuid import uuid4
|
||||
from flask import Blueprint, jsonify, request, g
|
||||
from SWSCloudAPI.API.compute.v2.common import *
|
||||
from SWSCloudCore.controllers.ips import ControllerIps
|
||||
from SWSCloudCore.controllers.plans import ControllerPlans
|
||||
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.tasks import ControllerTasks
|
||||
from SWSCloudCore.controllers.vms import ControllerVMS
|
||||
|
||||
api_v2_vms = Blueprint('v2vms', __name__, url_prefix='/api/compute/v2/vms')
|
||||
|
||||
|
||||
@api_v2_vms.route('/', methods=['GET'])
|
||||
def vms_list():
|
||||
"""
|
||||
get virtual servers list
|
||||
curl -X POST http://localhost:5000/api/v1/vms/ -u <email>:<secret>
|
||||
:return:
|
||||
"""
|
||||
if request.headers.get('Content-Type') != 'application/json':
|
||||
return jsonify(status='fail', message='content-type must be application/json')
|
||||
|
||||
# check exists token
|
||||
if not g.tokens.exists(TOKEN_PREFIX + request.headers.get('X-Auth-Token')):
|
||||
return jsonify(status='fail', message='token not exists')
|
||||
|
||||
# TODO: move to different endpoint
|
||||
g.tokens.expire(TOKEN_PREFIX + request.headers.get('X-Auth-Token'), TOKEN_TTL)
|
||||
|
||||
user = json.loads(g.tokens.get(TOKEN_PREFIX + request.headers.get('X-Auth-Token')))
|
||||
|
||||
return jsonify(status='ok', payload=ControllerVMS(user.get('user_id')).get_items())
|
||||
|
||||
|
||||
@api_v2_vms.route('/', methods=['POST'])
|
||||
def vms_create():
|
||||
"""
|
||||
curl -XPOST /api/v1/vms/ -u <email>:<secret> -d 'plan=<uuid>&datacenter=<uuid>'
|
||||
:return:
|
||||
"""
|
||||
if request.headers.get('Content-Type') != 'application/json':
|
||||
return jsonify(status='fail', message='content-type must be application/json')
|
||||
|
||||
# check exists token
|
||||
if not g.tokens.exists(TOKEN_PREFIX + request.headers.get('X-Auth-Token')):
|
||||
return jsonify(status='fail', message='token not exists')
|
||||
|
||||
# TODO: move to different endpoint
|
||||
g.tokens.expire(TOKEN_PREFIX + request.headers.get('X-Auth-Token'), TOKEN_TTL)
|
||||
|
||||
user = json.loads(g.tokens.get(TOKEN_PREFIX + request.headers.get('X-Auth-Token')))
|
||||
|
||||
#
|
||||
|
||||
user_balance = ControllerBilling().get(user.get('user_id'))
|
||||
user_ssh = ControllerSSHKey(user.get('user_id'))
|
||||
controller_plans = ControllerPlans()
|
||||
|
||||
# check user money
|
||||
if user_balance <= 0:
|
||||
return jsonify(status='error', message='no money')
|
||||
|
||||
new_vm = dict()
|
||||
new_vm['vm_id'] = str(uuid4())
|
||||
|
||||
# check exists plan
|
||||
if not controller_plans.exists(request.json.get('plan')):
|
||||
return jsonify(message='plan not exists')
|
||||
|
||||
# load plan details
|
||||
plan_details = controller_plans.plan_get(request.json.get('plan'))
|
||||
|
||||
new_vm['plan'] = request.json.get('plan')
|
||||
|
||||
# select server from selected region with available ip-addresses
|
||||
# select IP
|
||||
select_ip = ControllerIps().getfree(request.json.get('datacenter'))
|
||||
# mark ip as busy (taken)
|
||||
ControllerIps().setbusy(select_ip.id)
|
||||
|
||||
# generate password for container user
|
||||
new_vm['password'] = ControllerCommon().generate_password(size=14)
|
||||
new_vm['hostname'] = ControllerCommon().generate_password(size=7)
|
||||
|
||||
new_vm['datacenter_id'] = str(select_ip.datacenter.id)
|
||||
new_vm['server_id'] = str(select_ip.server.id)
|
||||
|
||||
new_vm['platform'] = 'x86_64'
|
||||
new_vm['ipv4'] = select_ip.ipv4
|
||||
new_vm['ipv6'] = select_ip.ipv6
|
||||
|
||||
new_vm['ipv4_gateway'] = select_ip.ipv4_gateway
|
||||
new_vm['ipv6_gateway'] = select_ip.ipv6_gateway
|
||||
|
||||
# TODO: remove hardcore
|
||||
new_vm['dns1'] = '8.8.8.8'
|
||||
new_vm['dns2'] = '8.8.4.4'
|
||||
|
||||
new_vm['cores'] = plan_details.cores
|
||||
new_vm['storage'] = plan_details.storage
|
||||
new_vm['swap'] = plan_details.swap
|
||||
new_vm['memory'] = plan_details.memory
|
||||
|
||||
new_vm['os_name'] = 'ubuntu'
|
||||
new_vm['os_suite'] = 'trusty'
|
||||
|
||||
# sshkey
|
||||
new_vm['ssh_key'] = None
|
||||
if user_ssh.check():
|
||||
new_vm['ssh_key'] = user_ssh.get()
|
||||
|
||||
# create container record in database
|
||||
# status 4: creation
|
||||
status = 4
|
||||
container_create = ControllerVMS(user.get('user_id')).create(
|
||||
vm_id=new_vm['vm_id'],
|
||||
datacenter_id=new_vm['datacenter_id'],
|
||||
server_id=new_vm['server_id'],
|
||||
hostname=new_vm['hostname'],
|
||||
ipv4=new_vm['ipv4'],
|
||||
ipv6=new_vm['ipv6'],
|
||||
plan=new_vm['plan'],
|
||||
platform=new_vm['platform'],
|
||||
os_name=new_vm['os_name'],
|
||||
os_suite=new_vm['os_suite'],
|
||||
status=status
|
||||
)
|
||||
# create default state data
|
||||
# ControllerContainersStatisticsState().set(new_container['container_id'], dict())
|
||||
if not container_create:
|
||||
# mark ip as free
|
||||
ControllerIps().setfree(select_ip.id)
|
||||
return jsonify(status='error', message='fail')
|
||||
|
||||
# create task for create new container
|
||||
ControllerTasks(user.get('user_id')).create(
|
||||
new_vm['datacenter_id'],
|
||||
new_vm['server_id'],
|
||||
'vm_create',
|
||||
0,
|
||||
vm_id=new_vm['vm_id'],
|
||||
ipv4=new_vm['ipv4'],
|
||||
ipv4_gateway=new_vm['ipv4_gateway'],
|
||||
ipv6=new_vm['ipv6'],
|
||||
ipv6_gateway=new_vm['ipv6_gateway'],
|
||||
password=new_vm['password'],
|
||||
hostname=new_vm['hostname'],
|
||||
platform=new_vm['platform'],
|
||||
# TODO: remove hardcore
|
||||
dns1=new_vm['dns1'],
|
||||
dns2=new_vm['dns2'],
|
||||
|
||||
cores=new_vm['cores'],
|
||||
storage=new_vm['storage'],
|
||||
swap=new_vm['swap'],
|
||||
memory=new_vm['memory'],
|
||||
|
||||
os_name=new_vm['os_name'],
|
||||
os_suite=new_vm['os_suite'],
|
||||
|
||||
ssh_key=new_vm['ssh_key'],
|
||||
)
|
||||
|
||||
# send mail message with recovery code
|
||||
message_parts = []
|
||||
|
||||
if new_vm['ipv4']:
|
||||
message_parts.append(u"IPv4: %s" % new_vm['ipv4'])
|
||||
if new_vm['ipv6']:
|
||||
message_parts.append(u"IPv6: %s" % new_vm['ipv6'])
|
||||
message_parts.append(u"Пользователь: %s" % 'administrator')
|
||||
# message_parts.append(u"Пользователь: %s" % new_vm['username'])
|
||||
message_parts.append(u"Пароль: %s" % new_vm['password'])
|
||||
if new_vm['ssh_key']:
|
||||
message_parts.append(u"SSH ключ: добавлен")
|
||||
|
||||
message = '<br/>\n'.join(message_parts)
|
||||
subject = u'GoCloud.ru: Новый виртуальный сервер'
|
||||
lead = u"""Поздравляем с новым виртуальным сервером."""
|
||||
callout = u"""
|
||||
Для входа в личный кабинет воспользуйтесь
|
||||
<a href="https://gocloud.ru/account/login">страницей авторизации</a>.
|
||||
"""
|
||||
|
||||
user_data = ControllerUsers(user.get('user_id')).get()
|
||||
|
||||
email = ControllerMessagesEmail()
|
||||
email.send(title=subject, to=user_data.email, lead=lead, message=message, callout=callout)
|
||||
|
||||
return jsonify(
|
||||
status=0, message='ok',
|
||||
user='root', password=new_vm['password'], ipv4=new_vm['ipv4'],
|
||||
public_ssh_key='added' if new_vm['ssh_key'] else 'empty')
|
||||
|
||||
|
||||
@api_v2_vms.route('/<uuid:vm_id>', methods=['POST'])
|
||||
def vm_actions(vm_id):
|
||||
"""
|
||||
"""
|
||||
if request.headers.get('Content-Type') != 'application/json':
|
||||
return jsonify(status='fail', message='content-type must be application/json')
|
||||
|
||||
# check exists token
|
||||
if not g.tokens.exists(TOKEN_PREFIX + request.headers.get('X-Auth-Token')):
|
||||
return jsonify(status='fail', message='token not exists')
|
||||
|
||||
# TODO: move to different endpoint
|
||||
g.tokens.expire(TOKEN_PREFIX + request.headers.get('X-Auth-Token'), TOKEN_TTL)
|
||||
user = json.loads(g.tokens.get(TOKEN_PREFIX + request.headers.get('X-Auth-Token')))
|
||||
|
||||
# init ...
|
||||
vm = ControllerVMS(user.get('user_id'))
|
||||
# get container details
|
||||
vm_details = vm.get(vm_id=vm_id)
|
||||
|
||||
if request.json.get('action') == "start":
|
||||
if ControllerBilling().get(user.get('user_id')) <= 0:
|
||||
return jsonify(message='no money')
|
||||
|
||||
vm.set_status(vm_id, 2)
|
||||
# Создание задания
|
||||
ControllerTasks(user.get('user_id')).create(
|
||||
datacenter_id=vm_details.datacenter.id,
|
||||
server_id=vm_details.server.id,
|
||||
task='vm_start',
|
||||
status=0,
|
||||
vm_id=vm_details.id
|
||||
)
|
||||
|
||||
if request.json.get('action') == "restart":
|
||||
return jsonify(message='not supported')
|
||||
|
||||
if request.json.get('action') == "stop":
|
||||
vm.status_set(vm_id, 3)
|
||||
# Создание задания
|
||||
ControllerTasks(user.get('user_id')).create(
|
||||
vm_details.datacenter.id,
|
||||
vm_details.server.id,
|
||||
'vm_stop',
|
||||
0,
|
||||
vm_id=vm_id
|
||||
)
|
||||
|
||||
|
||||
@api_v2_vms.route('/<uuid:vm_id>', methods=['DELETE'])
|
||||
def vm_delete(vm_id):
|
||||
"""
|
||||
Удаление виртуального сервера
|
||||
:param vm_id:
|
||||
:return:
|
||||
"""
|
||||
if request.headers.get('Content-Type') != 'application/json':
|
||||
return jsonify(status='fail', message='content-type must be application/json')
|
||||
|
||||
# check exists token
|
||||
if not g.tokens.exists(TOKEN_PREFIX + request.headers.get('X-Auth-Token')):
|
||||
return jsonify(status='fail', message='token not exists')
|
||||
|
||||
# TODO: move to different endpoint
|
||||
g.tokens.expire(TOKEN_PREFIX + request.headers.get('X-Auth-Token'), TOKEN_TTL)
|
||||
|
||||
user = json.loads(g.tokens.get(TOKEN_PREFIX + request.headers.get('X-Auth-Token')))
|
||||
|
||||
#
|
||||
vms = ControllerVMS(user.get('user_id'))
|
||||
tasks = ControllerTasks(user.get('user_id'))
|
||||
# check the user have a selected rule
|
||||
# if user not have a container then redirect to the container list
|
||||
if not vms.exists(vm_id):
|
||||
return jsonify(message='not exists')
|
||||
# get container details
|
||||
vm_details = vms.get(vm_id)
|
||||
# Обновляем статус "5" для правила
|
||||
vms.set_status(vm_id, 5)
|
||||
# Создание задания
|
||||
tasks.create(
|
||||
datacenter_id=vm_details.datacenter.id,
|
||||
server_id=vm_details.server.id,
|
||||
task='vm_delete',
|
||||
status=0,
|
||||
vm_id=vm_id,
|
||||
# hostname=vm_details.hostname
|
||||
)
|
||||
return jsonify(status=0, message='ok')
|
|
@ -1,20 +0,0 @@
|
|||
# coding: utf-8
|
||||
|
||||
from flask import Blueprint, jsonify
|
||||
from SWSCloudAPI.API import auth
|
||||
from SWSCloudCore.controllers.datacenters import ControllerDataCenters
|
||||
|
||||
|
||||
api_v1_datacenters = Blueprint('datacenters', __name__, url_prefix='/api/v1/datacenters')
|
||||
|
||||
|
||||
@api_v1_datacenters.route('/', methods=['GET'])
|
||||
@auth.login_required
|
||||
def index():
|
||||
"""
|
||||
get containers list
|
||||
curl -X http://localhost:5000/api/v1/datacenters/ -u <email>:<secret>
|
||||
:return:
|
||||
"""
|
||||
dc_list = ControllerDataCenters().get()
|
||||
return jsonify(total=dc_list.get('total'), items=dc_list.get('items'))
|
|
@ -1,14 +1,21 @@
|
|||
# coding: utf-8
|
||||
|
||||
import redis
|
||||
|
||||
from SWSCloudAPI.API.compute.v1.datacenters import api_v1_datacenters
|
||||
from SWSCloudAPI.API.compute.v1.containers import api_v1_containers
|
||||
from SWSCloudAPI.API.compute.v1.pricing import api_v1_pricing
|
||||
from SWSCloudAPI.API.compute.v1.vms import api_v1_vms
|
||||
from SWSCloudAPI.API.compute.v2.token import api_v2_token
|
||||
from SWSCloudAPI.API.compute.v2.pricing import api_v2_pricing
|
||||
from SWSCloudAPI.API.compute.v2.datacenters import api_v2_datacenters
|
||||
from SWSCloudAPI.API.compute.v2.vms import api_v2_vms
|
||||
|
||||
from flask import Flask, g, jsonify
|
||||
from SWSCloudAPI.API import api
|
||||
from SWSCloudAPI.API.vms import api_v1_vms
|
||||
from SWSCloudAPI.API.containers import api_v1_containers
|
||||
from SWSCloudAPI.API.datacenters import api_v1_datacenters
|
||||
from SWSCloudAPI.API.pricing import api_v1_pricing
|
||||
|
||||
from SWSCloudCore import models
|
||||
from SWSCloudCore.models import database
|
||||
from SWSCloudCore.config import config
|
||||
from SWSCloudCore.models import database
|
||||
|
||||
app = Flask(__name__)
|
||||
# Думал, что получится сделать автопрефик для всего приложения, но это не сработало
|
||||
|
@ -17,39 +24,42 @@ app = Flask(__name__)
|
|||
app.config['DEBUG'] = config.getboolean('Application', 'DEBUG')
|
||||
app.config['SECRET_KEY'] = config.get("Application", "SECRET_KEY")
|
||||
|
||||
app.register_blueprint(api)
|
||||
app.register_blueprint(api_v1_vms)
|
||||
app.register_blueprint(api_v1_containers)
|
||||
app.register_blueprint(api_v1_pricing)
|
||||
app.register_blueprint(api_v1_datacenters)
|
||||
app.register_blueprint(api_v2_token)
|
||||
app.register_blueprint(api_v2_pricing)
|
||||
app.register_blueprint(api_v2_datacenters)
|
||||
|
||||
|
||||
@app.errorhandler(404)
|
||||
def page_not_found(e):
|
||||
app.logger.error(e)
|
||||
return jsonify(dict(message='resource not found')), 404
|
||||
return jsonify(status='error', message='resource not found')
|
||||
|
||||
|
||||
@app.errorhandler(403)
|
||||
def access_deny(e):
|
||||
app.logger.error(e)
|
||||
return jsonify(dict(message='access deny')), 403
|
||||
return jsonify(status='error', message='access deny'), 403
|
||||
|
||||
|
||||
@app.errorhandler(410)
|
||||
def page_not_found(e):
|
||||
app.logger.error(e)
|
||||
return jsonify(dict()), 410
|
||||
return jsonify({})
|
||||
|
||||
|
||||
@app.errorhandler(500)
|
||||
def page_not_found(e):
|
||||
app.logger.error(e)
|
||||
return jsonify(dict(message='maintenance')), 500
|
||||
return jsonify(status='maintenance')
|
||||
|
||||
|
||||
@app.before_request
|
||||
def before_request():
|
||||
g.tokens = redis.StrictRedis(config.get('Redis', 'host'), config.get('Redis', 'port'), config.get('Redis', 'db'))
|
||||
g.settings = dict()
|
||||
# извлекаем настройки и определяем их в глобальную переменную
|
||||
for setting in models.Settings.select(models.Settings.key, models.Settings.val).execute():
|
||||
|
|
|
@ -21,35 +21,38 @@ from SWSCloudCore import models
|
|||
viewAdministrator = Blueprint('administrator', __name__, url_prefix='/administrator')
|
||||
|
||||
|
||||
@viewAdministrator.route('/login.html', methods=['GET', 'POST'])
|
||||
@viewAdministrator.route('/login.html', methods=['GET'])
|
||||
def login():
|
||||
if request.method == 'POST':
|
||||
admin_email = request.form.get('email').encode('utf-8')
|
||||
admin_password = request.form.get('password').encode('utf-8')
|
||||
|
||||
# validation entered data
|
||||
if not validators.email(admin_email):
|
||||
flash('Invalid registration data')
|
||||
return redirect(url_for('administrator.login'))
|
||||
|
||||
# try auth only active users (with status code 1)
|
||||
if models.Admins.auth(admin_email, admin_password, 1):
|
||||
# get user_id
|
||||
user_id = ControllerAdministrators().get_id_by_email(admin_email)
|
||||
|
||||
# save user data to session
|
||||
session['admin_id'] = str(user_id)
|
||||
session['admin_email'] = admin_email
|
||||
session['admin_password'] = admin_password
|
||||
|
||||
# redirect to rules list
|
||||
return redirect(url_for('administrator.dashboard'))
|
||||
else:
|
||||
flash('Invalid login. Please try again.')
|
||||
return redirect(url_for('administrator.login'))
|
||||
return render_template('administrator/login.html')
|
||||
|
||||
|
||||
@viewAdministrator.route('/login.html', methods=['POST'])
|
||||
def login_post():
|
||||
admin_email = request.form.get('email').encode('utf-8')
|
||||
admin_password = request.form.get('password').encode('utf-8')
|
||||
|
||||
# validation entered data
|
||||
if not validators.email(admin_email):
|
||||
flash('Invalid registration data')
|
||||
return redirect(url_for('administrator.login'))
|
||||
|
||||
# try auth only active users (with status code 1)
|
||||
if not models.Admins.auth(admin_email, admin_password, 1):
|
||||
flash('Invalid login. Please try again.')
|
||||
return redirect(url_for('administrator.login'))
|
||||
|
||||
# get user_id
|
||||
user_id = ControllerAdministrators().get_id_by_email(admin_email)
|
||||
|
||||
# save user data to session
|
||||
session['admin_id'] = str(user_id)
|
||||
session['admin_email'] = admin_email
|
||||
session['admin_password'] = admin_password
|
||||
|
||||
# redirect to rules list
|
||||
return redirect(url_for('administrator.dashboard'))
|
||||
|
||||
|
||||
@viewAdministrator.route('/logout.html')
|
||||
def logout():
|
||||
session.pop('admin_id', None)
|
||||
|
|
|
@ -14,8 +14,8 @@
|
|||
</div>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
<form action="{{ url_for('administrator.login') }}" method="post">
|
||||
<label for="email">email</lable>
|
||||
<form action="{{ url_for('administrator.login_post') }}" method="post">
|
||||
<label for="email">email</label>
|
||||
<input type="text" name="email" value="" id="email" />
|
||||
<label for="password">password</label>
|
||||
<input type="password" name="password" value="" id="password" />
|
||||
|
|
|
@ -42,6 +42,16 @@ class DataCenters(PgSQLModel):
|
|||
city = CharField()
|
||||
status = IntegerField(default=0)
|
||||
|
||||
@staticmethod
|
||||
def get_available():
|
||||
return DataCenters.select().where(
|
||||
DataCenters.status == 1 and
|
||||
DataCenters.id << Servers.select(Servers.datacenter).where(
|
||||
Servers.status == 1 and
|
||||
Servers.id << Ips.select(Ips.server).where(
|
||||
Ips.status == 0).group_by(Ips.server)
|
||||
).group_by(Servers.datacenter)).execute()
|
||||
|
||||
|
||||
class Servers(PgSQLModel):
|
||||
id = UUIDField(unique=True, primary_key=True)
|
||||
|
@ -110,7 +120,9 @@ class Users(PgSQLModel):
|
|||
@staticmethod
|
||||
def auth(email, password, status=1):
|
||||
if Users.select().where(
|
||||
Users.email == email, Users.password == Users.hash_password(password), Users.status == status
|
||||
Users.email == email,
|
||||
Users.password == Users.hash_password(password),
|
||||
Users.status == status
|
||||
).count() == 0:
|
||||
return False
|
||||
return True
|
||||
|
@ -121,7 +133,11 @@ class Users(PgSQLModel):
|
|||
|
||||
@staticmethod
|
||||
def get_by_id(user_id):
|
||||
return Users.select().where(Users.id == user_id).get()
|
||||
return Users.select().where(Users.id == user_id).first()
|
||||
|
||||
@staticmethod
|
||||
def get_by_email(email):
|
||||
return Users.select().where(Users.email == email).first()
|
||||
|
||||
|
||||
class UsersRecoveryCodes(PgSQLModel):
|
||||
|
|
BIN
SWSCloudWeb/static/images/btn_google_signin_dark_normal_web.png
Normal file
BIN
SWSCloudWeb/static/images/btn_google_signin_dark_normal_web.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.9 KiB |
|
@ -114,14 +114,15 @@ def registration():
|
|||
user_id = ControllerUsers().get_id_by_email(email)
|
||||
|
||||
ControllerUsersDetails(user_id).details_create()
|
||||
ControllerBilling().create(user_id, g.settings['bonus'])
|
||||
ControllerBilling().create(user_id, g.settings.get('bonus', 0))
|
||||
ControllerAPI().set(user_id=user_id, secret=user_id, acl='', status=0)
|
||||
# ControllerU
|
||||
# send mail message with recovery code
|
||||
|
||||
message = u"""
|
||||
Е-почта: %s
|
||||
Пароль: %s
|
||||
""" % (request.form['email'], request.form['password'])
|
||||
""" % (request.form.get('email'), request.form.get('password'))
|
||||
subject = u'GoCloud.ru: Успешная регистрация'
|
||||
lead = u"""
|
||||
Поздравляем с успешной регистрацией.
|
||||
|
@ -130,10 +131,12 @@ def registration():
|
|||
Для входа в личный кабинет воспользуйтесь
|
||||
<a href="https://gocloud.ru/account/login">страницей авторизации</a>.
|
||||
"""
|
||||
|
||||
email = ControllerMessagesEmail()
|
||||
email.send(title=subject, to=request.form['email'], lead=lead, message=message, callout=callout)
|
||||
|
||||
try:
|
||||
email = ControllerMessagesEmail()
|
||||
email.send(title=subject, to=request.form['email'], lead=lead, message=message, callout=callout)
|
||||
except Exception as e:
|
||||
# TODO: write message
|
||||
pass
|
||||
# redirect to login page
|
||||
flash(u'Учетная запись успешно зарегистрирована.', 'success')
|
||||
return redirect(url_for('account.login'))
|
||||
|
|
57
letter.pdf
57
letter.pdf
|
@ -1,57 +0,0 @@
|
|||
%PDF-1.4
|
||||
%“Œ‹ž ReportLab Generated PDF document http://www.reportlab.com
|
||||
1 0 obj
|
||||
<< /F1 2 0 R /F2 3 0 R /F3 4 0 R >>
|
||||
endobj
|
||||
2 0 obj
|
||||
<< /BaseFont /Helvetica /Encoding /WinAnsiEncoding /Name /F1 /Subtype /Type1 /Type /Font >>
|
||||
endobj
|
||||
3 0 obj
|
||||
<< /BaseFont /ZapfDingbats /Encoding /ZapfDingbatsEncoding /Name /F2 /Subtype /Type1 /Type /Font >>
|
||||
endobj
|
||||
4 0 obj
|
||||
<< /BaseFont /Helvetica-Bold /Encoding /WinAnsiEncoding /Name /F3 /Subtype /Type1 /Type /Font >>
|
||||
endobj
|
||||
5 0 obj
|
||||
<< /Contents 9 0 R /MediaBox [ 0 0 612 792 ] /Parent 8 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << >>
|
||||
/Type /Page >>
|
||||
endobj
|
||||
6 0 obj
|
||||
<< /Outlines 10 0 R /PageMode /UseNone /Pages 8 0 R /Type /Catalog >>
|
||||
endobj
|
||||
7 0 obj
|
||||
<< /Author (anonymous) /CreationDate (D:20161016043545-03'00') /Creator (ReportLab PDF Library - www.reportlab.com) /Keywords () /ModDate (D:20161016043545-03'00') /Producer (ReportLab PDF Library - www.reportlab.com)
|
||||
/Subject (unspecified) /Title (untitled) /Trapped /False >>
|
||||
endobj
|
||||
8 0 obj
|
||||
<< /Count 1 /Kids [ 5 0 R ] /Type /Pages >>
|
||||
endobj
|
||||
9 0 obj
|
||||
<< /Filter [ /ASCII85Decode /FlateDecode ] /Length 735 >>
|
||||
stream
|
||||
GasJPgN)"%&;KYAnN1Qb2mh$p3r4rMVN;4S9M8:0o\'IG#dN4>AdE<^Be<hY@c;s8q=i@@FtJURd5T$fOTF5_E-4g)1.YG2KeFQoJ8+#&rd#f(=\4%YGebF-,<qiQl'Vh@an4dMP`TG>kQ+u/`Zr=3r2g^b-k.lUmI^LCk74u@CK)JQ#\18LWr5OS(-LdAS.D-;?`\=9'WQ4E)2H=GYuQ&Q:IVk]/;C:l,6%eP0-JM^Zo*hl9jJh13EmLqHkqBD>Fd\H2g+u@9V&>(\Lr(ZQ1*g4Q1/*N?/uhi?OS@-82hCT,T;,0dWmd#HA`%oY>R#_4KDHdZUmAdH%(AsJ1C4KcP[FDkE/;>k(8W,b"d_+GdLB1<BW$RY%:1"40!+_$"V>@5R;R"gGohPUPnc7,oXVAuZmRX:!mDlIV+%o0q+r6%6G_c\l:h4ZQ0a*n,/G=3b/IIli@D4@7"^rsL,8!"o'B7*N6I_.<76^h:?OIIk_oRsp`I=[aXl(P.[]4MPhpSe,6WhKr^h$#^6Q'EJ(Cf#9[g^o.O'pVP1<l/9g\KR2>FGms]h6\mnF++Nc#`c[5M^T0T1R[^UYMBR$o3nG#;>SA&Z)_+*ZRTi=A]Th,)r\&#?IWGdY82-R'\?<!NN$c<6bWHVXIL#)60S&<+<jAYeJb)DkoSHQqsV@:.N>%O@5Fq@s],dSsSJJS`X-9'K]D3V<LYJ[Au3rWiC:C+3rf(rW.VMNog~>endstream
|
||||
endobj
|
||||
10 0 obj
|
||||
<< /Count 0 /Type /Outlines >>
|
||||
endobj
|
||||
xref
|
||||
0 11
|
||||
0000000000 65535 f
|
||||
0000000075 00000 n
|
||||
0000000129 00000 n
|
||||
0000000239 00000 n
|
||||
0000000357 00000 n
|
||||
0000000472 00000 n
|
||||
0000000669 00000 n
|
||||
0000000757 00000 n
|
||||
0000001057 00000 n
|
||||
0000001119 00000 n
|
||||
0000001949 00000 n
|
||||
trailer
|
||||
<< /ID
|
||||
% ReportLab generated PDF document -- digest (http://www.reportlab.com)
|
||||
[(F\377\262C\004ZI\203\233\321\244^\250\251\025\300) (F\377\262C\004ZI\203\233\321\244^\250\251\025\300)]
|
||||
/Info 7 0 R /Root 6 0 R /Size 11 >>
|
||||
startxref
|
||||
1999
|
||||
%%EOF
|
1
setup.py
1
setup.py
|
@ -162,5 +162,6 @@ setup(
|
|||
'wsgiref==0.1.2',
|
||||
'sshpubkeys==1.0.6',
|
||||
'dateutils',
|
||||
'redis',
|
||||
]
|
||||
)
|
||||
|
|
BIN
tutorial.pdf
BIN
tutorial.pdf
Binary file not shown.
Loading…
Add table
Reference in a new issue