simplifying schema
This commit is contained in:
parent
18d3d8cec1
commit
31ab20e837
11 changed files with 281 additions and 353 deletions
69
.gitignore
vendored
Normal file
69
.gitignore
vendored
Normal file
|
@ -0,0 +1,69 @@
|
|||
# Byte-compiled / optimized / DLL files
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*$py.class
|
||||
|
||||
# C extensions
|
||||
*.so
|
||||
|
||||
# Distribution / packaging
|
||||
.Python
|
||||
env/
|
||||
build/
|
||||
develop-eggs/
|
||||
dist/
|
||||
downloads/
|
||||
eggs/
|
||||
.eggs/
|
||||
lib/
|
||||
lib64/
|
||||
parts/
|
||||
sdist/
|
||||
var/
|
||||
*.egg-info/
|
||||
.installed.cfg
|
||||
*.egg
|
||||
|
||||
# PyInstaller
|
||||
# Usually these files are written by a python script from a template
|
||||
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||
*.manifest
|
||||
*.spec
|
||||
|
||||
# Installer logs
|
||||
pip-log.txt
|
||||
pip-delete-this-directory.txt
|
||||
|
||||
# Unit test / coverage reports
|
||||
htmlcov/
|
||||
.tox/
|
||||
.coverage
|
||||
.coverage.*
|
||||
.cache
|
||||
nosetests.xml
|
||||
coverage.xml
|
||||
*,cover
|
||||
.hypothesis/
|
||||
|
||||
# Translations
|
||||
*.mo
|
||||
*.pot
|
||||
|
||||
# Django stuff:
|
||||
*.log
|
||||
|
||||
# Sphinx documentation
|
||||
docs/_build/
|
||||
|
||||
# PyBuilder
|
||||
target/
|
||||
|
||||
#Ipython Notebook
|
||||
.ipynb_checkpoints
|
||||
|
||||
#proxadmin custom ignores
|
||||
*.sqlite
|
||||
db_repository/
|
||||
migrations/
|
||||
alchemydumps/
|
||||
config.py
|
156
app/models.py
156
app/models.py
|
@ -84,7 +84,7 @@ class User(db.Model, UserMixin):
|
|||
currency = db.Column(db.String(3), default='BGN')
|
||||
|
||||
inv_deployments = db.relationship('Deployment', backref='owner', lazy='dynamic')
|
||||
inv_contracts = db.relationship('Contract', backref='owner', lazy='dynamic')
|
||||
inv_services = db.relationship('Service', backref='owner', lazy='dynamic')
|
||||
inv_domains = db.relationship('Domain', backref='owner', lazy='dynamic')
|
||||
inv_address = db.relationship('Address', backref='owner', lazy='dynamic')
|
||||
|
||||
|
@ -219,104 +219,21 @@ def contact_proxmaster(data, method, cubeid=0):
|
|||
except:
|
||||
return None
|
||||
|
||||
#TEMPLATE CLASSES
|
||||
class Product(db.Model):
|
||||
__tablename__ = 'products'
|
||||
pid = db.Column(db.Integer, primary_key=True) #PK
|
||||
group = db.Column(db.Integer)
|
||||
name = db.Column(db.String(64))
|
||||
image = db.Column(db.String(128))
|
||||
description = db.Column(db.String(128))
|
||||
cpu = db.Column(db.Integer) #default cpu
|
||||
mem = db.Column(db.Integer) #default mem
|
||||
hdd = db.Column(db.Integer) #default hdd
|
||||
recipe = db.Column(db.String(128)) #defaut template name
|
||||
enabled = db.Column(db.Boolean)
|
||||
|
||||
@staticmethod
|
||||
def insert_products():
|
||||
products = current_app.config['PRODUCTS']
|
||||
for p in products:
|
||||
product = Product.query.filter_by(pid=p).first()
|
||||
if product is None:
|
||||
product = Product(name=p)
|
||||
|
||||
#insert default values
|
||||
product.group = products[p][0]
|
||||
product.name = products[p][1]
|
||||
product.image = products[p][2]
|
||||
product.description = products[p][3]
|
||||
product.cpu = products[p][4]
|
||||
product.mem = products[p][5]
|
||||
product.hdd = products[p][6]
|
||||
product.recipe = products[p][7]
|
||||
product.enabled = products[p][8]
|
||||
db.session.add(product)
|
||||
db.session.commit()
|
||||
|
||||
@staticmethod
|
||||
def get_products():
|
||||
result = Product.query.all()
|
||||
products = {}
|
||||
for product in result:
|
||||
if product.enabled == True:
|
||||
products[int(product.pid)] = { 'group': product.group,
|
||||
'img': '/static/images/' + product.image,
|
||||
'name': product.name,
|
||||
'description': product.description,
|
||||
'cpu': product.cpu,
|
||||
'mem': product.mem,
|
||||
'hdd': product.hdd,
|
||||
'recipe': product.recipe
|
||||
}
|
||||
return products
|
||||
|
||||
class Service(db.Model):
|
||||
__tablename__ = 'services'
|
||||
pid = db.Column(db.Integer, primary_key=True) #PK
|
||||
user_id = db.Column(db.Integer, db.ForeignKey('users.pid')) #FK
|
||||
name = db.Column(db.String(64))
|
||||
image = db.Column(db.String(128))
|
||||
description = db.Column(db.Unicode(128))
|
||||
unit = db.Column(db.Integer)
|
||||
unitprice = db.Column(db.Float)
|
||||
enabled = db.Column(db.Boolean)
|
||||
|
||||
@staticmethod
|
||||
def insert_services():
|
||||
services = current_app.config['SERVICES']
|
||||
for s in services:
|
||||
service = Service.query.filter_by(pid=p).first()
|
||||
if service is None:
|
||||
service = Service(name=s)
|
||||
|
||||
#insert default values
|
||||
service.name = products[p][1]
|
||||
service.image = products[p][2]
|
||||
service.description = products[p][3]
|
||||
service.unitprice = products[p][4]
|
||||
service.enabled = products[p][5]
|
||||
db.session.add(service)
|
||||
db.session.commit()
|
||||
|
||||
@staticmethod
|
||||
def get_services():
|
||||
result = Service.query.all()
|
||||
services = {}
|
||||
for service in result:
|
||||
if service.enabled == True:
|
||||
services[int(service.pid)] = {'img': '/static/images/' + service.image,
|
||||
'name': service.name,
|
||||
'description': service.description,
|
||||
'unitprice': service.unitprice
|
||||
}
|
||||
return services
|
||||
|
||||
|
||||
#INVENTORY CLASSES
|
||||
class Deployment(db.Model):
|
||||
__tablename__ = 'deployments'
|
||||
pid = db.Column(db.Integer, primary_key=True)
|
||||
user_id = db.Column(db.Integer, db.ForeignKey('users.pid')) #FK
|
||||
product_id = db.Column(db.Integer, db.ForeignKey('products.pid')) #FK
|
||||
date_created = db.Column(db.DateTime, index=True, default=datetime.utcnow)
|
||||
date_expire = db.Column(db.DateTime)
|
||||
enabled = db.Column(db.Boolean)
|
||||
|
@ -326,6 +243,7 @@ class Deployment(db.Model):
|
|||
machine_cpu = db.Column(db.Integer)
|
||||
machine_mem = db.Column(db.Integer)
|
||||
machine_hdd = db.Column(db.Integer)
|
||||
machine_ipv4list = db.Column(db.String)
|
||||
|
||||
def charge():
|
||||
result = Deployment.query.all()
|
||||
|
@ -347,33 +265,24 @@ class Deployment(db.Model):
|
|||
#TODO: Send emails here.
|
||||
db.session.commit()
|
||||
|
||||
class Contract(db.Model):
|
||||
__tablename__ = 'contracts'
|
||||
#NAMESPACE
|
||||
class Region(db.Model):
|
||||
__tablename__ = 'regions'
|
||||
pid = db.Column(db.Integer, primary_key=True)
|
||||
name = db.Column(db.String(64))
|
||||
description = db.Column(db.String(128))
|
||||
extraprice = db.Column(db.Float)
|
||||
|
||||
class Address(db.Model):
|
||||
__tablename__ = 'address'
|
||||
pid = db.Column(db.Integer, primary_key=True)
|
||||
date_assigned = db.Column(db.DateTime, index=True, default=datetime.utcnow)
|
||||
user_id = db.Column(db.Integer, db.ForeignKey('users.pid')) #FK
|
||||
service_id = db.Column(db.Integer, db.ForeignKey('services.pid')) #FK
|
||||
date_created = db.Column(db.DateTime, index=True, default=datetime.utcnow)
|
||||
date_expire = db.Column(db.DateTime)
|
||||
enabled = db.Column(db.Boolean)
|
||||
|
||||
description = db.Column(db.Unicode)
|
||||
units = db.Column(db.Integer)
|
||||
discount = db.Column(db.Integer) #percent
|
||||
|
||||
def charge():
|
||||
result = Contract.query.all()
|
||||
for contract in result:
|
||||
managed_user = User.query.get(contract.user_id)
|
||||
db.session.add(contract)
|
||||
#if datetime.utcnow.date() > (contract.date_expire - timedelta(days=10)):
|
||||
if contract.enabled == True:
|
||||
print('{}> Contract {} will expire in 10 days at {}. Creating new order...'.format(managed_user.email, contract.pid, contract.date_expire))
|
||||
current_service = Service.query.get(int(contract.product_id))
|
||||
transaction = Transaction(user_id=managed_user.id, units=contract.units, unitvalue=(current_service.unitprice * contract.units), description=current_service.name)
|
||||
db.session.add(transaction)
|
||||
contract.data_expire = datetime.utcnow.date() + timedelta(days=30)
|
||||
db.session.commit()
|
||||
return True
|
||||
region_id = db.Column(db.Integer, db.ForeignKey('regions.pid')) #FK
|
||||
ipv4 = db.Column(db.String(64))
|
||||
ipv6 = db.Column(db.String(256))
|
||||
rdns = db.Column(db.String(256))
|
||||
macaddr = db.Column(db.String(128))
|
||||
|
||||
class Domain(db.Model):
|
||||
__tablename__ = 'domains'
|
||||
|
@ -381,34 +290,9 @@ class Domain(db.Model):
|
|||
user_id = db.Column(db.Integer, db.ForeignKey('users.pid')) #FK
|
||||
date_created = db.Column(db.DateTime, index=True, default=datetime.utcnow)
|
||||
date_expire = db.Column(db.DateTime)
|
||||
enabled = db.Column(db.Boolean)
|
||||
|
||||
fqdn = db.Column(db.String, unique=True)
|
||||
auto_update = db.Column(db.Boolean)
|
||||
|
||||
def charge():
|
||||
result = Domain.query.all()
|
||||
for domain in result:
|
||||
managed_user = User.query.get(domain.user_id)
|
||||
db.session.add(domain)
|
||||
#if datetime.utcnow.date() > (domain.date_expire - timedelta(days=60)):
|
||||
if domain.enabled == True:
|
||||
print('{}> Domain {} will expire in 60 days at {}. Creating new order...'.format(managed_user.email, domain.fqdn, domain.date_expire))
|
||||
transaction = Transaction(user_id=managed_user.id, unitvalue=25, description=domain.fqdn)
|
||||
db.session.add(transaction)
|
||||
db.session.commit()
|
||||
return True
|
||||
|
||||
class Address(db.Model):
|
||||
__tablename__ = 'address'
|
||||
pid = db.Column(db.Integer, primary_key=True)
|
||||
user_id = db.Column(db.Integer, db.ForeignKey('users.pid')) #FK
|
||||
date_created = db.Column(db.DateTime, index=True, default=datetime.utcnow)
|
||||
|
||||
ipaddr = db.Column(db.String(128))
|
||||
macaddr = db.Column(db.String(128))
|
||||
|
||||
|
||||
#UINVOICE
|
||||
class Transaction(db.Model):
|
||||
__tablename__ = 'transaction'
|
||||
|
|
|
@ -177,10 +177,14 @@ a:active {
|
|||
padding-left: 16px;
|
||||
}
|
||||
|
||||
.container {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.container-fluid {
|
||||
position: relative;
|
||||
max-width: 1170px;
|
||||
min-width: 480px;
|
||||
max-width: 100%;
|
||||
min-width: 280px;
|
||||
}
|
||||
|
||||
.container-fluid-index {
|
||||
|
@ -252,9 +256,15 @@ a:active {
|
|||
border-color: #070;
|
||||
}
|
||||
|
||||
.panel > .panel-heading {
|
||||
.panel-heading {
|
||||
padding: 6px 15px;
|
||||
border-bottom: 1px solid transparent;
|
||||
border-top-left-radius: 3px;
|
||||
border-top-right-radius: 3px;
|
||||
}
|
||||
|
||||
.tooltip-inner {
|
||||
max-width: 350px;
|
||||
/* If max-width does not work, try using width instead */
|
||||
width: 350px;
|
||||
}
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% block head %}
|
||||
{{ super() }}
|
||||
{% endblock %}
|
||||
|
||||
{% block styles %}
|
||||
{{ super() }}
|
||||
<link href="/static/css/simple-slideshow-styles.css" type="text/css" rel="stylesheet" media="screen">
|
||||
{% endblock %}
|
||||
|
||||
{% block head %}
|
||||
{{ super() }}
|
||||
<style>
|
||||
body {
|
||||
background-image: url('/static/images/cloudsbg.jpeg');
|
||||
|
|
|
@ -1,18 +1,76 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% block styles %}
|
||||
{{ super() }}
|
||||
<style type="text/css">
|
||||
.tg {border-collapse:collapse;border-spacing:0;}
|
||||
.tg td{font-family:Arial, sans-serif;font-size:14px;padding:1px 1px;border-style:solid;border-width:1px;overflow:hidden;word-break:normal;}
|
||||
.tg th{font-family:Arial, sans-serif;font-size:14px;padding:1px 1px;font-weight:normal;padding:border-style:solid;border-width:1px;overflow:hidden;word-break:normal;}
|
||||
.tg .tg-yw4l{vertical-align:top}
|
||||
</style>
|
||||
|
||||
<style type="text/css">
|
||||
@media only screen and (max-width: 768px) {
|
||||
|
||||
/* Force table to not be like tables anymore */
|
||||
#no-more-tables table,
|
||||
#no-more-tables thead,
|
||||
#no-more-tables tbody,
|
||||
#no-more-tables th,
|
||||
#no-more-tables td,
|
||||
#no-more-tables tr {
|
||||
display: block;
|
||||
}
|
||||
|
||||
/* Hide table headers (but not display: none;, for accessibility) */
|
||||
#no-more-tables thead tr {
|
||||
position: absolute;
|
||||
top: -9999px;
|
||||
left: -9999px;
|
||||
}
|
||||
|
||||
#no-more-tables tr { border: 1px solid #ccc; }
|
||||
|
||||
#no-more-tables td {
|
||||
/* Behave like a "row" */
|
||||
border: none;
|
||||
border-bottom: 1px solid #eee;
|
||||
position: relative;
|
||||
padding-left: 50%;
|
||||
white-space: normal;
|
||||
text-align:left;
|
||||
}
|
||||
|
||||
#no-more-tables td:before {
|
||||
/* Now like a table header */
|
||||
position: absolute;
|
||||
/* Top/left values mimic padding */
|
||||
top: 6px;
|
||||
left: 6px;
|
||||
width: 45%;
|
||||
padding-right: 10px;
|
||||
white-space: nowrap;
|
||||
text-align:left;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/*
|
||||
Label the data
|
||||
*/
|
||||
#no-more-tables td:before { content: attr(data-title); }
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
{% block scripts %}
|
||||
{{ super() }}
|
||||
<script type="text/javascript">
|
||||
//$(function() {
|
||||
// $('.confirm').click(function() {
|
||||
// return window.confirm("Are you sure?");
|
||||
// });
|
||||
//});
|
||||
$('a[data-toggle="tooltip"]').tooltip({
|
||||
animated: 'fade',
|
||||
placement: 'bottom',
|
||||
html: true
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
{% block page_content %}
|
||||
|
||||
<script>
|
||||
// Only run what comes next *after* the page has loaded
|
||||
addEventListener("DOMContentLoaded", function() {
|
||||
|
@ -53,31 +111,72 @@ addEventListener("DOMContentLoaded", function() {
|
|||
}
|
||||
}, true);
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
<style type="text/css">
|
||||
.tg {border-collapse:collapse;border-spacing:0;}
|
||||
.tg td{font-family:Arial, sans-serif;font-size:14px;padding:1px 1px;border-style:solid;border-width:1px;overflow:hidden;word-break:normal;}
|
||||
.tg th{font-family:Arial, sans-serif;font-size:14px;padding:1px 1px;font-weight:normal;padding:border-style:solid;border-width:1px;overflow:hidden;word-break:normal;}
|
||||
.tg .tg-yw4l{vertical-align:top}
|
||||
</style>
|
||||
|
||||
|
||||
{% block page_content %}
|
||||
<div class="container-fluid">
|
||||
<br />
|
||||
<div class="row">
|
||||
|
||||
{% block sidebar %}
|
||||
<div class="col-md-4">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
{% include "/settings/acc_avatar.html" %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
<div class="col-md-12">
|
||||
<div class="panel panel-info" id="dashboard">
|
||||
<div class="panel-heading">Deployments</div>
|
||||
<div class="panel-body"><p>
|
||||
{% if inv_deploymens == None %}
|
||||
<table class="table table-hover table-striped table-condensed cf">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>CPU</th>
|
||||
<th>Mem</th>
|
||||
<th>HDD</th>
|
||||
<th>IPv4</th>
|
||||
<th>Control</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
<tbody>
|
||||
{% for deploy in inv_deployments %}
|
||||
<tr>
|
||||
<td>
|
||||
<a data-toggle="tooltip" title="ID# {{ deploy.machine_id }}<br />Deployment state: {{ status[deploy.machine_id] }}"><b>{% if status[deploy.machine_id] == 'running' %}<font color="green">{% else %}<font color="red">{% endif %}{{ deploy.machine_alias }}</font></b></a></td>
|
||||
<td><a data-toggle="tooltip" title="<img src='data:image/png;base64,{{ rrd[deploy.machine_id]['cpu'] }}' />">{{ deploy.machine_cpu }} Cores</a></td>
|
||||
<td><a data-toggle="tooltip" title="<img src='data:image/png;base64,{{ rrd[deploy.machine_id]['mem'] }}' />">{{ deploy.machine_mem }} MB</a></td>
|
||||
<td><a data-toggle="tooltip" title="<img src='data:image/png;base64,{{ rrd[deploy.machine_id]['hdd'] }}' />">{{ deploy.machine_hdd }} GB</a></td>
|
||||
<td><a data-toggle="tooltip" title="<img src='data:image/png;base64,{{ rrd[deploy.machine_id]['net'] }}' />">{% for ip in deploy.machine_ipv4list %}{{ ip }}{% endfor %}</a></td>
|
||||
<td>{% if status[deploy.machine_id] == 'running' %}
|
||||
<button class="confirm command command-vmshutdown btn btn-default btn-warning" value="vmshutdown" vmid="{{ deploy.machine_id }}"><span class="glyphicon glyphicon-off" aria-hidden="true"></span> Shutdown</button>
|
||||
<button class="confirm command command-vmstop btn btn-default btn-danger" value="vmstop" vmid="{{ deploy.machine_id }}"><span class="glyphicon glyphicon-alert" aria-hidden="true"></span> Force Stop</button>
|
||||
{% else %}
|
||||
<button class="command command-vmstart btn btn-default btn-success" value="vmstart" vmid="{{ deploy.machine_id }}"><span class="glyphicon glyphicon-play" aria-hidden="true"></span> Start</button>
|
||||
{% endif %}</td>
|
||||
<td>{% if status[deploy.machine_id] == 'running' %}
|
||||
<button class="btn btn-default btn-info" onclick="window.open('/vmanager/vmvnc/{{ deploy.machine_id }}', '_blank');"><span class="glyphicon glyphicon-console" aria-hidden="true"></span> Console</button>
|
||||
{% endif %}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% endif %}
|
||||
<button class="btn btn-default"><span class="glyphicon glyphicon-plus" aria-hiddent="true"></span> Create</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-8">
|
||||
<div class="panel panel-default" id="contracts">
|
||||
<div class="col-md-12">
|
||||
<div class="panel panel-info" id="dashboard">
|
||||
<div class="panel-heading">Domains</div>
|
||||
<div class="panel-body"><p>
|
||||
{% for domain in inv_domains %}
|
||||
{{ fqdn }}
|
||||
{% endfor %}
|
||||
<button class="btn btn-default" onclick="window.open('{{ url_for('main.index') }}')"><span class="glyphicon glyphicon-plus" aria-hiddent="true"></span> Create</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="col-md-12">
|
||||
<div class="panel panel-info" id="dashboard">
|
||||
<div class="panel-heading">Services</div>
|
||||
<div class="panel-body"><p>
|
||||
{% for contract in inv_contracts %}
|
||||
|
@ -85,115 +184,15 @@ addEventListener("DOMContentLoaded", function() {
|
|||
{{ contract.units }}<br />
|
||||
{% if not contract.discount == 0 %}
|
||||
Discount %{{ contract.discount }}<br />
|
||||
Credit: {{ contract.credit }}<br /><br />
|
||||
Credit: {{ contract.credit }}<br />
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
<p>
|
||||
<button class="btn btn-default" onclick="window.open('{{ url_for('main.index') }}')"><span class="glyphicon glyphicon-plus" aria-hiddent="true"></span> Create</button>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-4">
|
||||
<div class="panel panel-default" id="contracts">
|
||||
<div class="panel-heading">Domains</div>
|
||||
<div class="panel-body"><p>
|
||||
{% for domain in inv_domains %}
|
||||
{{ fqdn }}<br />
|
||||
{% endfor %}
|
||||
<p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="col-md-8">
|
||||
<div class="panel-group">
|
||||
<div class="panel panel-default" id="deploys">
|
||||
<div class="panel-heading">Deployments</div>
|
||||
<div class="panel-body"><p>
|
||||
{% for deploy in inv_deployments %}
|
||||
<ul class="nav nav-pills">
|
||||
<li class="active"><a data-toggle="pill" href="#home{{ deploy.machine_id }}">{{ deploy.machine_alias }}</a></li>
|
||||
<li><a data-toggle="pill" href="#control{{ deploy.machine_id }}">Control</a></li>
|
||||
<li><a data-toggle="pill" href="#stats{{ deploy.machine_id }}">Stats</a></li>
|
||||
<li><a data-toggle="pill" href="#keys{{ deploy.machine_id }}">Keys</a></li>
|
||||
</ul>
|
||||
<div class="tab-content">
|
||||
<div id="home{{ deploy.machine_id}}" class="tab-pane fade in active">
|
||||
<br />
|
||||
</div>
|
||||
|
||||
<div id="control{{ deploy.machine_id}}" class="tab-pane fade">
|
||||
<br />
|
||||
{% if status[deploy.machine_id] == 'running' %}
|
||||
<button class="btn btn-default btn-info" onclick="window.open('/vmanager/vmvnc/{{ deploy.machine_id }}', '_blank');"><span class="glyphicon glyphicon-console" aria-hidden="true"></span> Console</button>
|
||||
<button class="confirm command command-vmshutdown btn btn-default btn-warning" value="vmshutdown" vmid="{{ deploy.machine_id }}"><span class="glyphicon glyphicon-off" aria-hidden="true"></span> Shutdown</button>
|
||||
<button class="confirm command command-vmstop btn btn-default btn-danger" value="vmstop" vmid="{{ deploy.machine_id }}"><span class="glyphicon glyphicon-alert" aria-hidden="true"></span> Force Stop</button>
|
||||
{% else %}
|
||||
<button class="command command-vmstart btn btn-default btn-success" value="vmstart" vmid="{{ deploy.machine_id }}"><span class="glyphicon glyphicon-play" aria-hidden="true"></span> Start</button>
|
||||
{% endif %}
|
||||
<br /><br />
|
||||
Grid ID# {{ deploy.machine_id }}<br >
|
||||
CPU: {{ deploy.machine_cpu }} cores</br >
|
||||
Memory: {{ deploy.machine_mem }} MB</br >
|
||||
Disk Space: {{ deploy.machine_hdd }} GB</br >
|
||||
<br />
|
||||
Expiry date: {{ deploy.date_expire }}</br >
|
||||
Credit: {{ deploy.credit }}
|
||||
</div>
|
||||
|
||||
<div id="stats{{ deploy.machine_id}}" class="tab-pane fade">
|
||||
<table class="tg">
|
||||
<tr>
|
||||
<th class="tg-yw4l">Network Bandwidth</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="tg-yw4l"><img src="data:image/png;base64,{{ rrd[deploy.machine_id]['net'] }}" class="img-responsive"><br></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
||||
<table class="tg">
|
||||
<tr>
|
||||
<th class="tg-yw4l">CPU Load</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="tg-yw4l"><img src="data:image/png;base64,{{ rrd[deploy.machine_id]['cpu'] }}" class="img-responsive"><br></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<table class="tg">
|
||||
<tr>
|
||||
<th class="tg-yw4l">Memory Usage</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="tg-yw4l"><img src="data:image/png;base64,{{ rrd[deploy.machine_id]['mem'] }}" class="img-responsive"><br></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<table class="tg">
|
||||
<tr>
|
||||
<th class="tg-yw4l">Disk Input/Output</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="tg-yw4l"><img src="data:image/png;base64,{{ rrd[deploy.machine_id]['hdd'] }}" class="img-responsive"><br></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div id="keys{{ deploy.machine_id}}" class="tab-pane fade">
|
||||
Not yet implemented.
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<br />
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
|
|
@ -83,6 +83,7 @@
|
|||
{{ form.mem.label }} {{ form.mem }}<br />
|
||||
{{ form.hdd.label }} {{ form.hdd }}<br />
|
||||
{{ form.recipe.label }} {{ form.recipe }}<br />
|
||||
{{ form.ipv4.label }} {{ form.ipv4 }}<br />
|
||||
<p>
|
||||
|
||||
<br />
|
||||
|
|
|
@ -12,7 +12,7 @@ class DeployForm(FlaskForm):
|
|||
mem = StringField('Памет:')
|
||||
hdd = StringField('Дисково пространство:')
|
||||
recipe = SelectField('Рецепта')
|
||||
#ipv4 = SelectField('Брой публични IP адреса', choices=[('1', '1'),('2', '2' ), ('3', '3')])
|
||||
ipv4 = SelectField('Брой публични IP адреса', choices=[('1', '1'),('2', '2' ), ('3', '3')])
|
||||
invite_key = StringField('Покана', [validators.DataRequired(), validators.Length(6,35)])
|
||||
|
||||
def validate_invite_key(self, field):
|
||||
|
|
|
@ -6,13 +6,14 @@ from . import vmanager
|
|||
from .forms import DeployForm
|
||||
from .. import db
|
||||
from ..email import send_email
|
||||
from ..models import User, Role, Product, Deployment, contact_proxmaster, Contract, Domain
|
||||
from ..models import User, Role, Deployment, Service, Region, Address, Domain, contact_proxmaster
|
||||
from ..decorators import admin_required, permission_required
|
||||
|
||||
import base64
|
||||
import string
|
||||
import random
|
||||
from datetime import datetime, timedelta, date, time
|
||||
import ast
|
||||
|
||||
def randstr(n):
|
||||
return ''.join(random.SystemRandom().choice(string.ascii_lowercase + string.digits) for _ in range(n))
|
||||
|
@ -95,17 +96,16 @@ def deploy(product_id=None):
|
|||
'vps_cpu': form.cpu.data,
|
||||
'vps_mem': form.mem.data,
|
||||
'vps_hdd': form.hdd.data,
|
||||
'vps_ipv4': '1' }
|
||||
'vps_ipv4': form.ipv4.data }
|
||||
|
||||
try:
|
||||
query = contact_proxmaster(data, 'vmcreate')
|
||||
except:
|
||||
flash('Region unreachable! Please try again later...')
|
||||
return redirect(url_for('vmanager.index'))
|
||||
return redirect(url_for('vmanager.dashboard'))
|
||||
|
||||
if query is not None:
|
||||
cubeid = query['cube']
|
||||
deployment = Deployment(user_id=client_id, product_id=product_id, machine_alias=form.servername.data, machine_id=cubeid, machine_cpu=form.cpu.data, machine_mem=form.mem.data, machine_hdd=form.hdd.data, date_expire=(datetime.utcnow() + timedelta(days=30)), enabled=True)
|
||||
deployment = Deployment(user_id=client_id, product_id=product_id, machine_alias=form.servername.data, machine_id=query['cube'], machine_cpu=form.cpu.data, machine_mem=form.mem.data, machine_hdd=form.hdd.data, date_expire=(datetime.utcnow() + timedelta(days=30)), enabled=True)
|
||||
db.session.add(deployment)
|
||||
db.session.commit()
|
||||
|
||||
|
@ -113,7 +113,7 @@ def deploy(product_id=None):
|
|||
else:
|
||||
flash('Deploy cancelled! Please try again later...')
|
||||
|
||||
return redirect(url_for('vmanager.index'))
|
||||
return redirect(url_for('vmanager.dashboard'))
|
||||
|
||||
return render_template('vmanager/deploy.html', page=page, form=form, product_id=product_id, product_pic=product_pic, product_name=product_name, product_description=product_description, product_recipe=product_recipe)
|
||||
|
||||
|
@ -130,11 +130,11 @@ def dashboard():
|
|||
inv_deploycubeids.extend([invcls.machine_id])
|
||||
inv_deploynames.extend([invcls.machine_alias])
|
||||
|
||||
contracts = current_user.inv_contracts.order_by(Contract.date_created.desc()).all()
|
||||
inv_contracts = []
|
||||
for invcls in contracts:
|
||||
services = current_user.inv_services.order_by(Service.date_created.desc()).all()
|
||||
inv_services = []
|
||||
for invcls in services:
|
||||
if invcls.enabled == True:
|
||||
inv_contracts.extend([invcls.template])
|
||||
inv_services.extend([invcls.description])
|
||||
|
||||
domains = current_user.inv_domains.order_by(Domain.date_created.desc()).all()
|
||||
inv_domains = []
|
||||
|
@ -221,4 +221,3 @@ def command(cmd=None, vmid=0):
|
|||
#TODO: log ips
|
||||
abort(404)
|
||||
|
||||
|
||||
|
|
|
@ -1,36 +1,48 @@
|
|||
alembic==0.9.0
|
||||
Babel==2.3.4
|
||||
alembic==0.9.2
|
||||
appdirs==1.4.3
|
||||
Babel==2.4.0
|
||||
blinker==1.4
|
||||
certifi==2017.4.17
|
||||
chardet==3.0.3
|
||||
click==6.7
|
||||
dnspython==1.15.0
|
||||
dnspython3==1.15.0
|
||||
dominate==2.3.1
|
||||
Flask==0.12
|
||||
Flask-Babel==0.11.1
|
||||
facepy==1.0.9
|
||||
Flask==0.12.2
|
||||
Flask-AlchemyDumps==0.0.10
|
||||
Flask-Babel==0.11.2
|
||||
Flask-Bootstrap==3.3.7.1
|
||||
Flask-Login==0.4.0
|
||||
Flask-Mail==0.9.1
|
||||
Flask-Migrate==2.0.3
|
||||
Flask-Migrate==2.0.4
|
||||
Flask-Moment==0.5.1
|
||||
Flask-Script==2.0.5
|
||||
Flask-SQLAlchemy==2.2
|
||||
Flask-WTF==0.14.2
|
||||
gunicorn==19.7.0
|
||||
gunicorn==19.7.1
|
||||
idna==2.5
|
||||
iso3166==0.8
|
||||
itsdangerous==0.24
|
||||
Jinja2==2.9.5
|
||||
Jinja2==2.9.6
|
||||
Mako==1.0.6
|
||||
MarkupSafe==0.23
|
||||
MarkupSafe==1.0
|
||||
onetimepass==1.0.1
|
||||
pkg-resources==0.0.0
|
||||
psycopg2==2.6.2
|
||||
psycopg2==2.7.1
|
||||
Pygments==2.2.0
|
||||
PyQRCode==1.2.1
|
||||
python-dateutil==2.6.0
|
||||
python-editor==1.0.3
|
||||
pytz==2016.10
|
||||
requests==2.13.0
|
||||
pytz==2017.2
|
||||
requests==2.17.3
|
||||
schedule==0.4.2
|
||||
six==1.10.0
|
||||
sortedcontainers==1.5.7
|
||||
SQLAlchemy==1.1.6
|
||||
SQLAlchemy==1.1.10
|
||||
traits==4.6.0
|
||||
Unipath==1.1
|
||||
urllib3==1.21.1
|
||||
visitor==0.1.3
|
||||
Werkzeug==0.11.15
|
||||
Werkzeug==0.12.2
|
||||
WTForms==2.1
|
||||
|
|
20
manage.py
20
manage.py
|
@ -3,6 +3,7 @@
|
|||
import os
|
||||
import subprocess, shlex
|
||||
from app import app, db
|
||||
from flask_alchemydumps import AlchemyDumps, AlchemyDumpsCommand
|
||||
from flask_script import Manager, Shell, Command
|
||||
from flask_migrate import Migrate, MigrateCommand
|
||||
|
||||
|
@ -15,33 +16,29 @@ def make_shell_context():
|
|||
Deployment=Deployment)
|
||||
|
||||
migrate = Migrate(app, db)
|
||||
dump = AlchemyDumps(app, db)
|
||||
|
||||
manager = Manager(app)
|
||||
manager.add_command('shell', Shell(make_context=make_shell_context))
|
||||
manager.add_command('db', MigrateCommand)
|
||||
manager.add_command('dump', AlchemyDumpsCommand)
|
||||
|
||||
@manager.command
|
||||
def deploy():
|
||||
"""Run deployment tasks."""
|
||||
from flask_migrate import upgrade
|
||||
from app.models import Role, User, Deployment, Product
|
||||
from app.models import Role, User
|
||||
|
||||
# migrate database to latest revision
|
||||
upgrade()
|
||||
|
||||
# create user roles
|
||||
Role.insert_roles()
|
||||
Product.insert_products()
|
||||
|
||||
@manager.command
|
||||
@manager.option('-r' '--restore_file', help='Restore from grid dump file')
|
||||
def restore(restore_file):
|
||||
""" recreate db from grid export with python3 manage.py restore /path/grid.tar.bz2 """
|
||||
print(str(restore_file))
|
||||
#TODO
|
||||
from app.models import User
|
||||
db.session.add(User(email=str(user), password=str(password), confirmed=True, confirmed_on=datetime.datetime.now()))
|
||||
db.session.commit()
|
||||
def sampledata():
|
||||
"""Deploy Sample Data"""
|
||||
pass
|
||||
|
||||
def run_scheduler():
|
||||
command_line = 'python3 /home/proxadmin/appserver/proxmaster-panel/schedulerd.py'
|
||||
|
@ -65,7 +62,7 @@ def charge_domains():
|
|||
|
||||
@manager.command
|
||||
def runserver():
|
||||
print('Starting Scheduler...')
|
||||
#print('Starting Scheduler...')
|
||||
#run_scheduler()
|
||||
|
||||
print('Starting Flask...')
|
||||
|
@ -74,4 +71,3 @@ def runserver():
|
|||
if __name__ == '__main__':
|
||||
manager.run()
|
||||
|
||||
|
||||
|
|
|
@ -1,42 +0,0 @@
|
|||
alembic==0.9.2
|
||||
appdirs==1.4.3
|
||||
Babel==2.4.0
|
||||
blinker==1.4
|
||||
click==6.7
|
||||
dnspython==1.15.0
|
||||
dnspython3==1.15.0
|
||||
dominate==2.3.1
|
||||
facepy==1.0.8
|
||||
Flask==0.12.2
|
||||
Flask-Babel==0.11.2
|
||||
Flask-Bootstrap==3.3.7.1
|
||||
Flask-Login==0.4.0
|
||||
Flask-Mail==0.9.1
|
||||
Flask-Migrate==2.0.3
|
||||
Flask-Moment==0.5.1
|
||||
Flask-Script==2.0.5
|
||||
Flask-SQLAlchemy==2.2
|
||||
Flask-WTF==0.14.2
|
||||
gunicorn==19.7.1
|
||||
iso3166==0.8
|
||||
itsdangerous==0.24
|
||||
Jinja2==2.9.6
|
||||
Mako==1.0.6
|
||||
MarkupSafe==1.0
|
||||
onetimepass==1.0.1
|
||||
pkg-resources==0.0.0
|
||||
psycopg2==2.7.1
|
||||
Pygments==2.2.0
|
||||
PyQRCode==1.2.1
|
||||
python-dateutil==2.6.0
|
||||
python-editor==1.0.3
|
||||
pytz==2017.2
|
||||
requests==2.14.2
|
||||
schedule==0.4.2
|
||||
six==1.10.0
|
||||
sortedcontainers==1.5.7
|
||||
SQLAlchemy==1.1.10
|
||||
traits==4.6.0
|
||||
visitor==0.1.3
|
||||
Werkzeug==0.12.2
|
||||
WTForms==2.1
|
Loading…
Reference in a new issue