Compare commits
12 commits
master
...
dev/2.7.10
Author | SHA1 | Date | |
---|---|---|---|
![]() |
7655b8b97a | ||
![]() |
6a11181075 | ||
![]() |
bfe906a1cf | ||
![]() |
25444811aa | ||
![]() |
c7286dc164 | ||
![]() |
fceb922d94 | ||
4c4202b346 | |||
999452a488 | |||
9261b24730 | |||
ef3933802e | |||
60241f9ea8 | |||
15c1a81831 |
88 changed files with 1295 additions and 383 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -1,6 +1,6 @@
|
||||||
settings.ini
|
settings.ini
|
||||||
.idea/
|
.idea/
|
||||||
|
.venv/
|
||||||
# Created by .ignore support plugin (hsz.mobi)
|
# Created by .ignore support plugin (hsz.mobi)
|
||||||
### Python template
|
### Python template
|
||||||
# Byte-compiled / optimized / DLL files
|
# Byte-compiled / optimized / DLL files
|
||||||
|
|
5
.rsyncignore
Normal file
5
.rsyncignore
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
.venv
|
||||||
|
.git
|
||||||
|
__pycache__/
|
||||||
|
*.egg-info/
|
||||||
|
venv
|
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.
4
Makefile
Normal file
4
Makefile
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
DEST:=/opt/nativecloud
|
||||||
|
|
||||||
|
sync:
|
||||||
|
rsync -rvza --exclude-from .rsyncignore --delete ./ root@192.168.158.136:/opt/nativecloud/
|
11
README.md
11
README.md
|
@ -10,6 +10,7 @@ Statuses:
|
||||||
- 3: Процесс деактивации
|
- 3: Процесс деактивации
|
||||||
- 4: Создание...
|
- 4: Создание...
|
||||||
- 5: Удаление...
|
- 5: Удаление...
|
||||||
|
- 6: Перезапуск
|
||||||
|
|
||||||
_Tasks_
|
_Tasks_
|
||||||
|
|
||||||
|
@ -33,6 +34,12 @@ Statuses:
|
||||||
|
|
||||||
_Get containers status_
|
_Get containers status_
|
||||||
|
|
||||||
`curl -X GET http://127.0.0.1:5000/server_api/containers/status/ -u f411b7d6-bf93-4fcd-91ee-03e5343d0187:b3c9a8b0-95ca-11e5-bec1-28d244e159e9`
|
```shell
|
||||||
|
curl -X GET http://127.0.0.1:5000/server_api/containers/status/ \
|
||||||
|
-u f411b7d6-bf93-4fcd-91ee-03e5343d0187:b3c9a8b0-95ca-11e5-bec1-28d244e159e9
|
||||||
|
```
|
||||||
|
|
||||||
`curl -X POST http://127.0.0.1:5000/server_api/containers/status/663b31b4-22b1-4846-bfaf-27d6389beef4 -u f411b7d6-bf93-4fcd-91ee-03e5343d0187:b3c9a8b0-95ca-11e5-bec1-28d244e159e9 -d 'status=0&message="test"'`
|
```shell
|
||||||
|
curl -X POST http://127.0.0.1:5000/server_api/containers/status/663b31b4-22b1-4846-bfaf-27d6389beef4 \
|
||||||
|
-u f411b7d6-bf93-4fcd-91ee-03e5343d0187:b3c9a8b0-95ca-11e5-bec1-28d244e159e9 -d 'status=0&message="test"'
|
||||||
|
```
|
|
@ -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/auth/__init__.py
Normal file
0
SWSCloudAPI/API/auth/__init__.py
Normal file
2
SWSCloudAPI/API/auth/v2/__init__.py
Normal file
2
SWSCloudAPI/API/auth/v2/__init__.py
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
|
||||||
|
from .token import api_v2_token
|
59
SWSCloudAPI/API/auth/v2/token.py
Normal file
59
SWSCloudAPI/API/auth/v2/token.py
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
# coding: utf-8
|
||||||
|
|
||||||
|
from flask import Blueprint, jsonify, request, g
|
||||||
|
from SWSCloudCore.models import Users
|
||||||
|
from SWSCloudAPI.API.compute.v2.common import *
|
||||||
|
from SWSCloudAPI.Utils import decorators, Tokens
|
||||||
|
|
||||||
|
api_v2_token = Blueprint('v2token', __name__, url_prefix='/api/auth/v2')
|
||||||
|
|
||||||
|
|
||||||
|
@api_v2_token.route('/token', methods=['POST'])
|
||||||
|
@decorators.content_type
|
||||||
|
@decorators.login_required
|
||||||
|
def token_post():
|
||||||
|
"""Get token
|
||||||
|
|
||||||
|
_Example_
|
||||||
|
|
||||||
|
curl -X POST http://localhost:5001/api/auth/v2/token -d '{"email":"vanzhiganov@ya.ru","password":"qwepoi123"}' -H "Content-Type: application/json"
|
||||||
|
|
||||||
|
|
||||||
|
{
|
||||||
|
"status": "ok",
|
||||||
|
"payload": {
|
||||||
|
"token": "422f45a4-eab9-4a79-9954-61c568bae0eb",
|
||||||
|
"email": "email@my.com"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
# get user data
|
||||||
|
user = Users.get_by_email(request.json.get('email'))
|
||||||
|
#
|
||||||
|
new_token = Tokens().set(dict(user_id=str(user.id), email=user.email), TOKEN_TTL)
|
||||||
|
#
|
||||||
|
return jsonify(status='ok', payload={'token': new_token})
|
||||||
|
|
||||||
|
|
||||||
|
@api_v2_token.route('/token', methods=['GET'])
|
||||||
|
@decorators.content_type
|
||||||
|
@decorators.auth_token
|
||||||
|
def token_get():
|
||||||
|
"""Get token data
|
||||||
|
curl -X GET http://localhost:5001/api/auth/v2/token -H "X-Auth-Token: 422f45a4-eab9-4a79-9954-61c568bae0eb" -H "Content-Type: application/json"
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
return jsonify(status='ok', payload=g.tokens.get(g.auth_token))
|
||||||
|
|
||||||
|
|
||||||
|
@api_v2_token.route('/token', methods=['DELETE'])
|
||||||
|
@decorators.content_type
|
||||||
|
@decorators.auth_token
|
||||||
|
def token_delete():
|
||||||
|
"""
|
||||||
|
curl -X DELETE http://localhost:5001/api/auth/v2/token -H "X-Auth-Token: 422f45a4-eab9-4a79-9954-61c568bae0eb" -H "Content-Type: application/json"
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
g.tokens.delete(g.auth_token)
|
||||||
|
return jsonify(status='ok')
|
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
|
16
SWSCloudAPI/API/compute/v1/common.py
Normal file
16
SWSCloudAPI/API/compute/v1/common.py
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
|
||||||
|
from SWSCloudCore.controllers.users import ControllerAPI
|
||||||
|
from SWSCloudCore.controllers.users import ControllerUsers
|
||||||
|
|
||||||
|
from flask import g
|
||||||
|
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
|
4
SWSCloudAPI/API/compute/v1/views/__init__.py
Normal file
4
SWSCloudAPI/API/compute/v1/views/__init__.py
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
from .containers import api_v1_containers
|
||||||
|
from .datacenters import api_v1_datacenters
|
||||||
|
from .pricing import api_v1_pricing
|
||||||
|
from .vms import api_v1_vms
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
from uuid import uuid4
|
from uuid import uuid4
|
||||||
from flask import Blueprint, jsonify, request, g
|
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.datacenters import ControllerDataCenters
|
||||||
from SWSCloudCore.controllers.ips import ControllerIps
|
from SWSCloudCore.controllers.ips import ControllerIps
|
||||||
from SWSCloudCore.controllers.users import ControllerUsers
|
from SWSCloudCore.controllers.users import ControllerUsers
|
||||||
|
@ -13,7 +13,7 @@ from SWSCloudCore.controllers.tasks import ControllerTasks
|
||||||
from SWSCloudCore.controllers.containers import (
|
from SWSCloudCore.controllers.containers import (
|
||||||
ControllerContainers, ControllerContainersStatistics, ControllerContainersStatisticsState)
|
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'])
|
@api_v1_containers.route('/', methods=['GET'])
|
24
SWSCloudAPI/API/compute/v1/views/datacenters.py
Normal file
24
SWSCloudAPI/API/compute/v1/views/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
|
# coding: utf-8
|
||||||
|
|
||||||
from flask import Blueprint, jsonify
|
from flask import Blueprint, jsonify
|
||||||
from SWSCloudAPI.API import auth
|
from SWSCloudAPI.API.compute.v1.common import auth
|
||||||
from SWSCloudCore.controllers.plans import ControllerPlans
|
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
|
@auth.login_required
|
||||||
def pricing_vms():
|
def pricing_vms():
|
||||||
"""
|
"""
|
||||||
|
@ -18,7 +18,7 @@ def pricing_vms():
|
||||||
return jsonify(pricing=ControllerPlans().get_plans(status='active'))
|
return jsonify(pricing=ControllerPlans().get_plans(status='active'))
|
||||||
|
|
||||||
|
|
||||||
@api_v1_pricing.route('/pricing/containers/')
|
@api_v1_pricing.route('/containers')
|
||||||
@auth.login_required
|
@auth.login_required
|
||||||
def pricing_containers():
|
def pricing_containers():
|
||||||
"""
|
"""
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
from uuid import uuid4
|
from uuid import uuid4
|
||||||
from flask import Blueprint, jsonify, request, g
|
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.ips import ControllerIps
|
||||||
from SWSCloudCore.controllers.plans import ControllerPlans
|
from SWSCloudCore.controllers.plans import ControllerPlans
|
||||||
from SWSCloudCore.controllers.users import ControllerUsers
|
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.tasks import ControllerTasks
|
||||||
from SWSCloudCore.controllers.vms import ControllerVMS
|
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'])
|
@api_v1_vms.route('/', methods=['GET'])
|
3
SWSCloudAPI/API/compute/v2/__init__.py
Normal file
3
SWSCloudAPI/API/compute/v2/__init__.py
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
from .views.datacenters import api_v2_datacenters
|
||||||
|
from .views.pricing import api_v2_pricing
|
||||||
|
from .views.vms import api_v2_vms
|
4
SWSCloudAPI/API/compute/v2/common.py
Normal file
4
SWSCloudAPI/API/compute/v2/common.py
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
|
||||||
|
TOKEN_TTL = 1800
|
||||||
|
TOKEN_PREFIX = 'token_'
|
||||||
|
|
0
SWSCloudAPI/API/compute/v2/views/__init__.py
Normal file
0
SWSCloudAPI/API/compute/v2/views/__init__.py
Normal file
254
SWSCloudAPI/API/compute/v2/views/containers.py
Normal file
254
SWSCloudAPI/API/compute/v2/views/containers.py
Normal file
|
@ -0,0 +1,254 @@
|
||||||
|
# coding: utf-8
|
||||||
|
|
||||||
|
from uuid import uuid4
|
||||||
|
|
||||||
|
from flask import Blueprint, jsonify, request, g
|
||||||
|
|
||||||
|
from SWSCloudAPI.Utils import Tokens
|
||||||
|
from SWSCloudAPI.Utils import decorators
|
||||||
|
from SWSCloudCore.controllers.billing import ControllerBilling
|
||||||
|
from SWSCloudCore.controllers.common import ControllerCommon, ControllerMessagesEmail
|
||||||
|
from SWSCloudCore.controllers.containers import (
|
||||||
|
ControllerContainers, ControllerContainersStatistics, ControllerContainersStatisticsState)
|
||||||
|
from SWSCloudCore.controllers.datacenters import ControllerDataCenters
|
||||||
|
from SWSCloudCore.controllers.ips import ControllerIps
|
||||||
|
from SWSCloudCore.controllers.tasks import ControllerTasks
|
||||||
|
from SWSCloudCore.controllers.users import ControllerSSHKey
|
||||||
|
from SWSCloudCore.controllers.users import ControllerUsers
|
||||||
|
|
||||||
|
api_v2_containers = Blueprint('v2containers', __name__, url_prefix='/api/compute/v2/containers')
|
||||||
|
|
||||||
|
|
||||||
|
@api_v2_containers.route('/', methods=['GET'])
|
||||||
|
@decorators.content_type
|
||||||
|
@decorators.auth_token
|
||||||
|
def containers_list():
|
||||||
|
"""
|
||||||
|
curl -X GET http://localhost:5000/api/v1/containers/ -u <email>:<secret>
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
tokens = Tokens()
|
||||||
|
|
||||||
|
# get containers list
|
||||||
|
containers = ControllerContainers(g.user_id).get_items()
|
||||||
|
#
|
||||||
|
return jsonify(total=containers['total'], items=containers['items'])
|
||||||
|
|
||||||
|
|
||||||
|
@api_v2_containers.route('/', methods=['POST'])
|
||||||
|
@decorators.content_type
|
||||||
|
@decorators.auth_token
|
||||||
|
def container_create():
|
||||||
|
"""
|
||||||
|
curl -X POST http://localhost:5000/api/v1/containers/ -u <email>:<secret> -d "datacenter_id=123"
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
# Check exists data center
|
||||||
|
if not ControllerDataCenters().exists(request.form.get('datacenter')):
|
||||||
|
return jsonify(message='datacenter not exists')
|
||||||
|
|
||||||
|
tokens = Tokens()
|
||||||
|
|
||||||
|
# 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='',
|
||||||
|
)
|
||||||
|
|
||||||
|
# SSH key
|
||||||
|
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 = '<br/>\n'.join(message_parts)
|
||||||
|
subject = u'GoCloud.ru: Новый контейнер'
|
||||||
|
lead = u"""Поздравляем с новым контейнером."""
|
||||||
|
callout = u"""
|
||||||
|
Для входа в личный кабинет воспользуйтесь
|
||||||
|
<a href="https://gocloud.ru/account/login">страницей авторизации</a>.
|
||||||
|
"""
|
||||||
|
|
||||||
|
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_v2_containers.route('/container/<uuid:container_id>', methods=['DELETE'])
|
||||||
|
@decorators.content_type
|
||||||
|
@decorators.auth_token
|
||||||
|
def container_delete(container_id):
|
||||||
|
"""
|
||||||
|
curl -X DELETE http://gocloud.ru/api/v1/container/<uuid:container_id> -u <email>:<secret> -d "container_id=<uuid:container_id>"
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
auth_token = request.headers.get('X-Auth-Token')
|
||||||
|
tokens = Tokens()
|
||||||
|
|
||||||
|
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_v2_containers.route('/<uuid:container_id>', methods=['GET'])
|
||||||
|
@decorators.content_type
|
||||||
|
@decorators.auth_token
|
||||||
|
def container_info(container_id):
|
||||||
|
"""
|
||||||
|
curl -X GET http://localhost:5000/api/v1/container/<uuid:container_id> -u <email>:<secret>
|
||||||
|
: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 = list()
|
||||||
|
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_v2_containers.route('/<uuid:container_id>', methods=['POST'])
|
||||||
|
@decorators.content_type
|
||||||
|
@decorators.auth_token
|
||||||
|
def container_actions(container_id):
|
||||||
|
"""
|
||||||
|
curl -X POST http://localhost:5000/api/v1/container/<uuid:container_id> -u <email>:<secret> -d "status=inactive"
|
||||||
|
curl -X POST http://localhost:5000/api/v1/container/<uuid:container_id> -u <email>:<secret> -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(status='error', 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')
|
25
SWSCloudAPI/API/compute/v2/views/datacenters.py
Normal file
25
SWSCloudAPI/API/compute/v2/views/datacenters.py
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
# coding: utf-8
|
||||||
|
|
||||||
|
from flask import Blueprint, jsonify, g
|
||||||
|
|
||||||
|
from SWSCloudAPI.Utils import decorators
|
||||||
|
from SWSCloudCore.models import DataCenters
|
||||||
|
|
||||||
|
api_v2_datacenters = Blueprint('v2datacenters', __name__, url_prefix='/api/compute/v2/datacenters')
|
||||||
|
|
||||||
|
|
||||||
|
@api_v2_datacenters.route('/', methods=['GET'])
|
||||||
|
@decorators.content_type
|
||||||
|
@decorators.auth_token
|
||||||
|
def datacenter_list():
|
||||||
|
"""Get containers list
|
||||||
|
curl -X http://localhost:5000/api/compute/v2/datacenters/ -H "X-Auth-Token: a90bb6cd-681f-4f87-b1ca-ea30921e3440" -H "Content-Type: application/json"
|
||||||
|
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
#
|
||||||
|
dc_list = DataCenters.get_available()
|
||||||
|
items = list()
|
||||||
|
for x in dc_list:
|
||||||
|
items.append(dict(id=str(x.id), name=x.name, country=x.country, city=x.city))
|
||||||
|
return jsonify(status='ok', payload=items, total=len(dc_list))
|
22
SWSCloudAPI/API/compute/v2/views/pricing.py
Normal file
22
SWSCloudAPI/API/compute/v2/views/pricing.py
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
# coding: utf-8
|
||||||
|
|
||||||
|
from flask import Blueprint, jsonify, g
|
||||||
|
|
||||||
|
from SWSCloudAPI.Utils import decorators
|
||||||
|
from SWSCloudCore.controllers.plans import ControllerPlans
|
||||||
|
|
||||||
|
api_v2_pricing = Blueprint('v2pricing', __name__, url_prefix='/api/compute/v2/pricing')
|
||||||
|
|
||||||
|
|
||||||
|
@api_v2_pricing.route('/')
|
||||||
|
@decorators.content_type
|
||||||
|
@decorators.auth_token
|
||||||
|
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:
|
||||||
|
"""
|
||||||
|
#
|
||||||
|
payload = ControllerPlans().get_plans(status='active')
|
||||||
|
return jsonify(status='ok', payload=payload)
|
245
SWSCloudAPI/API/compute/v2/views/vms.py
Normal file
245
SWSCloudAPI/API/compute/v2/views/vms.py
Normal file
|
@ -0,0 +1,245 @@
|
||||||
|
# coding: utf-8
|
||||||
|
|
||||||
|
from uuid import uuid4
|
||||||
|
|
||||||
|
from flask import Blueprint, jsonify, request, g
|
||||||
|
|
||||||
|
from SWSCloudCore import models
|
||||||
|
from SWSCloudAPI.Utils import decorators
|
||||||
|
from SWSCloudCore.controllers.billing import ControllerBilling
|
||||||
|
from SWSCloudCore.controllers.common import ControllerCommon, ControllerMessagesEmail
|
||||||
|
from SWSCloudCore.controllers.ips import ControllerIps
|
||||||
|
from SWSCloudCore.controllers.plans import ControllerPlans
|
||||||
|
from SWSCloudCore.controllers.tasks import ControllerTasks
|
||||||
|
from SWSCloudCore.controllers.users import ControllerSSHKey
|
||||||
|
from SWSCloudCore.controllers.users import ControllerUsers
|
||||||
|
from SWSCloudCore.controllers.vms import ControllerVMS
|
||||||
|
|
||||||
|
api_v2_vms = Blueprint('v2vms', __name__, url_prefix='/api/compute/v2/vms')
|
||||||
|
|
||||||
|
|
||||||
|
@api_v2_vms.route('/', methods=['GET'])
|
||||||
|
@decorators.content_type
|
||||||
|
@decorators.auth_token
|
||||||
|
def vms_list():
|
||||||
|
"""Get virtual servers list"""
|
||||||
|
return jsonify(status='ok', payload=models.Vms.get_user_items(g.user.get('user_id')))
|
||||||
|
|
||||||
|
|
||||||
|
@api_v2_vms.route('/', methods=['POST'])
|
||||||
|
@decorators.content_type
|
||||||
|
@decorators.auth_token
|
||||||
|
def vms_create():
|
||||||
|
"""Create virtual server"""
|
||||||
|
user_balance = ControllerBilling().get(g.user.get('user_id'))
|
||||||
|
user_ssh = ControllerSSHKey(g.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(status='error', 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(g.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(g.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(g.user.get('user_id')).get()
|
||||||
|
|
||||||
|
email = ControllerMessagesEmail()
|
||||||
|
email.send(title=subject, to=user_data.email, lead=lead, message=message, callout=callout)
|
||||||
|
|
||||||
|
return jsonify(
|
||||||
|
status='ok', payload=dict(
|
||||||
|
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>/status', methods=['POST'])
|
||||||
|
@decorators.content_type
|
||||||
|
@decorators.auth_token
|
||||||
|
def vm_actions(vm_id):
|
||||||
|
"""
|
||||||
|
"""
|
||||||
|
# init ...
|
||||||
|
vm = ControllerVMS(g.user.get('user_id'))
|
||||||
|
# get container details
|
||||||
|
vm_details = vm.get(vm_id=vm_id)
|
||||||
|
|
||||||
|
if request.json.get('action') == "start":
|
||||||
|
if ControllerBilling().get(g.user.get('user_id')) <= 0:
|
||||||
|
return jsonify(message='no money')
|
||||||
|
|
||||||
|
vm.set_status(vm_id, 2)
|
||||||
|
# Создание задания
|
||||||
|
ControllerTasks(g.user.get('user_id')).create(
|
||||||
|
vm_details.datacenter.id, vm_details.server.id, 'vm_start', 0, vm_id=vm_details.id)
|
||||||
|
|
||||||
|
if request.json.get('action') == "restart":
|
||||||
|
#
|
||||||
|
vm.status_set(vm_id, 6)
|
||||||
|
# Создание задания
|
||||||
|
ControllerTasks(g.user.get('user_id')).create(
|
||||||
|
vm_details.datacenter.id, vm_details.server.id, 'vm_restart', 0, vm_id=vm_id)
|
||||||
|
|
||||||
|
if request.json.get('action') == "stop":
|
||||||
|
#
|
||||||
|
vm.status_set(vm_id, 3)
|
||||||
|
# Создание задания
|
||||||
|
ControllerTasks(g.user.get('user_id')).create(
|
||||||
|
vm_details.datacenter.id, vm_details.server.id, 'vm_stop', 0, vm_id=vm_id)
|
||||||
|
|
||||||
|
if request.json.get('action') == "delete":
|
||||||
|
# Обновляем статус "5" для правила
|
||||||
|
vm.set_status(vm_id, 5)
|
||||||
|
# Создание задания
|
||||||
|
models.Tasks.set_task(
|
||||||
|
vm_details.datacenter.id, vm_details.server.id, vm_details.user.id, 'vm_delete', 0, vm_id=vm_id)
|
||||||
|
return jsonify(status='ok')
|
||||||
|
|
||||||
|
|
||||||
|
@api_v2_vms.route('/<uuid:vm_id>', methods=['DELETE'])
|
||||||
|
@decorators.content_type
|
||||||
|
@decorators.auth_token
|
||||||
|
def vm_delete(vm_id):
|
||||||
|
"""Delete virtual machine
|
||||||
|
:param vm_id:
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
|
||||||
|
vms = ControllerVMS(g.user.get('user_id'))
|
||||||
|
tasks = ControllerTasks(g.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(status='error', message='not exists')
|
||||||
|
|
||||||
|
# get container details
|
||||||
|
vm_details = models.Vms.get_item(vm_id)
|
||||||
|
|
||||||
|
# Обновляем статус "5" для правила
|
||||||
|
vms.set_status(vm_id, 5)
|
||||||
|
|
||||||
|
# Создание задания
|
||||||
|
models.Tasks.set_task(
|
||||||
|
vm_details.datacenter.id, vm_details.server.id, vm_details.user.id, 'vm_delete', 0, vm_id=vm_id)
|
||||||
|
|
||||||
|
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'))
|
|
102
SWSCloudAPI/README.md
Normal file
102
SWSCloudAPI/README.md
Normal file
|
@ -0,0 +1,102 @@
|
||||||
|
# Compute API v1
|
||||||
|
|
||||||
|
...
|
||||||
|
|
||||||
|
# Compute API v2
|
||||||
|
|
||||||
|
## Auth
|
||||||
|
|
||||||
|
Create new Token
|
||||||
|
|
||||||
|
$ curl -X POST http://localhost:5001/api/auth/v2/token \
|
||||||
|
-d '{"email":"vanzhiganov@ya.ru","password":"qwepoi123"}' \
|
||||||
|
-H "Content-Type: application/json"
|
||||||
|
|
||||||
|
{
|
||||||
|
"payload": {
|
||||||
|
"token": true
|
||||||
|
},
|
||||||
|
"status": "ok"
|
||||||
|
}
|
||||||
|
|
||||||
|
Get token data
|
||||||
|
|
||||||
|
curl -X GET http://localhost:5001/api/auth/v2/token \
|
||||||
|
-H 'X-Auth-Token: e7a49627-1199-4c3a-a7d3-b482c00fa503' \
|
||||||
|
-H "Content-Type: application/json"
|
||||||
|
|
||||||
|
{
|
||||||
|
"payload": {
|
||||||
|
"email": "vanzhiganov@ya.ru",
|
||||||
|
"user_id": "1f3936af-be4c-43d5-b352-2f9c88c56857"
|
||||||
|
},
|
||||||
|
"status": "ok"
|
||||||
|
}
|
||||||
|
|
||||||
|
Delete token
|
||||||
|
|
||||||
|
curl -X DELETE http://localhost:5001/api/auth/v2/token \
|
||||||
|
-H 'X-Auth-Token: e7a49627-1199-4c3a-a7d3-b482c00fa503' \
|
||||||
|
-H "Content-Type: application/json"
|
||||||
|
|
||||||
|
{
|
||||||
|
"status": "ok"
|
||||||
|
}
|
||||||
|
|
||||||
|
## Data Centers
|
||||||
|
|
||||||
|
Get list data centers
|
||||||
|
|
||||||
|
curl -X GET http://localhost:5001/api/compute/v2/datacenters/ \
|
||||||
|
-H "X-Auth-Token: ef381b13-425d-4635-9d8a-bba91910dd26" \
|
||||||
|
-H "Content-Type: application/json"
|
||||||
|
{
|
||||||
|
"payload": [
|
||||||
|
{
|
||||||
|
"city": "moscow",
|
||||||
|
"country": "russia",
|
||||||
|
"id": "531511b2-dcf5-11e6-9175-a315ee8fdabf",
|
||||||
|
"name": "moscow 1"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"status": "ok",
|
||||||
|
"total": 1
|
||||||
|
}
|
||||||
|
|
||||||
|
## Pricing
|
||||||
|
|
||||||
|
curl -X GET http://localhost:5001/api/compute/v2/pricing/ \
|
||||||
|
-H "X-Auth-Token: ef381b13-425d-4635-9d8a-bba91910dd26" \
|
||||||
|
-H "Content-Type: application/json"
|
||||||
|
{
|
||||||
|
"payload": [],
|
||||||
|
"status": "ok"
|
||||||
|
}
|
||||||
|
|
||||||
|
## Virtual machines
|
||||||
|
|
||||||
|
Create new virtual achine
|
||||||
|
|
||||||
|
|
||||||
|
curl -X POST http://localhost:5001/api/compute/v2/vms/ \
|
||||||
|
-H "X-Auth-Token: ef381b13-425d-4635-9d8a-bba91910dd26" \
|
||||||
|
-H "Content-Type: application/json" '
|
||||||
|
-d '{"plan": "", "datacenter": "", }'
|
||||||
|
|
||||||
|
|
||||||
|
Errors
|
||||||
|
|
||||||
|
{
|
||||||
|
"message": "no money",
|
||||||
|
"status": "error"
|
||||||
|
}
|
||||||
|
|
||||||
|
Get list virtual achines
|
||||||
|
|
||||||
|
curl -X GET http://localhost:5001/api/compute/v2/vms/ \
|
||||||
|
-H "X-Auth-Token: ef381b13-425d-4635-9d8a-bba91910dd26" \
|
||||||
|
-H "Content-Type: application/json"
|
||||||
|
{
|
||||||
|
"payload": [],
|
||||||
|
"status": "ok"
|
||||||
|
}
|
1
SWSCloudAPI/Utils/__init__.py
Normal file
1
SWSCloudAPI/Utils/__init__.py
Normal file
|
@ -0,0 +1 @@
|
||||||
|
from .tokens import Tokens
|
48
SWSCloudAPI/Utils/decorators.py
Normal file
48
SWSCloudAPI/Utils/decorators.py
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
from functools import wraps
|
||||||
|
|
||||||
|
import validators
|
||||||
|
from flask import g, request, jsonify
|
||||||
|
|
||||||
|
from SWSCloudAPI.Utils import Tokens
|
||||||
|
from SWSCloudCore.models import Users
|
||||||
|
|
||||||
|
|
||||||
|
def login_required(f):
|
||||||
|
@wraps(f)
|
||||||
|
def decorated_function(*args, **kwargs):
|
||||||
|
# validate email
|
||||||
|
if not validators.email(request.json.get('email')):
|
||||||
|
return jsonify(status='error', message='invalid email format')
|
||||||
|
# verify email/password
|
||||||
|
if not Users.auth(request.json.get('email'), request.json.get('password').encode()):
|
||||||
|
return jsonify(status='error', message='invalid auth')
|
||||||
|
#
|
||||||
|
return f(*args, **kwargs)
|
||||||
|
return decorated_function
|
||||||
|
|
||||||
|
|
||||||
|
def content_type(f):
|
||||||
|
@wraps(f)
|
||||||
|
def decorated_function(*args, **kwargs):
|
||||||
|
if request.headers.get('Content-Type') != 'application/json':
|
||||||
|
return jsonify(status='error', message='content-type must be application/json')
|
||||||
|
return f(*args, **kwargs)
|
||||||
|
return decorated_function
|
||||||
|
|
||||||
|
|
||||||
|
def auth_token(f):
|
||||||
|
@wraps(f)
|
||||||
|
def decorated_function(*args, **kwargs):
|
||||||
|
#
|
||||||
|
g.auth_token = request.headers.get('X-Auth-Token', None)
|
||||||
|
#
|
||||||
|
if not g.auth_token:
|
||||||
|
return jsonify(status='error', message='X-Auth-Token not specified')
|
||||||
|
# check exists token
|
||||||
|
if not Tokens.exists(g.auth_token):
|
||||||
|
return jsonify(status='error', message='token not exists')
|
||||||
|
#
|
||||||
|
g.tokens = Tokens()
|
||||||
|
g.user = g.tokens.get(g.auth_token)
|
||||||
|
return f(*args, **kwargs)
|
||||||
|
return decorated_function
|
5
SWSCloudAPI/Utils/redisc.py
Normal file
5
SWSCloudAPI/Utils/redisc.py
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
|
||||||
|
from SWSCloudCore.config import config
|
||||||
|
from redis import StrictRedis
|
||||||
|
|
||||||
|
rediskc = StrictRedis(config.get('Redis', 'host'), config.get('Redis', 'port'), config.get('Redis', 'db'))
|
74
SWSCloudAPI/Utils/tokens.py
Normal file
74
SWSCloudAPI/Utils/tokens.py
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
import json
|
||||||
|
import uuid
|
||||||
|
from flask import g
|
||||||
|
from SWSCloudAPI.API.compute.v2.common import TOKEN_PREFIX, TOKEN_TTL
|
||||||
|
|
||||||
|
|
||||||
|
class Tokens(object):
|
||||||
|
def set(self, payload, ttl=1800):
|
||||||
|
"""Create new token
|
||||||
|
|
||||||
|
Example
|
||||||
|
>>> Tokens().set({'user_id': 1, 'email': 'user@email.com'}, 1800)
|
||||||
|
|
||||||
|
:param payload: dict
|
||||||
|
:param ttl: int
|
||||||
|
:return: boolean
|
||||||
|
"""
|
||||||
|
token = self.generate_id()
|
||||||
|
g.redis_connect.set(TOKEN_PREFIX + token, json.dumps(payload), ttl)
|
||||||
|
return token
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get(token, ttl=None):
|
||||||
|
"""Get token data
|
||||||
|
|
||||||
|
>>> Tokens.get('d0dd3bfa-e0f2-11e6-a2ce-17cec9ffa761')
|
||||||
|
>>> Tokens.get('d0dd3bfa-e0f2-11e6-a2ce-17cec9ffa761', 1800)
|
||||||
|
"""
|
||||||
|
if ttl and type(ttl) == int:
|
||||||
|
g.redis_connect.expire(TOKEN_PREFIX + token, ttl)
|
||||||
|
return json.loads(g.redis_connect.get(TOKEN_PREFIX + token))
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def expire(token, ttl=1800):
|
||||||
|
"""
|
||||||
|
|
||||||
|
>>> Tokens.expire('d0dd3bfa-e0f2-11e6-a2ce-17cec9ffa761', 1800)
|
||||||
|
|
||||||
|
:param token: uuid
|
||||||
|
:param ttl: int
|
||||||
|
:return: boolean
|
||||||
|
"""
|
||||||
|
g.redis_connect.expire(TOKEN_PREFIX + token, ttl)
|
||||||
|
return True
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def exists(token):
|
||||||
|
"""Check exists token in redis
|
||||||
|
|
||||||
|
:param token: uuid
|
||||||
|
:return: boolean
|
||||||
|
"""
|
||||||
|
if g.redis_connect.exists(TOKEN_PREFIX + token):
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def delete(token):
|
||||||
|
try:
|
||||||
|
g.redis_connect.delete(TOKEN_PREFIX + token)
|
||||||
|
except:
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
return True
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def generate_id():
|
||||||
|
"""Generate UUID strinfg
|
||||||
|
|
||||||
|
>>> Tokens.generate_id()
|
||||||
|
|
||||||
|
:return: str
|
||||||
|
"""
|
||||||
|
return str(uuid.uuid4())
|
|
@ -1,55 +1,61 @@
|
||||||
# coding: utf-8
|
# coding: utf-8
|
||||||
|
|
||||||
from flask import Flask, g, jsonify
|
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 import models
|
||||||
from SWSCloudCore.models import database
|
|
||||||
from SWSCloudCore.config import config
|
from SWSCloudCore.config import config
|
||||||
|
from SWSCloudCore.models import database
|
||||||
|
# v1
|
||||||
|
from SWSCloudAPI.API.compute.v1.views import *
|
||||||
|
# v2
|
||||||
|
from SWSCloudAPI.API.auth.v2 import *
|
||||||
|
from SWSCloudAPI.API.compute.v2 import *
|
||||||
|
#
|
||||||
|
from SWSCloudAPI.Utils.redisc import rediskc
|
||||||
|
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
# Думал, что получится сделать автопрефик для всего приложения, но это не сработало
|
|
||||||
# app.config["APPLICATION_ROOT"] = "/api/v1"
|
|
||||||
# app.config['SERVER_NAME'] = settings.get('Application', 'SERVER_NAME')
|
|
||||||
app.config['DEBUG'] = config.getboolean('Application', 'DEBUG')
|
app.config['DEBUG'] = config.getboolean('Application', 'DEBUG')
|
||||||
app.config['SECRET_KEY'] = config.get("Application", "SECRET_KEY")
|
app.config['SECRET_KEY'] = config.get("Application", "SECRET_KEY")
|
||||||
|
|
||||||
app.register_blueprint(api)
|
# V1
|
||||||
app.register_blueprint(api_v1_vms)
|
app.register_blueprint(api_v1_vms)
|
||||||
app.register_blueprint(api_v1_containers)
|
app.register_blueprint(api_v1_containers)
|
||||||
app.register_blueprint(api_v1_pricing)
|
app.register_blueprint(api_v1_pricing)
|
||||||
app.register_blueprint(api_v1_datacenters)
|
app.register_blueprint(api_v1_datacenters)
|
||||||
|
|
||||||
|
# V2
|
||||||
|
app.register_blueprint(api_v2_token)
|
||||||
|
app.register_blueprint(api_v2_pricing)
|
||||||
|
app.register_blueprint(api_v2_datacenters)
|
||||||
|
app.register_blueprint(api_v2_vms)
|
||||||
|
|
||||||
|
|
||||||
@app.errorhandler(404)
|
@app.errorhandler(404)
|
||||||
def page_not_found(e):
|
def page_not_found(e):
|
||||||
app.logger.error(e)
|
app.logger.error(e)
|
||||||
return jsonify(dict(message='resource not found')), 404
|
return jsonify(status='error', message='resource not found')
|
||||||
|
|
||||||
|
|
||||||
@app.errorhandler(403)
|
@app.errorhandler(403)
|
||||||
def access_deny(e):
|
def access_deny(e):
|
||||||
app.logger.error(e)
|
app.logger.error(e)
|
||||||
return jsonify(dict(message='access deny')), 403
|
return jsonify(status='error', message='access deny'), 403
|
||||||
|
|
||||||
|
|
||||||
@app.errorhandler(410)
|
@app.errorhandler(410)
|
||||||
def page_not_found(e):
|
def page_not_found(e):
|
||||||
app.logger.error(e)
|
app.logger.error(e)
|
||||||
return jsonify(dict()), 410
|
return jsonify({})
|
||||||
|
|
||||||
|
|
||||||
@app.errorhandler(500)
|
@app.errorhandler(500)
|
||||||
def page_not_found(e):
|
def page_not_found(e):
|
||||||
app.logger.error(e)
|
app.logger.error(e)
|
||||||
return jsonify(dict(message='maintenance')), 500
|
return jsonify(status='maintenance')
|
||||||
|
|
||||||
|
|
||||||
@app.before_request
|
@app.before_request
|
||||||
def before_request():
|
def before_request():
|
||||||
|
g.redis_connect = rediskc
|
||||||
g.settings = dict()
|
g.settings = dict()
|
||||||
# извлекаем настройки и определяем их в глобальную переменную
|
# извлекаем настройки и определяем их в глобальную переменную
|
||||||
for setting in models.Settings.select(models.Settings.key, models.Settings.val).execute():
|
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 = Blueprint('administrator', __name__, url_prefix='/administrator')
|
||||||
|
|
||||||
|
|
||||||
@viewAdministrator.route('/login.html', methods=['GET', 'POST'])
|
@viewAdministrator.route('/login.html', methods=['GET'])
|
||||||
def login():
|
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')
|
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')
|
@viewAdministrator.route('/logout.html')
|
||||||
def logout():
|
def logout():
|
||||||
session.pop('admin_id', None)
|
session.pop('admin_id', None)
|
||||||
|
@ -164,7 +167,7 @@ def ips_index():
|
||||||
def ips_create():
|
def ips_create():
|
||||||
#
|
#
|
||||||
if request.method == "POST":
|
if request.method == "POST":
|
||||||
print request.form
|
print(request.form)
|
||||||
if ControllerManageIPs().is_valid_ipv4_address(request.form['ipv4'])\
|
if ControllerManageIPs().is_valid_ipv4_address(request.form['ipv4'])\
|
||||||
and ControllerManageIPs().is_valid_ipv4_address(request.form['ipv4_gateway']):
|
and ControllerManageIPs().is_valid_ipv4_address(request.form['ipv4_gateway']):
|
||||||
ControllerManageIPs().item_create(
|
ControllerManageIPs().item_create(
|
||||||
|
@ -200,7 +203,7 @@ def ips_create():
|
||||||
def ips_edit(ip_id):
|
def ips_edit(ip_id):
|
||||||
#
|
#
|
||||||
if request.method == 'POST':
|
if request.method == 'POST':
|
||||||
print request.form
|
print(request.form)
|
||||||
# if ControllerManageIPs().is_valid_ipv4_address(request.form['ipv4'])\
|
# if ControllerManageIPs().is_valid_ipv4_address(request.form['ipv4'])\
|
||||||
# and ControllerManageIPs().is_valid_ipv4_address(request.form['ipv4_gateway']):
|
# and ControllerManageIPs().is_valid_ipv4_address(request.form['ipv4_gateway']):
|
||||||
ControllerManageIPs().item_update(
|
ControllerManageIPs().item_update(
|
||||||
|
@ -232,7 +235,7 @@ def ips_delete():
|
||||||
@requires_login
|
@requires_login
|
||||||
def servers_create():
|
def servers_create():
|
||||||
if request.method == "POST":
|
if request.method == "POST":
|
||||||
print request.form
|
print(request.form)
|
||||||
params = {
|
params = {
|
||||||
'datacenter_id': request.form['datacenter_id'],
|
'datacenter_id': request.form['datacenter_id'],
|
||||||
'server_id': uuid4(),
|
'server_id': uuid4(),
|
||||||
|
|
|
@ -7,15 +7,19 @@ from SWSCloudCore.controllers.tasks import ControllerTasks
|
||||||
from SWSCloudCore import models
|
from SWSCloudCore import models
|
||||||
from SWSCloudAdministrator.Administrator.common import requires_login
|
from SWSCloudAdministrator.Administrator.common import requires_login
|
||||||
|
|
||||||
view_administrator_compute_vms = Blueprint('administrator_compute_vms', __name__, url_prefix='/administrator/compute/vms')
|
view_administrator_compute_vms = Blueprint(
|
||||||
|
'administrator_compute_vms',
|
||||||
|
__name__,
|
||||||
|
url_prefix='/administrator/compute/vms')
|
||||||
|
|
||||||
|
|
||||||
@view_administrator_compute_vms.route('/', methods=['GET'])
|
@view_administrator_compute_vms.route('/', methods=['GET'])
|
||||||
@requires_login
|
@requires_login
|
||||||
def index():
|
def index():
|
||||||
# формируем список правил
|
"""Virtual Machines list"""
|
||||||
return render_template(
|
template = 'administrator/compute/vms/index.html'
|
||||||
'administrator/compute/vms/index.html', vms=models.Vms.get_items())
|
items = models.Vms.get_items()
|
||||||
|
return render_template(template, vms=items)
|
||||||
|
|
||||||
|
|
||||||
@view_administrator_compute_vms.route('/<uuid:vm_id>', methods=['GET'])
|
@view_administrator_compute_vms.route('/<uuid:vm_id>', methods=['GET'])
|
||||||
|
|
|
@ -1,16 +1,14 @@
|
||||||
# coding: utf-8
|
"""Stack Web Services LLC"""
|
||||||
|
|
||||||
# from uuid import uuid4
|
import validators
|
||||||
# import validators
|
from flask import Blueprint, redirect, render_template, request, url_for
|
||||||
|
|
||||||
from flask import Blueprint, flash, g, jsonify, redirect, render_template, request, session, url_for
|
|
||||||
|
|
||||||
from SWSCloudCore.controllers.administrators import ControllerAdministrators
|
|
||||||
from SWSCloudCore.controllers.tasks.manage import ControllerManageTasks
|
from SWSCloudCore.controllers.tasks.manage import ControllerManageTasks
|
||||||
from SWSCloudAdministrator.Administrator.common import requires_login
|
from SWSCloudAdministrator.Administrator.common import requires_login
|
||||||
from SWSCloudCore import models
|
from SWSCloudCore import models
|
||||||
|
|
||||||
view_administrator_tasks = Blueprint('administrator_tasks', __name__, url_prefix='/administrator/tasks')
|
view_administrator_tasks = Blueprint(
|
||||||
|
'administrator_tasks', __name__,
|
||||||
|
url_prefix='/administrator/tasks')
|
||||||
|
|
||||||
|
|
||||||
@view_administrator_tasks.route('/', methods=['GET'])
|
@view_administrator_tasks.route('/', methods=['GET'])
|
||||||
|
@ -25,23 +23,29 @@ def index():
|
||||||
@view_administrator_tasks.route('/edit.html', methods=['GET'])
|
@view_administrator_tasks.route('/edit.html', methods=['GET'])
|
||||||
@requires_login
|
@requires_login
|
||||||
def edit():
|
def edit():
|
||||||
task_id = request.args.get('task_id')
|
task_id = request.form.get('task_id')
|
||||||
|
if not validators.uuid(task_id) or not models.Tasks.exists(task_id):
|
||||||
# TODO: check exists
|
return redirect(url_for('administrator_tasks.index'))
|
||||||
|
task = ControllerManageTasks().get_task(task_id)
|
||||||
return render_template(
|
return render_template(
|
||||||
'administrator/tasks/edit.html',
|
'administrator/tasks/edit.html',
|
||||||
task=ControllerManageTasks().get_task(task_id))
|
task=task)
|
||||||
|
|
||||||
|
|
||||||
@view_administrator_tasks.route('/edit.html', methods=['POST'])
|
@view_administrator_tasks.route('/edit.html', methods=['POST'])
|
||||||
@requires_login
|
@requires_login
|
||||||
def edit_post():
|
def edit_post():
|
||||||
task_id = request.form.get('task_id')
|
task_id = request.form.get('task_id')
|
||||||
|
# todo: validate
|
||||||
|
status = request.form.get('status')
|
||||||
|
|
||||||
# TODO: check exists
|
if not validators.uuid(task_id) or not models.Tasks.exists(task_id):
|
||||||
x = models.Tasks.update(status=request.form.get('status')).where(models.Tasks.id == task_id)
|
return redirect(url_for('administrator_tasks.index'))
|
||||||
x.execute()
|
|
||||||
|
task = models.Tasks.update(
|
||||||
|
status=status
|
||||||
|
).where(models.Tasks.id == task_id)
|
||||||
|
task.execute()
|
||||||
|
|
||||||
return redirect(url_for('administrator_tasks.edit', task_id=task_id))
|
return redirect(url_for('administrator_tasks.edit', task_id=task_id))
|
||||||
|
|
||||||
|
@ -51,11 +55,13 @@ def edit_post():
|
||||||
def delete():
|
def delete():
|
||||||
task_id = request.args.get('task_id')
|
task_id = request.args.get('task_id')
|
||||||
|
|
||||||
# TODO: check exists
|
if not validators.uuid(task_id) or not models.Tasks.exists(task_id):
|
||||||
|
return redirect(url_for('administrator_tasks.index'))
|
||||||
|
|
||||||
|
task = ControllerManageTasks().get_task(task_id)
|
||||||
return render_template(
|
return render_template(
|
||||||
'administrator/tasks/delete.html',
|
'administrator/tasks/delete.html',
|
||||||
task=ControllerManageTasks().get_task(task_id)
|
task=task
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -64,8 +70,10 @@ def delete():
|
||||||
def delete_post():
|
def delete_post():
|
||||||
task_id = request.form.get('task_id')
|
task_id = request.form.get('task_id')
|
||||||
|
|
||||||
# TODO: check exists
|
if not validators.uuid(task_id) or not models.Tasks.exists(task_id):
|
||||||
x = models.Tasks.delete().where(models.Tasks.id == task_id)
|
return redirect(url_for('administrator_tasks.index'))
|
||||||
x.execute()
|
|
||||||
|
task = models.Tasks.delete().where(models.Tasks.id == task_id)
|
||||||
|
task.execute()
|
||||||
|
|
||||||
return redirect(url_for('administrator_tasks.index'))
|
return redirect(url_for('administrator_tasks.index'))
|
||||||
|
|
|
@ -43,7 +43,7 @@ app.register_blueprint(view_administrator_compute_containers)
|
||||||
|
|
||||||
# @app.errorhandler(500)
|
# @app.errorhandler(500)
|
||||||
# def page_not_found(e):
|
# def page_not_found(e):
|
||||||
# print e
|
# print(e)
|
||||||
# return render_template('errors/500.html'), 500
|
# return render_template('errors/500.html'), 500
|
||||||
|
|
||||||
|
|
||||||
|
@ -51,7 +51,11 @@ app.register_blueprint(view_administrator_compute_containers)
|
||||||
def before_request():
|
def before_request():
|
||||||
g.settings = dict()
|
g.settings = dict()
|
||||||
# извлекаем настройки и определяем их в глобальную переменную
|
# извлекаем настройки и определяем их в глобальную переменную
|
||||||
for setting in models.Settings.select(models.Settings.key, models.Settings.val).execute():
|
settings = models.Settings.select(
|
||||||
|
models.Settings.key,
|
||||||
|
models.Settings.val
|
||||||
|
).execute()
|
||||||
|
for setting in settings:
|
||||||
g.settings[setting.key] = setting.val
|
g.settings[setting.key] = setting.val
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -14,8 +14,8 @@
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endwith %}
|
{% endwith %}
|
||||||
<form action="{{ url_for('administrator.login') }}" method="post">
|
<form action="{{ url_for('administrator.login_post') }}" method="post">
|
||||||
<label for="email">email</lable>
|
<label for="email">email</label>
|
||||||
<input type="text" name="email" value="" id="email" />
|
<input type="text" name="email" value="" id="email" />
|
||||||
<label for="password">password</label>
|
<label for="password">password</label>
|
||||||
<input type="password" name="password" value="" id="password" />
|
<input type="password" name="password" value="" id="password" />
|
||||||
|
|
0
SWSCloudCore/compute/__init__.py
Normal file
0
SWSCloudCore/compute/__init__.py
Normal file
|
@ -1,13 +1,11 @@
|
||||||
# coding: utf-8
|
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
import ConfigParser
|
from configparser import ConfigParser
|
||||||
|
|
||||||
__config_file__ = os.getenv('CLOUD_CONFIG_FILE', '/etc/sws/cloud/core.ini')
|
__config_file__ = os.getenv('CONFIG', '/etc/sws/cloud/core.ini')
|
||||||
|
|
||||||
# setting file read
|
# setting file read
|
||||||
config = ConfigParser.ConfigParser()
|
config = ConfigParser()
|
||||||
if os.path.exists(__config_file__):
|
if os.path.exists(__config_file__):
|
||||||
config.read(__config_file__)
|
config.read(__config_file__)
|
||||||
|
|
||||||
|
|
|
@ -222,7 +222,7 @@ class Datacenters:
|
||||||
"status": i.status
|
"status": i.status
|
||||||
}
|
}
|
||||||
dcs['items'].append(dc)
|
dcs['items'].append(dc)
|
||||||
# print i
|
# print(i)
|
||||||
return dcs
|
return dcs
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,7 @@ class ControllerContainers:
|
||||||
)
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
# TODO: write to log
|
# TODO: write to log
|
||||||
print e
|
print(e)
|
||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
|
@ -36,7 +36,7 @@ class ControllerUsers:
|
||||||
def update(self, user_id, **kwargs):
|
def update(self, user_id, **kwargs):
|
||||||
if 'password' in kwargs:
|
if 'password' in kwargs:
|
||||||
x = models.Users.update(
|
x = models.Users.update(
|
||||||
password=md5(kwargs['password']).hexdigest()
|
password=md5(kwargs['password'].encode()).hexdigest()
|
||||||
).where(
|
).where(
|
||||||
models.Users.id == user_id
|
models.Users.id == user_id
|
||||||
)
|
)
|
||||||
|
@ -69,7 +69,7 @@ class ControllerUsers:
|
||||||
:param password:
|
:param password:
|
||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
password_hash = md5(password).hexdigest()
|
password_hash = md5(password.encode()).hexdigest()
|
||||||
result = models.Users.select().where(
|
result = models.Users.select().where(
|
||||||
models.Users.email == email,
|
models.Users.email == email,
|
||||||
models.Users.password == password_hash,
|
models.Users.password == password_hash,
|
||||||
|
@ -86,7 +86,7 @@ class ControllerUsers:
|
||||||
:param password:
|
:param password:
|
||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
password_hash = md5(password).hexdigest()
|
password_hash = md5(password.encode()).hexdigest()
|
||||||
user_id = uuid.uuid4()
|
user_id = uuid.uuid4()
|
||||||
# TODO: add date registration and update of date - =datetime.datetime.now()
|
# TODO: add date registration and update of date - =datetime.datetime.now()
|
||||||
user = models.Users.create(id=user_id, email=email, password=password_hash, status=1)
|
user = models.Users.create(id=user_id, email=email, password=password_hash, status=1)
|
||||||
|
@ -95,7 +95,7 @@ class ControllerUsers:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def password_update(self, user_id, password):
|
def password_update(self, user_id, password):
|
||||||
password_hash = md5(password).hexdigest()
|
password_hash = md5(password.encode()).hexdigest()
|
||||||
u = models.Users.get(models.Users.id == user_id)
|
u = models.Users.get(models.Users.id == user_id)
|
||||||
u.password = password_hash
|
u.password = password_hash
|
||||||
u.save()
|
u.save()
|
||||||
|
|
|
@ -35,7 +35,7 @@ class ControllerManageUsers:
|
||||||
models.UsersBalance
|
models.UsersBalance
|
||||||
)
|
)
|
||||||
for j in jj:
|
for j in jj:
|
||||||
print j.usersbalance.balance
|
print(j.usersbalance.balance)
|
||||||
return {
|
return {
|
||||||
'total': len(jj),
|
'total': len(jj),
|
||||||
'items': jj
|
'items': jj
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
# coding: utf-8
|
# coding: utf-8
|
||||||
|
|
||||||
|
import json
|
||||||
from hashlib import md5
|
from hashlib import md5
|
||||||
import datetime
|
import datetime
|
||||||
import uuid
|
import uuid
|
||||||
|
@ -42,6 +43,16 @@ class DataCenters(PgSQLModel):
|
||||||
city = CharField()
|
city = CharField()
|
||||||
status = IntegerField(default=0)
|
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):
|
class Servers(PgSQLModel):
|
||||||
id = UUIDField(unique=True, primary_key=True)
|
id = UUIDField(unique=True, primary_key=True)
|
||||||
|
@ -110,7 +121,9 @@ class Users(PgSQLModel):
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def auth(email, password, status=1):
|
def auth(email, password, status=1):
|
||||||
if Users.select().where(
|
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:
|
).count() == 0:
|
||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
@ -121,7 +134,11 @@ class Users(PgSQLModel):
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_by_id(user_id):
|
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):
|
class UsersRecoveryCodes(PgSQLModel):
|
||||||
|
@ -247,6 +264,14 @@ class Vms(PgSQLModel):
|
||||||
def get_items():
|
def get_items():
|
||||||
return Vms.select()
|
return Vms.select()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_user_items(user_id):
|
||||||
|
items = list()
|
||||||
|
for x in Vms.select().where(Vms.user == user_id):
|
||||||
|
items.append(dict(id=str(x.id), datacenter=str(x.datacenter.id), plan=x.plan.id, hostname=x.hostname,
|
||||||
|
osname=x.os_name, ossuite=x.os_suite, ipv4=x.ipv4, ipv6=x.ipv6, status=x.status))
|
||||||
|
return items
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_item(vm_id):
|
def get_item(vm_id):
|
||||||
return Vms.select().where(Vms.id == vm_id).first()
|
return Vms.select().where(Vms.id == vm_id).first()
|
||||||
|
@ -298,22 +323,27 @@ class Tasks(PgSQLModel):
|
||||||
Tasks.select().where(Tasks.status == status).count()
|
Tasks.select().where(Tasks.status == status).count()
|
||||||
return Tasks.select().count()
|
return Tasks.select().count()
|
||||||
|
|
||||||
# @staticmethod
|
@staticmethod
|
||||||
# def set_task(datacenter_id, server_id, task, status, **args):
|
def set_task(datacenter_id, server_id, user_id, task, status, **args):
|
||||||
# task_id = uuid.uuid4()
|
task_id = uuid.uuid4()
|
||||||
# plain = dict()
|
plain = dict()
|
||||||
# for arg in args:
|
for arg in args:
|
||||||
# plain[arg] = str(args[arg])
|
plain[arg] = str(args[arg])
|
||||||
#
|
|
||||||
# Tasks.create(
|
Tasks.create(
|
||||||
# id=task_id,
|
id=task_id,
|
||||||
# datacenter=datacenter_id,
|
datacenter=datacenter_id,
|
||||||
# server=server_id,
|
server=server_id,
|
||||||
# task=task,
|
task=task,
|
||||||
# status=status,
|
status=status,
|
||||||
# user=self.user_id,
|
user=user_id,
|
||||||
# plain=json.dumps(plain)
|
plain=json.dumps(plain))
|
||||||
# )
|
|
||||||
|
@staticmethod
|
||||||
|
def exists(task_id):
|
||||||
|
if Tasks.select().where(Tasks.id == task_id).count() == 0:
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
class Settings(PgSQLModel):
|
class Settings(PgSQLModel):
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
# coding: utf-8
|
"""Stack Web Services LLC."""
|
||||||
|
|
||||||
import json
|
import json
|
||||||
from flask import Blueprint, jsonify, request, g
|
from flask import Blueprint, jsonify, request, g
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# coding: utf-8
|
# coding: utf-8
|
||||||
|
import logging
|
||||||
import os
|
import os
|
||||||
from flask import Flask, g, render_template
|
from flask import Flask, g, render_template
|
||||||
from flask_babel import Babel
|
from flask_babel import Babel
|
||||||
|
@ -42,7 +42,7 @@ if app.config.get('THEME_STATIC_FOLDER', False):
|
||||||
static_folder = app.config['THEME_STATIC_FOLDER']
|
static_folder = app.config['THEME_STATIC_FOLDER']
|
||||||
if static_folder[0] != '/':
|
if static_folder[0] != '/':
|
||||||
static_folder = os.path.join(app.root_path, 'static', static_folder)
|
static_folder = os.path.join(app.root_path, 'static', static_folder)
|
||||||
print static_folder
|
# print(static_folder)
|
||||||
# Unlike templates, to serve static files from multiples folders we
|
# Unlike templates, to serve static files from multiples folders we
|
||||||
# need flask-multistatic
|
# need flask-multistatic
|
||||||
# app.static_folder = [static_folder, os.path.join(app.root_path, 'static')]
|
# app.static_folder = [static_folder, os.path.join(app.root_path, 'static')]
|
||||||
|
@ -90,17 +90,20 @@ def page_not_found(e):
|
||||||
|
|
||||||
@app.errorhandler(500)
|
@app.errorhandler(500)
|
||||||
def page_not_found(e):
|
def page_not_found(e):
|
||||||
print e
|
print(e)
|
||||||
return render_template('errors/500.html'), 500
|
return render_template('errors/500.html'), 500
|
||||||
|
|
||||||
|
|
||||||
@app.before_request
|
@app.before_request
|
||||||
def before_request():
|
def before_request():
|
||||||
g.settings = dict()
|
g.settings = dict()
|
||||||
# извлекаем настройки и определяем их в глобальную переменную
|
try:
|
||||||
for setting in models.Settings.select(models.Settings.key, models.Settings.val).execute():
|
# извлекаем настройки и определяем их в глобальную переменную
|
||||||
g.settings[setting.key] = setting.val
|
for setting in models.Settings.select(models.Settings.key, models.Settings.val).execute():
|
||||||
|
g.settings[setting.key] = setting.val
|
||||||
|
except Exception as e:
|
||||||
|
logging.error(e)
|
||||||
|
# exit(1)
|
||||||
|
|
||||||
@app.before_first_request
|
@app.before_first_request
|
||||||
def before_first_request():
|
def before_first_request():
|
||||||
|
|
|
@ -16,7 +16,7 @@ def requires_login(f):
|
||||||
else:
|
else:
|
||||||
return redirect(url_for("account.logout"))
|
return redirect(url_for("account.logout"))
|
||||||
|
|
||||||
if not Users.auth(session.get('email'), session.get('password'), 1):
|
if not Users.auth(session.get('email'), session.get('password').encode(), 1):
|
||||||
return redirect(url_for("account.logout"))
|
return redirect(url_for("account.logout"))
|
||||||
|
|
||||||
return f(*args, **kwargs)
|
return f(*args, **kwargs)
|
||||||
|
|
1
SWSCloudWeb/static/assets/css/app.min.css
vendored
Normal file
1
SWSCloudWeb/static/assets/css/app.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
7
SWSCloudWeb/static/assets/js/app.min.js
vendored
Normal file
7
SWSCloudWeb/static/assets/js/app.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
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 |
|
@ -83,6 +83,5 @@
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
|
||||||
{% block footer %}
|
{% block footer %}
|
||||||
{% endblock %}
|
{% endblock %}
|
|
@ -5,7 +5,7 @@
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="large-12 columns">
|
<div class="large-12 columns">
|
||||||
<h3>{{ _('Вход') }}</h3>
|
<h2>{{ _('Вход') }}</h2>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
|
|
|
@ -8,18 +8,12 @@
|
||||||
<h2>Регистрация</h2>
|
<h2>Регистрация</h2>
|
||||||
<form action="{{ url_for('account.registration') }}" method="post">
|
<form action="{{ url_for('account.registration') }}" method="post">
|
||||||
<input type="hidden" name="method" value="member_add" />
|
<input type="hidden" name="method" value="member_add" />
|
||||||
<label for="email">
|
<label for="email">Адрес электронной почты</label>
|
||||||
Адрес ел. почты
|
<input type="text" name="email" value="" class="email" id="email" />
|
||||||
<input type="text" name="email" value="" class="email" id="email" />
|
<label for="password">Пароль</label>
|
||||||
</label>
|
<input type="password" name="password" value="" id="password" />
|
||||||
<label for="password">
|
<label for="password2">Пароль (повторно)</label>
|
||||||
Пароль
|
<input type="password" name="password2" value="" id="password2" />
|
||||||
<input type="password" name="password" value="" id="password" />
|
|
||||||
</label>
|
|
||||||
<label for="password2">
|
|
||||||
Пароль (повторно)
|
|
||||||
<input type="password" name="password2" value="" id="password2" />
|
|
||||||
</label>
|
|
||||||
<input type="submit" value="Зарегистрироваться" class="button success" />
|
<input type="submit" value="Зарегистрироваться" class="button success" />
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,11 +0,0 @@
|
||||||
{% extends "default/_layout.html" %}
|
|
||||||
|
|
||||||
{% block title %}База знаний{% endblock %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
<div class="row">
|
|
||||||
<div class="large-12 columns">
|
|
||||||
{% filter markdown %}{{ kb_markdown }}{% endfilter %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endblock %}
|
|
|
@ -4,7 +4,8 @@
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<meta http-equiv="x-ua-compatible" content="ie=edge">
|
<meta http-equiv="x-ua-compatible" content="ie=edge">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>Облачный хостинг GoCloud</title>
|
<title>{% block title %}Облачный хостинг GoCloud{% endblock %}</title>
|
||||||
|
<meta name="description" content="{% block description %}GoCloud предлагает вам арендовать виртуальные серверные мощности{% endblock %}">
|
||||||
<link rel="stylesheet" href="{{ url_for('static', filename='assets/css/app.css') }}">
|
<link rel="stylesheet" href="{{ url_for('static', filename='assets/css/app.css') }}">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
<h1>Облачный хостинг</h1>
|
<h1>Облачный хостинг</h1>
|
||||||
<h2>Виртуальный сервер от 200 рублей в месяц</h2>
|
<h2>Виртуальный сервер от 200 рублей в месяц</h2>
|
||||||
<h2>
|
<h2>
|
||||||
<a href="{{ url_for('account.registration') }}" class="button success">Создать виртуальный сервер</a>
|
<a href="{{ url_for('account.registration') }}" class="button alert">Создать виртуальный сервер</a>
|
||||||
</h2>
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
{% extends "gocloud2016/layouts/default.html" %}
|
{% extends "gocloud2016/layouts/default.html" %}
|
||||||
|
|
||||||
|
{% block title %}Стоимость аренды виртуального сервера - GoCloud{% endblock %}
|
||||||
|
|
||||||
|
{% block description %}Расценки на стоимость аренды виртуальных серверов различной конфигурации{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="large-12 columns">
|
<div class="large-12 columns">
|
||||||
|
|
30
SWSCloudWeb/templates/gocloud2016/pages/support/index.html
Normal file
30
SWSCloudWeb/templates/gocloud2016/pages/support/index.html
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
{% extends "gocloud2016/layouts/default.html" %}
|
||||||
|
|
||||||
|
{% block title %}Поддержка онлайн виртуального сервера - GoCloud{% endblock %}
|
||||||
|
|
||||||
|
{% block description %}Наши технические специалисты ответят на ваши вопросы{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="row">
|
||||||
|
<div class="large-12 columns">
|
||||||
|
<h2>Поддержка</h2>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="large-12 columns">
|
||||||
|
<form action="{{ url_for('support.index_post') }}" method="post">
|
||||||
|
{% if not session['email'] %}
|
||||||
|
<label for="email">Адрес электронной почты</label>
|
||||||
|
<input type="text" name="email" id="email" />
|
||||||
|
{% else %}
|
||||||
|
<input type="hidden" name="email" value="{{ session['email'] }}" />
|
||||||
|
{% endif %}
|
||||||
|
<label for="subject">Заголовок</label>
|
||||||
|
<input type="text" name="subject" id="subject" />
|
||||||
|
<label for="message">Сообщение</label>
|
||||||
|
<textarea name="message" id="message" rows="7"></textarea>
|
||||||
|
<input type="submit" class="button success large" value="Отправить сообщение" />
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
21
SWSCloudWeb/templates/gocloud2016/pages/support/thanks.html
Normal file
21
SWSCloudWeb/templates/gocloud2016/pages/support/thanks.html
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
{% extends "gocloud2016/layouts/default.html" %}
|
||||||
|
|
||||||
|
{% block title %}Поддержка онлайн виртуального сервера - GoCloud{% endblock %}
|
||||||
|
|
||||||
|
{% block description %}Наши технические специалисты ответят на ваши вопросы{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="row">
|
||||||
|
<div class="large-12 columns">
|
||||||
|
<h2>Поддержка</h2>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="large-12 columns">
|
||||||
|
<h3>Спасибо!</h3>
|
||||||
|
</div>
|
||||||
|
<div class="large-12 columns">
|
||||||
|
<p>Спасибо за обращение в техническую поддержку. Мы ответим вам в кратчайшее время.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
|
@ -114,14 +114,15 @@ def registration():
|
||||||
user_id = ControllerUsers().get_id_by_email(email)
|
user_id = ControllerUsers().get_id_by_email(email)
|
||||||
|
|
||||||
ControllerUsersDetails(user_id).details_create()
|
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)
|
ControllerAPI().set(user_id=user_id, secret=user_id, acl='', status=0)
|
||||||
# ControllerU
|
# ControllerU
|
||||||
# send mail message with recovery code
|
# send mail message with recovery code
|
||||||
|
|
||||||
message = u"""
|
message = u"""
|
||||||
Е-почта: %s
|
Е-почта: %s
|
||||||
Пароль: %s
|
Пароль: %s
|
||||||
""" % (request.form['email'], request.form['password'])
|
""" % (request.form.get('email'), request.form.get('password'))
|
||||||
subject = u'GoCloud.ru: Успешная регистрация'
|
subject = u'GoCloud.ru: Успешная регистрация'
|
||||||
lead = u"""
|
lead = u"""
|
||||||
Поздравляем с успешной регистрацией.
|
Поздравляем с успешной регистрацией.
|
||||||
|
@ -130,10 +131,12 @@ def registration():
|
||||||
Для входа в личный кабинет воспользуйтесь
|
Для входа в личный кабинет воспользуйтесь
|
||||||
<a href="https://gocloud.ru/account/login">страницей авторизации</a>.
|
<a href="https://gocloud.ru/account/login">страницей авторизации</a>.
|
||||||
"""
|
"""
|
||||||
|
try:
|
||||||
email = ControllerMessagesEmail()
|
email = ControllerMessagesEmail()
|
||||||
email.send(title=subject, to=request.form['email'], lead=lead, message=message, callout=callout)
|
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
|
# redirect to login page
|
||||||
flash(u'Учетная запись успешно зарегистрирована.', 'success')
|
flash(u'Учетная запись успешно зарегистрирована.', 'success')
|
||||||
return redirect(url_for('account.login'))
|
return redirect(url_for('account.login'))
|
||||||
|
|
|
@ -1,42 +1,38 @@
|
||||||
# coding: utf-8
|
# coding: utf-8
|
||||||
|
|
||||||
|
import validators
|
||||||
|
from flask import Blueprint, g, redirect, render_template, request, url_for, flash
|
||||||
from SWSCloudCore.controllers.common import ControllerMessagesEmail
|
from SWSCloudCore.controllers.common import ControllerMessagesEmail
|
||||||
from flask import Blueprint
|
|
||||||
from flask import g
|
|
||||||
from flask import redirect
|
|
||||||
from flask import render_template
|
|
||||||
from flask import request
|
|
||||||
from flask import url_for
|
|
||||||
|
|
||||||
viewSupport = Blueprint('support', __name__, url_prefix='/support')
|
viewSupport = Blueprint('support', __name__, url_prefix='/support')
|
||||||
|
|
||||||
|
|
||||||
@viewSupport.route('/', methods=['GET', 'POST'])
|
@viewSupport.route('/', methods=['GET'])
|
||||||
def index():
|
def index():
|
||||||
# ControllerMessagesEmail().send()
|
return render_template('gocloud2016/pages/support/index.html')
|
||||||
# print session
|
|
||||||
|
|
||||||
if request.method == "POST":
|
|
||||||
print request.form
|
|
||||||
# TODO: validate
|
|
||||||
ticket_title = request.form['title']
|
|
||||||
ticket_message = request.form['message']
|
|
||||||
ticket_email = request.form['email']
|
|
||||||
|
|
||||||
# send mail message with recovery code
|
|
||||||
subject = ticket_title
|
|
||||||
message = ticket_message
|
|
||||||
lead = u'Отправитель: %s' % ticket_email
|
|
||||||
callout = u''
|
|
||||||
|
|
||||||
email = ControllerMessagesEmail()
|
|
||||||
# email.send(title=subject, to=ticket_email, lead=lead, message=message, callout=callout)
|
|
||||||
email.send(title=subject, to=g.settings['contacts.email'], lead=lead, message=message, callout=callout)
|
|
||||||
|
|
||||||
return redirect(url_for('support.thank'))
|
|
||||||
return render_template('default/support/index.html')
|
|
||||||
|
|
||||||
|
|
||||||
@viewSupport.route('/thank')
|
@viewSupport.route('/', methods=['POST'])
|
||||||
|
def index_post():
|
||||||
|
ticket_subject = request.form.get('subject')
|
||||||
|
ticket_message = request.form.get('message')
|
||||||
|
ticket_email = request.form.get('email')
|
||||||
|
|
||||||
|
if not validators.email(ticket_email):
|
||||||
|
flash('Некорректный адрес электронной почты', category='error')
|
||||||
|
return redirect(url_for('support.index'))
|
||||||
|
|
||||||
|
# send mail message with recovery code
|
||||||
|
lead = u'Отправитель: %s' % ticket_email
|
||||||
|
callout = u''
|
||||||
|
|
||||||
|
email = ControllerMessagesEmail()
|
||||||
|
# email.send(title=subject, to=ticket_email, lead=lead, message=message, callout=callout)
|
||||||
|
email.send(
|
||||||
|
title=ticket_subject, to=g.settings.get('contacts.email'), lead=lead, message=ticket_message, callout=callout)
|
||||||
|
return redirect(url_for('support.thank'))
|
||||||
|
|
||||||
|
|
||||||
|
@viewSupport.route('/thank.html')
|
||||||
def thank():
|
def thank():
|
||||||
return render_template('default/support/thank.html')
|
return render_template('gocloud2016/pages/support/thanks.html')
|
||||||
|
|
|
@ -23,7 +23,7 @@ def view(document_name):
|
||||||
if not os.path.exists('docs/%s.md' % document_name):
|
if not os.path.exists('docs/%s.md' % document_name):
|
||||||
return redirect(url_for('homepage.index'))
|
return redirect(url_for('homepage.index'))
|
||||||
#
|
#
|
||||||
print document_name
|
print(document_name)
|
||||||
doc_markdown = u''
|
doc_markdown = u''
|
||||||
for ss in file('docs/%s.md' % document_name, 'r'):
|
for ss in file('docs/%s.md' % document_name, 'r'):
|
||||||
doc_markdown += ss.decode('UTF-8')
|
doc_markdown += ss.decode('UTF-8')
|
||||||
|
|
|
@ -2,8 +2,13 @@ import requests
|
||||||
|
|
||||||
|
|
||||||
class SWSStatisticsClient(object):
|
class SWSStatisticsClient(object):
|
||||||
def get_vm(self, vm_id, limit=96):
|
def get_vm(self, vm_id: str, limit: int = 96):
|
||||||
r = requests.get('http://server-stats.gocloud.ru/stats/v1/compute/vms/%s' % vm_id, params={'limit': limit})
|
r = requests.get(
|
||||||
|
f"http://server-stats.gocloud.ru/stats/v1/compute/vms/{vm_id}",
|
||||||
|
params={
|
||||||
|
'limit': limit
|
||||||
|
}
|
||||||
|
)
|
||||||
if r.status_code == 200:
|
if r.status_code == 200:
|
||||||
return r.json()
|
return r.json()
|
||||||
return None
|
return None
|
||||||
|
|
5
cloud-admin-add.py
Normal file → Executable file
5
cloud-admin-add.py
Normal file → Executable file
|
@ -1,6 +1,7 @@
|
||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
# coding: utf-8
|
# coding: utf-8
|
||||||
|
|
||||||
|
import sys
|
||||||
import argparse
|
import argparse
|
||||||
import validators
|
import validators
|
||||||
from hashlib import md5
|
from hashlib import md5
|
||||||
|
@ -25,13 +26,13 @@ if not validators.email(args.email):
|
||||||
|
|
||||||
admin_id = uuid4()
|
admin_id = uuid4()
|
||||||
admin_email = args.email
|
admin_email = args.email
|
||||||
admin_password = md5(args.password).hexdigest()
|
admin_password = md5(args.password.encode()).hexdigest()
|
||||||
|
|
||||||
models.database.connect()
|
models.database.connect()
|
||||||
|
|
||||||
if models.Admins.select().where(models.Admins.email == args.email).count() == 0:
|
if models.Admins.select().where(models.Admins.email == args.email).count() == 0:
|
||||||
models.Admins.create(id=admin_id, email=admin_email, password=admin_password, status=1)
|
models.Admins.create(id=admin_id, email=admin_email, password=admin_password, status=1)
|
||||||
else:
|
else:
|
||||||
print "already exists"
|
print("already exists")
|
||||||
|
|
||||||
models.database.close()
|
models.database.close()
|
||||||
|
|
12
cloud-admin-ls.py
Normal file → Executable file
12
cloud-admin-ls.py
Normal file → Executable file
|
@ -9,13 +9,13 @@ __author__ = 'vanzhiganov'
|
||||||
admins_total = models.Admins.select().count()
|
admins_total = models.Admins.select().count()
|
||||||
admins_items = models.Admins.select()
|
admins_items = models.Admins.select()
|
||||||
|
|
||||||
print "Total admins: %i" % admins_total
|
print("Total admins: %i" % admins_total)
|
||||||
|
|
||||||
if admins_total == 0:
|
if admins_total == 0:
|
||||||
print ''
|
print('')
|
||||||
else:
|
else:
|
||||||
print 'List:'
|
print('List:')
|
||||||
for item in admins_items:
|
for item in admins_items:
|
||||||
print '%s\t%s\t%s' % (item.id, item.email, item.status)
|
print('%s\t%s\t%s' % (item.id, item.email, item.status))
|
||||||
print '---'
|
print('---')
|
||||||
print 'For create a new admin account use command "procdn-admin-add --email <email> --password <password>"'
|
print('For create a new admin account use command "procdn-admin-add --email <email> --password <password>"')
|
||||||
|
|
10
cloud-admin-password.py
Normal file → Executable file
10
cloud-admin-password.py
Normal file → Executable file
|
@ -18,13 +18,13 @@ args = parser.parse_args()
|
||||||
admin_id = uuid4()
|
admin_id = uuid4()
|
||||||
# todo: validate admin email
|
# todo: validate admin email
|
||||||
admin_email = args.email
|
admin_email = args.email
|
||||||
admin_password = md5(args.password).hexdigest()
|
admin_password = md5(args.password.encode()).hexdigest()
|
||||||
|
|
||||||
if models.Admins.select().where(models.Admins.email == args.email).count() == 0:
|
if models.Admins.select().where(models.Admins.email == args.email).count() == 0:
|
||||||
print "Admin account with email '%s' not exists." % admin_email
|
print("Admin account with email '%s' not exists." % admin_email)
|
||||||
print '---'
|
print('---')
|
||||||
print 'For create a new admin account use command "procdn-admin-add --email <email> --password <password>"'
|
print('For create a new admin account use command "procdn-admin-add --email <email> --password <password>"')
|
||||||
else:
|
else:
|
||||||
query = models.Admins.update(password=admin_password).where(models.Admins.email == admin_email)
|
query = models.Admins.update(password=admin_password).where(models.Admins.email == admin_email)
|
||||||
query.execute()
|
query.execute()
|
||||||
print 'Password updated.'
|
print('Password updated.')
|
||||||
|
|
10
cloud-cron-balance.py
Normal file → Executable file
10
cloud-cron-balance.py
Normal file → Executable file
|
@ -8,13 +8,13 @@ from SWSCloudCore.controllers.vms import ControllerVMS
|
||||||
nb = models.Settings.get_item('NEGATIVE_BALANCE')
|
nb = models.Settings.get_item('NEGATIVE_BALANCE')
|
||||||
|
|
||||||
if int(models.Settings.get_item('SERVICE_VMS_ENABLE')) == 1:
|
if int(models.Settings.get_item('SERVICE_VMS_ENABLE')) == 1:
|
||||||
print 'total vms:', models.Vms.select().where(models.Vms.status == 1).count()
|
print('total vms:', models.Vms.select().where(models.Vms.status == 1).count())
|
||||||
|
|
||||||
for vm in models.Vms.select().where(models.Vms.status == 1):
|
for vm in models.Vms.select().where(models.Vms.status == 1):
|
||||||
# Высчитываем, сколько стоит виртуальная машина 15 минут
|
# Высчитываем, сколько стоит виртуальная машина 15 минут
|
||||||
price_quarter = vm.plan.price / 30 / 24 / 4
|
price_quarter = vm.plan.price / 30 / 24 / 4
|
||||||
|
|
||||||
print dict(id=vm.id, user=vm.user.id, plan=vm.plan.id, cost_mo=vm.plan.price, cost_quarter=price_quarter)
|
print(dict(id=vm.id, user=vm.user.id, plan=vm.plan.id, cost_mo=vm.plan.price, cost_quarter=price_quarter))
|
||||||
|
|
||||||
# Списание средств
|
# Списание средств
|
||||||
x = models.UsersBalance.update(
|
x = models.UsersBalance.update(
|
||||||
|
@ -26,14 +26,14 @@ if int(models.Settings.get_item('SERVICE_VMS_ENABLE')) == 1:
|
||||||
user_balance = models.UsersBalance.select(
|
user_balance = models.UsersBalance.select(
|
||||||
models.UsersBalance.balance).where(models.UsersBalance.user == vm.user.id).get().balance
|
models.UsersBalance.balance).where(models.UsersBalance.user == vm.user.id).get().balance
|
||||||
if -500 > user_balance and models.Vms.get_state(vm.id) == 1:
|
if -500 > user_balance and models.Vms.get_state(vm.id) == 1:
|
||||||
print "user_balance", user_balance
|
print("user_balance", user_balance)
|
||||||
ControllerVMS(vm.user.id).status_set(vm.id, 3)
|
ControllerVMS(vm.user.id).status_set(vm.id, 3)
|
||||||
# Создание задания
|
# Создание задания
|
||||||
ControllerTasks(vm.user.id).create(vm.datacenter.id, vm.server.id, 'vm_stop', 0, vm_id=vm.id)
|
ControllerTasks(vm.user.id).create(vm.datacenter.id, vm.server.id, 'vm_stop', 0, vm_id=vm.id)
|
||||||
|
|
||||||
|
|
||||||
if int(models.Settings.get_item('SERVICE_CONTAINERS_ENABLE')) == 1:
|
if int(models.Settings.get_item('SERVICE_CONTAINERS_ENABLE')) == 1:
|
||||||
print 'total containers:', models.Containers.select().count()
|
print('total containers:', models.Containers.select().count())
|
||||||
for container in models.Containers.select():
|
for container in models.Containers.select():
|
||||||
container_state = models.ContainersStatisticsState.select().where(
|
container_state = models.ContainersStatisticsState.select().where(
|
||||||
models.ContainersStatisticsState.container == container.id
|
models.ContainersStatisticsState.container == container.id
|
||||||
|
@ -43,7 +43,7 @@ if int(models.Settings.get_item('SERVICE_CONTAINERS_ENABLE')) == 1:
|
||||||
# # Высчитываем, сколько стоит виртуальная машина 15 минут
|
# # Высчитываем, сколько стоит виртуальная машина 15 минут
|
||||||
price_quarter = min_price / 30 / 24 / 4
|
price_quarter = min_price / 30 / 24 / 4
|
||||||
#
|
#
|
||||||
# print dict(id=vm.id, user=vm.user.id, plan=vm.plan.id, cost_mo=vm.plan.price, cost_quarter=price_quarter)
|
# print(dict(id=vm.id, user=vm.user.id, plan=vm.plan.id, cost_mo=vm.plan.price, cost_quarter=price_quarter))
|
||||||
#
|
#
|
||||||
# Списание средств
|
# Списание средств
|
||||||
x = models.UsersBalance.update(
|
x = models.UsersBalance.update(
|
||||||
|
|
0
cloud-db-init.py
Normal file → Executable file
0
cloud-db-init.py
Normal file → Executable file
2
cloud-dc-add.py
Normal file → Executable file
2
cloud-dc-add.py
Normal file → Executable file
|
@ -28,4 +28,4 @@ if models.DataCenters.select().where(
|
||||||
status=1
|
status=1
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
print "Data center with code '%s' already exists." % args.code
|
print("Data center with code '%s' already exists." % args.code)
|
||||||
|
|
12
cloud-dc-ls.py
Normal file → Executable file
12
cloud-dc-ls.py
Normal file → Executable file
|
@ -25,13 +25,13 @@ x = models.Ips.select().join(models.Servers).where(
|
||||||
).first()
|
).first()
|
||||||
|
|
||||||
|
|
||||||
print 'total: %s' % total
|
print('total: %s' % total)
|
||||||
print 'items: '
|
print('items: ')
|
||||||
|
|
||||||
for item in items:
|
for item in items:
|
||||||
print 'id: %s code: %s name: %s country: %s, city: %s, status: %s' % (
|
print('id: %s code: %s name: %s country: %s, city: %s, status: %s' % (
|
||||||
item.id, item.code, item.name, item.country, item.city, item.status
|
item.id, item.code, item.name, item.country, item.city, item.status
|
||||||
)
|
))
|
||||||
|
|
||||||
print '---'
|
print('---')
|
||||||
print 'if you want to add a new data center, use cli-dc-add.py --'
|
print('if you want to add a new data center, use cli-dc-add.py --')
|
||||||
|
|
2
cloud-invoicer.py
Normal file → Executable file
2
cloud-invoicer.py
Normal file → Executable file
|
@ -169,7 +169,7 @@ html = u"""
|
||||||
</html>
|
</html>
|
||||||
"""
|
"""
|
||||||
|
|
||||||
print type(html)
|
print(type(html))
|
||||||
pdf = MyFPDF()
|
pdf = MyFPDF()
|
||||||
# First page
|
# First page
|
||||||
pdf.add_page()
|
pdf.add_page()
|
||||||
|
|
0
cloud-invoicer2.py
Normal file → Executable file
0
cloud-invoicer2.py
Normal file → Executable file
4
cloud-ip-add.py
Normal file → Executable file
4
cloud-ip-add.py
Normal file → Executable file
|
@ -3,7 +3,7 @@
|
||||||
import argparse
|
import argparse
|
||||||
|
|
||||||
from SWSCloudCore import models
|
from SWSCloudCore import models
|
||||||
from SWSCloudCore.controllers import ControllerManageIPs
|
from SWSCloudCore.controllers.ips.manage import ControllerManageIPs
|
||||||
|
|
||||||
parser = argparse.ArgumentParser(description='')
|
parser = argparse.ArgumentParser(description='')
|
||||||
parser.add_argument('--dc', dest="datacenter")
|
parser.add_argument('--dc', dest="datacenter")
|
||||||
|
@ -30,5 +30,5 @@ if success:
|
||||||
args.datacenter, args.server, args.ipv4, args.ipv4_gateway, args.ipv6, args.ipv6_gateway, args.status
|
args.datacenter, args.server, args.ipv4, args.ipv4_gateway, args.ipv6, args.ipv6_gateway, args.status
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
print 'fail'
|
print('fail')
|
||||||
# print "Admin account with email '%s' already exists." % args
|
# print "Admin account with email '%s' already exists." % args
|
||||||
|
|
0
cloud-runserver-admin.py
Normal file → Executable file
0
cloud-runserver-admin.py
Normal file → Executable file
1
cloud-runserver.py
Normal file → Executable file
1
cloud-runserver.py
Normal file → Executable file
|
@ -1,5 +1,4 @@
|
||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
# coding: utf-8
|
|
||||||
|
|
||||||
from SWSCloudWeb import app
|
from SWSCloudWeb import app
|
||||||
|
|
||||||
|
|
4
cloud-server-add.py
Normal file → Executable file
4
cloud-server-add.py
Normal file → Executable file
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
from uuid import uuid4
|
from uuid import uuid4
|
||||||
from SWSCloudCore.controllers import ControllerManageServer
|
from SWSCloudCore.controllers.servers.manage import ControllerManageServer
|
||||||
|
|
||||||
parser = argparse.ArgumentParser(description='')
|
parser = argparse.ArgumentParser(description='')
|
||||||
parser.add_argument('--dc', dest="datacenter")
|
parser.add_argument('--dc', dest="datacenter")
|
||||||
|
@ -21,5 +21,5 @@ if not ControllerManageServer().check_exists(args.ip, None, args.hostname):
|
||||||
args.ip, None, args.status
|
args.ip, None, args.status
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
print 'fail'
|
print('fail')
|
||||||
# print "Admin account with email '%s' already exists." % args
|
# print "Admin account with email '%s' already exists." % args
|
||||||
|
|
8
cloud-server-ls.py
Normal file → Executable file
8
cloud-server-ls.py
Normal file → Executable file
|
@ -16,10 +16,10 @@ items = models.Servers.select().where(
|
||||||
models.Servers.status == args.status
|
models.Servers.status == args.status
|
||||||
)
|
)
|
||||||
|
|
||||||
print 'total: %s' % total
|
print('total: %s' % total)
|
||||||
print 'items: '
|
print('items: ')
|
||||||
|
|
||||||
for item in items:
|
for item in items:
|
||||||
print 'id: %s dc: %s status: %s ip: %s hostname: %s' % (
|
print('id: %s dc: %s status: %s ip: %s hostname: %s' % (
|
||||||
item.id, item.datacenter.id, item.status, item.ip, item.hostname
|
item.id, item.datacenter.id, item.status, item.ip, item.hostname
|
||||||
)
|
))
|
||||||
|
|
2
cloud-settings-init.py
Normal file → Executable file
2
cloud-settings-init.py
Normal file → Executable file
|
@ -7,7 +7,7 @@ def create_key(key, val=''):
|
||||||
if models.Settings.select().where(models.Settings.key == key).count() == 0:
|
if models.Settings.select().where(models.Settings.key == key).count() == 0:
|
||||||
models.Settings.create(key=key, val=val)
|
models.Settings.create(key=key, val=val)
|
||||||
else:
|
else:
|
||||||
print 'key %s already exists' % key
|
print('key %s already exists' % key)
|
||||||
|
|
||||||
|
|
||||||
create_key('bonus', '300')
|
create_key('bonus', '300')
|
||||||
|
|
0
cloud-settings.py
Normal file → Executable file
0
cloud-settings.py
Normal file → Executable file
|
@ -1,9 +1,9 @@
|
||||||
[Database]
|
[Database]
|
||||||
host = localhost
|
host = localhost
|
||||||
user = postgres
|
user = cherry
|
||||||
password = postgres
|
password = P@ss5476
|
||||||
port = 5432
|
port = 5432
|
||||||
name = gocloud
|
name = testdb
|
||||||
|
|
||||||
[Application]
|
[Application]
|
||||||
DEBUG = true
|
DEBUG = true
|
||||||
|
|
|
@ -1,19 +1,23 @@
|
||||||
[uwsgi]
|
[uwsgi]
|
||||||
virtualenv = /home/gocloud/env
|
|
||||||
|
env = HOME=/opt/nativecloud/.venv
|
||||||
|
env = CONFIG=/opt/nativecloud/extra/settings.origin.ini
|
||||||
|
|
||||||
|
chdir = /opt/nativecloud
|
||||||
|
|
||||||
;for http
|
;for http
|
||||||
;protocol = http
|
protocol = http
|
||||||
;socket = 127.0.0.1:8080
|
socket = 0.0.0.0:8080
|
||||||
|
|
||||||
; for unix-socket
|
; for unix-socket
|
||||||
socket = /var/run/sws/gocloud_web.sock
|
; socket = /var/run/nativecloud-web.sock
|
||||||
chmod-socket = 777
|
; chmod-socket = 777
|
||||||
|
|
||||||
module = SWSCloudWeb:app
|
module = SWSCloudWeb:app
|
||||||
|
|
||||||
master = true
|
master = true
|
||||||
processes = 2
|
processes = 2
|
||||||
|
|
||||||
vacuum = true
|
vacuum = true
|
||||||
|
|
||||||
die-on-term = true
|
die-on-term = true
|
||||||
|
|
||||||
|
thunder-lock = true
|
||||||
|
enable-threads = true
|
13
kb/README.md
13
kb/README.md
|
@ -1,13 +0,0 @@
|
||||||
# База знаний
|
|
||||||
|
|
||||||
## Обзие вопросы
|
|
||||||
|
|
||||||
- Как создать контейнер
|
|
||||||
- Как оплатить
|
|
||||||
-
|
|
||||||
|
|
||||||
## API
|
|
||||||
|
|
||||||
- Описание
|
|
||||||
- Запросы
|
|
||||||
- Коды ошибок
|
|
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
|
|
38
requirements.txt
Normal file
38
requirements.txt
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
async-timeout==5.0.1
|
||||||
|
babel==2.16.0
|
||||||
|
certifi==2024.8.30
|
||||||
|
charset-normalizer==3.4.0
|
||||||
|
click==8.1.7
|
||||||
|
configparser==7.1.0
|
||||||
|
dateutils==0.6.12
|
||||||
|
decorator==5.1.1
|
||||||
|
ecdsa==0.19.0
|
||||||
|
Flask==0.12.5
|
||||||
|
Flask-Babel==0.9
|
||||||
|
Flask-HTTPAuth==3.1.1
|
||||||
|
Flask-Markdown==0.3
|
||||||
|
flask-multistatic==1.0
|
||||||
|
flask-peewee==0.6.0
|
||||||
|
idna==3.10
|
||||||
|
importlib_metadata==8.5.0
|
||||||
|
itsdangerous==2.0.1
|
||||||
|
Jinja2==2.8
|
||||||
|
Markdown==3.7
|
||||||
|
MarkupSafe==2.0.1
|
||||||
|
peewee==2.8.0
|
||||||
|
psycopg2-binary==2.9.10
|
||||||
|
pycrypto==2.6.1
|
||||||
|
python-dateutil==2.9.0.post0
|
||||||
|
pytz==2024.2
|
||||||
|
pyuwsgi==2.0.28.post1
|
||||||
|
redis==5.2.1
|
||||||
|
requests==2.32.3
|
||||||
|
six==1.17.0
|
||||||
|
speaklater==1.3
|
||||||
|
sshpubkeys==1.0.6
|
||||||
|
urllib3==2.2.3
|
||||||
|
validators==0.10
|
||||||
|
Werkzeug==0.16.1
|
||||||
|
wtf-peewee==0.2.6
|
||||||
|
WTForms==3.2.1
|
||||||
|
zipp==3.21.0
|
30
setup.py
30
setup.py
|
@ -1,10 +1,12 @@
|
||||||
# coding: utf-8
|
import os
|
||||||
|
|
||||||
from setuptools import setup
|
from setuptools import setup
|
||||||
|
|
||||||
|
with open('requirements.txt') as f:
|
||||||
|
required = f.read().splitlines()
|
||||||
|
|
||||||
setup(
|
setup(
|
||||||
name='SWSCloudCore',
|
name='SWSCloudCore',
|
||||||
version='2.7.9',
|
version='2.7.10',
|
||||||
author='Vyacheslav Anzhiganov',
|
author='Vyacheslav Anzhiganov',
|
||||||
author_email='hello@anzhiganov.com',
|
author_email='hello@anzhiganov.com',
|
||||||
packages=[
|
packages=[
|
||||||
|
@ -79,7 +81,6 @@ setup(
|
||||||
'templates/default/documents/*.html',
|
'templates/default/documents/*.html',
|
||||||
'templates/default/homepage/*.html',
|
'templates/default/homepage/*.html',
|
||||||
'templates/default/id/*.html',
|
'templates/default/id/*.html',
|
||||||
'templates/default/kb/*.html',
|
|
||||||
'templates/default/payment/*.html',
|
'templates/default/payment/*.html',
|
||||||
'templates/default/payment/robokassa/*.html',
|
'templates/default/payment/robokassa/*.html',
|
||||||
'templates/default/support/*.html',
|
'templates/default/support/*.html',
|
||||||
|
@ -90,6 +91,7 @@ setup(
|
||||||
'templates/gocloud2016/layouts/*.html',
|
'templates/gocloud2016/layouts/*.html',
|
||||||
'templates/gocloud2016/macros/*.html',
|
'templates/gocloud2016/macros/*.html',
|
||||||
'templates/gocloud2016/pages/*.html',
|
'templates/gocloud2016/pages/*.html',
|
||||||
|
'templates/gocloud2016/pages/*/*.html',
|
||||||
# Errors
|
# Errors
|
||||||
'templates/errors/*.html',
|
'templates/errors/*.html',
|
||||||
],
|
],
|
||||||
|
@ -118,7 +120,6 @@ setup(
|
||||||
'templates/administrator/settings/messages/*.html',
|
'templates/administrator/settings/messages/*.html',
|
||||||
'templates/administrator/tasks/*.html',
|
'templates/administrator/tasks/*.html',
|
||||||
'templates/administrator/users/*.html',
|
'templates/administrator/users/*.html',
|
||||||
# 'templates/administrator/payments/*.html',
|
|
||||||
'templates/administrator/wiki/*.html',
|
'templates/administrator/wiki/*.html',
|
||||||
'templates/administrator/wiki/article/*.html',
|
'templates/administrator/wiki/article/*.html',
|
||||||
'templates/administrator/wiki/category/*.html',
|
'templates/administrator/wiki/category/*.html',
|
||||||
|
@ -146,22 +147,5 @@ setup(
|
||||||
# billing
|
# billing
|
||||||
'cloud-cron-balance.py',
|
'cloud-cron-balance.py',
|
||||||
],
|
],
|
||||||
install_requires=[
|
install_requires=required
|
||||||
'Flask==0.10',
|
|
||||||
'Flask-Markdown==0.3',
|
|
||||||
'Flask-Babel==0.9',
|
|
||||||
'flask-peewee==0.6.0',
|
|
||||||
'flask-multistatic',
|
|
||||||
'Jinja2==2.8',
|
|
||||||
'peewee==2.8',
|
|
||||||
'validators==0.10',
|
|
||||||
'psycopg2==2.6.1',
|
|
||||||
'configparser',
|
|
||||||
'flask_httpauth==3.1.1',
|
|
||||||
'requests==2.7',
|
|
||||||
'uWSGI==2.0.11.1',
|
|
||||||
'wsgiref==0.1.2',
|
|
||||||
'sshpubkeys==1.0.6',
|
|
||||||
'dateutils',
|
|
||||||
]
|
|
||||||
)
|
)
|
||||||
|
|
BIN
tutorial.pdf
BIN
tutorial.pdf
Binary file not shown.
Loading…
Add table
Reference in a new issue