Compare commits
14 commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
1e35e778f0 | ||
974e35cfc3 | |||
![]() |
7655b8b97a | ||
![]() |
6a11181075 | ||
![]() |
bfe906a1cf | ||
![]() |
25444811aa | ||
![]() |
c7286dc164 | ||
![]() |
fceb922d94 | ||
4c4202b346 | |||
999452a488 | |||
9261b24730 | |||
ef3933802e | |||
60241f9ea8 | |||
15c1a81831 |
94 changed files with 1431 additions and 429 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -1,6 +1,6 @@
|
|||
settings.ini
|
||||
.idea/
|
||||
|
||||
.venv/
|
||||
# Created by .ignore support plugin (hsz.mobi)
|
||||
### Python template
|
||||
# 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 -rvz --exclude-from .rsyncignore --delete ./ root@192.168.11.11:/opt/nativecloud/
|
26
README.md
26
README.md
|
@ -1,4 +1,17 @@
|
|||
# GoCloud
|
||||
# nativecloud
|
||||
|
||||
## install
|
||||
|
||||
```shell
|
||||
git clone https://git.org.ru/vmbuilder/console.git /opt/nativecloud
|
||||
python -m venv /opt/nativecloud/.venv
|
||||
. /opt/nativecloud/.venv/bin/activate
|
||||
pip install -r /opt/nativecloud/requrements.txt
|
||||
```
|
||||
|
||||
|
||||
|
||||
##
|
||||
|
||||
_Containers_
|
||||
|
||||
|
@ -10,6 +23,7 @@ Statuses:
|
|||
- 3: Процесс деактивации
|
||||
- 4: Создание...
|
||||
- 5: Удаление...
|
||||
- 6: Перезапуск
|
||||
|
||||
_Tasks_
|
||||
|
||||
|
@ -33,6 +47,12 @@ Statuses:
|
|||
|
||||
_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 flask import Blueprint, jsonify, request, g
|
||||
from SWSCloudAPI.API import auth
|
||||
from SWSCloudAPI.API.compute.v1.common import auth
|
||||
from SWSCloudCore.controllers.datacenters import ControllerDataCenters
|
||||
from SWSCloudCore.controllers.ips import ControllerIps
|
||||
from SWSCloudCore.controllers.users import ControllerUsers
|
||||
|
@ -13,7 +13,7 @@ from SWSCloudCore.controllers.tasks import ControllerTasks
|
|||
from SWSCloudCore.controllers.containers import (
|
||||
ControllerContainers, ControllerContainersStatistics, ControllerContainersStatisticsState)
|
||||
|
||||
api_v1_containers = Blueprint('containers', __name__, url_prefix='/api/v1/containers')
|
||||
api_v1_containers = Blueprint('containers', __name__, url_prefix='/api/compute/v1/containers')
|
||||
|
||||
|
||||
@api_v1_containers.route('/', methods=['GET'])
|
24
SWSCloudAPI/API/compute/v1/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
|
||||
|
||||
from flask import Blueprint, jsonify
|
||||
from SWSCloudAPI.API import auth
|
||||
from SWSCloudAPI.API.compute.v1.common import auth
|
||||
from SWSCloudCore.controllers.plans import ControllerPlans
|
||||
|
||||
api_v1_pricing = Blueprint('pricing', __name__, url_prefix='/api/v1/pricing')
|
||||
api_v1_pricing = Blueprint('pricing', __name__, url_prefix='/api/compute/v1/pricing')
|
||||
|
||||
|
||||
@api_v1_pricing.route('/pricing/vms/')
|
||||
@api_v1_pricing.route('/vms')
|
||||
@auth.login_required
|
||||
def pricing_vms():
|
||||
"""
|
||||
|
@ -18,7 +18,7 @@ def pricing_vms():
|
|||
return jsonify(pricing=ControllerPlans().get_plans(status='active'))
|
||||
|
||||
|
||||
@api_v1_pricing.route('/pricing/containers/')
|
||||
@api_v1_pricing.route('/containers')
|
||||
@auth.login_required
|
||||
def pricing_containers():
|
||||
"""
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
from uuid import uuid4
|
||||
from flask import Blueprint, jsonify, request, g
|
||||
from SWSCloudAPI.API import auth
|
||||
from SWSCloudAPI.API.compute.v1.common import auth
|
||||
from SWSCloudCore.controllers.ips import ControllerIps
|
||||
from SWSCloudCore.controllers.plans import ControllerPlans
|
||||
from SWSCloudCore.controllers.users import ControllerUsers
|
||||
|
@ -12,7 +12,7 @@ from SWSCloudCore.controllers.common import ControllerCommon, ControllerMessages
|
|||
from SWSCloudCore.controllers.tasks import ControllerTasks
|
||||
from SWSCloudCore.controllers.vms import ControllerVMS
|
||||
|
||||
api_v1_vms = Blueprint('vms', __name__, url_prefix='/api/v1/vms')
|
||||
api_v1_vms = Blueprint('vms', __name__, url_prefix='/api/compute/v1/vms')
|
||||
|
||||
|
||||
@api_v1_vms.route('/', methods=['GET'])
|
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
|
||||
|
||||
from flask import Flask, g, jsonify
|
||||
from SWSCloudAPI.API import api
|
||||
from SWSCloudAPI.API.vms import api_v1_vms
|
||||
from SWSCloudAPI.API.containers import api_v1_containers
|
||||
from SWSCloudAPI.API.datacenters import api_v1_datacenters
|
||||
from SWSCloudAPI.API.pricing import api_v1_pricing
|
||||
from SWSCloudCore import models
|
||||
from SWSCloudCore.models import database
|
||||
from SWSCloudCore.config import config
|
||||
from SWSCloudCore.models import database
|
||||
# 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.config["APPLICATION_ROOT"] = "/api/v1"
|
||||
# app.config['SERVER_NAME'] = settings.get('Application', 'SERVER_NAME')
|
||||
app.config['DEBUG'] = config.getboolean('Application', 'DEBUG')
|
||||
app.config['SECRET_KEY'] = config.get("Application", "SECRET_KEY")
|
||||
|
||||
app.register_blueprint(api)
|
||||
# V1
|
||||
app.register_blueprint(api_v1_vms)
|
||||
app.register_blueprint(api_v1_containers)
|
||||
app.register_blueprint(api_v1_pricing)
|
||||
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)
|
||||
def page_not_found(e):
|
||||
app.logger.error(e)
|
||||
return jsonify(dict(message='resource not found')), 404
|
||||
return jsonify(status='error', message='resource not found')
|
||||
|
||||
|
||||
@app.errorhandler(403)
|
||||
def access_deny(e):
|
||||
app.logger.error(e)
|
||||
return jsonify(dict(message='access deny')), 403
|
||||
return jsonify(status='error', message='access deny'), 403
|
||||
|
||||
|
||||
@app.errorhandler(410)
|
||||
def page_not_found(e):
|
||||
app.logger.error(e)
|
||||
return jsonify(dict()), 410
|
||||
return jsonify({})
|
||||
|
||||
|
||||
@app.errorhandler(500)
|
||||
def page_not_found(e):
|
||||
app.logger.error(e)
|
||||
return jsonify(dict(message='maintenance')), 500
|
||||
return jsonify(status='maintenance')
|
||||
|
||||
|
||||
@app.before_request
|
||||
def before_request():
|
||||
g.redis_connect = rediskc
|
||||
g.settings = dict()
|
||||
# извлекаем настройки и определяем их в глобальную переменную
|
||||
for setting in models.Settings.select(models.Settings.key, models.Settings.val).execute():
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
# coding: utf-8
|
||||
|
||||
from uuid import uuid4
|
||||
from hashlib import md5
|
||||
import validators
|
||||
|
||||
from datetime import datetime
|
||||
from flask import Blueprint, flash, g, jsonify, redirect, render_template, request, session, url_for
|
||||
from SWSCloudAdministrator.Administrator.common import requires_login
|
||||
|
||||
|
@ -12,19 +13,25 @@ from SWSCloudCore.controllers.common import ControllerMessagesEmail
|
|||
from SWSCloudCore.controllers.datacenters.manage import ControllerManageDatacenters
|
||||
from SWSCloudCore.controllers.ips.manage import ControllerManageIPs
|
||||
from SWSCloudCore.controllers.servers.manage import ControllerManageServer
|
||||
from SWSCloudCore.controllers.settings import ControllerSettings
|
||||
# from SWSCloudCore.controllers.users.manage import ControllerManageUsers
|
||||
# from SWSCloudCore.controllers.users.manage import ControllerManageUsersBalance
|
||||
# from SWSCloudCore.controllers.users.manage import ControllerManageUsersDetails
|
||||
from SWSCloudCore.controllers.plans import ControllerPlans
|
||||
from SWSCloudCore import models
|
||||
|
||||
|
||||
viewAdministrator = Blueprint('administrator', __name__, url_prefix='/administrator')
|
||||
|
||||
|
||||
@viewAdministrator.route('/login.html', methods=['GET', 'POST'])
|
||||
@viewAdministrator.route('/login.html', methods=['GET'])
|
||||
def login():
|
||||
if request.method == 'POST':
|
||||
admin_email = request.form.get('email').encode('utf-8')
|
||||
return render_template('administrator/login.html')
|
||||
|
||||
|
||||
@viewAdministrator.route('/login.html', methods=['POST'])
|
||||
def login_post():
|
||||
admin_email = request.form.get('email')
|
||||
admin_password = request.form.get('password').encode('utf-8')
|
||||
|
||||
# validation entered data
|
||||
|
@ -33,7 +40,10 @@ def login():
|
|||
return redirect(url_for('administrator.login'))
|
||||
|
||||
# try auth only active users (with status code 1)
|
||||
if models.Admins.auth(admin_email, admin_password, 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)
|
||||
|
||||
|
@ -44,11 +54,7 @@ def login():
|
|||
|
||||
# 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 ""
|
||||
|
||||
@viewAdministrator.route('/logout.html')
|
||||
def logout():
|
||||
|
@ -164,7 +170,7 @@ def ips_index():
|
|||
def ips_create():
|
||||
#
|
||||
if request.method == "POST":
|
||||
print request.form
|
||||
print(request.form)
|
||||
if ControllerManageIPs().is_valid_ipv4_address(request.form['ipv4'])\
|
||||
and ControllerManageIPs().is_valid_ipv4_address(request.form['ipv4_gateway']):
|
||||
ControllerManageIPs().item_create(
|
||||
|
@ -200,7 +206,7 @@ def ips_create():
|
|||
def ips_edit(ip_id):
|
||||
#
|
||||
if request.method == 'POST':
|
||||
print request.form
|
||||
print(request.form)
|
||||
# if ControllerManageIPs().is_valid_ipv4_address(request.form['ipv4'])\
|
||||
# and ControllerManageIPs().is_valid_ipv4_address(request.form['ipv4_gateway']):
|
||||
ControllerManageIPs().item_update(
|
||||
|
@ -232,7 +238,7 @@ def ips_delete():
|
|||
@requires_login
|
||||
def servers_create():
|
||||
if request.method == "POST":
|
||||
print request.form
|
||||
print(request.form)
|
||||
params = {
|
||||
'datacenter_id': request.form['datacenter_id'],
|
||||
'server_id': uuid4(),
|
||||
|
@ -405,3 +411,40 @@ def plan_edit(plan_id):
|
|||
return render_template(
|
||||
'administrator/plans/edit.html',
|
||||
plan_details=models.PlansVMs.select().where(models.PlansVMs.id == plan_id).get())
|
||||
|
||||
|
||||
|
||||
|
||||
@viewAdministrator.route('/setup', methods=['GET', 'POST'])
|
||||
# @requires_login
|
||||
def setup():
|
||||
# # check exists plan
|
||||
# if models.PlansVMs.select().where(models.PlansVMs.id == plan_id).count() == 0:
|
||||
# return redirect(url_for('administrator.plans_index'))
|
||||
|
||||
if request.method == 'POST':
|
||||
|
||||
admin_id = uuid4()
|
||||
admin_email = request.form.get('email')
|
||||
admin_password = md5(request.form.get('password').encode()).hexdigest()
|
||||
|
||||
# models.database.connect()
|
||||
|
||||
if models.Admins.select().where(models.Admins.email == admin_email).count() == 0:
|
||||
models.Admins.create(id=admin_id, email=admin_email, password=admin_password, status=1)
|
||||
|
||||
cs = ControllerSettings()
|
||||
cs.create('_setup_finish', str(datetime.now()))
|
||||
|
||||
return redirect(url_for('administrator.login'))
|
||||
|
||||
_setup_finish = models.Settings.select().where(
|
||||
models.Settings.key == "_setup_finish"
|
||||
).count()
|
||||
|
||||
if _setup_finish != 0:
|
||||
return redirect(url_for('login'))
|
||||
|
||||
return render_template(
|
||||
'administrator/setup/index.html'
|
||||
)
|
||||
|
|
|
@ -7,15 +7,19 @@ from SWSCloudCore.controllers.tasks import ControllerTasks
|
|||
from SWSCloudCore import models
|
||||
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'])
|
||||
@requires_login
|
||||
def index():
|
||||
# формируем список правил
|
||||
return render_template(
|
||||
'administrator/compute/vms/index.html', vms=models.Vms.get_items())
|
||||
"""Virtual Machines list"""
|
||||
template = 'administrator/compute/vms/index.html'
|
||||
items = models.Vms.get_items()
|
||||
return render_template(template, vms=items)
|
||||
|
||||
|
||||
@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
|
||||
|
||||
from flask import Blueprint, flash, g, jsonify, redirect, render_template, request, session, url_for
|
||||
|
||||
from SWSCloudCore.controllers.administrators import ControllerAdministrators
|
||||
import validators
|
||||
from flask import Blueprint, redirect, render_template, request, url_for
|
||||
from SWSCloudCore.controllers.tasks.manage import ControllerManageTasks
|
||||
from SWSCloudAdministrator.Administrator.common import requires_login
|
||||
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'])
|
||||
|
@ -25,23 +23,29 @@ def index():
|
|||
@view_administrator_tasks.route('/edit.html', methods=['GET'])
|
||||
@requires_login
|
||||
def edit():
|
||||
task_id = request.args.get('task_id')
|
||||
|
||||
# TODO: check exists
|
||||
|
||||
task_id = request.form.get('task_id')
|
||||
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(
|
||||
'administrator/tasks/edit.html',
|
||||
task=ControllerManageTasks().get_task(task_id))
|
||||
task=task)
|
||||
|
||||
|
||||
@view_administrator_tasks.route('/edit.html', methods=['POST'])
|
||||
@requires_login
|
||||
def edit_post():
|
||||
task_id = request.form.get('task_id')
|
||||
# todo: validate
|
||||
status = request.form.get('status')
|
||||
|
||||
# TODO: check exists
|
||||
x = models.Tasks.update(status=request.form.get('status')).where(models.Tasks.id == task_id)
|
||||
x.execute()
|
||||
if not validators.uuid(task_id) or not models.Tasks.exists(task_id):
|
||||
return redirect(url_for('administrator_tasks.index'))
|
||||
|
||||
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))
|
||||
|
||||
|
@ -51,11 +55,13 @@ def edit_post():
|
|||
def delete():
|
||||
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(
|
||||
'administrator/tasks/delete.html',
|
||||
task=ControllerManageTasks().get_task(task_id)
|
||||
task=task
|
||||
)
|
||||
|
||||
|
||||
|
@ -64,8 +70,10 @@ def delete():
|
|||
def delete_post():
|
||||
task_id = request.form.get('task_id')
|
||||
|
||||
# TODO: check exists
|
||||
x = models.Tasks.delete().where(models.Tasks.id == task_id)
|
||||
x.execute()
|
||||
if not validators.uuid(task_id) or not models.Tasks.exists(task_id):
|
||||
return redirect(url_for('administrator_tasks.index'))
|
||||
|
||||
task = models.Tasks.delete().where(models.Tasks.id == task_id)
|
||||
task.execute()
|
||||
|
||||
return redirect(url_for('administrator_tasks.index'))
|
||||
|
|
|
@ -43,7 +43,7 @@ app.register_blueprint(view_administrator_compute_containers)
|
|||
|
||||
# @app.errorhandler(500)
|
||||
# def page_not_found(e):
|
||||
# print e
|
||||
# print(e)
|
||||
# return render_template('errors/500.html'), 500
|
||||
|
||||
|
||||
|
@ -51,7 +51,11 @@ app.register_blueprint(view_administrator_compute_containers)
|
|||
def before_request():
|
||||
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
|
||||
|
||||
|
||||
|
|
|
@ -14,8 +14,8 @@
|
|||
</div>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
<form action="{{ url_for('administrator.login') }}" method="post">
|
||||
<label for="email">email</lable>
|
||||
<form action="{{ url_for('administrator.login_post') }}" method="post">
|
||||
<label for="email">email</label>
|
||||
<input type="text" name="email" value="" id="email" />
|
||||
<label for="password">password</label>
|
||||
<input type="password" name="password" value="" id="password" />
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
{% extends 'administrator/_layout.noauth.html' %}
|
||||
|
||||
{% block content %}
|
||||
<div class="row">
|
||||
<div class="large-12 columns">
|
||||
<h1>Setup</h1>
|
||||
<h2>Create an administrator</h2>
|
||||
{% with messages = get_flashed_messages() %}
|
||||
{% if messages %}
|
||||
<div class="alert-box alert">
|
||||
<ul>
|
||||
{% for message in messages %}
|
||||
<li>{{ message }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
<form action="{{ url_for('administrator.setup') }}" method="post">
|
||||
<label for="email">email</label>
|
||||
<input type="text" name="email" value="" id="email" />
|
||||
<label for="password">password</label>
|
||||
<input type="password" name="password" value="" id="password" />
|
||||
<input type="submit" value="login" class="button" />
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
0
SWSCloudCore/compute/__init__.py
Normal file
0
SWSCloudCore/compute/__init__.py
Normal file
|
@ -1,13 +1,11 @@
|
|||
# coding: utf-8
|
||||
|
||||
import sys
|
||||
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/nativecloud/config.ini')
|
||||
|
||||
# setting file read
|
||||
config = ConfigParser.ConfigParser()
|
||||
config = ConfigParser()
|
||||
if os.path.exists(__config_file__):
|
||||
config.read(__config_file__)
|
||||
|
||||
|
@ -30,4 +28,4 @@ if os.path.exists(__config_file__):
|
|||
if not config.has_option('Database', 'password'):
|
||||
sys.exit(1)
|
||||
else:
|
||||
sys.exit('config file not found: %s' % __config_file__)
|
||||
sys.exit(f'config file not found: {__config_file__}')
|
||||
|
|
|
@ -222,7 +222,7 @@ class Datacenters:
|
|||
"status": i.status
|
||||
}
|
||||
dcs['items'].append(dc)
|
||||
# print i
|
||||
# print(i)
|
||||
return dcs
|
||||
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ class ControllerContainers:
|
|||
)
|
||||
except Exception as e:
|
||||
# TODO: write to log
|
||||
print e
|
||||
print(e)
|
||||
return False
|
||||
return True
|
||||
|
||||
|
|
|
@ -3,9 +3,14 @@ import datetime
|
|||
from SWSCloudCore import models
|
||||
|
||||
|
||||
|
||||
class ControllerServerServers:
|
||||
def get_secret(self, server_id):
|
||||
return models.Servers.select(models.Servers.secret).where(models.Servers.id == server_id).get().secret
|
||||
return models.Servers.select(
|
||||
models.Servers.secret
|
||||
).where(
|
||||
models.Servers.id == server_id
|
||||
).get().secret
|
||||
|
||||
def exists(self, server_id):
|
||||
try:
|
||||
|
|
|
@ -36,7 +36,7 @@ class ControllerUsers:
|
|||
def update(self, user_id, **kwargs):
|
||||
if 'password' in kwargs:
|
||||
x = models.Users.update(
|
||||
password=md5(kwargs['password']).hexdigest()
|
||||
password=md5(kwargs['password'].encode()).hexdigest()
|
||||
).where(
|
||||
models.Users.id == user_id
|
||||
)
|
||||
|
@ -69,7 +69,7 @@ class ControllerUsers:
|
|||
:param password:
|
||||
:return:
|
||||
"""
|
||||
password_hash = md5(password).hexdigest()
|
||||
password_hash = md5(password.encode()).hexdigest()
|
||||
result = models.Users.select().where(
|
||||
models.Users.email == email,
|
||||
models.Users.password == password_hash,
|
||||
|
@ -86,7 +86,7 @@ class ControllerUsers:
|
|||
:param password:
|
||||
:return:
|
||||
"""
|
||||
password_hash = md5(password).hexdigest()
|
||||
password_hash = md5(password.encode()).hexdigest()
|
||||
user_id = uuid.uuid4()
|
||||
# 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)
|
||||
|
@ -95,7 +95,7 @@ class ControllerUsers:
|
|||
return False
|
||||
|
||||
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.password = password_hash
|
||||
u.save()
|
||||
|
|
|
@ -35,7 +35,7 @@ class ControllerManageUsers:
|
|||
models.UsersBalance
|
||||
)
|
||||
for j in jj:
|
||||
print j.usersbalance.balance
|
||||
print(j.usersbalance.balance)
|
||||
return {
|
||||
'total': len(jj),
|
||||
'items': jj
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
# coding: utf-8
|
||||
|
||||
import json
|
||||
from hashlib import md5
|
||||
import datetime
|
||||
import uuid
|
||||
|
@ -42,6 +43,16 @@ class DataCenters(PgSQLModel):
|
|||
city = CharField()
|
||||
status = IntegerField(default=0)
|
||||
|
||||
@staticmethod
|
||||
def get_available():
|
||||
return DataCenters.select().where(
|
||||
DataCenters.status == 1 and
|
||||
DataCenters.id << Servers.select(Servers.datacenter).where(
|
||||
Servers.status == 1 and
|
||||
Servers.id << Ips.select(Ips.server).where(
|
||||
Ips.status == 0).group_by(Ips.server)
|
||||
).group_by(Servers.datacenter)).execute()
|
||||
|
||||
|
||||
class Servers(PgSQLModel):
|
||||
id = UUIDField(unique=True, primary_key=True)
|
||||
|
@ -110,7 +121,9 @@ class Users(PgSQLModel):
|
|||
@staticmethod
|
||||
def auth(email, password, status=1):
|
||||
if Users.select().where(
|
||||
Users.email == email, Users.password == Users.hash_password(password), Users.status == status
|
||||
Users.email == email,
|
||||
Users.password == Users.hash_password(password),
|
||||
Users.status == status
|
||||
).count() == 0:
|
||||
return False
|
||||
return True
|
||||
|
@ -121,7 +134,11 @@ class Users(PgSQLModel):
|
|||
|
||||
@staticmethod
|
||||
def get_by_id(user_id):
|
||||
return Users.select().where(Users.id == user_id).get()
|
||||
return Users.select().where(Users.id == user_id).first()
|
||||
|
||||
@staticmethod
|
||||
def get_by_email(email):
|
||||
return Users.select().where(Users.email == email).first()
|
||||
|
||||
|
||||
class UsersRecoveryCodes(PgSQLModel):
|
||||
|
@ -247,6 +264,14 @@ class Vms(PgSQLModel):
|
|||
def get_items():
|
||||
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
|
||||
def get_item(vm_id):
|
||||
return Vms.select().where(Vms.id == vm_id).first()
|
||||
|
@ -298,22 +323,27 @@ class Tasks(PgSQLModel):
|
|||
Tasks.select().where(Tasks.status == status).count()
|
||||
return Tasks.select().count()
|
||||
|
||||
# @staticmethod
|
||||
# def set_task(datacenter_id, server_id, task, status, **args):
|
||||
# task_id = uuid.uuid4()
|
||||
# plain = dict()
|
||||
# for arg in args:
|
||||
# plain[arg] = str(args[arg])
|
||||
#
|
||||
# Tasks.create(
|
||||
# id=task_id,
|
||||
# datacenter=datacenter_id,
|
||||
# server=server_id,
|
||||
# task=task,
|
||||
# status=status,
|
||||
# user=self.user_id,
|
||||
# plain=json.dumps(plain)
|
||||
# )
|
||||
@staticmethod
|
||||
def set_task(datacenter_id, server_id, user_id, task, status, **args):
|
||||
task_id = uuid.uuid4()
|
||||
plain = dict()
|
||||
for arg in args:
|
||||
plain[arg] = str(args[arg])
|
||||
|
||||
Tasks.create(
|
||||
id=task_id,
|
||||
datacenter=datacenter_id,
|
||||
server=server_id,
|
||||
task=task,
|
||||
status=status,
|
||||
user=user_id,
|
||||
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):
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
# coding: utf-8
|
||||
"""Stack Web Services LLC."""
|
||||
|
||||
import json
|
||||
import logging
|
||||
|
||||
|
||||
from flask import Blueprint, jsonify, request, g
|
||||
from flask_httpauth import HTTPBasicAuth
|
||||
from SWSCloudCore.controllers.servers.server import ControllerServerStatistics
|
||||
|
@ -8,30 +11,52 @@ from SWSCloudCore.controllers.servers.server import ControllerServerServers
|
|||
from SWSCloudCore.controllers.tasks.server import ControllerTasksServer
|
||||
from SWSCloudCore.controllers.containers.server import ControllerContainersServer
|
||||
|
||||
|
||||
FORMAT = '%(asctime)-15s NODEAGENT %(levelname)s: %(message)s'
|
||||
|
||||
logging.basicConfig(format=FORMAT)
|
||||
|
||||
logger = logging.getLogger('tcpserver')
|
||||
|
||||
api_auth = HTTPBasicAuth()
|
||||
viewServerAPI = Blueprint('ServerAPI', __name__, url_prefix='/server_api')
|
||||
|
||||
|
||||
@api_auth.get_password
|
||||
def get_pw(server_id):
|
||||
logger.error(f"{server_id}")
|
||||
if ControllerServerServers().exists(server_id):
|
||||
g.server_id = server_id
|
||||
return ControllerServerServers().get_secret(g.server_id)
|
||||
return ControllerServerServers().get_secret(server_id)
|
||||
return None
|
||||
|
||||
|
||||
@api_auth.error_handler
|
||||
def auth_error():
|
||||
return jsonify(status='error', description='Unauthorized'), 403
|
||||
description = 'Unauthorized'
|
||||
return jsonify(
|
||||
status='error',
|
||||
description=description
|
||||
), 403
|
||||
|
||||
|
||||
@viewServerAPI.route('/ping')
|
||||
@api_auth.login_required
|
||||
# @api_auth.login_required
|
||||
def ping():
|
||||
"""
|
||||
Тест. Проверка соединения и авторизации
|
||||
"""
|
||||
return jsonify(ping='pong', server_id=g.server_id), 200
|
||||
|
||||
hhh = dict()
|
||||
for i in request.headers:
|
||||
hhh[i[0]] = str(i[1])
|
||||
|
||||
|
||||
return jsonify(
|
||||
ping='pong',
|
||||
cnt='1',
|
||||
h=hhh
|
||||
), 200
|
||||
|
||||
|
||||
# TASKS
|
||||
|
@ -65,9 +90,10 @@ def task_item():
|
|||
"""
|
||||
sapi = ControllerTasksServer(g.server_id)
|
||||
|
||||
# Если задач нет, то надо вернуть ответ с кодом 204 (no content)
|
||||
# Если задач нет,
|
||||
# то надо вернуть ответ с кодом 204 (no content)
|
||||
if sapi.count() == 0:
|
||||
return '', 204
|
||||
return jsonify(status='nothing'), 204
|
||||
|
||||
task = sapi.queue_item_oldest_get(status=0)
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# coding: utf-8
|
||||
|
||||
import logging
|
||||
import os
|
||||
from flask import Flask, g, render_template
|
||||
from flask_babel import Babel
|
||||
|
@ -42,7 +42,7 @@ if app.config.get('THEME_STATIC_FOLDER', False):
|
|||
static_folder = app.config['THEME_STATIC_FOLDER']
|
||||
if static_folder[0] != '/':
|
||||
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
|
||||
# need flask-multistatic
|
||||
# app.static_folder = [static_folder, os.path.join(app.root_path, 'static')]
|
||||
|
@ -72,7 +72,6 @@ app.register_blueprint(viewServerAPI)
|
|||
# /administrator
|
||||
app.register_blueprint(viewAdministrator)
|
||||
|
||||
|
||||
@app.errorhandler(404)
|
||||
def page_not_found(e):
|
||||
return render_template('errors/404.html'), 404
|
||||
|
@ -90,17 +89,20 @@ def page_not_found(e):
|
|||
|
||||
@app.errorhandler(500)
|
||||
def page_not_found(e):
|
||||
print e
|
||||
print(e)
|
||||
return render_template('errors/500.html'), 500
|
||||
|
||||
|
||||
@app.before_request
|
||||
def before_request():
|
||||
g.settings = dict()
|
||||
try:
|
||||
# извлекаем настройки и определяем их в глобальную переменную
|
||||
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
|
||||
def before_first_request():
|
||||
|
|
|
@ -16,7 +16,7 @@ def requires_login(f):
|
|||
else:
|
||||
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 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>
|
||||
{% endblock %}
|
||||
|
||||
|
||||
{% block footer %}
|
||||
{% endblock %}
|
|
@ -5,7 +5,7 @@
|
|||
{% block content %}
|
||||
<div class="row">
|
||||
<div class="large-12 columns">
|
||||
<h3>{{ _('Вход') }}</h3>
|
||||
<h2>{{ _('Вход') }}</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
|
|
|
@ -8,18 +8,12 @@
|
|||
<h2>Регистрация</h2>
|
||||
<form action="{{ url_for('account.registration') }}" method="post">
|
||||
<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" />
|
||||
</label>
|
||||
<label for="password">
|
||||
Пароль
|
||||
<label for="password">Пароль</label>
|
||||
<input type="password" name="password" value="" id="password" />
|
||||
</label>
|
||||
<label for="password2">
|
||||
Пароль (повторно)
|
||||
<label for="password2">Пароль (повторно)</label>
|
||||
<input type="password" name="password2" value="" id="password2" />
|
||||
</label>
|
||||
<input type="submit" value="Зарегистрироваться" class="button success" />
|
||||
</form>
|
||||
</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 http-equiv="x-ua-compatible" content="ie=edge">
|
||||
<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') }}">
|
||||
</head>
|
||||
<body>
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<h1>Облачный хостинг</h1>
|
||||
<h2>Виртуальный сервер от 200 рублей в месяц</h2>
|
||||
<h2>
|
||||
<a href="{{ url_for('account.registration') }}" class="button success">Создать виртуальный сервер</a>
|
||||
<a href="{{ url_for('account.registration') }}" class="button alert">Создать виртуальный сервер</a>
|
||||
</h2>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
{% extends "gocloud2016/layouts/default.html" %}
|
||||
|
||||
{% block title %}Стоимость аренды виртуального сервера - GoCloud{% endblock %}
|
||||
|
||||
{% block description %}Расценки на стоимость аренды виртуальных серверов различной конфигурации{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="row">
|
||||
<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)
|
||||
|
||||
ControllerUsersDetails(user_id).details_create()
|
||||
ControllerBilling().create(user_id, g.settings['bonus'])
|
||||
ControllerBilling().create(user_id, g.settings.get('bonus', 0))
|
||||
ControllerAPI().set(user_id=user_id, secret=user_id, acl='', status=0)
|
||||
# ControllerU
|
||||
# send mail message with recovery code
|
||||
|
||||
message = u"""
|
||||
Е-почта: %s
|
||||
Пароль: %s
|
||||
""" % (request.form['email'], request.form['password'])
|
||||
""" % (request.form.get('email'), request.form.get('password'))
|
||||
subject = u'GoCloud.ru: Успешная регистрация'
|
||||
lead = u"""
|
||||
Поздравляем с успешной регистрацией.
|
||||
|
@ -130,10 +131,12 @@ def registration():
|
|||
Для входа в личный кабинет воспользуйтесь
|
||||
<a href="https://gocloud.ru/account/login">страницей авторизации</a>.
|
||||
"""
|
||||
|
||||
try:
|
||||
email = ControllerMessagesEmail()
|
||||
email.send(title=subject, to=request.form['email'], lead=lead, message=message, callout=callout)
|
||||
|
||||
except Exception as e:
|
||||
# TODO: write message
|
||||
pass
|
||||
# redirect to login page
|
||||
flash(u'Учетная запись успешно зарегистрирована.', 'success')
|
||||
return redirect(url_for('account.login'))
|
||||
|
|
|
@ -1,42 +1,38 @@
|
|||
# coding: utf-8
|
||||
|
||||
import validators
|
||||
from flask import Blueprint, g, redirect, render_template, request, url_for, flash
|
||||
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.route('/', methods=['GET', 'POST'])
|
||||
@viewSupport.route('/', methods=['GET'])
|
||||
def index():
|
||||
# ControllerMessagesEmail().send()
|
||||
# print session
|
||||
return render_template('gocloud2016/pages/support/index.html')
|
||||
|
||||
if request.method == "POST":
|
||||
print request.form
|
||||
# TODO: validate
|
||||
ticket_title = request.form['title']
|
||||
ticket_message = request.form['message']
|
||||
ticket_email = request.form['email']
|
||||
|
||||
@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
|
||||
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)
|
||||
|
||||
email.send(
|
||||
title=ticket_subject, to=g.settings.get('contacts.email'), lead=lead, message=ticket_message, callout=callout)
|
||||
return redirect(url_for('support.thank'))
|
||||
return render_template('default/support/index.html')
|
||||
|
||||
|
||||
@viewSupport.route('/thank')
|
||||
@viewSupport.route('/thank.html')
|
||||
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):
|
||||
return redirect(url_for('homepage.index'))
|
||||
#
|
||||
print document_name
|
||||
print(document_name)
|
||||
doc_markdown = u''
|
||||
for ss in file('docs/%s.md' % document_name, 'r'):
|
||||
doc_markdown += ss.decode('UTF-8')
|
||||
|
|
|
@ -2,8 +2,13 @@ import requests
|
|||
|
||||
|
||||
class SWSStatisticsClient(object):
|
||||
def get_vm(self, vm_id, limit=96):
|
||||
r = requests.get('http://server-stats.gocloud.ru/stats/v1/compute/vms/%s' % vm_id, params={'limit': limit})
|
||||
def get_vm(self, vm_id: str, limit: int = 96):
|
||||
r = requests.get(
|
||||
f"http://server-stats.gocloud.ru/stats/v1/compute/vms/{vm_id}",
|
||||
params={
|
||||
'limit': limit
|
||||
}
|
||||
)
|
||||
if r.status_code == 200:
|
||||
return r.json()
|
||||
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
|
||||
# coding: utf-8
|
||||
|
||||
import sys
|
||||
import argparse
|
||||
import validators
|
||||
from hashlib import md5
|
||||
|
@ -25,13 +26,13 @@ if not validators.email(args.email):
|
|||
|
||||
admin_id = uuid4()
|
||||
admin_email = args.email
|
||||
admin_password = md5(args.password).hexdigest()
|
||||
admin_password = md5(args.password.encode()).hexdigest()
|
||||
|
||||
models.database.connect()
|
||||
|
||||
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)
|
||||
else:
|
||||
print "already exists"
|
||||
print("already exists")
|
||||
|
||||
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_items = models.Admins.select()
|
||||
|
||||
print "Total admins: %i" % admins_total
|
||||
print("Total admins: %i" % admins_total)
|
||||
|
||||
if admins_total == 0:
|
||||
print ''
|
||||
print('')
|
||||
else:
|
||||
print 'List:'
|
||||
print('List:')
|
||||
for item in admins_items:
|
||||
print '%s\t%s\t%s' % (item.id, item.email, item.status)
|
||||
print '---'
|
||||
print 'For create a new admin account use command "procdn-admin-add --email <email> --password <password>"'
|
||||
print('%s\t%s\t%s' % (item.id, item.email, item.status))
|
||||
print('---')
|
||||
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()
|
||||
# todo: validate admin 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:
|
||||
print "Admin account with email '%s' not exists." % admin_email
|
||||
print '---'
|
||||
print 'For create a new admin account use command "procdn-admin-add --email <email> --password <password>"'
|
||||
print("Admin account with email '%s' not exists." % admin_email)
|
||||
print('---')
|
||||
print('For create a new admin account use command "procdn-admin-add --email <email> --password <password>"')
|
||||
else:
|
||||
query = models.Admins.update(password=admin_password).where(models.Admins.email == admin_email)
|
||||
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')
|
||||
|
||||
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):
|
||||
# Высчитываем, сколько стоит виртуальная машина 15 минут
|
||||
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(
|
||||
|
@ -26,14 +26,14 @@ if int(models.Settings.get_item('SERVICE_VMS_ENABLE')) == 1:
|
|||
user_balance = models.UsersBalance.select(
|
||||
models.UsersBalance.balance).where(models.UsersBalance.user == vm.user.id).get().balance
|
||||
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)
|
||||
# Создание задания
|
||||
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:
|
||||
print 'total containers:', models.Containers.select().count()
|
||||
print('total containers:', models.Containers.select().count())
|
||||
for container in models.Containers.select():
|
||||
container_state = models.ContainersStatisticsState.select().where(
|
||||
models.ContainersStatisticsState.container == container.id
|
||||
|
@ -43,7 +43,7 @@ if int(models.Settings.get_item('SERVICE_CONTAINERS_ENABLE')) == 1:
|
|||
# # Высчитываем, сколько стоит виртуальная машина 15 минут
|
||||
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(
|
||||
|
|
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
|
||||
)
|
||||
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()
|
||||
|
||||
|
||||
print 'total: %s' % total
|
||||
print 'items: '
|
||||
print('total: %s' % total)
|
||||
print('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
|
||||
)
|
||||
))
|
||||
|
||||
print '---'
|
||||
print 'if you want to add a new data center, use cli-dc-add.py --'
|
||||
print('---')
|
||||
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>
|
||||
"""
|
||||
|
||||
print type(html)
|
||||
print(type(html))
|
||||
pdf = MyFPDF()
|
||||
# First 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
|
||||
|
||||
from SWSCloudCore import models
|
||||
from SWSCloudCore.controllers import ControllerManageIPs
|
||||
from SWSCloudCore.controllers.ips.manage import ControllerManageIPs
|
||||
|
||||
parser = argparse.ArgumentParser(description='')
|
||||
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
|
||||
)
|
||||
else:
|
||||
print 'fail'
|
||||
print('fail')
|
||||
# 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
|
||||
# coding: utf-8
|
||||
|
||||
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
|
||||
from uuid import uuid4
|
||||
from SWSCloudCore.controllers import ControllerManageServer
|
||||
from SWSCloudCore.controllers.servers.manage import ControllerManageServer
|
||||
|
||||
parser = argparse.ArgumentParser(description='')
|
||||
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
|
||||
)
|
||||
else:
|
||||
print 'fail'
|
||||
print('fail')
|
||||
# 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
|
||||
)
|
||||
|
||||
print 'total: %s' % total
|
||||
print 'items: '
|
||||
print('total: %s' % total)
|
||||
print('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
|
||||
)
|
||||
))
|
||||
|
|
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:
|
||||
models.Settings.create(key=key, val=val)
|
||||
else:
|
||||
print 'key %s already exists' % key
|
||||
print('key %s already exists' % key)
|
||||
|
||||
|
||||
create_key('bonus', '300')
|
||||
|
|
0
cloud-settings.py
Normal file → Executable file
0
cloud-settings.py
Normal file → Executable file
|
@ -1 +0,0 @@
|
|||
# Политика конфиденциальности
|
|
@ -1,34 +0,0 @@
|
|||
# Правила и условия использования хостинга
|
||||
|
||||
## Нарушение закона
|
||||
|
||||
Все предоставляемые услуги могут использоваться только для целей не противоречащих действующему общегосударственному и
|
||||
международному законодательству. Пользователь несет полную ответственность за публикуемые материалы. Содержимое сайтов
|
||||
и иных ресурсов клиентов может быть раскрыто третьим лицам не иначе, как в установленном Законом порядке.
|
||||
|
||||
## Нарушение прав третьих лиц
|
||||
|
||||
Примеры некорректных действий включают в себя рассылку информации частного характера о персоне без ее согласия,
|
||||
нарушение прав интеллектуальной собственности, распространение клеветы на персону или юридическое лицо. Блокирование
|
||||
сайта может быть вызвано ущемлением законных прав третьих лиц.
|
||||
|
||||
## Информационное содержание ресурса
|
||||
|
||||
При нарушении следующих правил Ваш ресурс может быть заблокирован или удален:
|
||||
|
||||
- Запрещается размещать материалы порнографического характера и ссылки на них.
|
||||
- Запрещена рассылка спама и всех его проявлений.
|
||||
- Не разрешается запуск резидентных программ.
|
||||
- Не допускается запуск скриптов, вызывающих критическую загрузку сервера.
|
||||
- Запрещается размещение материалов, нарушающее авторские права.
|
||||
|
||||
## Примите во внимание
|
||||
|
||||
Мы не несем ответственности за действие или бездействие третьих лиц в случае, если оно нарушает целостность сети
|
||||
Интернет или отдельных ее сегментов, приводя к невозможности обеспечения связи, доступа или доставки данных (например,
|
||||
электронной почты) между клиентом и сторонними участниками сети Интернет. Ответственность за безопасность использования
|
||||
клиентом программного обеспечения третьих лиц лежит на клиенте.
|
||||
|
||||
В дополнение к этому, администрация компании оставляет за собой право в любое время вносить уточнения и дополнения в
|
||||
настоящие правила, своевременно уведомляя пользователей. Нарушение пользователями настоящих правил будет
|
||||
квалифицироваться как несоблюдение договорных отношений вплоть до отключения аккаунта.
|
|
@ -1,9 +1,9 @@
|
|||
[Database]
|
||||
host = localhost
|
||||
user = postgres
|
||||
password = postgres
|
||||
user = cherry
|
||||
password = P@ss5476
|
||||
port = 5432
|
||||
name = gocloud
|
||||
name = testdb
|
||||
|
||||
[Application]
|
||||
DEBUG = true
|
||||
|
|
|
@ -1,19 +1,23 @@
|
|||
[uwsgi]
|
||||
virtualenv = /home/gocloud/env
|
||||
|
||||
env = HOME=/opt/nativecloud/.venv
|
||||
env = CONFIG=/opt/nativecloud/extra/settings.origin.ini
|
||||
|
||||
chdir = /opt/nativecloud
|
||||
|
||||
;for http
|
||||
;protocol = http
|
||||
;socket = 127.0.0.1:8080
|
||||
protocol = http
|
||||
socket = 0.0.0.0:8080
|
||||
|
||||
; for unix-socket
|
||||
socket = /var/run/sws/gocloud_web.sock
|
||||
chmod-socket = 777
|
||||
; socket = /var/run/nativecloud-web.sock
|
||||
; chmod-socket = 777
|
||||
|
||||
module = SWSCloudWeb:app
|
||||
|
||||
master = true
|
||||
processes = 2
|
||||
|
||||
vacuum = 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
|
7
mngr.wsgi
Normal file
7
mngr.wsgi
Normal file
|
@ -0,0 +1,7 @@
|
|||
import sys
|
||||
import logging
|
||||
|
||||
logging.basicConfig(stream=sys.stderr)
|
||||
sys.path.insert(0, "/opt/nativecloud")
|
||||
|
||||
from SWSCloudAdministrator import app as application
|
7
nativecloud.wsgi
Normal file
7
nativecloud.wsgi
Normal file
|
@ -0,0 +1,7 @@
|
|||
import sys
|
||||
import logging
|
||||
|
||||
logging.basicConfig(stream=sys.stderr)
|
||||
sys.path.insert(0, "/opt/nativecloud")
|
||||
|
||||
from SWSCloudWeb import app as application
|
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
|
||||
|
||||
with open('requirements.txt') as f:
|
||||
required = f.read().splitlines()
|
||||
|
||||
setup(
|
||||
name='SWSCloudCore',
|
||||
version='2.7.9',
|
||||
version='2.7.10',
|
||||
author='Vyacheslav Anzhiganov',
|
||||
author_email='hello@anzhiganov.com',
|
||||
packages=[
|
||||
|
@ -79,7 +81,6 @@ setup(
|
|||
'templates/default/documents/*.html',
|
||||
'templates/default/homepage/*.html',
|
||||
'templates/default/id/*.html',
|
||||
'templates/default/kb/*.html',
|
||||
'templates/default/payment/*.html',
|
||||
'templates/default/payment/robokassa/*.html',
|
||||
'templates/default/support/*.html',
|
||||
|
@ -90,6 +91,7 @@ setup(
|
|||
'templates/gocloud2016/layouts/*.html',
|
||||
'templates/gocloud2016/macros/*.html',
|
||||
'templates/gocloud2016/pages/*.html',
|
||||
'templates/gocloud2016/pages/*/*.html',
|
||||
# Errors
|
||||
'templates/errors/*.html',
|
||||
],
|
||||
|
@ -118,7 +120,6 @@ setup(
|
|||
'templates/administrator/settings/messages/*.html',
|
||||
'templates/administrator/tasks/*.html',
|
||||
'templates/administrator/users/*.html',
|
||||
# 'templates/administrator/payments/*.html',
|
||||
'templates/administrator/wiki/*.html',
|
||||
'templates/administrator/wiki/article/*.html',
|
||||
'templates/administrator/wiki/category/*.html',
|
||||
|
@ -146,22 +147,5 @@ setup(
|
|||
# billing
|
||||
'cloud-cron-balance.py',
|
||||
],
|
||||
install_requires=[
|
||||
'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',
|
||||
]
|
||||
install_requires=required
|
||||
)
|
||||
|
|
BIN
tutorial.pdf
BIN
tutorial.pdf
Binary file not shown.
Loading…
Add table
Reference in a new issue