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.
815 lines
23 KiB
815 lines
23 KiB
#!/usr/bin/perl |
|
# |
|
# Manages VNC ports for server VMs that have VNC enabled. |
|
# |
|
|
|
use strict; |
|
use warnings; |
|
use Anvil::Tools; |
|
|
|
$| = 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(); |
|
|
|
my $manage_tunnel = $anvil->data->{path}{exe}{'anvil-manage-tunnel'}; |
|
my $echo = $anvil->data->{path}{exe}{'echo'}; |
|
my $grep = $anvil->data->{path}{exe}{'grep'}; |
|
my $kill = $anvil->data->{path}{exe}{'kill'}; |
|
my $pgrep = $anvil->data->{path}{exe}{'pgrep'}; |
|
my $ps = $anvil->data->{path}{exe}{'ps'}; |
|
my $ss = $anvil->data->{path}{exe}{'ss'}; |
|
my $sed = $anvil->data->{path}{exe}{'sed'}; |
|
my $websockify = $anvil->data->{path}{exe}{'websockify'}; |
|
|
|
$anvil->Get->switches; |
|
|
|
$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 }); |
|
} |
|
|
|
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'}; |
|
|
|
if (defined $server) |
|
{ |
|
$server_uuid //= is_uuid_v4($server) ? $server : $anvil->Get->server_uuid_from_name({ server_name => $server }); |
|
} |
|
|
|
$anvil->Log->variables({ source => $THIS_FILE, line => __LINE__, level => $switch_debug, list => { |
|
open => $open, |
|
server => $server, |
|
server_uuid => $server_uuid, |
|
server_vnc_port => $server_vnc_port |
|
} }); |
|
|
|
my $map_to_operation = { start => \&start_pipe, stop => \&stop_pipe }; |
|
|
|
if ($server_uuid) |
|
{ |
|
my $rcode; |
|
|
|
my $operation = $open ? "start" : "stop"; |
|
|
|
$anvil->Log->variables({ source => $THIS_FILE, line => __LINE__, level => $switch_debug, list => { operation => $operation } }); |
|
|
|
($rcode) = $map_to_operation->{$operation}({ |
|
debug => $switch_debug, |
|
svr_uuid => $server_uuid, |
|
svr_vnc_port => $server_vnc_port, |
|
}); |
|
|
|
$anvil->nice_exit({ exit_code => $rcode }); |
|
} |
|
|
|
$anvil->nice_exit({ exit_code => 0 }); |
|
|
|
# |
|
# Functions |
|
# |
|
|
|
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; |
|
|
|
$anvil->Log->variables({ source => $THIS_FILE, line => __LINE__, level => $debug, list => $parameters, prefix => "build_find_available_port_call" }); |
|
|
|
return (1) if ( (not $step_operator =~ /^[+-]$/) |
|
|| (not is_int($step_size)) || ($step_size < 1) ); |
|
|
|
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"; |
|
|
|
return (0, $call); |
|
} |
|
|
|
sub build_tunnel_call |
|
{ |
|
my $parameters = shift; |
|
my $ctl_cmd = $parameters->{ctl_cmd} // "forward"; |
|
my $ctl_path = $parameters->{ctl_path}; |
|
my $debug = $parameters->{debug} || 3; |
|
my $lport = $parameters->{lport}; |
|
my $rport = $parameters->{rport}; |
|
my $svr_uuid = $parameters->{svr_uuid}; |
|
|
|
$anvil->Log->variables({ source => $THIS_FILE, line => __LINE__, level => $debug, list => $parameters, prefix => "build_tunnel_call" }); |
|
|
|
return (1) if ( (not defined $ctl_path) |
|
|| (not defined $lport) |
|
|| (not defined $rport) ); |
|
|
|
my $ls_prefix_opt = defined $svr_uuid ? "--tunnel-ls-prefix '$svr_uuid'" : ""; |
|
|
|
my $call = "$manage_tunnel --child --ctl-cmd $ctl_cmd --ctl-path '$ctl_path' --debug $debug --forward-lport $lport --forward-rport $rport $ls_prefix_opt"; |
|
|
|
return (0, $call); |
|
} |
|
|
|
sub build_tunnel_variable_name |
|
{ |
|
my ($svr_uuid, $tp_target_uuid) = @_; |
|
|
|
return "sshctl::${svr_uuid}::${tp_target_uuid}"; |
|
} |
|
|
|
sub call |
|
{ |
|
my $parameters = shift; |
|
my $call = $parameters->{call}; |
|
my $debug = $parameters->{debug} || 3; |
|
|
|
$anvil->Log->variables({ source => $THIS_FILE, line => __LINE__, level => $debug, list => $parameters, prefix => "call" }); |
|
|
|
return (1) if ( (not defined $call) || ($call eq "") ); |
|
|
|
my ($output, $rcode) = $anvil->System->call({ shell_call => $call }); |
|
|
|
$anvil->Log->variables({ source => $THIS_FILE, line => __LINE__, level => $debug, list => { |
|
output => $output, |
|
rcode => $rcode |
|
} }); |
|
|
|
return ($rcode, $output); |
|
} |
|
|
|
sub find_available_port |
|
{ |
|
my $parameters = shift; |
|
my $debug = $parameters->{debug} || 3; |
|
|
|
$anvil->Log->variables({ source => $THIS_FILE, line => __LINE__, level => $debug, list => $parameters, prefix => "find_available_port" }); |
|
|
|
my ($build_rcode, $call) = build_find_available_port_call($parameters); |
|
|
|
return (1) if ($build_rcode); |
|
|
|
return call({ call => $call, debug => $debug }); |
|
} |
|
|
|
sub find_ws_processes |
|
{ |
|
my $parameters = shift; |
|
my $debug = $parameters->{debug} || 3; |
|
my $ps_name = $parameters->{ps_name} // "websockify"; |
|
|
|
$anvil->Log->variables({ source => $THIS_FILE, line => __LINE__, level => $debug, list => $parameters, prefix => "find_ws_processes" }); |
|
|
|
my $ps_call = "$pgrep -a '$ps_name' | $sed -En 's/^([[:digit:]]+).*${ps_name}[[:space:]:]+([[:digit:]]+)[[:space:]:]+([[:digit:]]+).*\$/\\1,\\2,\\3/p'"; |
|
|
|
my ($rcode, $output) = call({ call => $ps_call, debug => $debug }); |
|
|
|
return (1) if ($rcode); |
|
|
|
my $result = { pids => {}, sources => {}, targets => {} }; |
|
|
|
foreach my $line (split(/\n/, $output)) |
|
{ |
|
chomp($line); |
|
|
|
$anvil->Log->variables({ source => $THIS_FILE, line => __LINE__, level => $debug, list => { ws_line => $line } }); |
|
|
|
my ($pid, $sport, $tport) = split(/,/, $line); |
|
|
|
my $process = { pid => $pid, sport => $sport, tport => $tport }; |
|
|
|
set_ws_process({ debug => $debug, entry => $process, entries => $result }); |
|
} |
|
|
|
return (0, $result); |
|
} |
|
|
|
sub find_tp_processes |
|
{ |
|
my $parameters = shift; |
|
my $debug = $parameters->{debug} || 3; |
|
my $ps_name = $parameters->{ps_name} // "anvil-manage-tunnel"; |
|
|
|
$anvil->Log->variables({ source => $THIS_FILE, line => __LINE__, level => $debug, list => $parameters, prefix => "find_tp_processes" }); |
|
|
|
my $ps_call = "$pgrep -a '$ps_name' | $sed - En 's/^([[:digit:]]+).*--target[[:space:]]+([^[:space:]]+).*--ctl-path[[:space:]]+([^[:space:]]+).*--tunnel-ls-path[[:space:]]+([^[:space:]]+).*\$/\\1,\\2,\\3,\\4/p'"; |
|
|
|
my ($rcode, $output) = call({ call => $ps_call, debug => $debug }); |
|
|
|
return (1) if ($rcode); |
|
|
|
my $result = { pids => {}, targets => {} }; |
|
|
|
foreach my $line (split(/\n/, $output)) |
|
{ |
|
chomp($line); |
|
|
|
$anvil->Log->variables({ source => $THIS_FILE, line => __LINE__, level => $debug, list => { tp_line => $line } }); |
|
|
|
my ($pid, $target, $ctl_path, $tunnel_ls_path) = split(/,/, $line); |
|
|
|
my $process = { ctl_path => $ctl_path, pid => $pid, target => $target, tunnel_ls_path => $tunnel_ls_path }; |
|
|
|
set_tp_process({ debug => $debug, entry => $process, entries => $result }); |
|
} |
|
|
|
return (0, $result); |
|
} |
|
|
|
sub find_tunnels |
|
{ |
|
my $parameters = shift; |
|
my $debug = $parameters->{debug} || 3; |
|
my $tunnel_ls_path = $parameters->{tunnel_ls_path}; |
|
|
|
return (1) if ( (not defined $tunnel_ls_path) || (not -e $tunnel_ls_path) ); |
|
|
|
open(my $tunnel_ls_fh, "< :encoding(UTF-8)", $tunnel_ls_path) or return (1); |
|
|
|
my $result = { server_uuids => {}, lports => {} }; |
|
|
|
while my $line (<$tunnel_ls_fh>) |
|
{ |
|
chomp($line); |
|
|
|
$anvil->Log->variables({ source => $THIS_FILE, line => __LINE__, level => $debug, list => { tunnel_line => $line } }); |
|
|
|
my ($svr_uuid, $tunnel_lport, $tunnel_rport) = $line =~ /^([^\s]+)-[L|R].*:(\d+):.*:(\d+)$/; |
|
|
|
my $tunnel = { lport => $lport, rport => $rport, server_uuid => $svr_uuid }; |
|
|
|
set_tunnel({ debug => $debug, entry => $tunnel, entries => $result }); |
|
} |
|
|
|
close($tunnel_ls_fh) or return (1); |
|
|
|
return (0, $result); |
|
} |
|
|
|
sub get_strikers |
|
{ |
|
my $query = " |
|
SELECT host_name, host_uuid |
|
FROM hosts |
|
WHERE host_status = 'online' AND host_type = 'striker' |
|
;"; |
|
my $rows = $anvil->Database->query({ query => $query, source => $THIS_FILE, line => __LINE__ }); |
|
|
|
my $strikers = { names => {}, uuids => {} }; |
|
|
|
foreach my $row (@{$rows}) |
|
{ |
|
my $host_name = $row->[0]; |
|
my $host_uuid = $row->[1]; |
|
|
|
$strikers->{uuids}{$host_uuid} = { name => $host_name, uuid => $host_uuid }; |
|
$strikers->{names}{$host_name} = $host_uuid; |
|
} |
|
|
|
return (0, $strikers); |
|
} |
|
|
|
sub get_tunnel_variable |
|
{ |
|
my $parameters = shift; |
|
my $svr_uuid = $parameters->{svr_uuid}; |
|
my $tp_target_uuid = $parameters->{tp_target_uuid}; |
|
|
|
my $variable_name = build_tunnel_variable_name($svr_uuid, $tp_target_uuid); |
|
|
|
my $query = " |
|
SELECT variable_value |
|
FROM variables |
|
WHERE |
|
variable_name = ".$anvil->Database->quote($variable_name)." |
|
AND |
|
variable_source_table = 'hosts' |
|
AND |
|
variable_source_uuid = ".$anvil->Database->quote($tp_target_uuid)." |
|
;"; |
|
my $rows = $anvil->Database->query({ query => $query, source => $THIS_FILE, line => __LINE__ }); |
|
|
|
return (1) if (not @{$rows}); |
|
|
|
my $end_port = $rows->[0]->[0]; |
|
|
|
return (0, int($end_port)); |
|
} |
|
|
|
sub is_int |
|
{ |
|
return $_[0] =~ /^\d+$/; |
|
} |
|
|
|
sub is_uuid_v4 |
|
{ |
|
return $_[0] =~ /[a-f0-9]{8}-[a-f0-9]{4}-[1-5][a-f0-9]{3}-[89ab][a-f0-9]{3}-[a-f0-9]{12}/; |
|
} |
|
|
|
sub set_entry |
|
{ |
|
my $parameters = shift; |
|
my $debug = $parameters->{debug} || 3; |
|
my $handle_delete = $parameters->{handle_delete}; |
|
my $handle_set = $parameters->{handle_set}; |
|
my $id = $parameters->{id}; |
|
my $entry = $parameters->{entry}; |
|
my $entries = $parameters->{entries}; |
|
|
|
$anvil->Log->variables({ source => $THIS_FILE, line => __LINE__, level => $debug, list => $parameters, prefix => "set_entry" }); |
|
$anvil->Log->variables({ source => $THIS_FILE, line => __LINE__, level => $debug, list => $entry }); |
|
|
|
return (1) if (not defined $entries); |
|
|
|
if (defined $entry) |
|
{ |
|
$handle_set->($id, $entry, $entries); |
|
} |
|
elsif (defined $id) |
|
{ |
|
$handle_delete->($id, $entry, $entries); |
|
} |
|
|
|
return (0); |
|
} |
|
|
|
sub set_tp_process |
|
{ |
|
my $parameters = shift; |
|
|
|
$parameters->{handle_delete} = sub { |
|
my ($pid, $process, $processes) = @_; |
|
|
|
$process = $processes->{pids}{$pid}; |
|
|
|
my $target = $process->{target}; |
|
|
|
delete $processes->{pids}{$pid}; |
|
delete $processes->{targets}{$target}; |
|
}; |
|
|
|
$parameters->{handle_set} = sub { |
|
my ($pid, $process, $processes) = @_; |
|
|
|
$pid = $process->{pid}; |
|
|
|
my $target = $process->{target}; |
|
|
|
$processes->{pids}{$pid} = $process; |
|
$processes->{targets}{$target} = $pid; |
|
}; |
|
|
|
return set_entry($parameters); |
|
} |
|
|
|
sub set_tunnel |
|
{ |
|
my $parameters = shift; |
|
|
|
$parameters->{handle_delete} = sub { |
|
my ($svr_uuid, $tunnel, $tunnels) = @_; |
|
|
|
$tunnel = $tunnels->{server_uuids}{$svr_uuid}; |
|
|
|
my $lport = $tunnel->{lport}; |
|
|
|
delete $tunnels->{server_uuids}{$svr_uuid}; |
|
delete $tunnels->{lports}{$lport}; |
|
}; |
|
|
|
$parameters->{handle_set} = sub { |
|
my ($svr_uuid, $tunnel, $tunnels) = @_; |
|
|
|
$svr_uuid = $tunnel->{server_uuid}; |
|
|
|
my $lport = $tunnel->{lport}; |
|
|
|
$tunnels->{server_uuids}{$svr_uuid} = $tunnel; |
|
$tunnels->{lports}{$lport} = $svr_uuid; |
|
}; |
|
|
|
return set_entry($parameters); |
|
} |
|
|
|
sub set_tunnel_variable |
|
{ |
|
my $parameters = shift; |
|
my $debug = $parameters->{debug} || 3; |
|
my $end_port = $parameters->{end_port}; |
|
my $svr_uuid = $parameters->{svr_uuid}; |
|
my $tp_target_uuid = $parameters->{tp_target_uuid}; |
|
|
|
$anvil->Log->variables({ source => $THIS_FILE, line => __LINE__, level => $debug, list => $parameters, prefix => "set_tunnel_variable" }); |
|
|
|
my ($variable_uuid) = $anvil->Database->insert_or_update_variables({ |
|
file => $THIS_FILE, |
|
line => __LINE__, |
|
variable_name => build_tunnel_variable_name($svr_uuid, $tp_target_uuid), |
|
variable_source_table => "hosts", |
|
variable_source_uuid => $tp_target_uuid, |
|
variable_value => $end_port, |
|
}); |
|
|
|
return (1) if (not is_uuid_v4($variable_uuid)); |
|
|
|
return (0); |
|
} |
|
|
|
sub set_ws_process |
|
{ |
|
my $parameters = shift; |
|
|
|
$parameters->{handle_delete} = sub { |
|
my ($pid, $process, $processes) = @_; |
|
|
|
$process = $processes->{pids}{$pid}; |
|
|
|
my $sport = $process->{sport}; |
|
my $tport = $process->{tport}; |
|
|
|
delete $processes->{pids}{$pid}; |
|
delete $processes->{sources}{$sport}; |
|
delete $processes->{targets}{$tport}; |
|
}; |
|
|
|
$parameters->{handle_set} = sub { |
|
my ($pid, $process, $processes) = @_; |
|
|
|
$pid = $process->{pid}; |
|
|
|
my $sport = $process->{sport}; |
|
my $tport = $process->{tport}; |
|
|
|
$processes->{pids}{$pid} = $process; |
|
$processes->{sources}{$sport} = $pid; |
|
$processes->{targets}{$tport} = $pid; |
|
}; |
|
|
|
return set_entry($parameters); |
|
} |
|
|
|
sub start_pipe |
|
{ |
|
my $parameters = shift; |
|
my $debug = $parameters->{debug} || 3; |
|
my $svr_uuid = $parameters->{svr_uuid}; |
|
my $svr_vnc_port = $parameters->{svr_vnc_port}; |
|
|
|
return (1) if (not is_uuid_v4($svr_uuid)); |
|
|
|
my $common_params = { debug => $debug }; |
|
|
|
my $rcode; |
|
|
|
# If we don't have the server's VNC port, find it in its qemu-kvm process. |
|
if ( (not defined $svr_vnc_port) || (not is_int($svr_vnc_port)) ) |
|
{ |
|
($rcode, my $svr_processes) = $anvil->Server->find_processes($common_params); |
|
|
|
my $svr_process = $svr_processes->{uuids}{$svr_uuid}; |
|
my $svr_vnc_alive = $svr_process->{vnc_alive}; |
|
|
|
return (1) if (not $svr_vnc_alive); |
|
|
|
$svr_vnc_port = $svr_process->{vnc_port}; |
|
} |
|
|
|
($rcode, my $ws_processes) = find_ws_processes($common_params); |
|
|
|
return ($rcode) if ($rcode); |
|
|
|
($rcode, my $ws_pid) = start_ws({ svr_vnc_port => $svr_vnc_port, ws_processes => $ws_processes, %$common_params }); |
|
|
|
return ($rcode) if ($rcode); |
|
|
|
($rcode, my $hosts) = get_strikers($common_params); |
|
|
|
return ($rcode) if ($rcode); |
|
|
|
($rcode, my $tp_processes) = find_tp_processes($common_params); |
|
|
|
return ($rcode) if ($rcode); |
|
|
|
my $ws_process = $ws_processes->{pids}{$ws_pid}; |
|
|
|
foreach my $host_uuid (keys %{$hosts->{uuids}}) |
|
{ |
|
my $host_name = $hosts->{uuids}{$host_uuid}{name}; |
|
|
|
($rcode, my $tp_pid) = start_tp({ tp_processes => $tp_processes, tp_target => $host_name, %$common_params }); |
|
|
|
next if ($rcode); |
|
|
|
my $tp_process = $tp_processes->{pids}{$tp_pid}; |
|
|
|
my $tunnels = find_tunnels({ tunnel_ls_path => $tp_process->{tunnel_ls_path} }); |
|
|
|
($rcode) = start_tunnel({ |
|
svr_uuid => $svr_uuid, |
|
tp_ctl_path => $tp_process->{ctl_path}, |
|
tp_target => $host_name, |
|
tp_target_uuid => $host_uuid, |
|
tunnels => $tunnels, |
|
ws_sport => $ws_process->{sport}, |
|
%$common_params, |
|
}); |
|
|
|
next if ($rcode); |
|
|
|
($rcode) = set_tunnel_variable({ |
|
debug => $debug, |
|
end_port => $tunnel_rport, |
|
svr_uuid => $svr_uuid, |
|
tp_target_uuid => $host_uuid |
|
}); |
|
|
|
if ($rcode) |
|
{ |
|
stop_tunnel({ |
|
lport => $ws_process->{sport}, |
|
rport => $tunnel->{end_port}, |
|
tp_ctl_path => $tp_process->{ctl_path}, |
|
%$common_params, |
|
}); |
|
} |
|
} |
|
|
|
return (0); |
|
} |
|
|
|
sub start_tp |
|
{ |
|
my $parameters = shift; |
|
my $debug = $parameters->{debug} || 3; |
|
my $tp_ctl_path = $parameters->{tp_ctl_path}; |
|
my $tp_processes = $parameters->{tp_processes}; |
|
my $tp_target = $parameters->{tp_target}; |
|
my $tp_tunnel_ls_path = $parameters->{tp_tunnel_ls_path}; |
|
|
|
$anvil->Log->variables({ source => $THIS_FILE, line => __LINE__, level => $debug, list => $parameters, prefix => "start_tp" }); |
|
|
|
return (1) if ( (not defined $tp_processes) || (not defined $tp_target) ); |
|
|
|
my $tp_ctl_name = "sshctl-${tp_target}"; |
|
|
|
$tp_ctl_path //= "~/.libnet-openssh-perl/${tp_ctl_name}"; |
|
$tp_tunnel_ls_path //= $anvil->data->{path}{'directories'}{'tmp'}."/${tp_ctl_name}-tunnel-ls"; |
|
|
|
my $existing_tp_pid = $tp_processes->{targets}{$tp_target}; |
|
|
|
$anvil->Log->variables({ source => $THIS_FILE, line => __LINE__, level => $debug, list => { existing_tp_pid => $existing_tp_pid } }); |
|
|
|
return (0, $existing_tp_pid) if (defined $existing_tp_pid); |
|
|
|
my $tp_call = "$manage_tunnel --debug $debug --target $tp_target --ctl-path '$tp_ctl_path' --tunnel-ls-path '$tp_tunnel_ls_path' & $echo pid:\$!"; |
|
|
|
my ($start_rcode, $start_output) = call({ call => $tp_call, debug => $debug }); |
|
|
|
return (1) if ($start_rcode); |
|
|
|
my ($tp_pid) = $start_output =~ /pid:(\d+)$/; |
|
|
|
my $tp_process = { ctl_path => $tp_ctl_path, pid => $tp_pid, target => $tp_target, tunnel_ls_path => $tp_tunnel_ls_path }; |
|
|
|
set_tp_process({ debug => $debug, entry => $tp_process, entries => $tp_processes }); |
|
|
|
return (0, $tp_pid); |
|
} |
|
|
|
sub start_tunnel |
|
{ |
|
my $parameters = shift; |
|
my $debug = $parameters->{debug}; |
|
my $svr_uuid = $parameters->{svr_uuid}; |
|
my $tp_ctl_path = $parameters->{tp_ctl_path}; |
|
my $tp_target = $parameters->{tp_target}; |
|
my $tp_target_uuid = $parameters->{tp_target_uuid}; |
|
my $tunnels = $parameters->{tunnels}; |
|
my $ws_sport = $parameters->{ws_sport}; |
|
|
|
$anvil->Log->variables({ source => $THIS_FILE, line => __LINE__, level => $debug, list => $parameters, prefix => "start_tunnel" }); |
|
|
|
return (1) if ( (not defined $svr_uuid) |
|
|| (not defined $tp_target) |
|
|| (not defined $tp_target_uuid) |
|
|| (not defined $tp_ctl_path) || ($tp_ctl_path eq "") || (not -e $tp_ctl_path) |
|
|| (not defined $tunnels) |
|
|| (not defined $ws_sport) ); |
|
|
|
my $existing_tunnel = $tunnels->{server_uuids}{$svr_uuid}; |
|
|
|
$anvil->Log->variables({ source => $THIS_FILE, line => __LINE__, level => $debug, list => { existing_tunnel => $existing_tunnel } }); |
|
|
|
return (0, $svr_uuid) if (defined $existing_tunnel); |
|
|
|
my $build_rcode; |
|
my $sh_call; |
|
|
|
# ----- Try to find a usable port on the target host. |
|
($build_rcode, $sh_call) = build_find_available_port_call({ start => $ws_sport }); |
|
|
|
return (1) if ($build_rcode); |
|
|
|
$anvil->Log->variables({ source => $THIS_FILE, line => __LINE__, level => $debug, list => { find_available_port_call => $sh_call } }); |
|
|
|
my ($tunnel_rport, $find_error, $find_rcode) = $anvil->Remote->call({ |
|
no_cache => 1, |
|
ossh_opts => [ ctl_path => $tp_ctl_path, external_master => 1 ], |
|
shell_call => $sh_call, |
|
target => "0.0.0.0", |
|
}); |
|
|
|
$anvil->Log->variables({ source => $THIS_FILE, line => __LINE__, level => $debug, list => { |
|
find_error => $find_error, |
|
find_rcode => $find_rcode, |
|
tunnel_rport => $tunnel_rport, |
|
} }); |
|
|
|
return (1) if ($find_rcode); |
|
# ----- |
|
|
|
($build_rcode, $sh_call) = build_tunnel_call({ |
|
ctl_path => $tp_ctl_path, |
|
debug => $debug, |
|
lport => $ws_sport, |
|
rport => $tunnel_rport, |
|
svr_uuid => $svr_uuid, |
|
}); |
|
|
|
return (1) if ($build_rcode); |
|
|
|
my ($start_rcode) = call({ call => $sh_call, debug => $debug }); |
|
|
|
return (1) if ($start_rcode); |
|
|
|
my $tunnel = { lport => $ws_sport, rport => $tunnel_rport, server_uuid => $svr_uuid }; |
|
|
|
set_tunnel({ debug => $debug, entry => $tunnel, entries => $tunnels }); |
|
|
|
return (0, $svr_uuid); |
|
} |
|
|
|
sub start_ws |
|
{ |
|
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; |
|
|
|
$anvil->Log->variables({ source => $THIS_FILE, line => __LINE__, level => $debug, list => $parameters, prefix => "start_ws" }); |
|
|
|
return (1) if ( (not defined $ws_processes) |
|
|| (not defined $svr_vnc_port) || (not is_int($svr_vnc_port)) |
|
|| (not is_int($ws_sport_offset)) ); |
|
|
|
my $existing_ws_pid = $ws_processes->{targets}{$svr_vnc_port}; |
|
|
|
$anvil->Log->variables({ source => $THIS_FILE, line => __LINE__, level => $debug, list => { existing_ws_pid => $existing_ws_pid } }); |
|
|
|
return (0, $existing_ws_pid) if (defined $existing_ws_pid); |
|
|
|
my ($find_rcode, $ws_sport) = find_available_port({ debug => $debug, start => int($svr_vnc_port) + int($ws_sport_offset) }); |
|
|
|
return (1) if ($find_rcode); |
|
|
|
my $ws_call = "$websockify $ws_sport :$svr_vnc_port &>/dev/null & $echo pid:\$!"; |
|
|
|
my ($start_rcode, $start_output) = call({ call => $ws_call, debug => $debug }); |
|
|
|
return (1) if ($start_rcode); |
|
|
|
my ($ws_pid) = $start_output =~ /pid:(\d+)$/; |
|
|
|
my $ws_process = { pid => $ws_pid, sport => $ws_sport, tport => $svr_vnc_port }; |
|
|
|
set_ws_process({ debug => $debug, entry => $ws_process, entries => $ws_processes }); |
|
|
|
return (0, $ws_pid); |
|
} |
|
|
|
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}; |
|
my $tunnels = $parameters->{tunnels}; |
|
|
|
return (1) if ( (not is_uuid_v4($svr_uuid)) || (not defined $tunnels) ); |
|
|
|
my $common_params = { debug => $debug }; |
|
|
|
my $rcode; |
|
|
|
# If we don't have the server's VNC port, find it in its qemu-kvm process. |
|
if ( (not defined $svr_vnc_port) || (not is_int($svr_vnc_port)) ) |
|
{ |
|
($rcode, my $svr_processes) = $anvil->Server->find_processes($common_params); |
|
|
|
my $svr_process = $svr_processes->{uuids}{$svr_uuid}; |
|
my $svr_vnc_alive = $svr_process->{vnc_alive}; |
|
|
|
return (1) if (not $svr_vnc_alive); |
|
|
|
$svr_vnc_port = $svr_process->{vnc_port}; |
|
} |
|
|
|
($rcode, my $ws_processes) = find_ws_processes($common_params); |
|
|
|
return ($rcode) if ($rcode); |
|
|
|
my $ws_pid = $ws_processes->{targets}{$svr_vnc_port}; |
|
|
|
stop_ws({ ws_pid => $ws_pid, ws_processes => $ws_processes }); |
|
|
|
($rcode, my $hosts) = get_strikers($common_params); |
|
|
|
return ($rcode) if ($rcode); |
|
|
|
($rcode, my $tp_processes) = find_tp_processes($common_params); |
|
|
|
return ($rcode) if ($rcode); |
|
|
|
foreach my $host_uuid (keys %{$hosts->{uuids}}) |
|
{ |
|
my $host_name = $hosts->{uuids}{$host_uuid}{name}; |
|
my $tp_pid = $tp_processes->{targets}{$host_name}; |
|
my $tp_process = $tp_processes->{pids}{$tp_pid}; |
|
|
|
my $tunnel = $tunnels->{server_uuids}{$svr_uuid}; |
|
|
|
next if (not defined $tunnel); |
|
|
|
stop_tunnel({ %$tunnel, tp_ctl_path => $tp_process->{ctl_path}, %$common_params }); |
|
} |
|
|
|
return (0); |
|
} |
|
|
|
sub stop_tp |
|
{ |
|
my $parameters = shift; |
|
my $debug = $parameters->{debug} || 3; |
|
my $tp_pid = $parameters->{tp_pid}; |
|
my $tp_processes = $parameters->{tp_processes}; |
|
|
|
$anvil->Log->variables({ source => $THIS_FILE, line => __LINE__, level => $debug, list => $parameters, prefix => "stop_tp" }); |
|
|
|
call({ debug => $debug, call => "$kill $tp_pid || $kill -9 $tp_pid" }); |
|
|
|
set_tp_process({ debug => $debug, id => $tp_pid, entries => $tp_processes }); |
|
} |
|
|
|
sub stop_tunnel |
|
{ |
|
my $parameters = shift; |
|
my $debug = $parameters->{debug} || 3; |
|
my $lport = $parameters->{lport}; |
|
my $rport = $parameters->{rport}; |
|
my $tp_ctl_path = $parameters->{tp_ctl_path}; |
|
|
|
$anvil->Log->variables({ source => $THIS_FILE, line => __LINE__, level => $debug, list => $parameters, prefix => "stop_tunnel" }); |
|
|
|
my ($build_rcode, $call) = build_tunnel_call({ |
|
ctl_cmd => "cancel", |
|
ctl_path => $tp_ctl_path, |
|
debug => $debug, |
|
lport => $lport, |
|
rport => $rport, |
|
}); |
|
|
|
return (1) if ($build_rcode); |
|
|
|
my ($stop_rcode) = call({ call => $call, debug => $debug }); |
|
|
|
return (1) if ($stop_rcode); |
|
|
|
return (0); |
|
} |
|
|
|
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" }); |
|
|
|
call({ debug => $debug, call => "$kill $ws_pid || $kill -9 $ws_pid" }); |
|
|
|
set_ws_process({ debug => $debug, id => $ws_pid, entries => $ws_processes }); |
|
}
|
|
|