#!C:\StrawberryPerl\perl\bin\perl5.30.2.exe
###!/usr/bin/perl
###!perl
# See perldoc.perl.org for information on Perl
# # comments out a line ; / ... / comments out everything between the slashes
# Include this whenever creating code; If you want to comment it out for production, your call
use warnings;
# You may want to comment this out for production (resource usage) but use for development
use diagnostics;
# Use this to ensure you properly declare variables prior to their use and reserve space for them
use strict;
# Enable the module that will setup SSH connections
# Make sure the module is installed and if not, install it with "cpan install Net::SSH::Perl"
use Net::SSH::Perl;
# Establish Parameters for the connection and command to use for fetching the SPICE ticket
my $host = 'host_ip_address';
my $debug_flag = 1;
my $port_number = 22;
my $protocol_selection = '2,1';
my $user = 'linux_user_name_on_remote_host';
my $user_password = "linux_user_password_on_remote_host";
my $node_name = "Proxmox_node_name";
my $vm_number = number_of_virtual_machine;
my @identity_file_location = ( "C:\\path\ to\ file\\using\ windows\slashes.pem" );
# Establish Parameters for the conversion of the raw ticket to a format remoteviewer can use
# Tell the system what encoding you will be using: more necessary for read but a good habit to get into
my $encoding = ":encoding(UTF-8)";
# Set the filename and path for edited file
my $output_filename_with_path = "C:\\path\ to\ ticket\ file\\using\ windows\slashes.vv";
# identify the location of the Remote viewer application that will use the ticket / configuration file generated
# Put this inside single brackets and do NOT use \ to designate literal character
my $path_to_remoteviewer_program = 'C:\Program Files\VirtViewer v8.0-256\bin\remote-viewer.exe';
# =======================================================
# Instantiate the SSH connection object using the method enabled above NET:SSH:Perl
my $ssh_connection = Net::SSH::Perl->new( $host , debug => $debug_flag , port => $port_number , protocol => $protocol_selection , identity_files => \@identity_file_location );
# Or, to have it work with user/password (when user/password is enabled)
# my $ssh_connection = Net::SSH::Perl->new( $host , debug => 1 , port => 22 , protocol => 2 );
# Login to the remote host
$ssh_connection->login($user);
# Or, to have it work with user/password (when user/password is enabled)
# $ssh_connection->login($user,$user_password);
# Issue the command at the remote host to generate the SPICE ticket and put it into a variable called $output
# I know storing a password in a script and sending it is a security issue
# If someone else wants to use Expect or React for making an interactive script, be my guest
# This script uses key-pair to make the encrypted connection, then sends the password so I am ok with the transmission
# Yes, storage of password in a readable text file is risky; I password protect my PC and do not allow others access
my $command = ( "echo $user_password | sudo -S pvesh create /nodes/$node_name/qemu/$vm_number/spiceproxy" );
my ($output, $error_message, $exit_code) = $ssh_connection->cmd( "$command" );
# Read the raw ticket content, edit the content to match what remoteviewer is looking for
# and write the edited content to a file on the system that is hosting the script
# We will use this edited content file as the configuration settings when we launch remoteviewer
# Create the file handler, with read and/or write permission (include the $encoding as shown)
# The '>' designator tells the system this file handler is for writing
# To Read, use "< $encoding"
# To Read and Write use "+< $encoding"
# To Read and Write by deleting existing content in a file (truncating) use "+> $encoding"
# To Read and Write by appending to existing contents of a file use "+>> $encoding"
# If the file deos not already exist, it will be created
# Note: the $! system variable contains the error code for the failure. If $! is empty, there was no error
open ( my $raw_content_handler , "< $encoding" , \$output ) or die "Could not open the raw content due to $! \r\n";
open ( my $output_file_handler , "> $encoding" , $output_filename_with_path ) or die "Could not open file $output_filename_with_path due to $! \r\n";
# Bring the file contents in one line at a time
# When you use <filehandler> syntax, the <> brackets bring in the next line of a file
# When you us <STDIN>, the system assumes there will user input from STDIN and waits
# If you do not define a variable for bringing the contents in, Perl uses the system variable $_ to hold each line
# So if you use while ( <file_handler> ) without assigning it to a variable, the line will be in $_
# I prefer the explicit assignment to a variable so I use while ( my $variable = <file_handler> ) and use $variable
# This script is parsing a specific format to convert it to another specific format,
# so the sequence is unlikely to be exactly what you will want to use in your situation
# but the functions shown give you a sample of what text manipulation looks like in Perl
# Re-set the file pointer for the input file to the start of the file
# Usually not needed but a good habit to get into
seek $raw_content_handler , 0 , 0;
# Since we are creating a linux file from a Windows script,
# the newline character will be Windows and will be problematic on linux
# We need to change the $INPUT_RECORD_SEPARATOR = $/ but do not want to do that globally, just in this script
# so we put the editing functions into a subroutine and change a local version of $/
# Initialize the first line of the file (specific to this situation; normally initialize to blank)
our $edited_contents = "[virt-viewer]\n";
while ( my $file_line = <$raw_content_handler> ) {
# Delete / skip lines that have + as the first character; they are delimeter lines
if ( substr( $file_line , 0 , 1 ) eq '+' ) {
next;
# Delete / skip the second line - it is a header line
} elsif ( substr( $file_line , 0 , 5 ) eq '| key' ) {
next;
} else {
# The remaining lines have the content we want, so we will manipulate them to our format
# Delete the first two characters of each line (they are "| ")
substr( $file_line , 0 , 2 ) = '';
# Convert what was the middle | character (now the first | in the line) to an = sign
# and insert a ~ character before and after the = sign so we can hold a spot for them later
$file_line =~ s/ \| /~=~/;
# Convert all the remaining | to spaces
$file_line =~ s/\|/ /g;
# Trim white space at start and end of each line
# Remove white spaces from left side of string
$file_line =~ s/^\s+//;
# Remove white spaces from right side of string
$file_line =~ s/\s+$//;
# Remove white space between first "word" and = sign
# Make sure there is at least one space before making the edit
my $first_space_location = index( $file_line , " " , 0 );
if ( $first_space_location != -1 ) {
my $first_character_location_after_space = index($file_line , "~" , $first_space_location + 1 );
substr( $file_line , $first_space_location , $first_character_location_after_space - $first_space_location ) = '';
}
# Delete the temporary placeholder ~ characters surrounding the = sign
$file_line =~ s/\~//g;
# Replace the Windows newline \r\n with the Linux newline \n
# Remove the Windows newline
chomp $file_line;
# Save the remaining characters into the output line with the linux newline
$edited_contents .= $file_line . "\n";
}
}
# Save the edited contents into the output file
# Set the file pointer to the start of the file and erase the existing contents to create a blank file
# Not necessary for a new file but a good habit to get into IF you do not want to append to a file's contents
seek $output_file_handler , 0 , 0;
truncate $output_file_handler , 0;
# Write your edited contents to the output file
print $output_file_handler $edited_contents;
# Close the file - which will ensure that buffered content is completely written and any lock is released
close $raw_content_handler or die "Could not close the raw content holder due to $! so content may not be properly written \r\n";
close $output_file_handler or die "Could not close the file $output_filename_with_path due to $! so content may not be properly written \r\n";
# Launch the remoteviewer application using the formatted configuration file
# There will be a series of warnings generated but the viewer will launch and work
system ( "$path_to_remoteviewer_program" , "$output_filename_with_path" ) or die "Errors encountered while launching from $path_to_remoteviewer_program \r\n";
# (Use when debugging) Show that you made it to the end of the script without erroring out
# print "\r\n\r\nMade it to the end of the script!\r\n\r\n";