2018-01-18 09:01:17 -05:00
from flask import jsonify , render_template , abort , redirect , url_for , abort , flash , request , current_app , make_response , g
2017-03-08 13:53:09 -05:00
from flask_login import login_required , login_user , logout_user , current_user
from flask_sqlalchemy import get_debug_queries
2017-03-08 19:55:12 -05:00
from . import vmanager
2018-04-02 04:49:32 -04:00
from . forms import ActivateForm
2018-01-25 12:48:50 -05:00
from . . import db , csrf
2017-03-08 13:53:09 -05:00
from . . email import send_email
2018-05-06 12:13:02 -04:00
from . . models import User , Permission , Transaction , Order , Deployment , PubVLAN , Service , Region , Server , Address , Domain , SupportTopic , contact_proxmaster
2017-03-08 13:53:09 -05:00
from . . decorators import admin_required , permission_required
2018-01-25 12:48:50 -05:00
import json
2017-03-08 13:53:09 -05:00
import base64
import string
import random
from datetime import datetime , timedelta , date , time
2017-07-15 00:13:57 -04:00
from dateutil . relativedelta import relativedelta
2017-06-01 18:27:17 -04:00
import ast
2017-12-14 18:00:02 -05:00
import time
2017-03-08 13:53:09 -05:00
def randstr ( n ) :
return ' ' . join ( random . SystemRandom ( ) . choice ( string . ascii_lowercase + string . digits ) for _ in range ( n ) )
2017-03-08 19:55:12 -05:00
@vmanager.after_app_request
2017-03-08 13:53:09 -05:00
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 \n Parameters: %s \n Duration: %f s \n Context: %s \n ' % ( query . statement , query . parameters , query . duration , query . context ) )
return response
2018-01-25 12:48:50 -05:00
@vmanager.route ( ' /slavetables ' , methods = [ ' POST ' ] )
@csrf.exempt
def slavetables ( ) :
postdata = request . get_json ( )
if postdata [ ' passphrase ' ] == ' batkataisthebest1 ' :
selected_slave = Server . query . filter_by ( name = str ( postdata [ ' slavename ' ] ) ) . first ( )
if selected_slave == None :
return jsonify ( { ' status ' : ' slave_not_found ' } )
2018-01-29 11:29:35 -05:00
addrlist = { }
try :
deploylist = selected_slave . inv_deployments . all ( )
for deploy in deploylist :
pubvlanlist = deploy . inv_pubvlans . all ( )
for pubvlan in pubvlanlist :
if pubvlan . pubaddr != None :
addrlist [ str ( pubvlan . pubaddr . ip ) ] = str ( pubvlan . vlan_id )
addrlist [ ' status ' ] = ' ok '
except :
addrlist [ ' status ' ] = ' tables_gen_error '
return jsonify ( addrlist )
2017-03-08 13:53:09 -05:00
2018-04-01 09:29:17 -04:00
@vmanager.route ( ' /vmcreate/<int:orderid> ' , methods = [ ' GET ' , ' POST ' ] )
2017-03-08 13:53:09 -05:00
@login_required
2018-02-20 05:17:28 -05:00
@admin_required
2018-04-01 09:29:17 -04:00
def vmcreate ( orderid ) :
2018-04-02 04:49:32 -04:00
from flask_wtf import FlaskForm
from wtforms import validators , RadioField , SubmitField
2018-04-16 07:28:52 -04:00
from sqlalchemy . sql . expression import func , select
2018-04-02 04:49:32 -04:00
order = Order . query . filter_by ( pid = int ( orderid ) ) . first ( )
if order == None :
abort ( 403 )
2017-09-28 07:10:19 -04:00
2018-04-02 04:49:32 -04:00
servers = Server . query . filter_by ( region_id = int ( order . region_id ) ) . all ( )
serverchoices = [ ]
for server in servers :
serverchoice = ( str ( server . pid ) , str ( server . name ) )
serverchoices . append ( serverchoice )
#TODO: check api for happiness and preselect suggested slave
2018-04-07 08:55:24 -04:00
#happyslave = '2' #warrior in our case
happyslave = ' 1 '
2018-04-02 04:49:32 -04:00
2018-04-16 07:28:52 -04:00
rand_pub_addr = Address . query . filter_by ( region_id = int ( order . region_id ) ) . filter_by ( reserved = False ) . filter_by ( pubvlan_id = None ) . order_by ( func . random ( ) ) . first ( )
if rand_pub_addr == None :
flash ( ' No free addresses in the selected region ' )
return redirect ( url_for ( ' admin.list_addresses ' ) )
2018-04-02 04:49:32 -04:00
class SlaveForm ( FlaskForm ) :
slaveswitcher = RadioField ( ' Select Slave Server ' , [ validators . Required ( ) ] , choices = serverchoices , default = happyslave )
submit = SubmitField ( ' Create ' )
form = SlaveForm ( )
if form . validate_on_submit ( ) :
2018-04-02 09:12:30 -04:00
selectedslaveswitch = form . slaveswitcher . data
selectedslave = Server . query . filter_by ( pid = int ( selectedslaveswitch ) ) . first ( )
2018-04-02 08:44:33 -04:00
data = { ' clientid ' : str ( order . user_id ) ,
' clientemail ' : str ( order . owner . email ) ,
' hostname ' : ' c ' + str ( order . user_id ) + ' - ' + str ( order . parameter1 ) ,
2018-04-02 09:12:30 -04:00
' slave ' : str ( selectedslave . name ) ,
2018-04-05 05:43:36 -04:00
' region ' : str ( order . region . name ) ,
2017-10-29 17:06:54 -04:00
' type ' : ' kvm ' ,
2018-04-05 05:43:36 -04:00
' cpu ' : str ( int ( float ( order . parameter2 ) ) ) ,
' mem ' : str ( int ( float ( order . parameter3 ) ) ) ,
' hdd ' : str ( int ( float ( order . parameter4 ) ) ) ,
2018-01-24 03:58:28 -05:00
' net0if ' : ' vmbr7 '
2017-07-30 17:10:08 -04:00
}
2017-03-08 13:53:09 -05:00
try :
2017-10-19 11:59:17 -04:00
query = contact_proxmaster ( data , ' create ' )
2017-03-08 13:53:09 -05:00
except :
2017-10-15 07:38:38 -04:00
flash ( ' Region not available! Please try again later... ' )
2018-01-11 08:19:59 -05:00
return redirect ( url_for ( ' panel.dashboard ' ) )
2017-03-08 13:53:09 -05:00
2017-10-29 17:06:54 -04:00
if query [ ' status ' ] == ' kvm_created ' :
2018-01-25 12:48:50 -05:00
selected_slave = Server . query . filter_by ( name = query [ ' slave ' ] ) . first ( )
2018-05-06 12:13:02 -04:00
#create new topic
new_topic = SupportTopic ( hashtag = ' deploy- ' + str ( query [ ' unit_id ' ] ) )
db . session . add ( new_topic )
db . session . commit ( )
deployment = Deployment ( user_id = order . user_id , machine_alias = str ( order . parameter1 ) , period = 1 , machine_id = query [ ' unit_id ' ] , machine_cpu = data [ ' cpu ' ] , machine_mem = data [ ' mem ' ] , machine_hdd = data [ ' hdd ' ] , enabled = True , protected = False , daysleft = 15 , warning = True , discount = 0 , server_id = int ( selected_slave . pid ) , topic_id = int ( new_topic . pid ) )
2017-03-08 13:53:09 -05:00
db . session . add ( deployment )
db . session . commit ( )
2018-04-02 04:49:32 -04:00
2018-01-31 18:55:35 -05:00
new_vlan = PubVLAN ( deploy_id = int ( deployment . pid ) , vlan_id = int ( query [ ' vlanid ' ] ) )
db . session . add ( new_vlan )
db . session . commit ( )
2018-04-16 07:28:52 -04:00
rand_pub_addr . pubvlan_id = new_vlan . pid
rand_pub_addr . user_id = order . user_id
db . session . commit ( )
2018-04-02 04:49:32 -04:00
order . status = ' accepted '
db . session . commit ( )
2018-04-02 08:44:33 -04:00
flash ( ' A new deployment is created successfully in region " {} " . ' . format ( str ( order . region . description ) ) )
2018-01-11 08:19:59 -05:00
return redirect ( url_for ( ' panel.dashboard ' ) )
2017-03-08 13:53:09 -05:00
else :
2018-01-24 03:58:28 -05:00
flash ( ' Deployment could not be created! Please try again later... ' )
2017-03-08 13:53:09 -05:00
2018-01-11 08:19:59 -05:00
return redirect ( url_for ( ' panel.dashboard ' ) )
2018-04-02 04:49:32 -04:00
return render_template ( ' vmanager/create.html ' , form = form , order = order )
@vmanager.route ( ' /vmremove/<int:unit_id> ' , methods = [ ' GET ' , ' POST ' ] )
@login_required
@admin_required
def remove ( unit_id = 0 ) :
data = { ' unit_id ' : int ( unit_id ) ,
' type ' : ' kvm ' }
deploy = Deployment . query . filter_by ( machine_id = int ( unit_id ) ) . first ( )
if current_user . is_administrator ( ) :
if deploy . protected is not True :
try :
2018-04-10 10:06:01 -04:00
query = contact_proxmaster ( data , ' status ' )
if query [ ' status ' ] == ' UNREACHABLE ' :
flash ( ' Physical machine is not reachable. Cannot be deleted from the database ' )
return redirect ( url_for ( ' admin.list_archive ' ) )
if query [ ' status ' ] == ' running ' :
query = contact_proxmaster ( data , ' stop ' )
flash ( ' Machine {} force stopped ' . format ( unit_id ) )
time . sleep ( 7 )
2018-04-02 04:49:32 -04:00
#pubvlans depends on deploy as foreign key so delete them first
for pubvlan in deploy . inv_pubvlans :
#clean public addr assignment
if pubvlan . pubaddr != None :
pubvlan . pubaddr . pubvlan_id = None
pubvlan . pubaddr . user_id = None
db . session . commit ( )
db . session . delete ( pubvlan )
db . session . commit ( )
query = contact_proxmaster ( data , ' remove ' )
flash ( ' Machine {} terminated ' . format ( unit_id ) )
deploy . deleted = True
deploy . enabled = False
deploy . warning = False
db . session . commit ( )
except Exception as e :
current_app . logger . error ( e )
flash ( ' Cannot delete machine {} ' . format ( unit_id ) )
return redirect ( url_for ( ' admin.list_archive ' ) )
else :
current_app . logger . warning ( ' Deployment id: {} is protected! Cannot be removed ' . format ( unit_id ) )
else :
current_app . logger . warning ( ' [WARNING] Unauthorized attempt to remove Deployment id: {} ' . format ( unit_id ) )
abort ( 404 )
2017-03-08 13:53:09 -05:00
2017-07-14 09:04:27 -04:00
@vmanager.route ( ' /activate/<int:itemid> ' , methods = [ ' GET ' , ' POST ' ] )
2017-07-06 17:15:02 -04:00
@login_required
2017-07-14 09:00:04 -04:00
def activate ( itemid = 0 ) :
2017-10-07 11:39:50 -04:00
result = current_user . inv_deployments . filter_by ( deleted = False ) . all ( )
2017-07-06 17:15:02 -04:00
inventory = [ ]
for invcls in result :
inventory . extend ( [ invcls . machine_id ] )
2017-07-13 19:46:51 -04:00
if current_user . is_administrator ( ) :
2017-07-15 20:48:18 -04:00
current_app . logger . warning ( ' [ADMIN] Access override for deployment id: {} ' . format ( itemid ) )
2017-07-14 09:00:04 -04:00
elif not itemid in inventory :
2017-07-15 20:48:18 -04:00
current_app . logger . error ( ' [ {} ] Access violation with deployment id: {} ' . format ( current_user . email , itemid ) )
2017-10-15 07:38:38 -04:00
abort ( 403 )
2017-07-13 19:46:51 -04:00
2017-07-15 00:13:57 -04:00
deploy = Deployment . query . filter_by ( machine_id = itemid ) . first ( )
2017-10-15 07:38:38 -04:00
if deploy is None :
2017-07-20 19:30:09 -04:00
abort ( 404 )
2017-10-15 07:38:38 -04:00
if deploy . enabled == True and deploy . warning == False :
abort ( 403 )
2017-07-15 00:13:57 -04:00
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 ' ]
2018-01-09 06:05:45 -05:00
tpm = cpu_cost + mem_cost + hdd_cost
discount = round ( ( tpm * deploy . discount ) / 100 )
ppm = round ( tpm - discount )
2017-08-01 07:21:22 -04:00
2017-09-09 02:32:04 -04:00
#default period = 1 for virgin deployments
2017-08-01 07:21:22 -04:00
if deploy . period is None :
form = ActivateForm ( period = 1 )
total = ppm * 1
else :
form = ActivateForm ( period = int ( deploy . period ) )
total = ppm * deploy . period
2017-07-15 00:13:57 -04:00
2017-07-15 20:48:18 -04:00
owner = deploy . owner
if owner . confirmed and form . validate_on_submit ( ) :
2017-07-20 19:30:09 -04:00
total = ppm * form . period . data
2017-07-15 20:48:18 -04:00
if owner . wallet < total :
2018-03-24 18:44:06 -04:00
flash ( ' Activation costs {} {} . Insufficient Funds ' . format ( total , owner . currency ) , ' danger ' )
2017-09-20 20:08:58 -04:00
if current_user . is_administrator ( ) :
return redirect ( url_for ( ' admin.list_users ' ) )
else :
return redirect ( url_for ( ' uinvoice.transactions ' ) )
2017-07-15 20:48:18 -04:00
current_app . logger . info ( ' [ {} ] Charge deployment: {} ' . format ( owner . email , deploy . machine_id ) )
2017-07-15 00:13:57 -04:00
today = datetime . utcnow ( )
2017-07-15 20:48:18 -04:00
expiry = today + relativedelta ( today , months = + ( form . period . data ) )
daysleft = expiry - today
extradays = relativedelta ( today , days = + ( deploy . daysleft ) )
deploy . date_last_charge = today + extradays
2017-07-15 00:13:57 -04:00
deploy . period = form . period . data
2017-07-20 19:30:09 -04:00
deploy . daysleft = daysleft . days + extradays . days
2017-07-15 00:13:57 -04:00
deploy . warning = False
2017-07-15 00:28:04 -04:00
deploy . enabled = True
2017-08-01 07:21:22 -04:00
deploy . protected = True
2017-10-15 07:38:38 -04:00
db . session . commit ( )
2017-10-07 11:39:50 -04:00
2017-12-26 20:54:50 -05:00
email_content = ' Deployment {} is activated for {} month(s). It will expire at {} ' . format ( str ( deploy . machine_alias ) , form . period . data , str ( ( expiry + extradays ) . strftime ( ' %c ' ) ) )
send_email ( current_app . config [ ' MAIL_USERNAME ' ] , str ( email_content ) , ' email/adm_logger ' , user = owner , content = str ( email_content ) )
send_email ( str ( owner . email ) , str ( email_content ) , ' email/client_logger ' , content = str ( email_content ) )
transaction = Transaction ( user_id = int ( owner . pid ) , description = str ( email_content ) , value = - total )
2017-07-15 00:13:57 -04:00
db . session . add ( transaction )
db . session . commit ( )
2017-07-15 20:48:18 -04:00
owner . wallet = owner . wallet - total
2017-07-15 00:13:57 -04:00
db . session . commit ( )
2017-07-20 19:30:09 -04:00
flash ( ' Deployment {} activated for {} month(s) ' . format ( str ( deploy . machine_alias ) , form . period . data ) )
2017-12-14 18:00:02 -05:00
if current_user . is_administrator ( ) :
2017-07-25 10:33:23 -04:00
return redirect ( url_for ( ' admin.list_deployments ' ) )
2017-07-15 20:48:18 -04:00
else :
2018-01-11 08:19:59 -05:00
return redirect ( url_for ( ' panel.dashboard ' ) )
2018-01-09 06:05:45 -05:00
return render_template ( ' vmanager/activate.html ' , form = form , deploy = deploy , cpu_cost = cpu_cost , mem_cost = mem_cost , hdd_cost = hdd_cost , tpm = tpm , ppm = ppm , discount = discount , total = total , currency = owner . currency )
2017-07-06 17:15:02 -04:00
2017-10-19 11:59:17 -04:00
@vmanager.route ( ' /command/<cmd>/<int:unit_id> ' )
2017-03-08 13:53:09 -05:00
@login_required
2017-10-19 11:59:17 -04:00
def command ( cmd = None , unit_id = 0 ) :
2017-03-08 13:53:09 -05:00
#checks whether this is a valid command
2017-10-19 11:59:17 -04:00
valid_commands = [ ' status ' , ' start ' , ' shutdown ' , ' stop ' , ' vmvnc ' ]
2017-03-08 13:53:09 -05:00
if not cmd in valid_commands :
2017-06-06 09:49:32 -04:00
current_app . logger . warning ( cmd + ' is not a valid command! ' )
2017-03-08 13:53:09 -05:00
abort ( 404 )
2017-07-30 17:10:08 -04:00
#work with enabled deploys only that you own.
2017-07-06 17:15:02 -04:00
result = current_user . inv_deployments . filter_by ( enabled = True )
2017-03-08 13:53:09 -05:00
inventory = [ ]
for invcls in result :
2017-06-26 10:31:30 -04:00
inventory . extend ( [ invcls . machine_id ] )
2017-06-06 09:49:32 -04:00
2017-10-29 17:06:54 -04:00
data = { ' type ' : ' kvm ' ,
2017-10-19 11:59:17 -04:00
' unit_id ' : int ( unit_id ) }
2017-09-20 20:08:58 -04:00
2017-06-06 09:49:32 -04:00
if current_user . is_administrator ( ) :
2017-10-19 11:59:17 -04:00
#current_app.logger.warning('[ADMIN] Access override for cube id:{}'.format(unitunit__id))
db_result = contact_proxmaster ( data , cmd )
2017-07-06 17:15:02 -04:00
if cmd == ' vmvnc ' :
return redirect ( db_result [ ' url ' ] )
else :
2017-10-19 11:59:17 -04:00
#checks if current user owns this unit_id
if not unit_id in inventory :
current_app . logger . warning ( ' [ {} ] Access violation with unit id: {} ' . format ( current_user . email , unit_id ) )
2017-07-06 17:15:02 -04:00
#TODO: log ips
else :
2017-10-19 11:59:17 -04:00
db_result = contact_proxmaster ( data , cmd )
2017-07-06 17:15:02 -04:00
#print(db_result)
2017-07-15 20:48:18 -04:00
if cmd == ' vmvnc ' :
return redirect ( db_result [ ' url ' ] )
2017-03-08 13:53:09 -05:00
abort ( 404 )