2021-07-08 19:10:14 +00:00
import re
import sys
import json
import ipaddress
2021-12-09 20:41:25 +00:00
import pprint
2021-07-08 19:10:14 +00:00
from datetime import datetime , timedelta
2021-12-09 17:21:33 +00:00
from flask import Blueprint , current_app , render_template , make_response , session , request , redirect , url_for
from flask_mail import Message
2021-07-08 19:10:14 +00:00
from werkzeug . exceptions import abort
2021-07-09 19:13:28 +00:00
from nanoid import generate
2021-07-08 19:10:14 +00:00
from capsulflask . metrics import durations as metric_durations
from capsulflask . auth import admin_account_required
from capsulflask . db import get_model
2021-12-09 20:38:17 +00:00
from capsulflask . consistency import get_all_vms_from_db , get_all_vms_from_hosts
2021-07-08 19:10:14 +00:00
from capsulflask . shared import my_exec_info_message
bp = Blueprint ( " admin " , __name__ , url_prefix = " /admin " )
2021-12-09 17:29:06 +00:00
@bp.route ( " / " , methods = ( " GET " , " POST " ) )
2021-07-08 19:10:14 +00:00
@admin_account_required
def index ( ) :
2021-12-05 22:47:37 +00:00
2021-12-09 17:21:33 +00:00
if request . method == " POST " :
if " csrf-token " not in request . form or request . form [ ' csrf-token ' ] != session [ ' csrf-token ' ] :
return abort ( 418 , f " u want tea " )
if ' action ' not in request . form :
return abort ( 400 , " action is required " )
if request . form [ ' action ' ] == " megaphone " :
emails_list = get_model ( ) . all_accounts_with_active_vms ( )
current_app . logger . info ( f " sending ' { request . form [ ' subject ' ] } ' email to { len ( emails_list ) } users... " )
2021-12-09 17:44:30 +00:00
# for email in emails_list:
# current_app.logger.info(email)
suffix1 = " This email was sent by the Capsul Admin Megaphone. "
suffix2 = " If you have any questions DO NOT REPLY TO THIS EMAIL, direct your inquiry to support@cyberia.club "
2021-12-09 17:21:33 +00:00
current_app . config [ " FLASK_MAIL_INSTANCE " ] . send (
Message (
request . form [ ' subject ' ] ,
sender = current_app . config [ " MAIL_DEFAULT_SENDER " ] ,
2021-12-09 17:44:30 +00:00
body = f " { request . form [ ' body ' ] } \n \n { suffix1 } \n { suffix2 } " ,
bcc = emails_list ,
2021-12-09 17:21:33 +00:00
)
)
current_app . logger . info ( f " sending email is done. " )
return redirect ( f " { url_for ( ' admin.index ' ) } " )
else :
return abort ( 400 , " unknown form action " )
2021-12-09 20:38:17 +00:00
# moving on from the form post stuff...
2021-12-09 17:21:33 +00:00
# first create the hosts list w/ ip allocation visualization from the database
2021-12-05 22:47:37 +00:00
#
2021-12-09 17:21:33 +00:00
db_hosts = get_model ( ) . list_hosts_with_networks ( None )
2021-12-09 20:38:17 +00:00
db_vms_by_id = get_all_vms_from_db ( )
2021-07-12 17:27:07 +00:00
network_display_width_px = float ( 270 )
2021-07-09 19:13:28 +00:00
#operations = get_model().list_all_operations()
2021-07-08 19:10:14 +00:00
display_hosts = [ ]
2021-07-09 19:13:28 +00:00
inline_styles = [ f """
. network - display { ' { ' }
width : { network_display_width_px } px ;
{ ' } ' }
""" ]
2021-07-08 19:10:14 +00:00
2021-12-09 20:38:17 +00:00
db_vms_by_host_network = dict ( )
for vm in db_vms_by_id . values ( ) :
host_network_key = f " { vm [ ' host ' ] } _ { vm [ ' network_name ' ] } "
if host_network_key not in db_vms_by_host_network :
db_vms_by_host_network [ host_network_key ] = [ ]
db_vms_by_host_network [ host_network_key ] . append ( vm )
2021-12-05 22:47:37 +00:00
2021-12-09 17:21:33 +00:00
for kv in db_hosts . items ( ) :
2021-07-09 19:13:28 +00:00
host_id = kv [ 0 ]
2021-07-08 19:10:14 +00:00
value = kv [ 1 ]
2021-07-09 19:13:28 +00:00
display_host = dict ( name = host_id , networks = value [ ' networks ' ] )
2021-07-08 19:10:14 +00:00
2021-07-09 19:13:28 +00:00
for network in display_host [ ' networks ' ] :
2021-07-12 16:29:33 +00:00
2021-07-12 19:38:56 +00:00
network_start_int = int ( ipaddress . ip_address ( network [ " public_ipv4_first_usable_ip " ] ) )
network_end_int = int ( ipaddress . ip_address ( network [ " public_ipv4_last_usable_ip " ] ) )
2021-07-12 16:29:33 +00:00
2021-07-09 19:13:28 +00:00
network [ ' allocations ' ] = [ ]
2021-07-12 17:27:07 +00:00
network_addresses_width = float ( ( network_end_int - network_start_int ) + 1 )
2021-07-09 19:13:28 +00:00
2021-12-09 20:38:17 +00:00
host_network_key = f " { host_id } _ { network [ ' network_name ' ] } "
if host_network_key in db_vms_by_host_network :
for vm in db_vms_by_host_network [ host_network_key ] :
ip_address_int = int ( ipaddress . ip_address ( vm [ ' public_ipv4 ' ] ) )
if network_start_int < = ip_address_int and ip_address_int < = network_end_int :
allocation = f " { host_id } _ { network [ ' network_name ' ] } _ { len ( network [ ' allocations ' ] ) } "
inline_styles . append (
f """
. { allocation } { ' { ' }
left : { ( float ( ip_address_int - network_start_int ) / network_addresses_width ) * network_display_width_px } px ;
width : { network_display_width_px / network_addresses_width } px ;
{ ' } ' }
"""
)
network [ ' allocations ' ] . append ( allocation )
else :
current_app . logger . warning ( f " /admin: capsul { vm [ ' id ' ] } has public_ipv4 { vm [ ' public_ipv4 ' ] } which is out of range for its host network { host_id } { network [ ' network_name ' ] } { network [ ' public_ipv4_cidr_block ' ] } " )
2021-07-09 19:13:28 +00:00
display_hosts . append ( display_host )
2021-12-05 22:47:37 +00:00
2021-12-09 20:38:17 +00:00
# Now creating the capsul consistency / running status ui
2021-12-05 22:47:37 +00:00
#
2021-12-09 20:38:17 +00:00
virt_vms_by_id = get_all_vms_from_hosts ( )
2021-12-05 22:47:37 +00:00
2021-12-09 20:41:25 +00:00
pprint . pprint ( db_vms_by_id )
pprint . pprint ( virt_vms_by_id )
2021-12-09 20:38:17 +00:00
virt_vm_id_by_ipv4 = dict ( )
for vm_id , virt_vm in virt_vms_by_id . items ( ) :
virt_vm_id_by_ipv4 [ virt_vm [ ' public_ipv4 ' ] ] = vm_id
db_vm_id_by_ipv4 = dict ( )
for vm_id , db_vm in db_vms_by_id . items ( ) :
db_vm_id_by_ipv4 [ db_vm [ ' public_ipv4 ' ] ] = vm_id
in_db_but_not_in_virt = [ ]
state_not_equal_to_desired_state = [ ]
stole_someone_elses_ip_and_own_ip_avaliable = [ ]
stole_someone_elses_ip_but_own_ip_also_stolen = [ ]
has_wrong_ip = [ ]
for vm_id , db_vm in db_vms_by_id . items ( ) :
if vm_id not in virt_vms_by_id :
in_db_but_not_in_virt . append ( db_vm )
elif virt_vms_by_id [ vm_id ] [ ' state ' ] != db_vm [ " desired_state " ] :
db_vm [ " state " ] = virt_vms_by_id [ vm_id ] [ ' state ' ]
state_not_equal_to_desired_state . append ( db_vm )
elif virt_vms_by_id [ vm_id ] [ ' public_ipv4 ' ] != db_vm [ " public_ipv4 " ] :
db_vm [ " desired_ipv4 " ] = db_vm [ " public_ipv4 " ]
db_vm [ " current_ipv4 " ] = virt_vms_by_id [ vm_id ] [ ' public_ipv4 ' ]
if virt_vms_by_id [ vm_id ] [ ' public_ipv4 ' ] in db_vm_id_by_ipv4 :
if db_vm [ " public_ipv4 " ] not in virt_vm_id_by_ipv4 :
stole_someone_elses_ip_and_own_ip_avaliable . append ( db_vm )
else :
stole_someone_elses_ip_but_own_ip_also_stolen . append ( db_vm )
has_wrong_ip . append ( db_vm )
2021-12-09 17:21:33 +00:00
# current_app.logger.info(f"list_of_networks: {json.dumps(list_of_networks)}")
2021-12-05 22:47:37 +00:00
2021-07-09 19:13:28 +00:00
csp_inline_style_nonce = generate ( alphabet = " 1234567890qwertyuiopasdfghjklzxcvbnm " , size = 10 )
response_text = render_template (
" admin.html " ,
2021-12-09 17:21:33 +00:00
csrf_token = session [ " csrf-token " ] ,
2021-07-09 19:13:28 +00:00
display_hosts = display_hosts ,
2021-12-09 17:21:33 +00:00
# in_db_but_not_in_virt=in_db_but_not_in_virt,
# needs_to_be_started=needs_to_be_started,
# needs_to_be_started_missing_ipv4=needs_to_be_started_missing_ipv4,
2021-07-09 19:13:28 +00:00
network_display_width_px = network_display_width_px ,
csp_inline_style_nonce = csp_inline_style_nonce ,
2021-12-09 17:21:33 +00:00
inline_style = ' \n ' . join ( inline_styles ) ,
2021-12-09 20:38:17 +00:00
in_db_but_not_in_virt = in_db_but_not_in_virt ,
state_not_equal_to_desired_state = state_not_equal_to_desired_state ,
stole_someone_elses_ip_and_own_ip_avaliable = stole_someone_elses_ip_and_own_ip_avaliable ,
stole_someone_elses_ip_but_own_ip_also_stolen = stole_someone_elses_ip_but_own_ip_also_stolen ,
has_wrong_ip = has_wrong_ip
2021-07-09 19:13:28 +00:00
)
response = make_response ( response_text )
2021-07-08 19:10:14 +00:00
2021-07-09 19:13:28 +00:00
response . headers . set ( ' Content-Type ' , ' text/html ' )
response . headers . set ( ' Content-Security-Policy ' , f " default-src ' self ' ; style-src ' self ' ' nonce- { csp_inline_style_nonce } ' " )
2021-07-08 19:10:14 +00:00
2021-07-09 19:13:28 +00:00
return response