from flask import render_template, abort, redirect, url_for, abort, flash, request, current_app, make_response, g from flask_login import login_required, login_user, logout_user, current_user from flask_sqlalchemy import get_debug_queries from . import vmanager from .forms import CreateForm, ActivateForm from .. import db from ..email import send_email from ..models import User, Permission, Transaction, 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 from dateutil.relativedelta import relativedelta import ast def randstr(n): return ''.join(random.SystemRandom().choice(string.ascii_lowercase + string.digits) for _ in range(n)) @vmanager.after_app_request def after_request(response): for query in get_debug_queries(): if query.duration >= current_app.config['SLOW_DB_QUERY_TIME']: current_app.logger.warning('Slow query: %s\nParameters: %s\nDuration: %fs\nContext: %s\n' % (query.statement, query.parameters, query.duration, query.context)) return response @vmanager.route('/createvm', methods=['GET', 'POST']) @login_required def createvm(): if current_user.name is None: flash('Please update profile info for this operation.') return redirect(url_for('settings.profile')) deployment_seeds = current_user.inv_deployments.filter_by(cancelled=False).filter_by(protected=False).all() if deployment_seeds != []: flash('Offline deployments still exist.') return redirect(url_for('main.dashboard')) form = CreateForm() if current_user.confirmed and form.validate_on_submit(): selected_region = Region.query.filter_by(pid=int(form.region.data)).first() ### #flash('Region: {}'.format(str(selected_region.description))) #return redirect(url_for('main.dashboard')) data = { 'clientid': str(current_user.pid), 'clientemail': str(current_user.email), 'hostname': str(form.servername.data), 'region': str(selected_region.name), 'type': 'kvm', 'cpu': '1', 'mem': '512', 'hdd': '20' } try: query = contact_proxmaster(data, 'vmcreate') except: flash('Region unreachable! Please try again later...') return redirect(url_for('main.dashboard')) if query is not None: deployment = Deployment(user_id=int(current_user.pid), machine_alias=query['hostname'], machine_id=query['cube'], machine_cpu=data['cpu'], machine_mem=data['mem'], machine_hdd=data['hdd'], enabled=True, protected=False, daysleft=15, warning=True, discount=0) db.session.add(deployment) db.session.commit() flash('Deploy created successfully in region "{}".'.format(str(selected_region.description))) else: flash('Deploy cancelled! Please try again later...') return redirect(url_for('main.dashboard')) return render_template('vmanager/create.html', form=form) @vmanager.route('/vmremove/', methods=['GET', 'POST']) @login_required def remove(itemid=0): data = {} result = Deployment.query.filter_by(machine_id=int(itemid)).first() if current_user.is_administrator(): try: query = contact_proxmaster(data, 'vmremove', int(itemid)) flash('Machine {} terminated'.format(itemid)) except: flash('Cannot delete machine {}'.format(itemid)) return redirect(url_for('admin.list_cancelled')) abort(404) @vmanager.route('/activate/', methods=['GET', 'POST']) @login_required def activate(itemid=0): result = current_user.inv_deployments.filter_by(cancelled=False).all() inventory = [] for invcls in result: inventory.extend([invcls.machine_id]) if current_user.is_administrator(): current_app.logger.warning('[ADMIN] Access override for deployment id:{}'.format(itemid)) elif not itemid in inventory: current_app.logger.error('[{}] Access violation with deployment id: {}'.format(current_user.email, itemid)) abort(404) deploy = Deployment.query.filter_by(machine_id=itemid).first() if deploy.enabled == True and deploy.warning == False: abort(404) cpu_cost = deploy.machine_cpu * current_app.config['CPU_RATIO'] mem_cost = ( deploy.machine_mem / 1024 ) * current_app.config['MEM_RATIO'] hdd_cost = deploy.machine_hdd * current_app.config['HDD_RATIO'] ppm = cpu_cost + mem_cost + hdd_cost discount = round(( ppm * deploy.discount ) / 100) ppm = round(ppm - discount) #default period = 1 for virgin deployments if deploy.period is None: form = ActivateForm(period=1) total = ppm * 1 else: form = ActivateForm(period=int(deploy.period)) total = ppm * deploy.period owner = deploy.owner if owner.confirmed and form.validate_on_submit(): total = ppm * form.period.data if owner.wallet < total: flash('Activation costs {} {}. Insufficient Funds'.format(total, owner.currency)) if current_user.is_administrator(): return redirect(url_for('admin.list_users')) else: return redirect(url_for('uinvoice.transactions')) current_app.logger.info('[{}] Charge deployment: {}'.format(owner.email, deploy.machine_id)) today = datetime.utcnow() expiry = today + relativedelta(today, months=+(form.period.data)) daysleft = expiry - today extradays = relativedelta(today, days=+(deploy.daysleft)) deploy.date_last_charge = today + extradays deploy.period = form.period.data deploy.daysleft = daysleft.days + extradays.days deploy.warning = False deploy.enabled = True deploy.protected = True db.session.commit() transaction = Transaction(user_id=int(owner.pid), description='Deployment {} activated for {} month(s)'.format(str(deploy.machine_alias), form.period.data), value=-total) db.session.add(transaction) db.session.commit() owner.wallet = owner.wallet - total db.session.commit() flash('Deployment {} activated for {} month(s)'.format(str(deploy.machine_alias), form.period.data)) if owner.is_administrator: return redirect(url_for('admin.list_deployments')) else: return redirect(url_for('main.dashboard')) return render_template('vmanager/activate.html', form=form, deploy=deploy, cpu_cost=cpu_cost, mem_cost=mem_cost, hdd_cost=hdd_cost, ppm=ppm, discount=discount, total=total, currency=owner.currency) @vmanager.route('//') @login_required def command(cmd=None, vmid=0): #checks whether this is a valid command valid_commands = ['vmstatus', 'vmstart', 'vmshutdown', 'vmstop', 'vmvnc'] if not cmd in valid_commands: current_app.logger.warning(cmd + ' is not a valid command!') abort(404) #work with enabled deploys only that you own. result = current_user.inv_deployments.filter_by(enabled=True) inventory = [] for invcls in result: inventory.extend([invcls.machine_id]) data = {} if current_user.is_administrator(): #current_app.logger.warning('[ADMIN] Access override for cube id:{}'.format(vmid)) db_result = contact_proxmaster(data, cmd, int(vmid)) if cmd == 'vmvnc': return redirect(db_result['url']) else: #checks if current user owns this vmid if not vmid in inventory: current_app.logger.warning('[{}] Access violation with cube id: {}'.format(current_user.email, vmid)) #TODO: log ips else: db_result = contact_proxmaster(data, cmd, int(vmid)) #print(db_result) if cmd == 'vmvnc': return redirect(db_result['url']) abort(404) #APP STORE @vmanager.route('/market/', methods=['GET']) @login_required def market(group_id=0): page = { 'title': 'Market' } allproducts = Product.get_products() allgroups = current_app.config['GROUPS'] if group_id == 0: return render_template('vmanager/market.html', groups=allgroups, products=allproducts) filtered_products = {} for key, value in allproducts.items(): if value['group'] == group_id: filtered_products[key] = value if filtered_products == {}: abort(404) return render_template('vmanager/marketgroup.html', groupname=allgroups[group_id], products=filtered_products)