39 QEMU virtual machines

This commit is contained in:
Vyacheslav Anzhiganov 2016-05-16 09:24:27 +03:00
parent 56dd407b57
commit 93ccb6f7c2
21 changed files with 661 additions and 27 deletions

View file

@ -9,6 +9,7 @@ from SWSCloudCore.views.account import viewAccount
from SWSCloudCore.views.administrator import viewAdministrator
from SWSCloudCore.views.api import viewAPI
from SWSCloudCore.views.containers import viewContainers
from SWSCloudCore.views.vms import viewVMs
from SWSCloudCore.views.documents import viewDocuments
from SWSCloudCore.views.kb import viewKB
from SWSCloudCore.views.server_api import viewServerAPI
@ -38,6 +39,7 @@ app.register_blueprint(viewAPI)
app.register_blueprint(viewTasks)
# /containers
app.register_blueprint(viewContainers)
app.register_blueprint(viewVMs)
# /id
app.register_blueprint(viewAccount)
# /payments

View file

@ -0,0 +1,15 @@
# coding: utf-8
from SWSCloudCore.models import PlansVMs
class ControllerPlans(object):
def get(self, status=None):
"""
Тарифные планы
:param status:
:return:
"""
if status:
return PlansVMs.select().where(PlansVMs.status == status)
return PlansVMs.select()

View file

@ -10,9 +10,8 @@ class ControllerManageTasks:
def __init__(self):
pass
def items_get(self, limit=100):
models.Tasks.select().limit(limit)
return None
def get(self, limit=100):
return models.Tasks.select().limit(limit)
def get_by_server(self, server_id):
task = models.Tasks.select(models.Tasks.plain).\

View file

@ -0,0 +1,29 @@
from SWSCloudCore.models import Vms
class ControllerVMS(object):
def __init__(self, user_id):
self.user_id = user_id
pass
def get(self):
return Vms.select().where(Vms.user == self.user_id)
def create(self, datacenter_id, server_id, vm_id,
hostname, ipv4, ipv6, plan, platform,
os_name, os_suite, status):
Vms.create(
id=vm_id,
datacenter=datacenter_id,
server=server_id,
user=self.user_id,
hostname=hostname,
ipv4=ipv4,
ipv6=ipv6,
plan=plan,
platform=platform,
os_name=os_name,
os_suite=os_suite,
status=status
)
return True

View file

@ -64,6 +64,27 @@ class Ips(PgSQLModel):
status = IntegerField()
class Plans(PgSQLModel):
id = UUIDField(primary_key=True, unique=True)
name = CharField(unique=True, null=False)
status = CharField(null=False, default='active')
storage = IntegerField(null=False)
swap = IntegerField(null=False)
memory = IntegerField(null=False)
cores = IntegerField(null=False)
class PlansVMs(PgSQLModel):
id = UUIDField(primary_key=True, unique=True)
name = CharField(unique=True, null=False)
status = CharField(null=False, default='active')
price = FloatField(null=False)
storage = IntegerField(null=False)
swap = IntegerField(null=False)
memory = IntegerField(null=False)
cores = IntegerField(null=False)
class Users(PgSQLModel):
id = UUIDField(primary_key=True, unique=True)
email = CharField(unique=True, null=False)
@ -164,6 +185,23 @@ class ContainersStatisticsState(PgSQLModel):
net_total = BigIntegerField(default=0, null=False)
class Vms(PgSQLModel):
id = UUIDField(primary_key=True, unique=True)
datacenter = ForeignKeyField(DataCenters)
server = ForeignKeyField(Servers)
user = ForeignKeyField(Users)
plan = ForeignKeyField(PlansVMs)
# 386, x86_64
hostname = CharField()
platform = CharField()
os_name = CharField()
os_suite = CharField()
ipv4 = CharField()
ipv6 = CharField()
# 0: inactive, 1: active, 2: ..., 3: ..., 4: ..., 5: ...
status = IntegerField()
class Tasks(PgSQLModel):
id = UUIDField(primary_key=True, unique=True)
datacenter = ForeignKeyField(DataCenters)

View file

@ -26,6 +26,7 @@
<ul>
<li><a href="{{ url_for('administrator.users') }}">Users</a></li>
<li><a href="{{ url_for('administrator.payments') }}">Payments</a></li>
<li><a href="{{ url_for('administrator.plans_index') }}">Plans</a></li>
</ul>
<li>Services
<ul>

View file

