2021-07-08 19:10:14 +00:00
import re
import sys
import json
import ipaddress
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
from capsulflask . shared import my_exec_info_message
bp = Blueprint ( " admin " , __name__ , url_prefix = " /admin " )
@bp.route ( " / " )
@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... " )
for email in emails_list :
current_app . logger . info ( email )
current_app . config [ " FLASK_MAIL_INSTANCE " ] . send (
Message (
request . form [ ' subject ' ] ,
sender = current_app . config [ " MAIL_DEFAULT_SENDER " ] ,
body = request . form [ ' body ' ] ,
bcc = [ " forest.n.johnson@gmail.com " , " forest@sequentialread.com " ]
)
)
current_app . logger . info ( f " sending email is done. " )
return redirect ( f " { url_for ( ' admin.index ' ) } " )
else :
return abort ( 400 , " unknown form action " )
# 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 )
db_vms_by_host_and_network = get_model ( ) . non_deleted_vms_by_host_and_network ( None )
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 17:21:33 +00:00
db_vm_by_id = dict ( )
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 17:21:33 +00:00
if host_id in db_vms_by_host_and_network :
if network [ ' network_name ' ] in db_vms_by_host_and_network [ host_id ] :
for vm in db_vms_by_host_and_network [ host_id ] [ network [ ' network_name ' ] ] :
2021-12-05 22:50:55 +00:00
vm [ ' network_name ' ] = network [ ' network_name ' ]
vm [ ' virtual_bridge_name ' ] = network [ ' virtual_bridge_name ' ]
vm [ ' host ' ] = host_id
2021-12-09 17:21:33 +00:00
db_vm_by_id [ vm [ ' id ' ] ] = vm
2021-07-09 19:13:28 +00:00
ip_address_int = int ( ipaddress . ip_address ( vm [ ' public_ipv4 ' ] ) )
2021-07-11 17:18:58 +00:00
if network_start_int < = ip_address_int and ip_address_int < = network_end_int :
2021-07-09 19:13:28 +00:00
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 ' ] } " )
display_hosts . append ( display_host )
2021-12-05 22:47:37 +00:00
# Now creating the capsuls running status ui
#
2021-12-09 17:21:33 +00:00
virt_vms_by_host_and_network = current_app . config [ " HUB_MODEL " ] . get_all_by_host_and_network ( )
2021-12-05 22:47:37 +00:00
2021-12-09 17:21:33 +00:00
# virt_vms_dict = dict()
# for vm in virt_vms:
# virt_vms_dict[vm["id"]] = vm["state"]
2021-12-05 22:47:37 +00:00
2021-12-09 17:21:33 +00:00
# in_db_but_not_in_virt = []
# needs_to_be_started = []
# needs_to_be_started_missing_ipv4 = []
# for vm in db_vms:
# if vm["id"] not in virt_vms_dict:
# in_db_but_not_in_virt.append(vm["id"])
# elif vm["desired_state"] == "running" and virt_vms_dict[vm["id"]] != "running":
# if vm["id"] in db_vm_by_id:
# needs_to_be_started.append(db_vm_by_id[vm["id"]])
# else:
# needs_to_be_started_missing_ipv4.append(vm["id"])
# elif vm["ipv4"] != current_ipv4
# 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 ) ,
db_vms_by_host_and_network = json . dumps ( db_vms_by_host_and_network ) ,
virt_vms_by_host_and_network = json . dumps ( virt_vms_by_host_and_network ) ,
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