You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
432 lines
12 KiB
432 lines
12 KiB
3 years ago
|
#!/usr/bin/perl
|
||
|
#
|
||
|
# Manages VNC ports for server VMs that have VNC enabled.
|
||
|
#
|
||
|
|
||
|
use strict;
|
||
|
use warnings;
|
||
|
use Anvil::Tools;
|
||
1 year ago
|
use Data::Dumper;
|
||
3 years ago
|
|
||
|
$| = 1;
|
||
|
|
||
|
my $THIS_FILE = ($0 =~ /^.*\/(.*)$/)[0];
|
||
|
my $running_directory = ($0 =~ /^(.*?)\/$THIS_FILE$/)[0];
|
||
|
if (($running_directory =~ /^\./) && ($ENV{PWD}))
|
||
|
{
|
||
|
$running_directory =~ s/^\./$ENV{PWD}/;
|
||
|
}
|
||
|
|
||
|
my $anvil = Anvil::Tools->new();
|
||
|
|
||
1 year ago
|
my $echo = $anvil->data->{path}{exe}{'echo'};
|
||
1 year ago
|
my $grep = $anvil->data->{path}{exe}{'grep'};
|
||
1 year ago
|
my $kill = $anvil->data->{path}{exe}{'kill'};
|
||
|
my $pgrep = $anvil->data->{path}{exe}{'pgrep'};
|
||
|
my $ss = $anvil->data->{path}{exe}{'ss'};
|
||
|
my $sed = $anvil->data->{path}{exe}{'sed'};
|
||
|
my $websockify = $anvil->data->{path}{exe}{'websockify'};
|
||
1 year ago
|
|
||
1 year ago
|
$anvil->Get->switches;
|
||
2 years ago
|
|
||
1 year ago
|
$anvil->Database->connect;
|
||
|
$anvil->Log->entry({ source => $THIS_FILE, line => __LINE__, level => 2, secure => 0, key => "log_0132" });
|
||
|
if (not $anvil->data->{sys}{database}{connections})
|
||
|
{
|
||
|
# No databases, exit.
|
||
|
$anvil->Log->entry({ source => $THIS_FILE, line => __LINE__, level => 0, 'print' => 1, priority => "err", key => "error_0003" });
|
||
|
$anvil->nice_exit({ exit_code => 1 });
|
||
|
}
|
||
2 years ago
|
|
||
1 year ago
|
my $switch_debug = $anvil->data->{switches}{'debug'};
|
||
|
my $open = $anvil->data->{switches}{'open'};
|
||
|
my $server = $anvil->data->{switches}{'server'};
|
||
|
my $server_uuid = $anvil->data->{switches}{'server-uuid'};
|
||
|
my $server_vnc_port = $anvil->data->{switches}{'server-vnc-port'};
|
||
2 years ago
|
|
||
1 year ago
|
if (defined $server)
|
||
|
{
|
||
|
$server_uuid //= is_uuid_v4($server) ? $server : $anvil->Get->server_uuid_from_name({ server_name => $server });
|
||
2 years ago
|
}
|
||
|
|
||
1 year ago
|
$anvil->Log->variables({ source => $THIS_FILE, line => __LINE__, level => $switch_debug, list => {
|
||
1 year ago
|
open => $open,
|
||
|
server => $server,
|
||
|
server_uuid => $server_uuid,
|
||
|
server_vnc_port => $server_vnc_port
|
||
|
} });
|
||
2 years ago
|
|
||
1 year ago
|
my $map_to_operation = { start => \&start_pipe, stop => \&stop_pipe };
|
||
2 years ago
|
|
||
1 year ago
|
if ($server_uuid)
|
||
1 year ago
|
{
|
||
|
my $operation = $open ? "start" : "stop";
|
||
2 years ago
|
|
||
1 year ago
|
$anvil->Log->variables({ source => $THIS_FILE, line => __LINE__, level => $switch_debug, list => { operation => $operation } });
|
||
|
|
||
1 year ago
|
my ($rcode) = $map_to_operation->{$operation}({
|
||
1 year ago
|
debug => $switch_debug,
|
||
|
svr_uuid => $server_uuid,
|
||
|
svr_vnc_port => $server_vnc_port,
|
||
|
});
|
||
2 years ago
|
|
||
1 year ago
|
$anvil->nice_exit({ exit_code => $rcode });
|
||
|
}
|
||
2 years ago
|
|
||
1 year ago
|
$anvil->nice_exit({ exit_code => 0 });
|
||
2 years ago
|
|
||
1 year ago
|
#
|
||
|
# Functions
|
||
|
#
|
||
3 years ago
|
|
||
1 year ago
|
sub build_find_available_port_call
|
||
|
{
|
||
|
my $parameters = shift;
|
||
|
my $debug = $parameters->{debug} || 3;
|
||
|
my $start = $parameters->{start};
|
||
|
my $step_operator = $parameters->{step_operator} // "+";
|
||
|
my $step_size = $parameters->{step_size} || 1;
|
||
2 years ago
|
|
||
1 year ago
|
$anvil->Log->variables({ source => $THIS_FILE, line => __LINE__, level => $debug, list => $parameters, prefix => "build_find_available_port_call" });
|
||
3 years ago
|
|
||
1 year ago
|
return (1) if ( (not $step_operator =~ /^[+-]$/)
|
||
|
|| (not is_int($step_size)) || ($step_size < 1) );
|
||
3 years ago
|
|
||
1 year ago
|
my $call = "ss_output=\$($ss -ant) && port=${start} && while $grep -Eq \":\${port}[[:space:]]+[^[:space:]]+\" <<<\$ss_output; do (( port ${step_operator}= $step_size )); done && $echo \$port";
|
||
3 years ago
|
|
||
1 year ago
|
return (0, $call);
|
||
3 years ago
|
}
|
||
|
|
||
1 year ago
|
sub build_vncinfo_variable_name
|
||
3 years ago
|
{
|
||
1 year ago
|
my ($svr_uuid) = @_;
|
||
3 years ago
|
|
||
1 year ago
|
return "server::${svr_uuid}::vncport";
|
||
3 years ago
|
}
|
||
|
|
||
1 year ago
|
sub call
|
||
3 years ago
|
{
|
||
1 year ago
|
my $parameters = shift;
|
||
1 year ago
|
my $background = $parameters->{background} || 0;
|
||
1 year ago
|
my $call = $parameters->{call};
|
||
|
my $debug = $parameters->{debug} || 3;
|
||
2 years ago
|
|
||
1 year ago
|
$anvil->Log->variables({ source => $THIS_FILE, line => __LINE__, level => $debug, list => $parameters, prefix => "call" });
|
||
3 years ago
|
|
||
1 year ago
|
return (1) if ( (not defined $call) || ($call eq "") );
|
||
3 years ago
|
|
||
1 year ago
|
my ($output, $rcode) = $anvil->System->call({ background => $background, shell_call => $call });
|
||
3 years ago
|
|
||
1 year ago
|
$anvil->Log->variables({ source => $THIS_FILE, line => __LINE__, level => $debug, list => {
|
||
|
output => $output,
|
||
|
rcode => $rcode
|
||
|
} });
|
||
3 years ago
|
|
||
1 year ago
|
# Output order reversed keep returns consistent.
|
||
1 year ago
|
return ($rcode, $output);
|
||
3 years ago
|
}
|
||
|
|
||
1 year ago
|
sub find_available_port
|
||
3 years ago
|
{
|
||
|
my $parameters = shift;
|
||
1 year ago
|
my $debug = $parameters->{debug} || 3;
|
||
3 years ago
|
|
||
1 year ago
|
$anvil->Log->variables({ source => $THIS_FILE, line => __LINE__, level => $debug, list => $parameters, prefix => "find_available_port" });
|
||
3 years ago
|
|
||
1 year ago
|
my ($build_rcode, $call) = build_find_available_port_call($parameters);
|
||
2 years ago
|
|
||
1 year ago
|
return (1) if ($build_rcode);
|
||
3 years ago
|
|
||
1 year ago
|
return call({ call => $call, debug => $debug });
|
||
3 years ago
|
}
|
||
|
|
||
1 year ago
|
sub find_server_vnc_port
|
||
|
{
|
||
|
my $parameters = shift;
|
||
|
my $debug = $parameters->{debug};
|
||
|
my $svr_uuid = $parameters->{svr_uuid};
|
||
|
my $svr_vnc_port = $parameters->{svr_vnc_port};
|
||
|
|
||
1 year ago
|
return (0, $svr_vnc_port) if (is_int($svr_vnc_port));
|
||
1 year ago
|
|
||
|
# If we don't have the server's VNC port, find it in its qemu-kvm process.
|
||
|
|
||
1 year ago
|
my ($rcode, $svr_processes) = $anvil->Server->find_processes({ debug => $debug });
|
||
|
|
||
|
return (1) if ($rcode);
|
||
1 year ago
|
|
||
|
my $svr_process = $svr_processes->{uuids}{$svr_uuid};
|
||
|
my $svr_vnc_alive = $svr_process->{vnc_alive};
|
||
|
|
||
|
return (1) if (not $svr_vnc_alive);
|
||
|
|
||
|
return (0, $svr_process->{vnc_port});
|
||
|
}
|
||
|
|
||
1 year ago
|
sub find_ws_processes
|
||
3 years ago
|
{
|
||
1 year ago
|
my $parameters = shift;
|
||
|
my $debug = $parameters->{debug} || 3;
|
||
1 year ago
|
my $ps_name = $parameters->{ps_name} // "websockify";
|
||
1 year ago
|
|
||
1 year ago
|
$anvil->Log->variables({ source => $THIS_FILE, line => __LINE__, level => $debug, list => $parameters, prefix => "find_ws_processes" });
|
||
1 year ago
|
|
||
1 year ago
|
my $ps_call = "$pgrep -a '$ps_name' | $sed -En 's/^([[:digit:]]+).*${ps_name}([[:space:]]+(--?[^[:space:]]+))*[[:space:]:]+([[:digit:]]+)[[:space:]:]+([[:digit:]]+).*\$/\\1,\\4,\\5/p'";
|
||
3 years ago
|
|
||
1 year ago
|
my ($rcode, $output) = call({ call => $ps_call, debug => $debug });
|
||
3 years ago
|
|
||
1 year ago
|
return (1) if ($rcode);
|
||
3 years ago
|
|
||
1 year ago
|
my $result = { pids => {}, sources => {}, targets => {} };
|
||
3 years ago
|
|
||
1 year ago
|
foreach my $line (split(/\n/, $output))
|
||
2 years ago
|
{
|
||
1 year ago
|
chomp($line);
|
||
3 years ago
|
|
||
1 year ago
|
$anvil->Log->variables({ source => $THIS_FILE, line => __LINE__, level => $debug, list => { ws_line => $line } });
|
||
1 year ago
|
|
||
1 year ago
|
my ($pid, $sport, $tport) = split(/,/, $line);
|
||
1 year ago
|
|
||
1 year ago
|
my $process = { pid => $pid, sport => $sport, tport => $tport };
|
||
3 years ago
|
|
||
1 year ago
|
set_ws_process({ debug => $debug, entry => $process, entries => $result });
|
||
1 year ago
|
}
|
||
3 years ago
|
|
||
1 year ago
|
$anvil->Log->entry({ source => $THIS_FILE, line => __LINE__, level => $debug, raw => prettify($result, "ws_processes") });
|
||
1 year ago
|
|
||
1 year ago
|
return (0, $result);
|
||
1 year ago
|
}
|
||
2 years ago
|
|
||
1 year ago
|
sub is_int
|
||
3 years ago
|
{
|
||
1 year ago
|
return defined $_[0] && $_[0] =~ /^\d+$/;
|
||
1 year ago
|
}
|
||
3 years ago
|
|
||
1 year ago
|
sub is_uuid_v4
|
||
|
{
|
||
1 year ago
|
return defined $_[0] && $_[0] =~ /[a-f0-9]{8}-[a-f0-9]{4}-[1-5][a-f0-9]{3}-[89ab][a-f0-9]{3}-[a-f0-9]{12}/;
|
||
1 year ago
|
}
|
||
|
|
||
1 year ago
|
sub prettify
|
||
|
{
|
||
|
my $var_value = shift;
|
||
|
my $var_name = shift;
|
||
|
|
||
|
local $Data::Dumper::Indent = 1;
|
||
|
local $Data::Dumper::Varname = $var_name;
|
||
|
|
||
|
return Dumper($var_value);
|
||
|
}
|
||
|
|
||
1 year ago
|
sub set_entry
|
||
3 years ago
|
{
|
||
1 year ago
|
my $parameters = shift;
|
||
|
my $debug = $parameters->{debug} || 3;
|
||
|
my $handle_delete = $parameters->{handle_delete};
|
||
|
my $handle_set = $parameters->{handle_set};
|
||
1 year ago
|
my $id = $parameters->{id};
|
||
|
my $entry = $parameters->{entry};
|
||
|
my $entries = $parameters->{entries};
|
||
1 year ago
|
|
||
1 year ago
|
$anvil->Log->variables({ source => $THIS_FILE, line => __LINE__, level => $debug, list => {
|
||
|
%$parameters,
|
||
|
p_entry => prettify($entry),
|
||
|
p_entries => prettify($entries),
|
||
|
}, prefix => "set_entry" });
|
||
3 years ago
|
|
||
1 year ago
|
return (1) if (not defined $entries);
|
||
1 year ago
|
|
||
1 year ago
|
if (defined $entry)
|
||
3 years ago
|
{
|
||
1 year ago
|
$handle_set->($id, $entry, $entries);
|
||
3 years ago
|
}
|
||
1 year ago
|
elsif (defined $id)
|
||
3 years ago
|
{
|
||
1 year ago
|
$handle_delete->($id, $entry, $entries);
|
||
1 year ago
|
}
|
||
3 years ago
|
|
||
1 year ago
|
$anvil->Log->entry({ source => $THIS_FILE, line => __LINE__, level => $debug, raw => prettify($entries, "entries") });
|
||
|
|
||
1 year ago
|
return (0);
|
||
|
}
|
||
3 years ago
|
|
||
1 year ago
|
sub set_vncinfo_variable
|
||
3 years ago
|
{
|
||
1 year ago
|
my $parameters = shift;
|
||
|
my $debug = $parameters->{debug} || 3;
|
||
|
my $end_port = $parameters->{end_port};
|
||
|
my $svr_uuid = $parameters->{svr_uuid};
|
||
|
|
||
1 year ago
|
$anvil->Log->variables({ source => $THIS_FILE, line => __LINE__, level => $debug, list => $parameters, prefix => "set_vncinfo_variable" });
|
||
|
|
||
|
my $local_host_name = $anvil->data->{sys}{host_name};
|
||
1 year ago
|
|
||
|
my ($variable_uuid) = $anvil->Database->insert_or_update_variables({
|
||
1 year ago
|
file => $THIS_FILE,
|
||
|
line => __LINE__,
|
||
1 year ago
|
variable_name => build_vncinfo_variable_name($svr_uuid),
|
||
|
variable_value => "${local_host_name}:${end_port}",
|
||
1 year ago
|
});
|
||
3 years ago
|
|
||
1 year ago
|
return (1) if (not is_uuid_v4($variable_uuid));
|
||
3 years ago
|
|
||
1 year ago
|
return (0);
|
||
3 years ago
|
}
|
||
|
|
||
1 year ago
|
sub set_ws_process
|
||
3 years ago
|
{
|
||
1 year ago
|
my $parameters = shift;
|
||
3 years ago
|
|
||
1 year ago
|
$parameters->{handle_delete} = sub {
|
||
|
my ($pid, $process, $processes) = @_;
|
||
2 years ago
|
|
||
1 year ago
|
$process = $processes->{pids}{$pid};
|
||
|
|
||
1 year ago
|
my $sport = $process->{sport};
|
||
|
my $tport = $process->{tport};
|
||
2 years ago
|
|
||
1 year ago
|
delete $processes->{pids}{$pid};
|
||
|
delete $processes->{sources}{$sport};
|
||
|
delete $processes->{targets}{$tport};
|
||
1 year ago
|
};
|
||
3 years ago
|
|
||
1 year ago
|
$parameters->{handle_set} = sub {
|
||
|
my ($pid, $process, $processes) = @_;
|
||
3 years ago
|
|
||
1 year ago
|
$pid = $process->{pid};
|
||
|
|
||
1 year ago
|
my $sport = $process->{sport};
|
||
|
my $tport = $process->{tport};
|
||
2 years ago
|
|
||
1 year ago
|
$processes->{pids}{$pid} = $process;
|
||
|
$processes->{sources}{$sport} = $pid;
|
||
|
$processes->{targets}{$tport} = $pid;
|
||
1 year ago
|
};
|
||
|
|
||
1 year ago
|
return set_entry($parameters);
|
||
2 years ago
|
}
|
||
|
|
||
1 year ago
|
sub start_pipe
|
||
2 years ago
|
{
|
||
|
my $parameters = shift;
|
||
1 year ago
|
my $debug = $parameters->{debug} || 3;
|
||
|
my $svr_uuid = $parameters->{svr_uuid};
|
||
|
my $svr_vnc_port = $parameters->{svr_vnc_port};
|
||
2 years ago
|
|
||
1 year ago
|
return (1) if (not is_uuid_v4($svr_uuid));
|
||
2 years ago
|
|
||
1 year ago
|
my $common_params = { debug => $debug };
|
||
2 years ago
|
|
||
1 year ago
|
my $rcode;
|
||
2 years ago
|
|
||
1 year ago
|
($rcode, $svr_vnc_port) = find_server_vnc_port($parameters);
|
||
2 years ago
|
|
||
1 year ago
|
return ($rcode) if ($rcode);
|
||
2 years ago
|
|
||
1 year ago
|
($rcode, my $ws_processes) = find_ws_processes($common_params);
|
||
3 years ago
|
|
||
1 year ago
|
return ($rcode) if ($rcode);
|
||
2 years ago
|
|
||
1 year ago
|
($rcode, my $ws_pid) = start_ws({ svr_vnc_port => $svr_vnc_port, ws_processes => $ws_processes, %$common_params });
|
||
3 years ago
|
|
||
1 year ago
|
return ($rcode) if ($rcode);
|
||
3 years ago
|
|
||
1 year ago
|
my $ws_process = $ws_processes->{pids}{$ws_pid};
|
||
3 years ago
|
|
||
1 year ago
|
set_vncinfo_variable({ end_port => $ws_process->{sport}, svr_uuid => $svr_uuid, %$common_params });
|
||
3 years ago
|
|
||
1 year ago
|
return (0);
|
||
2 years ago
|
}
|
||
|
|
||
1 year ago
|
sub start_ws
|
||
2 years ago
|
{
|
||
1 year ago
|
my $parameters = shift;
|
||
|
my $debug = $parameters->{debug} || 3;
|
||
|
my $svr_vnc_port = $parameters->{svr_vnc_port};
|
||
|
my $ws_processes = $parameters->{ws_processes};
|
||
|
my $ws_sport_offset = $parameters->{ws_sport_offset} || 10000;
|
||
2 years ago
|
|
||
1 year ago
|
$anvil->Log->variables({ source => $THIS_FILE, line => __LINE__, level => $debug, list => $parameters, prefix => "start_ws" });
|
||
2 years ago
|
|
||
1 year ago
|
return (1) if ( (not defined $ws_processes)
|
||
1 year ago
|
|| (not is_int($svr_vnc_port))
|
||
1 year ago
|
|| (not is_int($ws_sport_offset)) );
|
||
2 years ago
|
|
||
1 year ago
|
my $existing_ws_pid = $ws_processes->{targets}{$svr_vnc_port};
|
||
2 years ago
|
|
||
1 year ago
|
$anvil->Log->variables({ source => $THIS_FILE, line => __LINE__, level => $debug, list => { existing_ws_pid => $existing_ws_pid } });
|
||
|
|
||
1 year ago
|
return (0, $existing_ws_pid) if (defined $existing_ws_pid);
|
||
2 years ago
|
|
||
1 year ago
|
my $rcode;
|
||
|
|
||
|
($rcode, my $ws_sport) = find_available_port({ debug => $debug, start => int($svr_vnc_port) + int($ws_sport_offset) });
|
||
|
|
||
|
return ($rcode) if ($rcode);
|
||
2 years ago
|
|
||
1 year ago
|
my $ws_call = "$websockify -D $ws_sport :$svr_vnc_port &>/dev/null";
|
||
2 years ago
|
|
||
1 year ago
|
($rcode) = call({ call => $ws_call, debug => $debug });
|
||
3 years ago
|
|
||
1 year ago
|
return ($rcode) if ($rcode);
|
||
3 years ago
|
|
||
1 year ago
|
# Re-find to locate the new daemon.
|
||
|
($rcode, my $re_ws_processes) = find_ws_processes({ debug => $debug });
|
||
3 years ago
|
|
||
1 year ago
|
return ($rcode) if ($rcode);
|
||
3 years ago
|
|
||
1 year ago
|
my $ws_pid = $re_ws_processes->{targets}{$svr_vnc_port};
|
||
|
my $ws_process = $re_ws_processes->{pids}{$ws_pid};
|
||
3 years ago
|
|
||
1 year ago
|
# Remember the started daemon.
|
||
1 year ago
|
set_ws_process({ debug => $debug, entry => $ws_process, entries => $ws_processes });
|
||
3 years ago
|
|
||
1 year ago
|
return (0, $ws_pid);
|
||
3 years ago
|
}
|
||
|
|
||
1 year ago
|
sub stop_pipe
|
||
|
{
|
||
|
my $parameters = shift;
|
||
|
my $debug = $parameters->{debug} || 3;
|
||
|
my $svr_uuid = $parameters->{svr_uuid};
|
||
|
my $svr_vnc_port = $parameters->{svr_vnc_port};
|
||
3 years ago
|
|
||
1 year ago
|
return (1) if (not is_uuid_v4($svr_uuid));
|
||
2 years ago
|
|
||
1 year ago
|
my $common_params = { debug => $debug };
|
||
2 years ago
|
|
||
1 year ago
|
my $rcode;
|
||
|
|
||
1 year ago
|
($rcode, $svr_vnc_port) = find_server_vnc_port($parameters);
|
||
3 years ago
|
|
||
1 year ago
|
return ($rcode) if ($rcode);
|
||
3 years ago
|
|
||
1 year ago
|
($rcode, my $ws_processes) = find_ws_processes($common_params);
|
||
2 years ago
|
|
||
1 year ago
|
return ($rcode) if ($rcode);
|
||
2 years ago
|
|
||
1 year ago
|
my $ws_pid = $ws_processes->{targets}{$svr_vnc_port};
|
||
2 years ago
|
|
||
1 year ago
|
stop_ws({ ws_pid => $ws_pid, ws_processes => $ws_processes, %$common_params });
|
||
1 year ago
|
|
||
|
return (0);
|
||
3 years ago
|
}
|
||
2 years ago
|
|
||
1 year ago
|
sub stop_ws
|
||
|
{
|
||
|
my $parameters = shift;
|
||
|
my $debug = $parameters->{debug} || 3;
|
||
|
my $ws_pid = $parameters->{ws_pid};
|
||
|
my $ws_processes = $parameters->{ws_processes};
|
||
|
|
||
|
$anvil->Log->variables({ source => $THIS_FILE, line => __LINE__, level => $debug, list => $parameters, prefix => "stop_ws" });
|
||
|
|
||
1 year ago
|
return (1) if ( (not is_int($ws_pid)) || (not defined $ws_processes) );
|
||
|
|
||
1 year ago
|
call({ debug => $debug, call => "$kill $ws_pid || $kill -9 $ws_pid" });
|
||
|
|
||
1 year ago
|
set_ws_process({ debug => $debug, id => $ws_pid, entries => $ws_processes });
|
||
1 year ago
|
|
||
|
return (0);
|
||
1 year ago
|
}
|