@ -1,32 +1,32 @@
{% extends 'administrator/_layout.auth.html' %}
{% block title %}IPs{% endblock %}
{% set title="Infrastructure" %}
{% block subtitle %}New IP{% endblock %}
{% set subtitle="New IP" %}
{% block content %}
<form method="post" action="{{ url_for('administrator.ips_create') }}">
<table class="table table-bordered">
<thead>
<tbody>
<tr>
<th>Data center</th>
<th>
<select name="datacenter">
{% for item in datacenters['items'] %}
<option name="{{ item.id }}">{{ item.name }}</option>
<option value="{{ item.id }}">{{ item.name }}</option>
{% endfor %}
</select>
</th>
</tr>
<tr>
<th>Server</th>
<th>
<td>Server</td>
<td>
<select name="server">
{% for item in servers['items'] %}
<option value="{{ item.id }}">{{ item.hostname }}</option>
{% endfor %}
</select>
</th>
</td>
</tr>
<tr>
<th>IPv4</th>
@ -51,7 +51,7 @@
<input type="reset" />
</th>
</tr>
</thead>
</tbody>
</table>
</form>
{% endblock %}

View file

@ -1,8 +1,8 @@
{% extends 'administrator/_layout.auth.html' %}
{% block title %}IPs{% endblock %}
{% set title="Infrastructure" %}
{% block subtitle %}Edit IP{% endblock %}
{% set subtitle="Edit IP" %}
{% block content %}
<form method="post" action="{{ url_for('administrator.ips_edit', ip_id=ip.id) }}">

View file

@ -1,12 +1,15 @@
{% extends 'administrator/_layout.auth.html' %}
{% block title %}IPs{% endblock %}
{% set title="Infrastructure" %}
{% block subtitle %}IPs list <label><a href="{{ url_for('administrator.ips_create') }}">New IP</a></label>{% endblock %}
{% set subtitle="IPs list" %}
{% block content %}
Total: {{ ips['total'] }}
<table class="table table-bordered">
<p>
Total: {{ ips['total'] }}
<a href="{{ url_for('administrator.ips_create') }}">New IP</a>
</p>
<table class="table table-bordered" width="100%">
<thead>
<tr>
<th>Id</th>

View file

@ -0,0 +1,43 @@
{% extends 'administrator/_layout.auth.html' %}
{% set title="Billing" %}
{% set subtitle="New Plan" %}
{% block content %}
<form action="{{ url_for('administrator.plans_create') }}" method="POST">
<table class="table table-bordered" width="100%">
<tbody>
<tr>
<td>Name</td>
<td><input type="text" name="name" value="" /></td>
</tr>
<tr>
<td>Status</td>
<td>
<select name="status">
<option>inactive</option>
<option>active</option>
</select>
</td>
</tr>
<tr>
<td>Storage (Mb)</td>
<td><input type="text" name="storage" value="" /></td>
</tr>
<tr>
<td>SWAP (Mb)</td>
<td><input type="text" name="swap" value="" /></td>
</tr>
<tr>
<td>Memory (Mb)</td>
<td><input type="text" name="memory" value="" /></td>
</tr>
<tr>
<td>Cores (int)</td>
<td><input type="text" name="cores" value="" /></td>
</tr>
</tbody>
</table>
<input type="submit" value="Create"/>
</form>
{% endblock %}

View file

@ -0,0 +1,42 @@
{% extends 'administrator/_layout.auth.html' %}
{% set title="Billing" %}
{% set subtitle="Plans" %}
{% block content %}
<p>Total: {{ plans|length }} <a href="{{ url_for('administrator.plans_create') }}">Create one</a></p>
<table class="table table-bordered" width="100%">
<thead>
<tr>
<th>ID</th>
<th>Name</th>
<th>Price</th>
<th>Cores</th>
<th>Storage</th>
<th>Swap</th>
<th>Memory</th>
<th>&nbsp;</th>
</tr>
</thead>
<tbody>
{% if plans|length == 0 %}
<tr>
<td colspan="7">No plans.</td>
</tr>
{% else %}
{% for plan in plans %}
<tr>
<td>{{ plan.id }}</td>
<td>{{ plan.name }}</td>
<td>{{ plan.price }}</td>
<td>{{ plan.cores }}</td>
<td>{{ plan.storage }}</td>
<td>{{ plan.swap }}</td>
<td>{{ plan.memory }}</td>
<td><a href="">Edit</a></td>
</tr>
{% endfor %}
{% endif %}
</tbody>
</table>
{% endblock %}

