diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..429160a --- /dev/null +++ b/.gitignore @@ -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 diff --git a/app/models.py b/app/models.py index bd3f72c..f44a88d 100644 --- a/app/models.py +++ b/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' diff --git a/app/static/css/style.css b/app/static/css/style.css index 483749f..0b8df70 100644 --- a/app/static/css/style.css +++ b/app/static/css/style.css @@ -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; +} diff --git a/app/templates/main/index.html b/app/templates/main/index.html index a127ba6..b42fd26 100644 --- a/app/templates/main/index.html +++ b/app/templates/main/index.html @@ -1,12 +1,12 @@ {% extends "base.html" %} +{% block head %} +{{ super() }} +{% endblock %} + {% block styles %} {{ super() }} -{% endblock %} - -{% block head %} -{{ super() }} + + +{% endblock %} + {% block scripts %} {{ super() }} -{% endblock %} - -{% block page_content %} - +{% endblock %} - - - +{% block page_content %}
+ {% if inv_deploymens == None %} +
Name | +CPU | +Mem | +HDD | +IPv4 | +Control | ++ |
---|---|---|---|---|---|---|
+ {% if status[deploy.machine_id] == 'running' %}{% else %}{% endif %}{{ deploy.machine_alias }} | +{{ deploy.machine_cpu }} Cores | +{{ deploy.machine_mem }} MB | +{{ deploy.machine_hdd }} GB | +{% for ip in deploy.machine_ipv4list %}{{ ip }}{% endfor %} | +{% if status[deploy.machine_id] == 'running' %} + + + {% else %} + + {% endif %} | +{% if status[deploy.machine_id] == 'running' %} + + {% endif %} | +
+ {% for domain in inv_domains %} + {{ fqdn }} + {% endfor %} + +
{% for contract in inv_contracts %}
@@ -85,115 +184,15 @@ addEventListener("DOMContentLoaded", function() {
{{ contract.units }}
{% if not contract.discount == 0 %}
Discount %{{ contract.discount }}
- Credit: {{ contract.credit }}
+ Credit: {{ contract.credit }}
{% endif %}
{% endfor %}
-
+ +
- {% for domain in inv_domains %}
- {{ fqdn }}
- {% endfor %}
-
-
- {% for deploy in inv_deployments %} -
-Network Bandwidth | -
---|
CPU Load | -
---|
Memory Usage | -
---|
Disk Input/Output | -
---|
diff --git a/app/vmanager/forms.py b/app/vmanager/forms.py
index 57b5d60..e4a92db 100644
--- a/app/vmanager/forms.py
+++ b/app/vmanager/forms.py
@@ -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):
diff --git a/app/vmanager/routes.py b/app/vmanager/routes.py
index 0208a2a..1449d32 100644
--- a/app/vmanager/routes.py
+++ b/app/vmanager/routes.py
@@ -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)
-
diff --git a/before_upgrade.txt b/before_upgrade.txt
index 6ec6465..f0aa4ea 100644
--- a/before_upgrade.txt
+++ b/before_upgrade.txt
@@ -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
diff --git a/manage.py b/manage.py
index 95ff0ae..67134e4 100644
--- a/manage.py
+++ b/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()
-
diff --git a/requirements.txt b/requirements.txt
deleted file mode 100644
index fff826c..0000000
--- a/requirements.txt
+++ /dev/null
@@ -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