|
|
|
@ -88,6 +88,8 @@ WHERE server_uuid = ".$anvil->Database->quote($server_uuid)." |
|
|
|
|
my $results = $anvil->Database->query({ query => $query, source => $THIS_FILE, line => __LINE__ }); |
|
|
|
|
my $count = @{$results}; |
|
|
|
|
|
|
|
|
|
$anvil->Log->variables({ source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query, count => $count }, prefix => "get_server_info" }); |
|
|
|
|
|
|
|
|
|
if ($count == 1) |
|
|
|
|
{ |
|
|
|
|
my $row = $results->[0]; |
|
|
|
@ -205,34 +207,46 @@ sub is_websockify_exists |
|
|
|
|
my $ws_host_uuid = $parameters->{ws_host_uuid}; |
|
|
|
|
my $server_vnc_port = $parameters->{server_vnc_port}; |
|
|
|
|
|
|
|
|
|
# Expect 0 to 1 record(s) because each VM server can only have 1 |
|
|
|
|
# websockify instance (not considering shared VNC sessions). |
|
|
|
|
my $query = " |
|
|
|
|
SELECT |
|
|
|
|
vnc.server_vnc_port, hos.host_name, vnc.ws_host_uuid, vnc.ws_pid, vnc.ws_source_port, vnc.ssh_tunnel_host_uuid |
|
|
|
|
FROM |
|
|
|
|
public.vnc_pipes AS vnc |
|
|
|
|
JOIN |
|
|
|
|
public.hosts AS hos |
|
|
|
|
ON |
|
|
|
|
vnc.ws_host_uuid = hos.host_uuid |
|
|
|
|
a.server_vnc_port, |
|
|
|
|
b.host_name, |
|
|
|
|
a.ws_host_uuid, |
|
|
|
|
a.ws_pid, |
|
|
|
|
a.ws_dest_port, |
|
|
|
|
a.ssh_tunnel_host_uuid |
|
|
|
|
FROM vnc_pipes AS a |
|
|
|
|
JOIN hosts AS b ON a.ws_host_uuid = b.host_uuid |
|
|
|
|
WHERE |
|
|
|
|
vnc.server_uuid = ".$anvil->Database->quote($server_uuid)." |
|
|
|
|
a.server_uuid = ".$anvil->Database->quote($server_uuid)." |
|
|
|
|
AND |
|
|
|
|
a.ws_host_uuid = ".$anvil->Database->quote($ws_host_uuid)." |
|
|
|
|
AND |
|
|
|
|
vnc.ws_host_uuid = ".$anvil->Database->quote($ws_host_uuid)." |
|
|
|
|
a.server_vnc_port IS NOT NULL |
|
|
|
|
ORDER BY a.ws_pid DESC |
|
|
|
|
;"; |
|
|
|
|
|
|
|
|
|
my $results = $anvil->Database->query({ query => $query, source => $THIS_FILE, line => __LINE__ }); |
|
|
|
|
my $results = $anvil->Database->query({ query => $query, source => $THIS_FILE, line => __LINE__ }); |
|
|
|
|
my $count = @{$results}; |
|
|
|
|
|
|
|
|
|
$anvil->Log->variables({ source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query, count => $count }, prefix => "is_websockify_exists" }); |
|
|
|
|
|
|
|
|
|
my $ws_exists_info = { exists_code => 0 }; |
|
|
|
|
|
|
|
|
|
foreach my $row (@{$results}) |
|
|
|
|
{ |
|
|
|
|
my $server_vnc_port_in_record = $row->[0] // 0; |
|
|
|
|
my $server_vnc_port_in_record = $row->[0]; |
|
|
|
|
my $ws_host_name = $row->[1]; |
|
|
|
|
my $ws_host_uuid_in_record = $row->[2] // ''; |
|
|
|
|
my $ws_host_uuid_in_record = $row->[2]; |
|
|
|
|
my $ws_pid = $row->[3]; |
|
|
|
|
my $ws_source_port = $row->[4]; |
|
|
|
|
my $ws_dest_port = $row->[4]; |
|
|
|
|
my $ssh_tunnel_host_uuid = $row->[5]; |
|
|
|
|
my $clean_up_parameters = { host_name => $ws_host_name, ws_pid => $ws_pid }; |
|
|
|
|
|
|
|
|
|
$ws_exists_info->{exists_code} = 1; |
|
|
|
|
|
|
|
|
|
if ($ws_host_uuid ne $ws_host_uuid_in_record) |
|
|
|
|
{ |
|
|
|
|
# VNC server host mismatch; try to stop the recorded instance. |
|
|
|
@ -242,32 +256,25 @@ AND |
|
|
|
|
# No need to preserve the websockify source port in |
|
|
|
|
# this case because the tunnel will need to be replaced |
|
|
|
|
# as well. |
|
|
|
|
$ws_exists_info->{exists_code} = 1; |
|
|
|
|
} |
|
|
|
|
elsif ($server_vnc_port != $server_vnc_port_in_record) |
|
|
|
|
{ |
|
|
|
|
# VNC server port mismatch; try to stop the recorded instance. |
|
|
|
|
stop_websockify($clean_up_parameters); |
|
|
|
|
|
|
|
|
|
$ws_exists_info->{ws_source_port} = $ws_source_port; |
|
|
|
|
$ws_exists_info->{exists_code} = 1; |
|
|
|
|
$ws_exists_info->{ws_dest_port} = $ws_dest_port; |
|
|
|
|
} |
|
|
|
|
elsif (not is_websockify_process($clean_up_parameters)) |
|
|
|
|
{ |
|
|
|
|
# The recorded instance died. |
|
|
|
|
$ws_exists_info->{ws_source_port} = $ws_source_port; |
|
|
|
|
$ws_exists_info->{exists_code} = 1; |
|
|
|
|
$ws_exists_info->{ws_dest_port} = $ws_dest_port; |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
# Found one websockify instance that passed all tests. |
|
|
|
|
$ws_exists_info->{ws_pid} = $ws_pid; |
|
|
|
|
$ws_exists_info->{ws_source_port} = $ws_source_port; |
|
|
|
|
# Code 2: the websockify instance is not recorded for the pipe made from the current host, do update only. |
|
|
|
|
# Code 3: the websockify instance is recorded for the pipe made from the current host, do nothing. |
|
|
|
|
$ws_exists_info->{exists_code} = $host_uuid eq $ssh_tunnel_host_uuid ? 3 : 2; |
|
|
|
|
# Don't continue the loop because all pipes should align to this verified instance. |
|
|
|
|
last; |
|
|
|
|
$ws_exists_info->{exists_code} = 2; |
|
|
|
|
$ws_exists_info->{ws_pid} = $ws_pid; |
|
|
|
|
$ws_exists_info->{ws_dest_port} = $ws_dest_port; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -282,66 +289,88 @@ sub is_ssh_tunnel_exists |
|
|
|
|
my $server_uuid = $parameters->{server_uuid}; |
|
|
|
|
my $ssh_tunnel_host_uuid = $parameters->{ssh_tunnel_host_uuid}; |
|
|
|
|
my $ws_host_uuid = $parameters->{ws_host_uuid}; |
|
|
|
|
my $ws_source_port = $parameters->{ws_source_port}; |
|
|
|
|
|
|
|
|
|
my $ws_dest_port = $parameters->{ws_dest_port}; |
|
|
|
|
|
|
|
|
|
# Expect 0 to n record(s), where n is the number of subnodes: |
|
|
|
|
# n=0: no SSH tunnel connected to the server's ws instance |
|
|
|
|
# n>0: at least one SSH tunnel is known, regardless of whether it is |
|
|
|
|
# actually alive |
|
|
|
|
# |
|
|
|
|
# Order by clause ensures NULL record(s) are at first. |
|
|
|
|
my $query = " |
|
|
|
|
SELECT |
|
|
|
|
ws_host_uuid, ws_source_port, ssh_tunnel_pid, ssh_tunnel_forward_port |
|
|
|
|
FROM |
|
|
|
|
public.vnc_pipes |
|
|
|
|
a.ws_host_uuid, |
|
|
|
|
a.ws_pid, |
|
|
|
|
a.ws_dest_port, |
|
|
|
|
a.ssh_tunnel_dest_port, |
|
|
|
|
b.host_name, |
|
|
|
|
a.ssh_tunnel_host_uuid, |
|
|
|
|
a.ssh_tunnel_pid, |
|
|
|
|
a.ssh_tunnel_source_port |
|
|
|
|
FROM vnc_pipes AS a |
|
|
|
|
JOIN hosts AS b ON a.ssh_tunnel_host_uuid = b.host_uuid |
|
|
|
|
WHERE |
|
|
|
|
server_uuid = ".$anvil->Database->quote($server_uuid)." |
|
|
|
|
a.server_uuid = ".$anvil->Database->quote($server_uuid)." |
|
|
|
|
AND |
|
|
|
|
ssh_tunnel_host_uuid = ".$anvil->Database->quote($ssh_tunnel_host_uuid)." |
|
|
|
|
a.ssh_tunnel_host_uuid IS NOT NULL |
|
|
|
|
ORDER BY a.ws_pid DESC |
|
|
|
|
;"; |
|
|
|
|
|
|
|
|
|
my $results = $anvil->Database->query({ query => $query, source => $THIS_FILE, line => __LINE__ }); |
|
|
|
|
my $count = @{$results}; |
|
|
|
|
my $ssh_tunnel_exists_info = { exists_code => 0 }; |
|
|
|
|
my $results = $anvil->Database->query({ query => $query, source => $THIS_FILE, line => __LINE__ }); |
|
|
|
|
my $count = @{$results}; |
|
|
|
|
|
|
|
|
|
if ($count == 1) |
|
|
|
|
{ |
|
|
|
|
my $row = $results->[0]; |
|
|
|
|
my $ws_host_uuid_in_record = $row->[0] // ''; |
|
|
|
|
my $ws_source_port_in_record = $row->[1] // 0; |
|
|
|
|
my $ssh_tunnel_pid = $row->[2]; |
|
|
|
|
my $ssh_tunnel_forward_port = $row->[3]; |
|
|
|
|
my $clean_up_parameters = { ssh_tunnel_pid => $ssh_tunnel_pid }; |
|
|
|
|
$anvil->Log->variables({ source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query, count => $count }, prefix => "is_ssh_tunnel_exists" }); |
|
|
|
|
|
|
|
|
|
$ssh_tunnel_exists_info->{ssh_tunnel_pid} = $ssh_tunnel_pid; |
|
|
|
|
$ssh_tunnel_exists_info->{ssh_tunnel_forward_port} = $ssh_tunnel_forward_port; |
|
|
|
|
$ssh_tunnel_exists_info->{exists_code} = 1; |
|
|
|
|
my $ssh_tunnel_exists_info = { exists_code => 0 }; |
|
|
|
|
|
|
|
|
|
if ($ws_host_uuid ne $ws_host_uuid_in_record) |
|
|
|
|
foreach my $row (@{$results}) |
|
|
|
|
{ |
|
|
|
|
my $row = $results->[0]; |
|
|
|
|
my $ws_host_uuid_in_record = $row->[0]; |
|
|
|
|
my $ws_pid_in_record = $row->[1]; |
|
|
|
|
my $ws_dest_port_in_record = $row->[2]; |
|
|
|
|
my $ssh_tunnel_dest_port = $row->[3]; |
|
|
|
|
my $ssh_tunnel_host_name = $row->[4]; |
|
|
|
|
my $ssh_tunnel_host_uuid_in_record = $row->[5]; |
|
|
|
|
my $ssh_tunnel_pid = $row->[6]; |
|
|
|
|
my $ssh_tunnel_source_port = $row->[7]; |
|
|
|
|
my $clean_up_parameters = { host_name => $ssh_tunnel_host_name, ssh_tunnel_pid => $ssh_tunnel_pid }; |
|
|
|
|
|
|
|
|
|
$ssh_tunnel_exists_info->{exists_code} = 1; |
|
|
|
|
|
|
|
|
|
if (not defined $ws_pid_in_record and defined $ssh_tunnel_pid) |
|
|
|
|
{ |
|
|
|
|
# Websockify host mismatch; try to stop the recorded instance. |
|
|
|
|
# Likely happens after a server migration. |
|
|
|
|
# Websockify instance doesn't exist but tunnel does. |
|
|
|
|
# Remove the tunnel that's not connected to anything. |
|
|
|
|
stop_ssh_tunnel($clean_up_parameters); |
|
|
|
|
|
|
|
|
|
# No need to preserve the SSH tunnel forward port in |
|
|
|
|
# this case because the websockify instance will need |
|
|
|
|
# to be replaced as well. |
|
|
|
|
delete $ssh_tunnel_exists_info->{ssh_tunnel_forward_port}; |
|
|
|
|
clear_vnc_pipe_st({ server_uuid => $server_uuid, ws_host_uuid => $ws_host_uuid_in_record }); |
|
|
|
|
|
|
|
|
|
return $ssh_tunnel_exists_info; |
|
|
|
|
# No need to preserve any tunnel info because this |
|
|
|
|
# tunnel doesn't need to be recreated. |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if ($ws_source_port != $ws_source_port_in_record) |
|
|
|
|
elsif ($ssh_tunnel_source_port != $ws_dest_port_in_record) |
|
|
|
|
{ |
|
|
|
|
# Websockify source port mismatch; try to stop the recorded instance. |
|
|
|
|
# Tunnel is not pointing to the destination port of the |
|
|
|
|
# websockify instance; stop it and recreate. |
|
|
|
|
stop_ssh_tunnel($clean_up_parameters); |
|
|
|
|
|
|
|
|
|
return $ssh_tunnel_exists_info; |
|
|
|
|
# Port mismatch means we need to recreate the tunnel. |
|
|
|
|
$ssh_tunnel_exists_info->{ssh_tunnel_dest_port} = $ssh_tunnel_dest_port; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (not is_ssh_process($clean_up_parameters)) |
|
|
|
|
elsif (not is_ssh_process($clean_up_parameters)) |
|
|
|
|
{ |
|
|
|
|
# The recorded tunnel died. |
|
|
|
|
return $ssh_tunnel_exists_info; |
|
|
|
|
# The tunnel pid doesn't point to an active tunnel; |
|
|
|
|
# mark as need-to-be recreated. |
|
|
|
|
$ssh_tunnel_exists_info->{ssh_tunnel_dest_port} = $ssh_tunnel_dest_port; |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
# Passed all tests; tunnel considered exists. |
|
|
|
|
$ssh_tunnel_exists_info->{exists_code} = 2; |
|
|
|
|
$ssh_tunnel_exists_info->{ssh_tunnel_dest_port} = $ssh_tunnel_dest_port; |
|
|
|
|
$ssh_tunnel_exists_info->{ssh_tunnel_pid} = $ssh_tunnel_pid; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
# Passed all tests; tunnel considered exists. |
|
|
|
|
$ssh_tunnel_exists_info->{exists_code} = 2; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
$anvil->Log->variables({ source => $THIS_FILE, line => __LINE__, level => 2, list => $ssh_tunnel_exists_info, prefix => "is_ssh_tunnel_exists" }); |
|
|
|
@ -388,24 +417,19 @@ sub start_websockify |
|
|
|
|
server_vnc_port => $target_port |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
if ($ws_exists_info->{exists_code} =~ /^[23]$/) |
|
|
|
|
if ($ws_exists_info->{exists_code} == 2) |
|
|
|
|
{ |
|
|
|
|
$ws_info = {}; |
|
|
|
|
$ws_info->{pid} = $ws_exists_info->{ws_pid}; |
|
|
|
|
$ws_info->{source_port} = $ws_exists_info->{ws_source_port}; |
|
|
|
|
|
|
|
|
|
if ($ws_exists_info->{exists_code} == 2) |
|
|
|
|
{ |
|
|
|
|
$ws_info->{is_update} = 1; |
|
|
|
|
} |
|
|
|
|
$ws_info->{source_port} = $ws_exists_info->{ws_dest_port}; |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
if (not defined $source_port) |
|
|
|
|
{ |
|
|
|
|
if (defined $ws_exists_info->{ws_source_port}) |
|
|
|
|
if (defined $ws_exists_info->{ws_dest_port}) |
|
|
|
|
{ |
|
|
|
|
$source_port = $ws_exists_info->{ws_source_port}; |
|
|
|
|
$source_port = $ws_exists_info->{ws_dest_port}; |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
@ -467,58 +491,58 @@ sub stop_websockify |
|
|
|
|
|
|
|
|
|
sub start_ssh_tunnel |
|
|
|
|
{ |
|
|
|
|
my $parameters = shift; |
|
|
|
|
my $server_uuid = $parameters->{server_uuid}; |
|
|
|
|
my $host_name = $parameters->{host_name}; |
|
|
|
|
my $host_uuid = $parameters->{host_uuid}; |
|
|
|
|
my $ws_host_name = $parameters->{ws_host_name}; |
|
|
|
|
my $ws_host_uuid = $parameters->{ws_host_uuid}; |
|
|
|
|
my $ws_source_port = $parameters->{ws_source_port}; |
|
|
|
|
my $ssh_tunnel_forward_port = $parameters->{ssh_tunnel_forward_port}; |
|
|
|
|
my $parameters = shift; |
|
|
|
|
my $server_uuid = $parameters->{server_uuid}; |
|
|
|
|
my $host_name = $parameters->{host_name}; |
|
|
|
|
my $host_uuid = $parameters->{host_uuid}; |
|
|
|
|
my $ws_host_name = $parameters->{ws_host_name}; |
|
|
|
|
my $ws_host_uuid = $parameters->{ws_host_uuid}; |
|
|
|
|
my $ws_dest_port = $parameters->{ws_dest_port}; |
|
|
|
|
my $ssh_tunnel_dest_port = $parameters->{ssh_tunnel_dest_port}; |
|
|
|
|
my $ssh_tunnel_info; |
|
|
|
|
|
|
|
|
|
my $ssh_tunnel_exists_info = is_ssh_tunnel_exists({ |
|
|
|
|
server_uuid => $server_uuid, |
|
|
|
|
ssh_tunnel_host_uuid => $host_uuid, |
|
|
|
|
ws_host_uuid => $ws_host_uuid, |
|
|
|
|
ws_source_port => $ws_source_port |
|
|
|
|
ws_dest_port => $ws_dest_port |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
if ($ssh_tunnel_exists_info->{exists_code} == 2) |
|
|
|
|
{ |
|
|
|
|
$ssh_tunnel_info = {}; |
|
|
|
|
$ssh_tunnel_info->{pid} = $ssh_tunnel_exists_info->{ssh_tunnel_pid}; |
|
|
|
|
$ssh_tunnel_info->{forward_port} = $ssh_tunnel_exists_info->{ssh_tunnel_forward_port}; |
|
|
|
|
$ssh_tunnel_info->{forward_port} = $ssh_tunnel_exists_info->{ssh_tunnel_dest_port}; |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
if (not defined $ssh_tunnel_forward_port) |
|
|
|
|
if (not defined $ssh_tunnel_dest_port) |
|
|
|
|
{ |
|
|
|
|
if (defined $ssh_tunnel_exists_info->{ssh_tunnel_forward_port}) |
|
|
|
|
if (defined $ssh_tunnel_exists_info->{ssh_tunnel_dest_port}) |
|
|
|
|
{ |
|
|
|
|
$ssh_tunnel_forward_port = $ssh_tunnel_exists_info->{ssh_tunnel_forward_port}; |
|
|
|
|
$ssh_tunnel_dest_port = $ssh_tunnel_exists_info->{ssh_tunnel_dest_port}; |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
$ssh_tunnel_forward_port = $ws_source_port; |
|
|
|
|
$ssh_tunnel_dest_port = $ws_dest_port; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
$ssh_tunnel_forward_port = get_available_port({ start_port => $ssh_tunnel_forward_port }); |
|
|
|
|
$ssh_tunnel_dest_port = get_available_port({ start_port => $ssh_tunnel_dest_port }); |
|
|
|
|
|
|
|
|
|
$anvil->Log->variables({ source => $THIS_FILE, line => __LINE__, level => 2, list => { |
|
|
|
|
ssh_tunnel_forward_port => $ssh_tunnel_forward_port |
|
|
|
|
ssh_tunnel_dest_port => $ssh_tunnel_dest_port |
|
|
|
|
}, prefix => "start_ssh_tunnel" }); |
|
|
|
|
|
|
|
|
|
if (not defined $ssh_tunnel_forward_port) |
|
|
|
|
if (not defined $ssh_tunnel_dest_port) |
|
|
|
|
{ |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
my $shell_call = $anvil->data->{path}{exe}{'striker-open-ssh-tunnel'} |
|
|
|
|
." --remote-user admin --target ".$ws_host_name |
|
|
|
|
." --forward-local-port ".$ssh_tunnel_forward_port |
|
|
|
|
." --forward-remote-port ".$ws_source_port |
|
|
|
|
." --forward-local-port ".$ssh_tunnel_dest_port |
|
|
|
|
." --forward-remote-port ".$ws_dest_port |
|
|
|
|
." &>/dev/null & echo pid:\$!"; |
|
|
|
|
|
|
|
|
|
my ($shell_output, $shell_error, $shell_return_code) = call({ host_name => $host_name, shell_call => $shell_call }); |
|
|
|
@ -529,7 +553,7 @@ sub start_ssh_tunnel |
|
|
|
|
|
|
|
|
|
$ssh_tunnel_info = {}; |
|
|
|
|
$ssh_tunnel_info->{pid} = $ssh_tunnel_pid; |
|
|
|
|
$ssh_tunnel_info->{forward_port} = $ssh_tunnel_forward_port; |
|
|
|
|
$ssh_tunnel_info->{forward_port} = $ssh_tunnel_dest_port; |
|
|
|
|
|
|
|
|
|
if ($ssh_tunnel_exists_info->{exists_code} == 1) |
|
|
|
|
{ |
|
|
|
@ -567,10 +591,11 @@ CREATE TABLE IF NOT EXISTS public.vnc_pipes ( |
|
|
|
|
server_vnc_port numeric, |
|
|
|
|
ws_host_uuid uuid, |
|
|
|
|
ws_pid numeric, |
|
|
|
|
ws_source_port numeric, |
|
|
|
|
ws_dest_port numeric, |
|
|
|
|
ssh_tunnel_dest_port numeric, |
|
|
|
|
ssh_tunnel_host_uuid uuid, |
|
|
|
|
ssh_tunnel_pid numeric, |
|
|
|
|
ssh_tunnel_forward_port numeric, |
|
|
|
|
ssh_tunnel_source_port numeric, |
|
|
|
|
modified_date timestamp with time zone not null, |
|
|
|
|
unique(server_uuid, ws_host_uuid) |
|
|
|
|
);"; |
|
|
|
@ -592,14 +617,15 @@ sub insert_or_update_vnc_pipe |
|
|
|
|
|
|
|
|
|
return (1) if (not defined $server_uuid); |
|
|
|
|
|
|
|
|
|
my $server_vnc_port = $parameters->{server_vnc_port}; |
|
|
|
|
my $ssh_tunnel_forward_port = $parameters->{ssh_tunnel_forward_port}; |
|
|
|
|
my $ssh_tunnel_host_uuid = $parameters->{ssh_tunnel_host_uuid}; |
|
|
|
|
my $ssh_tunnel_pid = $parameters->{ssh_tunnel_pid}; |
|
|
|
|
my $vnc_pipe_uuid = $parameters->{vnc_pipe_uuid} // $anvil->Get->uuid(); |
|
|
|
|
my $ws_host_uuid = $parameters->{ws_host_uuid}; |
|
|
|
|
my $ws_pid = $parameters->{ws_pid}; |
|
|
|
|
my $ws_source_port = $parameters->{ws_source_port}; |
|
|
|
|
my $server_vnc_port = $parameters->{server_vnc_port}; |
|
|
|
|
my $ssh_tunnel_dest_port = $parameters->{ssh_tunnel_dest_port}; |
|
|
|
|
my $ssh_tunnel_host_uuid = $parameters->{ssh_tunnel_host_uuid}; |
|
|
|
|
my $ssh_tunnel_pid = $parameters->{ssh_tunnel_pid}; |
|
|
|
|
my $ssh_tunnel_source_port = $parameters->{ssh_tunnel_source_port}; |
|
|
|
|
my $vnc_pipe_uuid = $parameters->{vnc_pipe_uuid} // $anvil->Get->uuid(); |
|
|
|
|
my $ws_host_uuid = $parameters->{ws_host_uuid}; |
|
|
|
|
my $ws_pid = $parameters->{ws_pid}; |
|
|
|
|
my $ws_dest_port = $parameters->{ws_dest_port}; |
|
|
|
|
|
|
|
|
|
$anvil->Log->variables({ source => $THIS_FILE, line => __LINE__, level => 2, list => $parameters, prefix => "insert_or_update_vnc_pipe" }); |
|
|
|
|
|
|
|
|
@ -614,10 +640,11 @@ sub insert_or_update_vnc_pipe |
|
|
|
|
"server_vnc_port", |
|
|
|
|
"ws_host_uuid", |
|
|
|
|
"ws_pid", |
|
|
|
|
"ws_source_port", |
|
|
|
|
"ws_dest_port", |
|
|
|
|
"ssh_tunnel_dest_port", |
|
|
|
|
"ssh_tunnel_host_uuid", |
|
|
|
|
"ssh_tunnel_pid", |
|
|
|
|
"ssh_tunnel_forward_port" |
|
|
|
|
"ssh_tunnel_source_port" |
|
|
|
|
) |
|
|
|
|
{ |
|
|
|
|
my $column_value = $parameters->{$column_name}; |
|
|
|
@ -649,6 +676,45 @@ INSERT INTO public.vnc_pipes ( |
|
|
|
|
modified_date = $quoted_vnc_pipe_mdate;"; |
|
|
|
|
|
|
|
|
|
$anvil->Database->write({ query => $query, source => $THIS_FILE, line => __LINE__ }); |
|
|
|
|
|
|
|
|
|
return (0); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
sub clear_vnc_pipe_ws |
|
|
|
|
{ |
|
|
|
|
my $parameters = shift; |
|
|
|
|
my $server_uuid = $parameters->{server_uuid}; |
|
|
|
|
my $ws_host_uuid = $parameters->{ws_host_uuid}; |
|
|
|
|
|
|
|
|
|
return (1) if (not defined $ws_host_uuid); |
|
|
|
|
|
|
|
|
|
insert_or_update_vnc_pipe({ |
|
|
|
|
server_uuid => $server_uuid, |
|
|
|
|
server_vnc_port => "NULL", |
|
|
|
|
ws_dest_port => "NULL", |
|
|
|
|
ws_host_uuid => $ws_host_uuid, |
|
|
|
|
ws_pid => "NULL" |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
return (0); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
sub clear_vnc_pipe_st |
|
|
|
|
{ |
|
|
|
|
my $parameters = shift; |
|
|
|
|
my $server_uuid = $parameters->{server_uuid}; |
|
|
|
|
my $ws_host_uuid = $parameters->{ws_host_uuid}; |
|
|
|
|
|
|
|
|
|
return (1) if (not defined $ws_host_uuid); |
|
|
|
|
|
|
|
|
|
insert_or_update_vnc_pipe({ |
|
|
|
|
server_uuid => $server_uuid, |
|
|
|
|
ssh_tunnel_dest_port => "NULL", |
|
|
|
|
ssh_tunnel_host_uuid => "NULL", |
|
|
|
|
ssh_tunnel_pid => "NULL", |
|
|
|
|
ssh_tunnel_source_port => "NULL", |
|
|
|
|
ws_host_uuid => $ws_host_uuid |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
sub get_vnc_pipe |
|
|
|
@ -658,56 +724,62 @@ sub get_vnc_pipe |
|
|
|
|
|
|
|
|
|
return if (not defined $server_uuid); |
|
|
|
|
|
|
|
|
|
my $is_ws_pid = $parameters->{is_ws_pid}; |
|
|
|
|
my $ssh_tunnel_host_uuid = $parameters->{ssh_tunnel_host_uuid}; |
|
|
|
|
my $ws_host_uuid = $parameters->{ws_host_uuid}; |
|
|
|
|
|
|
|
|
|
my $vnc_pipe_info; |
|
|
|
|
|
|
|
|
|
my $cond_ws_pid = defined $is_ws_pid |
|
|
|
|
? "AND a.ws_pid IS NOT NULL" : ""; |
|
|
|
|
my $cond_ssht_huuid = defined $ssh_tunnel_host_uuid |
|
|
|
|
? "AND ssh_tunnel_host_uuid = ".$anvil->Database->quote($ssh_tunnel_host_uuid) : ""; |
|
|
|
|
? "AND a.ssh_tunnel_host_uuid = ".$anvil->Database->quote($ssh_tunnel_host_uuid) : ""; |
|
|
|
|
my $cond_ws_huuid = defined $ws_host_uuid |
|
|
|
|
? "AND ws_host_uuid = ".$anvil->Database->quote($ws_host_uuid) : ""; |
|
|
|
|
? "AND a.ws_host_uuid = ".$anvil->Database->quote($ws_host_uuid) : ""; |
|
|
|
|
|
|
|
|
|
my $query = " |
|
|
|
|
SELECT |
|
|
|
|
vnc.server_vnc_port, |
|
|
|
|
hos.host_name, |
|
|
|
|
vnc.ws_host_uuid, |
|
|
|
|
vnc.ws_pid, |
|
|
|
|
vnc.ws_source_port, |
|
|
|
|
vnc.ssh_tunnel_host_uuid, |
|
|
|
|
vnc.ssh_tunnel_pid, |
|
|
|
|
vnc.ssh_tunnel_forward_port |
|
|
|
|
a.server_vnc_port, |
|
|
|
|
b.host_name, |
|
|
|
|
a.ws_host_uuid, |
|
|
|
|
a.ws_pid, |
|
|
|
|
a.ws_dest_port, |
|
|
|
|
a.ssh_tunnel_host_uuid, |
|
|
|
|
a.ssh_tunnel_pid, |
|
|
|
|
a.ssh_tunnel_dest_port |
|
|
|
|
FROM |
|
|
|
|
public.vnc_pipes AS vnc |
|
|
|
|
public.vnc_pipes AS a |
|
|
|
|
JOIN |
|
|
|
|
public.hosts AS hos |
|
|
|
|
public.hosts AS b |
|
|
|
|
ON |
|
|
|
|
vnc.ws_host_uuid = hos.host_uuid |
|
|
|
|
a.ws_host_uuid = b.host_uuid |
|
|
|
|
WHERE |
|
|
|
|
server_uuid = ".$anvil->Database->quote($server_uuid)." |
|
|
|
|
$cond_ws_pid |
|
|
|
|
$cond_ssht_huuid |
|
|
|
|
$cond_ws_huuid |
|
|
|
|
ORDER BY |
|
|
|
|
vnc.modified_date DESC |
|
|
|
|
a.modified_date DESC |
|
|
|
|
;"; |
|
|
|
|
|
|
|
|
|
my $results = $anvil->Database->query({ query => $query, source => $THIS_FILE, line => __LINE__ }); |
|
|
|
|
my $count = @{$results}; |
|
|
|
|
|
|
|
|
|
$anvil->Log->variables({ source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query, count => $count }, prefix => "get_vnc_pipe" }); |
|
|
|
|
|
|
|
|
|
if ($count == 1) |
|
|
|
|
{ |
|
|
|
|
my $row = $results->[0]; |
|
|
|
|
|
|
|
|
|
$vnc_pipe_info = {}; |
|
|
|
|
$vnc_pipe_info->{server_vnc_port} = $row->[0]; |
|
|
|
|
$vnc_pipe_info->{host_name} = $row->[1]; |
|
|
|
|
$vnc_pipe_info->{ws_host_uuid} = $row->[2]; |
|
|
|
|
$vnc_pipe_info->{ws_pid} = $row->[3]; |
|
|
|
|
$vnc_pipe_info->{ws_source_port} = $row->[4]; |
|
|
|
|
$vnc_pipe_info->{ssh_tunnel_host_uuid} = $row->[5]; |
|
|
|
|
$vnc_pipe_info->{ssh_tunnel_pid} = $row->[6]; |
|
|
|
|
$vnc_pipe_info->{ssh_tunnel_forward_port} = $row->[7]; |
|
|
|
|
$vnc_pipe_info = {}; |
|
|
|
|
$vnc_pipe_info->{server_vnc_port} = $row->[0]; |
|
|
|
|
$vnc_pipe_info->{host_name} = $row->[1]; |
|
|
|
|
$vnc_pipe_info->{ws_host_uuid} = $row->[2]; |
|
|
|
|
$vnc_pipe_info->{ws_pid} = $row->[3]; |
|
|
|
|
$vnc_pipe_info->{ws_dest_port} = $row->[4]; |
|
|
|
|
$vnc_pipe_info->{ssh_tunnel_host_uuid} = $row->[5]; |
|
|
|
|
$vnc_pipe_info->{ssh_tunnel_pid} = $row->[6]; |
|
|
|
|
$vnc_pipe_info->{ssh_tunnel_dest_port} = $row->[7]; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
$anvil->Log->variables({ source => $THIS_FILE, line => __LINE__, level => 2, list => $vnc_pipe_info, prefix => "get_vnc_pipe" }); |
|
|
|
@ -753,7 +825,7 @@ sub open_ws |
|
|
|
|
server_vnc_port => $vnc_info->{port}, |
|
|
|
|
ws_host_uuid => $server_info->{host_uuid}, |
|
|
|
|
ws_pid => $ws_info->{pid}, |
|
|
|
|
ws_source_port => $ws_info->{source_port} |
|
|
|
|
ws_dest_port => $ws_info->{source_port} |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -776,13 +848,7 @@ sub close_ws |
|
|
|
|
|
|
|
|
|
stop_websockify({ host_name => $vnc_pipe_info->{host_name}, ws_pid => $vnc_pipe_info->{ws_pid} }); |
|
|
|
|
|
|
|
|
|
insert_or_update_vnc_pipe({ |
|
|
|
|
server_uuid => $server_uuid, |
|
|
|
|
server_vnc_port => "NULL", |
|
|
|
|
ws_host_uuid => $vnc_pipe_info->{ws_host_uuid}, |
|
|
|
|
ws_pid => "NULL", |
|
|
|
|
ws_source_port => "NULL" |
|
|
|
|
}); |
|
|
|
|
clear_vnc_pipe_ws({ server_uuid => $server_uuid, ws_host_uuid => $vnc_pipe_info->{ws_host_uuid} }); |
|
|
|
|
|
|
|
|
|
return (0); |
|
|
|
|
} |
|
|
|
@ -801,16 +867,16 @@ sub open_st |
|
|
|
|
|
|
|
|
|
return (1, "error_0313") if (not defined $server_info); |
|
|
|
|
|
|
|
|
|
my $vnc_pipe_info = get_vnc_pipe({ server_uuid => $server_uuid, ws_host_uuid => $server_info->{host_uuid} }); |
|
|
|
|
my $vnc_pipe_info = get_vnc_pipe({ is_ws_pid => 1, server_uuid => $server_uuid, ws_host_uuid => $server_info->{host_uuid} }); |
|
|
|
|
|
|
|
|
|
return (1, "error_0317") if (not defined $vnc_pipe_info); |
|
|
|
|
|
|
|
|
|
my $ssh_tunnel_info = start_ssh_tunnel({ |
|
|
|
|
server_uuid => $server_uuid, |
|
|
|
|
host_uuid => $host_uuid, |
|
|
|
|
ws_host_name => $vnc_pipe_info->{host_name}, |
|
|
|
|
ws_host_uuid => $vnc_pipe_info->{ws_host_uuid}, |
|
|
|
|
ws_source_port => $vnc_pipe_info->{ws_source_port} |
|
|
|
|
server_uuid => $server_uuid, |
|
|
|
|
host_uuid => $host_uuid, |
|
|
|
|
ws_host_name => $vnc_pipe_info->{host_name}, |
|
|
|
|
ws_host_uuid => $vnc_pipe_info->{ws_host_uuid}, |
|
|
|
|
ws_dest_port => $vnc_pipe_info->{ws_dest_port} |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
return (1, "error_0316") if (not defined $ssh_tunnel_info); |
|
|
|
@ -818,11 +884,12 @@ sub open_st |
|
|
|
|
if ($ssh_tunnel_info->{is_new} or $ssh_tunnel_info->{is_update}) |
|
|
|
|
{ |
|
|
|
|
insert_or_update_vnc_pipe({ |
|
|
|
|
server_uuid => $server_uuid, |
|
|
|
|
ssh_tunnel_host_uuid => $host_uuid, |
|
|
|
|
ssh_tunnel_pid => $ssh_tunnel_info->{pid}, |
|
|
|
|
ssh_tunnel_forward_port => $ssh_tunnel_info->{forward_port}, |
|
|
|
|
ws_host_uuid => $vnc_pipe_info->{ws_host_uuid} |
|
|
|
|
server_uuid => $server_uuid, |
|
|
|
|
ssh_tunnel_dest_port => $ssh_tunnel_info->{forward_port}, |
|
|
|
|
ssh_tunnel_host_uuid => $host_uuid, |
|
|
|
|
ssh_tunnel_pid => $ssh_tunnel_info->{pid}, |
|
|
|
|
ssh_tunnel_source_port => $vnc_pipe_info->{ws_dest_port}, |
|
|
|
|
ws_host_uuid => $vnc_pipe_info->{ws_host_uuid} |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -852,104 +919,11 @@ sub close_st |
|
|
|
|
|
|
|
|
|
stop_ssh_tunnel({ ssh_tunnel_pid => $vnc_pipe_info->{ssh_tunnel_pid} }); |
|
|
|
|
|
|
|
|
|
insert_or_update_vnc_pipe({ |
|
|
|
|
server_uuid => $server_uuid, |
|
|
|
|
ssh_tunnel_host_uuid => "NULL", |
|
|
|
|
ssh_tunnel_pid => "NULL", |
|
|
|
|
ssh_tunnel_forward_port => "NULL", |
|
|
|
|
ws_host_uuid => $vnc_pipe_info->{ws_host_uuid} |
|
|
|
|
}); |
|
|
|
|
clear_vnc_pipe_st({ server_uuid => $server_uuid, ws_host_uuid => $vnc_pipe_info->{ws_host_uuid} }); |
|
|
|
|
|
|
|
|
|
return (0); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
sub handle_vnc_pipe_error |
|
|
|
|
{ |
|
|
|
|
my $error_key = shift; |
|
|
|
|
my $parameters = shift; |
|
|
|
|
my $host_uuid = $parameters->{host_uuid}; |
|
|
|
|
my $server_uuid = $parameters->{server_uuid}; |
|
|
|
|
|
|
|
|
|
$anvil->Log->entry({ source => $THIS_FILE, line => __LINE__, level => 1, key => $error_key, variables => { |
|
|
|
|
server_uuid => $server_uuid, |
|
|
|
|
host_uuid => $host_uuid |
|
|
|
|
} }); |
|
|
|
|
|
|
|
|
|
$anvil->Job->update_progress({ |
|
|
|
|
progress => 100, |
|
|
|
|
message => "$error_key,!!server_uuid!$server_uuid!!,!!host_uuid!$host_uuid!!", |
|
|
|
|
job_status => "failed" |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
sub open_vnc_pipe |
|
|
|
|
{ |
|
|
|
|
my $parameters = shift; |
|
|
|
|
my $host_uuid = $parameters->{host_uuid}; |
|
|
|
|
my $is_print = $parameters->{print}; |
|
|
|
|
my $server_host_uuid = $parameters->{server_host_uuid}; |
|
|
|
|
my $server_uuid = $parameters->{server_uuid}; |
|
|
|
|
my $server_vnc_port = $parameters->{server_vnc_port}; |
|
|
|
|
|
|
|
|
|
my $is_error; |
|
|
|
|
my $open_output; |
|
|
|
|
|
|
|
|
|
my $open_params = { |
|
|
|
|
host_uuid => $host_uuid, |
|
|
|
|
print => $is_print, |
|
|
|
|
server_info => get_server_info($parameters), |
|
|
|
|
server_uuid => $server_uuid, |
|
|
|
|
server_vnc_port => $server_vnc_port |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
($is_error, $open_output) = open_ws($open_params); |
|
|
|
|
|
|
|
|
|
return handle_vnc_pipe_error($open_output, $open_params) if ($is_error); |
|
|
|
|
|
|
|
|
|
($is_error, $open_output) = open_st($open_params); |
|
|
|
|
|
|
|
|
|
return handle_vnc_pipe_error($open_output, $open_params) if ($is_error); |
|
|
|
|
|
|
|
|
|
$anvil->Job->update_progress({ |
|
|
|
|
progress => 100, |
|
|
|
|
message => "message_0260,!!operation!opening!!,!!server_uuid!".$server_uuid."!!,!!host_uuid!".$host_uuid."!!" |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
return (0, { forward_port => $open_params->{forward_port} }); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
sub close_vnc_pipe |
|
|
|
|
{ |
|
|
|
|
my $parameters = shift; |
|
|
|
|
my $host_uuid = $parameters->{host_uuid}; |
|
|
|
|
my $server_uuid = $parameters->{server_uuid}; |
|
|
|
|
|
|
|
|
|
my $is_error; |
|
|
|
|
my $close_output; |
|
|
|
|
|
|
|
|
|
my $close_params = { |
|
|
|
|
host_uuid => $host_uuid, |
|
|
|
|
server_uuid => $server_uuid, |
|
|
|
|
vnc_pipe_info => get_vnc_pipe({ |
|
|
|
|
server_uuid => $server_uuid, |
|
|
|
|
ssh_tunnel_host_uuid => $host_uuid |
|
|
|
|
}) |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
($is_error, $close_output) = close_ws($close_params); |
|
|
|
|
|
|
|
|
|
return handle_vnc_pipe_error($close_output, $close_params) if ($is_error); |
|
|
|
|
|
|
|
|
|
($is_error, $close_output) = close_st($close_params); |
|
|
|
|
|
|
|
|
|
return handle_vnc_pipe_error($close_output, $close_params) if ($is_error); |
|
|
|
|
|
|
|
|
|
$anvil->Job->update_progress({ |
|
|
|
|
progress => 100, |
|
|
|
|
message => "message_0260,!!operation!closing!!,!!server_uuid!".$server_uuid."!!,!!host_uuid!".$host_uuid."!!" |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
$anvil->Get->switches; |
|
|
|
|
|
|
|
|
|
$anvil->Database->connect; |
|
|
|
@ -1036,7 +1010,6 @@ $anvil->Log->variables({ source => $THIS_FILE, line => __LINE__, level => 2, lis |
|
|
|
|
} }); |
|
|
|
|
|
|
|
|
|
my $map_to_operation = { |
|
|
|
|
all => { close => \&close_vnc_pipe, open => \&open_vnc_pipe }, |
|
|
|
|
st => { close => \&close_st, open => \&open_st }, |
|
|
|
|
ws => { close => \&close_ws, open => \&open_ws }, |
|
|
|
|
}; |
|
|
|
@ -1055,14 +1028,39 @@ if ($server_uuid =~ /[a-f0-9]{8}-[a-f0-9]{4}-[1-5][a-f0-9]{3}-[89ab][a-f0-9]{3}- |
|
|
|
|
|
|
|
|
|
$anvil->Log->variables({ source => $THIS_FILE, line => __LINE__, level => 2, list => { operation => $op } }); |
|
|
|
|
|
|
|
|
|
my ($is_error) = $ops->{$op}({ |
|
|
|
|
host_uuid => $anvil->data->{sys}{host_uuid}, |
|
|
|
|
my $host_uuid = $anvil->data->{sys}{host_uuid}; |
|
|
|
|
|
|
|
|
|
my ($is_error, $error) = $ops->{$op}({ |
|
|
|
|
host_uuid => $host_uuid, |
|
|
|
|
server_host_uuid => $server_host_uuid, |
|
|
|
|
server_uuid => $server_uuid, |
|
|
|
|
server_vnc_port => $server_vnc_port |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
$anvil->nice_exit({ exit_code => 2 }) if ($is_error); |
|
|
|
|
if ($is_error) |
|
|
|
|
{ |
|
|
|
|
$anvil->Log->variables({ source => $THIS_FILE, line => __LINE__, level => 1, list => { |
|
|
|
|
error => $error, |
|
|
|
|
host_uuid => $host_uuid, |
|
|
|
|
server_uuid => $server_uuid |
|
|
|
|
} }); |
|
|
|
|
|
|
|
|
|
if (defined $error and $error =~ /^error_/) |
|
|
|
|
{ |
|
|
|
|
$anvil->Job->update_progress({ |
|
|
|
|
progress => 100, |
|
|
|
|
message => "$error,!!server_uuid!$server_uuid!!,!!host_uuid!$host_uuid!!", |
|
|
|
|
job_status => "failed" |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
$anvil->nice_exit({ exit_code => 2 }); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
$anvil->Job->update_progress({ |
|
|
|
|
progress => 100, |
|
|
|
|
message => "message_0260,!!operation!$op!!,!!server_uuid!$server_uuid!!,!!host_uuid!$host_uuid!!" |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
elsif ($is_drop_table) |
|
|
|
|
{ |
|
|
|
|