View file

@ -1,8 +1,8 @@
{% extends 'administrator/_layout.auth.html' %}
{% block title %}Servers{% endblock %}
{% set title="Servers" %}
{% block subtitle %}Edit server{% endblock %}
{% set subtitle="Edit server" %}
{% block content %}
<table class="table table-bordered">

View file

@ -18,6 +18,7 @@
</ul>
<ul class="left">
<li><a href="{{ url_for('containers.index') }}">Контейнеры</a></li>
<li><a href="{{ url_for('vms.index') }}">Виртуальные машины</a></li>
</ul>
{% else %}
<ul class="right">

View file

@ -5,7 +5,7 @@
{% block content %}
<div class="row">
<div class="large-12 columns">
<h3>Список <a href="{{ url_for('containers.create') }}">+</a></h3>
<h3>Список контейнеров <a href="{{ url_for('containers.create') }}">+</a></h3>
</div>
</div>
<div class="row">

View file

@ -0,0 +1,51 @@
{% extends "default/_layout.html" %}
{% block title %}Новый виртуальный сервер{% endblock %}
{% block content %}
<div class="row">
<div class="large-12 columns">
<h3>Новый виртуальный сервер</h3>
</div>
</div>
<div class="row">
<div class="large-12 columns">
{% if datacenters['total'] == 0 %}
<div class="row">
<div class="small-12 columns">
Нет возможности создать виртуальный сервер.
Обратитесь в <a href="mailto:support@gocloud.ru">поддержку</a>.
</div>
</div>
{% else %}
<div class="row">
<form action="{{ url_for('vms.create') }}" method="post" id="vmcreateform">
<div class="small-12 columns">
<label for="datacenter">
Датацентр
<select name="datacenter" class="form" id="datacenter">
{% for datacenter in datacenters['items'] %}
<option value="{{ datacenter.id }}">{{ datacenter.name }}: {{ datacenter.country }}, {{ datacenter.city }}</option>
{% endfor %}
</select>
</label>
</div>
<div class="small-12 columns">
<label for="plan">
Датацентр
<select name="plan" class="form" id="plan">
{% for plan in plans %}
<option value="{{ plan.id }}">{{ plan.name }}: {{ plan.price }}</option>
{% endfor %}
</select>
</label>
</div>
<div class="small-12 columns">
<input type="submit" value="Создать" class="button success" id="submitform" />
</div>
</form>
</div>
{% endif %}
</div>
</div>
{% endblock %}

View file

@ -1 +1,66 @@
<!-- list virtual machines -->
{% extends "default/_layout.html" %}
{% block title %}Виртуальные машины{% endblock %}
{% block content %}
<div class="row">
<div class="large-12 columns">
<h3>Список виртуальных машин <a href="{{ url_for('vms.create') }}">+</a></h3>
</div>
</div>
<div class="row">
<div class="large-12 columns">
<table id="zones" width="100%">
<thead>
<tr>
<th width="45%">ID</th>
<th>IP</th>
<th>Диск</th>
<th>Память</th>
<th>Ядра</th>
<th>Статус</th>
<th width="10%">&nbsp;</th>
</tr>
</thead>
<tbody>
{% if vms|length == 0 %}
<tr>
<td>Нет ни одной виртуальной машины. <a href="{{ url_for('vms.create') }}">Добавить</a>.</td>
</tr>
{% else %}
{% for vm in vms %}
<tr>
<td>{{ vm.id }}</td>
<td>
{% if vm['ipv4'] %}IPv4: {{ vm['ipv4'] }}{% endif %}
{% if vm['ipv6'] %}IPv6: {{ vm['ipv6'] }}{% endif %}
</td>
<td>{{ vm.plan.storage }}</td>
<td>{{ vm.plan.memory }}</td>
<td>{{ vm.plan.cores }}</td>
<td>
{% if vm['status'] == 0 %}
Неактивно
{% elif vm['status'] == 1 %}
Активно
{% elif vm['status'] == 2 %}
Процесс активации
{% elif vm['status'] == 3 %}
Процесс деактивации
{% elif vm['status'] == 4 %}
Создание...
{% elif vm['status'] == 5 %}
Удаление...
{% endif %}
</td>
<td>
<a href="{# { url_for('vm.settings', vm_id=vm.id) } #}">Настройки</a>
</td>
</tr>
{% endfor %}
{% endif %}
</tbody>
</table>
</div>
</div>
{% endblock %}

View file

@ -22,12 +22,14 @@ from SWSCloudCore.controllers.servers.manage import ControllerManageServer
from SWSCloudCore.controllers.users.manage import ControllerManageUsers
from SWSCloudCore.controllers.users.manage import ControllerManageUsersBalance
from SWSCloudCore.controllers.users.manage import ControllerManageUsersDetails
from SWSCloudCore.controllers.tasks.manage import ControllerManageTasks
from SWSCloudCore.controllers.plans import ControllerPlans
from SWSCloudCore import models
viewAdministrator = Blueprint('administrator', __name__, url_prefix='/administrator')
@viewAdministrator.route('/login', methods=['GET', 'POST'])
@viewAdministrator.route('/login.html', methods=['GET', 'POST'])
def login():
if request.method == 'POST':
admin_email = request.form['email'].encode('utf-8')
@ -56,7 +58,7 @@ def login():
return render_template('administrator/login.html')
@viewAdministrator.route('/logout')
@viewAdministrator.route('/logout.html')
def logout():
session.pop('admin_id', None)
session.pop('admin_email', None)
@ -64,7 +66,7 @@ def logout():
return redirect(url_for('administrator.login'))
@viewAdministrator.route('/dashboard')
@viewAdministrator.route('/dashboard.html')
def dashboard():
# check session
if not ControllerAdministrators().check_session():
@ -493,9 +495,35 @@ def json_datacenter_list():
@viewAdministrator.route('/tasks/', methods=['GET'])
def tasks_index():
from SWSCloudCore.controllers.tasks.manage import ControllerManageTasks
return render_template(
'administrator/tasks/index.html',
# tasks=ControllerManageTasks().get_by_server().get()
tasks=ControllerManageTasks().get()
)
@viewAdministrator.route('/plans/', methods=['GET'])
def plans_index():
return render_template(
'administrator/plans/index.html',
plans=ControllerPlans().get()
)
@viewAdministrator.route('/plans/create.html', methods=['GET', 'POST'])
def plans_create():
if request.method == "POST":
plan_id = str(uuid4())
models.PlansVMs.create(
id=plan_id,
name=request.form.get('name'),
status=request.form.get('status'),
storage=request.form.get('storage'),
swap=request.form.get('swap'),
memory=request.form.get('memory'),
cores=request.form.get('cores'),
)
flash('Plan has been created')
return redirect(url_for('administrator.plans_index'))
return render_template('administrator/plans/create.html')

View file

@ -0,0 +1,315 @@
# coding: utf-8
import uuid
from flask import Blueprint, g, redirect, render_template, request, session
from flask import url_for, flash
from SWSCloudCore.controllers.billing import ControllerBilling
from SWSCloudCore.controllers.common import ControllerCommon
from SWSCloudCore.controllers.common import ControllerMessagesEmail
from SWSCloudCore.controllers.vms import ControllerVMS
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
from SWSCloudCore.controllers.plans import ControllerPlans
viewVMs = Blueprint('vms', __name__, url_prefix='/vms')
@viewVMs.route('/')
def index():
# check session
if not ControllerUsers().check_session():
return redirect(url_for("account.logout"))
# auth user
if not ControllerUsers().auth(session['email'], session['password']):
return redirect(url_for("account.logout"))
return render_template(
'default/vms/index.html',
# get containers list
vms=ControllerVMS(session['user_id']).get()
)
@viewVMs.route('/create.html', methods=['GET', 'POST'])
def create():
# check session
if not ControllerUsers().check_session():
return redirect(url_for("account.logout"))
# auth user
if not ControllerUsers().auth(session['email'], session['password']):
return redirect(url_for("account.logout"))
user_balance = ControllerBilling().get(session['user_id'])
user_ssh = ControllerSSHKey(session['user_id'])
if request.method == "POST":
# check user money
if user_balance <= 0:
flash(u'Недостаточно средств на аккаунте')
return redirect(url_for('vms.create'))
new_vm = dict()
new_vm['vm_id'] = str(uuid.uuid4())
new_vm['plan'] = request.form.get('plan')
# select server from selected region with available ip-addresses
# select IP
select_ip = ControllerIps().getfree(request.form['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'] = 1
new_vm['storage'] = 20000
new_vm['swap'] = 512
new_vm['memory'] = 512
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(session['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 container_create:
# create task for create new container
ControllerTasks(session['user_id']).create(
new_vm['datacenter_id'],
new_vm['server_id'],
'vm_create',
0,
vm_id=new_vm['vm_id'],
ipv4=new_vm['ipv4'],
ipv6=new_vm['ipv6'],
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_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(session['user_id']).get()
#
# email = ControllerMessagesEmail()
# email.send(title=subject, to=user_data.email, lead=lead, message=message, callout=callout)
#
# return redirect(url_for('containers.index'))
else:
# mark ip as free
ControllerIps().setfree(select_ip.id)
# Get datacenters list
datacenters = ControllerDataCenters().get()
plans = ControllerPlans().get('active')
#
return render_template(
'default/vms/create.html',
datacenters=datacenters,
plans=plans,
)
@viewVMs.route('/delete/<uuid:container_id>.html', methods=['GET', 'POST'])
def delete(container_id):
# check session
if not ControllerUsers().check_session():
return redirect(url_for("account.logout"))
# auth user
if not ControllerUsers().auth(session['email'], session['password']):
return redirect(url_for("account.logout"))
#
containers = ControllerContainers(session['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 redirect(url_for('containers.index'))
# get container details
container_details = ControllerContainers(session['user_id']).get_item(container_id)
# POST
if request.method == "POST":
# Обновляем статус "5" для правила
containers.set_status(container_id, 5)
# Создание задания
ControllerTasks(session['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
# Редиректим на страницу со всеми правилами
flash(u'Контейнер был удалён')
return redirect(url_for('containers.index'))
return render_template(
'default/containers/delete.html',
container=container_details
)
@viewVMs.route('/settings/<uuid:container_id>', methods=['GET', 'POST'])
def settings(container_id):
# check session
if not ControllerUsers().check_session():
return redirect(url_for("account.logout"))
# auth user
if not ControllerUsers().auth(session['email'], session['password']):
return redirect(url_for("account.logout"))
containers = ControllerContainers(session['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 redirect(url_for('containers.index'))
# get container details
container_details = containers.get_item(container_id)
if request.method == 'POST':
if request.form['action'] == 'set_status':
if request.form['status'] == 'inactive':
containers.set_status(container_id, 3)
# Создание задания
ControllerTasks(session['user_id']).create(
container_details.datacenter.id,
container_details.server.id,
'container_stop',
0,
container_id=container_id
)
return redirect(url_for('containers.settings', container_id=container_id))
if request.form['status'] == 'active':
balance = ControllerBilling().get(session['user_id'])
if balance <= 0:
flash(u'Недостаточно средств на балансе.')
return redirect(url_for('containers.settings', container_id=container_id))
containers.set_status(container_id, 2)
# Создание задания
ControllerTasks(session['user_id']).create(
container_details.datacenter.id,
container_details.server.id,
'container_start',
0,
container_id=container_details.id
)
return redirect(url_for('containers.settings', container_id=container_id))
return render_template(
'default/containers/settings.html',
container=container_details
)
@viewVMs.route('/stats/<uuid:container_id>.html')
def stats(container_id):
# check session
if not ControllerUsers().check_session():
return redirect(url_for("account.logout"))
# auth user
if not ControllerUsers().auth(session['email'], session['password']):
return redirect(url_for("account.logout"))
# init
containers = ControllerContainers(session['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 redirect(url_for('containers.index'))
# get container details
container_details = containers.get_item(container_id)
# print ControllerContainersStatisticsState().get(container_id)
statistics = []
for s in ControllerContainersStatistics(container_id).size_get(1):
# print time.strftime(s.created, '%Y')
# print datetime.datetime.strptime(s.created, '%Y')
# print time.strftime("%B %d %Y", s.created)
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 render_template(
'default/containers/stats.html',
container=container_details,
stats_memory=statistics
)

View file

@ -19,6 +19,8 @@ tables = [
models.Containers,
models.ContainersStatistics,
models.ContainersStatisticsState,
models.PlansVMs,
models.Vms,
models.Tasks,
models.Settings,
models.Admins,

View file

@ -4,4 +4,4 @@
from SWSCloudCore import app
if __name__ == '__main__':
app.run()
app.run(host='0.0.0.0', port=5000, debug=True)

View file

@ -4,7 +4,7 @@ from setuptools import setup
setup(
name='SWSCloudCore',
version='2.1.7',
version='2.2.7',
author='Vyacheslav Anzhiganov',
author_email='hello@anzhiganov.com',
packages=[