mirror of
https://github.com/pragma-/pbot.git
synced 2024-11-25 13:29:29 +01:00
pbot-vm: massive refactor
* replace heartbeat with health-check * instead of steady stream of newlines every 5s, now awaits input and responds with `vmstat` output * more reliably use host/config/vm-exec.json to get libvirt domain name for snapshot-revert, server address, serial ports, vagrant setting, etc * use iptables/nftables to disable networking * added guest/bin/disable-network-[iptables,nftables] * added guest/bin/enable-network-[iptables,nftables] * replace ugly ___OUTPUT___ texts in sh, bash, ksh, zsh languages * documentation updates and tweaks
This commit is contained in:
parent
5d3f188a09
commit
17b69f04ff
9
applets/pbot-vm/guest/bin/disable-network-iptables
Executable file
9
applets/pbot-vm/guest/bin/disable-network-iptables
Executable file
@ -0,0 +1,9 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# disables all incoming, outgoing and forwarded traffic except incoming/established SSH
|
||||||
|
iptables -F
|
||||||
|
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
|
||||||
|
iptables -A INPUT -p tcp --dport 22 -j ACCEPT
|
||||||
|
iptables -P INPUT DROP
|
||||||
|
iptables -P FORWARD DROP
|
||||||
|
iptables -A OUTPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
|
||||||
|
iptables -P OUTPUT DROP
|
8
applets/pbot-vm/guest/bin/disable-network-nftables
Executable file
8
applets/pbot-vm/guest/bin/disable-network-nftables
Executable file
@ -0,0 +1,8 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# disables all incoming, outgoing and forwarded traffic except incoming/established SSH
|
||||||
|
nft add table ip filter
|
||||||
|
nft add chain ip filter INPUT '{ type filter hook input priority 0; policy drop; }'
|
||||||
|
nft add chain ip filter OUTPUT '{ type filter hook output priority 0; policy drop; }'
|
||||||
|
nft 'add rule ip filter INPUT ct state related,established counter accept'
|
||||||
|
nft 'add rule ip filter INPUT tcp dport 22 counter accept'
|
||||||
|
nft 'add rule ip filter OUTPUT ct state related,established counter accept'
|
3
applets/pbot-vm/guest/bin/enable-network-iptables
Executable file
3
applets/pbot-vm/guest/bin/enable-network-iptables
Executable file
@ -0,0 +1,3 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# removes all iptables rules to re-enable networking
|
||||||
|
iptables -F
|
3
applets/pbot-vm/guest/bin/enable-network-nftables
Executable file
3
applets/pbot-vm/guest/bin/enable-network-nftables
Executable file
@ -0,0 +1,3 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# deletes filter table to re-enable networking
|
||||||
|
nft delete table ip filter
|
@ -5,7 +5,7 @@
|
|||||||
# Purpose: PBot VM Guest server. Runs inside PBot VM Guest and processes
|
# Purpose: PBot VM Guest server. Runs inside PBot VM Guest and processes
|
||||||
# incoming VM commands from vm-exec.
|
# incoming VM commands from vm-exec.
|
||||||
|
|
||||||
# SPDX-FileCopyrightText: 2022 Pragmatic Software <pragma78@gmail.com>
|
# SPDX-FileCopyrightText: 2022-2024 Pragmatic Software <pragma78@gmail.com>
|
||||||
# SPDX-License-Identifier: MIT
|
# SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
use 5.020;
|
use 5.020;
|
||||||
@ -20,7 +20,7 @@ use constant {
|
|||||||
USERNAME => 'vm',
|
USERNAME => 'vm',
|
||||||
MOD_DIR => '/usr/local/share/pbot-vm/',
|
MOD_DIR => '/usr/local/share/pbot-vm/',
|
||||||
SERIAL => '/dev/ttyS2',
|
SERIAL => '/dev/ttyS2',
|
||||||
HEARTBEAT => '/dev/ttyS3',
|
HEALTH => '/dev/ttyS3',
|
||||||
VPORT => $ENV{PBOTVM_VPORT} // 5555,
|
VPORT => $ENV{PBOTVM_VPORT} // 5555,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -30,7 +30,6 @@ use lib MOD_DIR . "Languages";
|
|||||||
use Guest;
|
use Guest;
|
||||||
|
|
||||||
use File::Basename;
|
use File::Basename;
|
||||||
use IPC::Shareable;
|
|
||||||
|
|
||||||
my %languages;
|
my %languages;
|
||||||
|
|
||||||
@ -68,11 +67,9 @@ sub serial_server() {
|
|||||||
open(my $input, '<', SERIAL) or die $!;
|
open(my $input, '<', SERIAL) or die $!;
|
||||||
open(my $output, '>', SERIAL) or die $!;
|
open(my $output, '>', SERIAL) or die $!;
|
||||||
|
|
||||||
tie my $running, 'IPC::Shareable', { key => 'running' };
|
|
||||||
|
|
||||||
my $buffer = '';
|
my $buffer = '';
|
||||||
|
|
||||||
while ($running) {
|
while (1) {
|
||||||
my $command = Guest::read_input($input, \$buffer, 'Serial');
|
my $command = Guest::read_input($input, \$buffer, 'Serial');
|
||||||
|
|
||||||
if (not defined $command) {
|
if (not defined $command) {
|
||||||
@ -119,19 +116,20 @@ sub do_server() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sub do_heartbeat() {
|
sub do_healthcheck() {
|
||||||
open(my $heartbeat, '>', HEARTBEAT) or die $!;
|
open(my $health_in, '<', HEALTH) or die $!;
|
||||||
|
open(my $health_out, '>', HEALTH) or die $!;
|
||||||
|
|
||||||
tie my $running, 'IPC::Shareable', { key => 'running' };
|
print "Healthcheck listening on PID $$...\n";
|
||||||
|
|
||||||
print "Heart beating on PID $$...\n";
|
while (1) {
|
||||||
|
my $input = <$health_in>;
|
||||||
while ($running) {
|
my $vmstat = `vmstat`;
|
||||||
print $heartbeat "\n";
|
print $health_out "$vmstat\n";
|
||||||
sleep 5;
|
print $health_out ":END\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
print "Heart beat stopped.\n";
|
print "Healthcheck stopped.\n";
|
||||||
exit; # exit child process
|
exit; # exit child process
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -160,14 +158,10 @@ sub main() {
|
|||||||
|
|
||||||
install_signal_handlers();
|
install_signal_handlers();
|
||||||
|
|
||||||
tie my $running, 'IPC::Shareable', { key => 'running', create => 1, destroy => 1 };
|
|
||||||
|
|
||||||
$running = 1;
|
|
||||||
|
|
||||||
my $pid = fork // die "Fork failed: $!";
|
my $pid = fork // die "Fork failed: $!";
|
||||||
|
|
||||||
if ($pid == 0) {
|
if ($pid == 0) {
|
||||||
do_heartbeat();
|
do_healthcheck();
|
||||||
} else {
|
} else {
|
||||||
do_server();
|
do_server();
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
#!/bin/sh
|
#!/bin/bash
|
||||||
|
|
||||||
# File: setup-guest
|
# File: setup-guest
|
||||||
#
|
#
|
||||||
# Purpose: Sets up PBot VM Guest. Copies necessary files to the appropriate
|
# Purpose: Sets up PBot VM Guest. Copies necessary files to the appropriate
|
||||||
# location, sets up environment variables and various configuration details.
|
# location, sets up environment variables and various configuration details.
|
||||||
|
|
||||||
# SPDX-FileCopyrightText: 2022 Pragmatic Software <pragma78@gmail.com>
|
# SPDX-FileCopyrightText: 2022-2024 Pragmatic Software <pragma78@gmail.com>
|
||||||
# SPDX-License-Identifier: MIT
|
# SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
# determine OS/distribution
|
# determine OS/distribution
|
||||||
@ -56,9 +56,6 @@ cp guest/include/prelude.h /usr/include
|
|||||||
# require root password for polkit actions
|
# require root password for polkit actions
|
||||||
cp guest/polkit/* /etc/polkit-1/rules.d/
|
cp guest/polkit/* /etc/polkit-1/rules.d/
|
||||||
|
|
||||||
# disable networking
|
|
||||||
nmcli networking off
|
|
||||||
|
|
||||||
# set environment variables
|
# set environment variables
|
||||||
if ! grep -qF "pbot-vm" /root/.bashrc; then
|
if ! grep -qF "pbot-vm" /root/.bashrc; then
|
||||||
echo '# pbot-vm' >> /root/.bashrc
|
echo '# pbot-vm' >> /root/.bashrc
|
||||||
@ -66,8 +63,12 @@ if ! grep -qF "pbot-vm" /root/.bashrc; then
|
|||||||
echo export ASAN_OPTIONS=detect_leaks=0 >> /root/.bashrc
|
echo export ASAN_OPTIONS=detect_leaks=0 >> /root/.bashrc
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo PBot Guest VM is now set up.
|
export DEBUGINFOD_URLS
|
||||||
|
export ASAN_OPTIONS=detect_leaks=0
|
||||||
|
|
||||||
|
echo PBot Guest VM is set up.
|
||||||
echo
|
echo
|
||||||
echo !! Networking is now disabled. To re-enable networking run: nmcli networking on
|
echo To start PBot Guest Server: guest-server
|
||||||
echo
|
|
||||||
echo For changes to take effect, run this command now: source /root/.bashrc
|
# make environment variables take effect
|
||||||
|
exec /bin/bash
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
# Purpose: Collection of functions to interface with the PBot VM Guest and
|
# Purpose: Collection of functions to interface with the PBot VM Guest and
|
||||||
# execute VM commands.
|
# execute VM commands.
|
||||||
|
|
||||||
# SPDX-FileCopyrightText: 2022 Pragmatic Software <pragma78@gmail.com>
|
# SPDX-FileCopyrightText: 2022-2024 Pragmatic Software <pragma78@gmail.com>
|
||||||
# SPDX-License-Identifier: MIT
|
# SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
package Guest;
|
package Guest;
|
||||||
@ -22,7 +22,6 @@ use English;
|
|||||||
use Encode;
|
use Encode;
|
||||||
use File::Basename;
|
use File::Basename;
|
||||||
use JSON::XS;
|
use JSON::XS;
|
||||||
use IPC::Shareable;
|
|
||||||
use Data::Dumper;
|
use Data::Dumper;
|
||||||
|
|
||||||
sub read_input($input, $buffer, $tag) {
|
sub read_input($input, $buffer, $tag) {
|
||||||
@ -59,7 +58,13 @@ sub read_input($input, $buffer, $tag) {
|
|||||||
print STDERR "-" x 40, "\n";
|
print STDERR "-" x 40, "\n";
|
||||||
print STDERR "$tag got [$line]\n";
|
print STDERR "$tag got [$line]\n";
|
||||||
|
|
||||||
my $command = decode_json($line);
|
my $command = eval { decode_json($line) };
|
||||||
|
|
||||||
|
if ($@) {
|
||||||
|
print STDERR "Failed to decode JSON: $@\n";
|
||||||
|
return undef;
|
||||||
|
}
|
||||||
|
|
||||||
$command->{arguments} //= '';
|
$command->{arguments} //= '';
|
||||||
$command->{input} //= '';
|
$command->{input} //= '';
|
||||||
|
|
||||||
|
@ -16,10 +16,17 @@ apt install -y socat
|
|||||||
# for `cc` C language support
|
# for `cc` C language support
|
||||||
apt install -y libubsan1 libasan8 gdb gcc gcc-multilib clang
|
apt install -y libubsan1 libasan8 gdb gcc gcc-multilib clang
|
||||||
|
|
||||||
# for pbot-vm guest-server support
|
|
||||||
apt install -y --no-install-recommends libipc-shareable-perl libipc-run-perl libjson-xs-perl
|
|
||||||
|
|
||||||
# for `cc` additional languages
|
# for `cc` additional languages
|
||||||
apt install -y ksh zsh tcl lua5.4 php8.2-cli nodejs guile3.0 beef bc g++
|
apt install -y ksh zsh tcl lua5.4 php8.2-cli nodejs guile3.0 beef bc g++
|
||||||
apt install -y clisp golang-go
|
apt install -y clisp golang-go
|
||||||
apt install -y --no-install-recommends default-jre default-jdk
|
apt install -y --no-install-recommends default-jre default-jdk
|
||||||
|
|
||||||
|
# for pbot-vm guest-server support
|
||||||
|
apt install -y --no-install-recommends libipc-run-perl libjson-xs-perl
|
||||||
|
|
||||||
|
# disable networking
|
||||||
|
./guest/bin/disable-network-iptables
|
||||||
|
|
||||||
|
echo 'Networking disabled.'
|
||||||
|
echo 'To re-enable, run ./guest/bin/enable-networking-iptables'
|
||||||
|
echo 'To disable again, run ./guest/bin/disable-network-iptables'
|
||||||
|
@ -14,10 +14,16 @@ zypper -n in socat
|
|||||||
# for `cc` C language support
|
# for `cc` C language support
|
||||||
zypper -n in libubsan1 libasan8 gdb gcc gcc-32bit glibc-32bit clang
|
zypper -n in libubsan1 libasan8 gdb gcc gcc-32bit glibc-32bit clang
|
||||||
|
|
||||||
# for pbot-vm guest-server support
|
|
||||||
zypper -n in perl-IPC-Run perl-JSON-XS make cpanm
|
|
||||||
cpanm -n IPC::Shareable
|
|
||||||
|
|
||||||
# for `cc` additional languages
|
# for `cc` additional languages
|
||||||
zypper -n in ksh zsh tcl lua php8-cli nodejs-common guile bff bc gcc-c++
|
zypper -n in ksh zsh tcl lua php8-cli nodejs-common guile bff bc gcc-c++
|
||||||
zypper -n in --no-recommends clisp gcc-go java java-devel
|
zypper -n in --no-recommends clisp gcc-go java java-devel
|
||||||
|
|
||||||
|
# for pbot-vm guest-server support
|
||||||
|
zypper -n in perl-IPC-Run perl-JSON-XS
|
||||||
|
|
||||||
|
# disable networking
|
||||||
|
./guest/bin/disable-network-nftables
|
||||||
|
|
||||||
|
echo 'Networking disabled.'
|
||||||
|
echo 'To re-enable, run ./guest/bin/enable-networking-nftables'
|
||||||
|
echo 'To disable again, run ./guest/bin/disable-network-nftables'
|
||||||
|
@ -2,15 +2,18 @@
|
|||||||
|
|
||||||
# File: vm-exec
|
# File: vm-exec
|
||||||
#
|
#
|
||||||
# Purpose: Process and send commands to the PBot Guest server (guest-server) on
|
# Purpose: Process and send commands to the PBot Guest server (guest-server)
|
||||||
# the default VM socket CID/port (7/5555) or the default serial TCP port (5555).
|
# using the details from the config/vm-exec.json configuration file.
|
||||||
|
#
|
||||||
|
# Additionally, takes `-revert` and `-health` options to revert VM or check
|
||||||
|
# VM's health.
|
||||||
#
|
#
|
||||||
# Use the PBOTVM_CID, PBOTVM_VPORT and/or PBOTVM_SERIAL environment variables to
|
# Use the PBOTVM_CID, PBOTVM_VPORT and/or PBOTVM_SERIAL environment variables to
|
||||||
# override these defaults. E.g.:
|
# override the config/vm-exec.json values. E.g.:
|
||||||
#
|
#
|
||||||
# $ PBOTVM_CID=42 PBOTVM_SERIAL=7777 vm-exec -lang=sh echo test
|
# $ PBOTVM_CID=42 PBOTVM_SERIAL=7777 vm-exec -lang=sh echo test
|
||||||
|
|
||||||
# SPDX-FileCopyrightText: 2021 Pragmatic Software <pragma78@gmail.com>
|
# SPDX-FileCopyrightText: 2021-2024 Pragmatic Software <pragma78@gmail.com>
|
||||||
# SPDX-License-Identifier: MIT
|
# SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
use 5.020;
|
use 5.020;
|
||||||
@ -22,9 +25,13 @@ use feature qw(signatures);
|
|||||||
no warnings qw(experimental::signatures);
|
no warnings qw(experimental::signatures);
|
||||||
|
|
||||||
use constant {
|
use constant {
|
||||||
SERIAL => $ENV{PBOTVM_SERIAL} // 5555,
|
DOMAIN => $ENV{PBOTVM_DOMAIN} // 'pbot-vm',
|
||||||
CID => $ENV{PBOTVM_CID} // 7,
|
ADDR => $ENV{PBOTVM_ADDR} // '127.0.0.1',
|
||||||
VPORT => $ENV{PBOTVM_VPORT} // 5555,
|
SERIAL => $ENV{PBOTVM_SERIAL} // 5555,
|
||||||
|
HEALTH => $ENV{PBOTVM_HEALTH} // 5556,
|
||||||
|
CID => $ENV{PBOTVM_CID} // 7,
|
||||||
|
VPORT => $ENV{PBOTVM_VPORT} // 5555,
|
||||||
|
VAGRANT => $ENV{PBOTVM_VAGRANT} // 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
use File::Basename;
|
use File::Basename;
|
||||||
@ -64,7 +71,7 @@ sub connect_serial($context) {
|
|||||||
print STDERR "Connecting to remote VM serial port $context->{'vm-serial'}\n";
|
print STDERR "Connecting to remote VM serial port $context->{'vm-serial'}\n";
|
||||||
|
|
||||||
my $vm = IO::Socket::INET->new(
|
my $vm = IO::Socket::INET->new(
|
||||||
PeerAddr => '127.0.0.1',
|
PeerAddr => $context->{'vm-addr'},
|
||||||
PeerPort => $context->{'vm-serial'},
|
PeerPort => $context->{'vm-serial'},
|
||||||
Proto => 'tcp',
|
Proto => 'tcp',
|
||||||
Type => SOCK_STREAM
|
Type => SOCK_STREAM
|
||||||
@ -96,6 +103,12 @@ sub connect_vm($context) {
|
|||||||
sub make_context_from_args(@args_in) {
|
sub make_context_from_args(@args_in) {
|
||||||
my $args = join ' ', @args_in;
|
my $args = join ' ', @args_in;
|
||||||
|
|
||||||
|
# extract leading options
|
||||||
|
my %opts;
|
||||||
|
while ($args =~ s/^-(revert|health)\s+//) {
|
||||||
|
$opts{$1} = 1;
|
||||||
|
}
|
||||||
|
|
||||||
my $context = eval { decode_json $args };
|
my $context = eval { decode_json $args };
|
||||||
|
|
||||||
if ($@) {
|
if ($@) {
|
||||||
@ -108,8 +121,14 @@ sub make_context_from_args(@args_in) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# set extracted leading options
|
||||||
|
foreach my $opt (keys %opts) {
|
||||||
|
print STDERR "Setting option `$opt`.\n";
|
||||||
|
$context->{$opt} = 1;
|
||||||
|
}
|
||||||
|
|
||||||
# parse options specific to vm-exec
|
# parse options specific to vm-exec
|
||||||
while ($context->{code} =~ s/^-(lang|vm-cid|vm-vport|vm-serial|vm)=([^ ]+)\s*//) {
|
while ($context->{code} =~ s/^-(lang|revert|health|vm-domain|vm-health|vm-cid|vm-vport|vm-serial|vm)=([^ ]+)\s*//) {
|
||||||
my ($option, $value) = ($1, $2);
|
my ($option, $value) = ($1, $2);
|
||||||
print STDERR "Overriding `$option` to `$value`.\n";
|
print STDERR "Overriding `$option` to `$value`.\n";
|
||||||
$context->{$option} = lc $value;
|
$context->{$option} = lc $value;
|
||||||
@ -190,13 +209,17 @@ sub configure_context($context, $config) {
|
|||||||
if (not defined $entry) {
|
if (not defined $entry) {
|
||||||
my $machines = list_machines($config);
|
my $machines = list_machines($config);
|
||||||
print "Unknown machine '$machine'; available machines are: $machines\n";
|
print "Unknown machine '$machine'; available machines are: $machines\n";
|
||||||
exit 1;
|
exit 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
# override values
|
# override values
|
||||||
$context->{'vm-serial'} = $entry->{'serial'};
|
$context->{'vm-domain'} = $machine;
|
||||||
$context->{'vm-cid'} = $entry->{'cid'};
|
$context->{'vm-addr'} = $entry->{'addr'};
|
||||||
$context->{'vm-vport'} = $entry->{'vport'};
|
$context->{'vm-health'} = $entry->{'health'};
|
||||||
|
$context->{'vm-serial'} = $entry->{'serial'};
|
||||||
|
$context->{'vm-cid'} = $entry->{'cid'};
|
||||||
|
$context->{'vm-vport'} = $entry->{'vport'};
|
||||||
|
$context->{'vm-vagrant'} = $entry->{'vagrant'};
|
||||||
} else {
|
} else {
|
||||||
# otherwise configure any undefined values as default machine
|
# otherwise configure any undefined values as default machine
|
||||||
my $machine = $config->{'default-machine'};
|
my $machine = $config->{'default-machine'};
|
||||||
@ -207,22 +230,30 @@ sub configure_context($context, $config) {
|
|||||||
if (not defined $entry) {
|
if (not defined $entry) {
|
||||||
my $machines = list_machines($config);
|
my $machines = list_machines($config);
|
||||||
print "Unknown machine '$machine'; available machines are: $machines\n";
|
print "Unknown machine '$machine'; available machines are: $machines\n";
|
||||||
exit 1;
|
exit 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
# update any undefined values, preserving any existing values
|
# update any undefined values, preserving any existing values
|
||||||
$context->{'vm-serial'} //= $entry->{'serial'};
|
$context->{'vm-domain'} //= $machine;
|
||||||
$context->{'vm-cid'} //= $entry->{'cid'};
|
$context->{'vm-addr'} //= $entry->{'addr'};
|
||||||
$context->{'vm-vport'} //= $entry->{'vport'};
|
$context->{'vm-health'} //= $entry->{'health'};
|
||||||
|
$context->{'vm-serial'} //= $entry->{'serial'};
|
||||||
|
$context->{'vm-cid'} //= $entry->{'cid'};
|
||||||
|
$context->{'vm-vport'} //= $entry->{'vport'};
|
||||||
|
$context->{'vm-vagrant'} //= $entry->{'vagrant'};
|
||||||
}
|
}
|
||||||
|
|
||||||
# set any undefined values to default values
|
# set any undefined values to default values
|
||||||
$context->{nick} //= 'vm';
|
$context->{nick} //= 'vm';
|
||||||
$context->{channel} //= 'vm';
|
$context->{channel} //= 'vm';
|
||||||
$context->{lang} //= 'c2x';
|
$context->{lang} //= 'c2x';
|
||||||
$context->{'vm-serial'} //= SERIAL;
|
$context->{'vm-domain'} //= DOMAIN;
|
||||||
$context->{'vm-cid'} //= CID;
|
$context->{'vm-addr'} //= ADDR;
|
||||||
$context->{'vm-vport'} //= VPORT;
|
$context->{'vm-health'} //= HEALTH;
|
||||||
|
$context->{'vm-serial'} //= SERIAL;
|
||||||
|
$context->{'vm-cid'} //= CID;
|
||||||
|
$context->{'vm-vport'} //= VPORT;
|
||||||
|
$context->{'vm-vagrant'} //= VAGRANT;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub main() {
|
sub main() {
|
||||||
@ -232,6 +263,59 @@ sub main() {
|
|||||||
|
|
||||||
configure_context($context, $config);
|
configure_context($context, $config);
|
||||||
|
|
||||||
|
# instructed to revert machine
|
||||||
|
if ($context->{revert}) {
|
||||||
|
if (exists $config->{aliases}->{$context->{'vm-domain'}}) {
|
||||||
|
$context->{'vm-domain'} = $config->{aliases}->{$context->{'vm-domain'}};
|
||||||
|
}
|
||||||
|
|
||||||
|
print STDERR "REVERT $context->{'vm-domain'}\n";
|
||||||
|
|
||||||
|
if ($context->{'vm-vagrant'}) {
|
||||||
|
system("virsh -c qemu:///system snapshot-revert $context->{'vm-domain'} 1");
|
||||||
|
} else {
|
||||||
|
system("virsh snapshot-revert $context->{'vm-domain'} 1");
|
||||||
|
}
|
||||||
|
|
||||||
|
exit 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
# instructed to check health
|
||||||
|
if ($context->{health}) {
|
||||||
|
my $health = IO::Socket::INET->new(
|
||||||
|
PeerAddr => $context->{'vm-addr'},
|
||||||
|
PeerPort => $context->{'vm-health'},
|
||||||
|
Proto => 'tcp',
|
||||||
|
Type => SOCK_STREAM
|
||||||
|
);
|
||||||
|
|
||||||
|
if (not defined $health) {
|
||||||
|
print STDERR "Unable to connect to health $context->{'vm-addr'} $context->{'vm-health'}\n";
|
||||||
|
exit 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
print $health "\n";
|
||||||
|
|
||||||
|
|
||||||
|
eval {
|
||||||
|
alarm 2;
|
||||||
|
local $SIG{ALRM} = sub { die "Health timed-out\n"; };
|
||||||
|
|
||||||
|
while (my $output = <$health>) {
|
||||||
|
last if $output eq ":END\r\n";
|
||||||
|
print $output;
|
||||||
|
}
|
||||||
|
close $health;
|
||||||
|
};
|
||||||
|
|
||||||
|
if ($@) {
|
||||||
|
print STDERR "Failed to get health: $@\n";
|
||||||
|
exit 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
exit 0;
|
||||||
|
}
|
||||||
|
|
||||||
# load language before checking usage in order to handle -lang=? flag
|
# load language before checking usage in order to handle -lang=? flag
|
||||||
# to list languages instead of showing a usage message
|
# to list languages instead of showing a usage message
|
||||||
my $lang = load_language($context);
|
my $lang = load_language($context);
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
# listens for incoming commands from vm-client. Invokes vm-exec to send
|
# listens for incoming commands from vm-client. Invokes vm-exec to send
|
||||||
# commands to the PBot Guest Server (guest-server).
|
# commands to the PBot Guest Server (guest-server).
|
||||||
|
|
||||||
# SPDX-FileCopyrightText: 2021 Pragmatic Software <pragma78@gmail.com>
|
# SPDX-FileCopyrightText: 2021-2024 Pragmatic Software <pragma78@gmail.com>
|
||||||
# SPDX-License-Identifier: MIT
|
# SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
use 5.020;
|
use 5.020;
|
||||||
@ -25,19 +25,24 @@ use Encode;
|
|||||||
|
|
||||||
use constant {
|
use constant {
|
||||||
SERVER_PORT => $ENV{PBOTVM_PORT} // 9000,
|
SERVER_PORT => $ENV{PBOTVM_PORT} // 9000,
|
||||||
HEARTBEAT_PORT => $ENV{PBOTVM_HEART} // 5556,
|
|
||||||
DOMAIN_NAME => $ENV{PBOTVM_DOMAIN} // 'pbot-vm',
|
|
||||||
COMPILE_TIMEOUT => $ENV{PBOTVM_TIMEOUT} // 10,
|
COMPILE_TIMEOUT => $ENV{PBOTVM_TIMEOUT} // 10,
|
||||||
};
|
};
|
||||||
|
|
||||||
sub vm_revert() {
|
sub vm_revert($input) {
|
||||||
return if $ENV{PBOTVM_NOREVERT};
|
return if $ENV{PBOTVM_NOREVERT};
|
||||||
print "Reverting vm...\n";
|
print "Reverting vm...\n";
|
||||||
system('time virsh snapshot-revert '.DOMAIN_NAME.' 1');
|
execute("perl vm-exec -revert $input", 1000);
|
||||||
print "Reverted.\n";
|
print "Reverted.\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
sub execute($command) {
|
sub vm_check_health($input) {
|
||||||
|
print "Checking health...\n";
|
||||||
|
my ($ret, $result) = execute("perl vm-exec -health $input", 2);
|
||||||
|
print "$result\n" if length $result;
|
||||||
|
return ($ret, $result);
|
||||||
|
}
|
||||||
|
|
||||||
|
sub execute($command, $timeout = COMPILE_TIMEOUT) {
|
||||||
print "execute ($command)\n";
|
print "execute ($command)\n";
|
||||||
|
|
||||||
# to get $? from pipe
|
# to get $? from pipe
|
||||||
@ -53,7 +58,7 @@ sub execute($command) {
|
|||||||
my $result = eval {
|
my $result = eval {
|
||||||
my $output = '';
|
my $output = '';
|
||||||
local $SIG{ALRM} = sub { kill 9, $pid; die "Timed-out: $output\n"; };
|
local $SIG{ALRM} = sub { kill 9, $pid; die "Timed-out: $output\n"; };
|
||||||
alarm(COMPILE_TIMEOUT);
|
alarm($timeout);
|
||||||
|
|
||||||
while (my $line = decode('UTF-8', <$fh>)) {
|
while (my $line = decode('UTF-8', <$fh>)) {
|
||||||
$output .= $line;
|
$output .= $line;
|
||||||
@ -80,47 +85,6 @@ sub execute($command) {
|
|||||||
return ($ret, $result);
|
return ($ret, $result);
|
||||||
}
|
}
|
||||||
|
|
||||||
sub connect_to_heartbeat() {
|
|
||||||
my $heartbeat;
|
|
||||||
my $attempts = 15;
|
|
||||||
|
|
||||||
while (!$heartbeat && $attempts > 0) {
|
|
||||||
print "Connecting to heartbeat on port ".HEARTBEAT_PORT." ... ";
|
|
||||||
|
|
||||||
$heartbeat = IO::Socket::INET->new (
|
|
||||||
PeerAddr => '127.0.0.1',
|
|
||||||
PeerPort => HEARTBEAT_PORT,
|
|
||||||
Proto => 'tcp',
|
|
||||||
Type => SOCK_STREAM,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!$heartbeat) {
|
|
||||||
print "failed.\n";
|
|
||||||
--$attempts;
|
|
||||||
print "Trying again in 2 seconds ($attempts attempts remaining) ...\n" if $attempts > 0;
|
|
||||||
sleep 2;
|
|
||||||
} else {
|
|
||||||
print "success!\n";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $heartbeat;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub do_heartbeat() {
|
|
||||||
tie my $heartbeat, 'IPC::Shareable', { key => 'heartbeat' };
|
|
||||||
tie my $running, 'IPC::Shareable', { key => 'running' };
|
|
||||||
|
|
||||||
while ($running) {
|
|
||||||
my $heartbeat_monitor = connect_to_heartbeat();
|
|
||||||
|
|
||||||
while ($running and <$heartbeat_monitor>) {
|
|
||||||
$heartbeat = time;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub server_listen($port) {
|
sub server_listen($port) {
|
||||||
my $server = IO::Socket::INET->new (
|
my $server = IO::Socket::INET->new (
|
||||||
Proto => 'tcp',
|
Proto => 'tcp',
|
||||||
@ -135,29 +99,25 @@ sub server_listen($port) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
sub do_server() {
|
sub do_server() {
|
||||||
tie my $heartbeat, 'IPC::Shareable', { key => 'heartbeat' };
|
|
||||||
tie my $running, 'IPC::Shareable', { key => 'running' };
|
|
||||||
|
|
||||||
print "Starting PBot VM Server on port " . SERVER_PORT . "\n";
|
print "Starting PBot VM Server on port " . SERVER_PORT . "\n";
|
||||||
my $server = eval { server_listen(SERVER_PORT) };
|
my $server = eval { server_listen(SERVER_PORT) };
|
||||||
|
|
||||||
if ($@) {
|
if ($@) {
|
||||||
print STDERR $@;
|
print STDERR $@;
|
||||||
$running = 0;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
while ($running and my $client = $server->accept) {
|
while (my $client = $server->accept) {
|
||||||
print '-' x 20, "\n";
|
print '-' x 20, "\n";
|
||||||
my $hostinfo = gethostbyaddr($client->peeraddr);
|
my $hostinfo = gethostbyaddr($client->peeraddr);
|
||||||
print "Connect from ", $client->peerhost, " at ", scalar localtime, "\n";
|
print "Connect from ", $client->peerhost, " at ", scalar localtime, "\n";
|
||||||
handle_client($client, $heartbeat);
|
handle_client($client);
|
||||||
}
|
}
|
||||||
|
|
||||||
print "Shutting down server.\n";
|
print "Shutting down server.\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
sub handle_client($client, $heartbeat) {
|
sub handle_client($client) {
|
||||||
my ($timed_out, $killed) = (0, 0);
|
my ($timed_out, $killed) = (0, 0);
|
||||||
|
|
||||||
my $r = fork;
|
my $r = fork;
|
||||||
@ -177,30 +137,50 @@ sub handle_client($client, $heartbeat) {
|
|||||||
|
|
||||||
$client->autoflush(1);
|
$client->autoflush(1);
|
||||||
|
|
||||||
eval {
|
my $input = eval {
|
||||||
# give client 5 seconds to send a line
|
# give client 5 seconds to send a line
|
||||||
local $SIG{ALRM} = sub { die "Client I/O timed-out\n"; };
|
local $SIG{ALRM} = sub { die "Client I/O timed-out\n"; };
|
||||||
alarm 5;
|
alarm 5;
|
||||||
|
|
||||||
while (my $line = decode('UTF-8', <$client>)) {
|
my $input;
|
||||||
$line =~ s/[\r\n]+$//;
|
|
||||||
next if $line =~ m/^\s*$/;
|
while ($input = decode('UTF-8', <$client>)) {
|
||||||
|
$input =~ s/[\r\n]+$//;
|
||||||
|
next if $input =~ m/^\s*$/;
|
||||||
|
|
||||||
# give client 5 more seconds
|
# give client 5 more seconds
|
||||||
alarm 5;
|
alarm 5;
|
||||||
|
|
||||||
print "[$$] Read [$line]\n";
|
print "[$$] Read [$input]\n";
|
||||||
|
|
||||||
if (time - $heartbeat > 5) {
|
# check health
|
||||||
print "[$$] Lost heartbeat, ignoring compile attempt.\n";
|
my ($health, $health_message) = vm_check_health($input);
|
||||||
print $client "Virtual machine is resetting, try again soon.\n";
|
|
||||||
|
if ($health == 2) {
|
||||||
|
print "[$$] Unable to connect to VM health check, ignoring compile attempt.\n";
|
||||||
|
print $client "Virtual machine is offline.\n";
|
||||||
|
last;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($health == 1 || $health == -13) {
|
||||||
|
print "[$$] VM not responding to health check, ignoring compile attempt.\n";
|
||||||
|
print $client "Virtual machine is temporarily unavailable, try again soon.\n";
|
||||||
|
last;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($health != 0) {
|
||||||
|
if (length $health_message) {
|
||||||
|
print $client $health_message;
|
||||||
|
} else {
|
||||||
|
print $client "Virtual machine is misbehaving, try again soon.\n";
|
||||||
|
}
|
||||||
last;
|
last;
|
||||||
}
|
}
|
||||||
|
|
||||||
# disable client time-out
|
# disable client time-out
|
||||||
alarm 0;
|
alarm 0;
|
||||||
|
|
||||||
my ($ret, $result) = execute("perl vm-exec $line");
|
my ($ret, $result) = execute("perl vm-exec $input");
|
||||||
|
|
||||||
$result =~ s/\s+$//;
|
$result =~ s/\s+$//;
|
||||||
print "Ret: $ret; result: [$result]\n";
|
print "Ret: $ret; result: [$result]\n";
|
||||||
@ -217,6 +197,8 @@ sub handle_client($client, $heartbeat) {
|
|||||||
print $client encode('UTF-8', $result . "\n");
|
print $client encode('UTF-8', $result . "\n");
|
||||||
last;
|
last;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return $input;
|
||||||
};
|
};
|
||||||
|
|
||||||
# print client time-out exception
|
# print client time-out exception
|
||||||
@ -228,11 +210,11 @@ sub handle_client($client, $heartbeat) {
|
|||||||
print "[$$] timed out: $timed_out; killed: $killed\n";
|
print "[$$] timed out: $timed_out; killed: $killed\n";
|
||||||
|
|
||||||
if ($timed_out || $killed) {
|
if ($timed_out || $killed) {
|
||||||
vm_revert();
|
vm_revert($input);
|
||||||
}
|
}
|
||||||
|
|
||||||
# child done
|
# child done
|
||||||
print "[$$] client exiting\n";
|
print "[$$] client exit\n";
|
||||||
print "=" x 20, "\n";
|
print "=" x 20, "\n";
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
@ -244,23 +226,8 @@ sub main() {
|
|||||||
# let OS clean-up child exits
|
# let OS clean-up child exits
|
||||||
$SIG{CHLD} = 'IGNORE';
|
$SIG{CHLD} = 'IGNORE';
|
||||||
|
|
||||||
tie my $heartbeat, 'IPC::Shareable', { key => 'heartbeat', create => 1, destroy => 1 };
|
# start server
|
||||||
tie my $running, 'IPC::Shareable', { key => 'running', create => 1, destroy => 1 };
|
do_server();
|
||||||
|
|
||||||
$running = 1;
|
|
||||||
$heartbeat = 0;
|
|
||||||
|
|
||||||
my $heartbeat_pid = fork // die "Heartbeat fork failed: $!";
|
|
||||||
|
|
||||||
if ($heartbeat_pid == 0) {
|
|
||||||
do_heartbeat();
|
|
||||||
} else {
|
|
||||||
do_server();
|
|
||||||
}
|
|
||||||
|
|
||||||
print "Waiting for heart to stop...\n";
|
|
||||||
waitpid($heartbeat_pid, 0);
|
|
||||||
print "Heart stopped.\n";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
main();
|
main();
|
||||||
|
@ -1,21 +1,25 @@
|
|||||||
{
|
{
|
||||||
"machines" : {
|
"machines" : {
|
||||||
"pbot-vm" : {
|
"pbot-vm" : {
|
||||||
|
"addr" : "127.0.0.1",
|
||||||
"serial" : 5555,
|
"serial" : 5555,
|
||||||
"heart" : 5556,
|
"health" : 5556,
|
||||||
"cid" : 7,
|
"cid" : 7,
|
||||||
"vport" : 5555
|
"vport" : 5555,
|
||||||
|
"vagrant" : 0
|
||||||
},
|
},
|
||||||
"pbot-test-vm" : {
|
"pbot-test-vm" : {
|
||||||
|
"addr" : "127.0.0.1",
|
||||||
"serial" : 7777,
|
"serial" : 7777,
|
||||||
"heart" : 7778,
|
"health" : 7778,
|
||||||
"cid" : 42,
|
"cid" : 42,
|
||||||
"vport" : 5555
|
"vport" : 5555,
|
||||||
|
"vagrant" : 1
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"aliases" : {
|
"aliases" : {
|
||||||
"openSUSE" : "pbot-vm",
|
"main" : "pbot-vm",
|
||||||
"test" : "pbot-test-vm"
|
"test" : "pbot-test-vm"
|
||||||
},
|
},
|
||||||
"default-machine" : "openSUSE"
|
"default-machine" : "main"
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
DOMAIN="${PBOTVM_DOMAIN:-pbot-vm}"
|
DOMAIN="${PBOTVM_DOMAIN:-pbot-vm}"
|
||||||
SERIAL="${PBOTVM_SERIAL:-5555}"
|
SERIAL="${PBOTVM_SERIAL:-5555}"
|
||||||
HEART="${PBOTVM_HEART:-5556}"
|
HEALTH="${PBOTVM_HEALTH:-5556}"
|
||||||
|
|
||||||
cat > serial-2.xml <<EOF
|
cat > serial-2.xml <<EOF
|
||||||
<serial type='tcp'>
|
<serial type='tcp'>
|
||||||
@ -14,7 +14,7 @@ EOF
|
|||||||
|
|
||||||
cat > serial-3.xml <<EOF
|
cat > serial-3.xml <<EOF
|
||||||
<serial type='tcp'>
|
<serial type='tcp'>
|
||||||
<source mode='bind' host='127.0.0.1' service='$HEART' tls='no'/>
|
<source mode='bind' host='127.0.0.1' service='$HEALTH' tls='no'/>
|
||||||
<protocol type='raw'/>
|
<protocol type='raw'/>
|
||||||
<target port='3'/>
|
<target port='3'/>
|
||||||
</serial>
|
</serial>
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
#!/usr/bin/env perl
|
#!/usr/bin/env perl
|
||||||
|
|
||||||
# SPDX-FileCopyrightText: 2021 Pragmatic Software <pragma78@gmail.com>
|
# SPDX-FileCopyrightText: 2021-2024 Pragmatic Software <pragma78@gmail.com>
|
||||||
# SPDX-License-Identifier: MIT
|
# SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
use warnings;
|
use warnings;
|
||||||
@ -17,11 +17,11 @@ sub initialize {
|
|||||||
$self->{default_options} = '';
|
$self->{default_options} = '';
|
||||||
$self->{cmdline} = 'bash $options $sourcefile';
|
$self->{cmdline} = 'bash $options $sourcefile';
|
||||||
|
|
||||||
$self->{cmdline_opening_comment} = ": <<'____CMDLINE____'\n";
|
$self->{cmdline_opening_comment} = ": <<'CMDLINE'\n";
|
||||||
$self->{cmdline_closing_comment} = "____CMDLINE____\n";
|
$self->{cmdline_closing_comment} = "CMDLINE\n";
|
||||||
|
|
||||||
$self->{output_opening_comment} = ": << '____OUTPUT____'\n";
|
$self->{output_opening_comment} = ": << 'OUTPUT'\n";
|
||||||
$self->{output_closing_comment} = "____OUTPUT____\n";
|
$self->{output_closing_comment} = "OUTPUT\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
#!/usr/bin/env perl
|
#!/usr/bin/env perl
|
||||||
|
|
||||||
# SPDX-FileCopyrightText: 2021 Pragmatic Software <pragma78@gmail.com>
|
# SPDX-FileCopyrightText: 2021-2024 Pragmatic Software <pragma78@gmail.com>
|
||||||
# SPDX-License-Identifier: MIT
|
# SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
use warnings;
|
use warnings;
|
||||||
@ -17,11 +17,11 @@ sub initialize {
|
|||||||
$self->{default_options} = '';
|
$self->{default_options} = '';
|
||||||
$self->{cmdline} = 'ksh $options $sourcefile';
|
$self->{cmdline} = 'ksh $options $sourcefile';
|
||||||
|
|
||||||
$self->{cmdline_opening_comment} = ": <<'____CMDLINE____'\n";
|
$self->{cmdline_opening_comment} = ": <<'CMDLINE'\n";
|
||||||
$self->{cmdline_closing_comment} = "____CMDLINE____\n";
|
$self->{cmdline_closing_comment} = "CMDLINE\n";
|
||||||
|
|
||||||
$self->{output_opening_comment} = ": << '____OUTPUT____'\n";
|
$self->{output_opening_comment} = ": << 'OUTPUT'\n";
|
||||||
$self->{output_closing_comment} = "____OUTPUT____\n";
|
$self->{output_closing_comment} = "OUTPUT\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
#!/usr/bin/env perl
|
#!/usr/bin/env perl
|
||||||
|
|
||||||
# SPDX-FileCopyrightText: 2021 Pragmatic Software <pragma78@gmail.com>
|
# SPDX-FileCopyrightText: 2021-2024 Pragmatic Software <pragma78@gmail.com>
|
||||||
# SPDX-License-Identifier: MIT
|
# SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
use warnings;
|
use warnings;
|
||||||
@ -17,11 +17,11 @@ sub initialize {
|
|||||||
$self->{default_options} = '';
|
$self->{default_options} = '';
|
||||||
$self->{cmdline} = 'sh $options $sourcefile';
|
$self->{cmdline} = 'sh $options $sourcefile';
|
||||||
|
|
||||||
$self->{cmdline_opening_comment} = ": <<'____CMDLINE____'\n";
|
$self->{cmdline_opening_comment} = ": <<'CMDLINE'\n";
|
||||||
$self->{cmdline_closing_comment} = "____CMDLINE____\n";
|
$self->{cmdline_closing_comment} = "CMDLINE\n";
|
||||||
|
|
||||||
$self->{output_opening_comment} = ": << '____OUTPUT____'\n";
|
$self->{output_opening_comment} = ": << 'OUTPUT'\n";
|
||||||
$self->{output_closing_comment} = "____OUTPUT____\n";
|
$self->{output_closing_comment} = "OUTPUT\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
#!/usr/bin/env perl
|
#!/usr/bin/env perl
|
||||||
|
|
||||||
# SPDX-FileCopyrightText: 2021 Pragmatic Software <pragma78@gmail.com>
|
# SPDX-FileCopyrightText: 2021-2024 Pragmatic Software <pragma78@gmail.com>
|
||||||
# SPDX-License-Identifier: MIT
|
# SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
use warnings;
|
use warnings;
|
||||||
@ -17,11 +17,11 @@ sub initialize {
|
|||||||
$self->{default_options} = '';
|
$self->{default_options} = '';
|
||||||
$self->{cmdline} = 'zsh $options $sourcefile';
|
$self->{cmdline} = 'zsh $options $sourcefile';
|
||||||
|
|
||||||
$self->{cmdline_opening_comment} = ": <<'____CMDLINE____'\n";
|
$self->{cmdline_opening_comment} = ": <<'CMDLINE'\n";
|
||||||
$self->{cmdline_closing_comment} = "____CMDLINE____\n";
|
$self->{cmdline_closing_comment} = "CMDLINE\n";
|
||||||
|
|
||||||
$self->{output_opening_comment} = ": << '____OUTPUT____'\n";
|
$self->{output_opening_comment} = ": << 'OUTPUT'\n";
|
||||||
$self->{output_closing_comment} = "____OUTPUT____\n";
|
$self->{output_closing_comment} = "OUTPUT\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
@ -4,8 +4,8 @@
|
|||||||
ENV['VAGRANT_DEFAULT_PROVIDER'] = 'libvirt'
|
ENV['VAGRANT_DEFAULT_PROVIDER'] = 'libvirt'
|
||||||
|
|
||||||
PBOTVM_SERIAL = ENV['PBOTVM_SERIAL'] || 5555
|
PBOTVM_SERIAL = ENV['PBOTVM_SERIAL'] || 5555
|
||||||
PBOTVM_HEART = ENV['PBOTVM_HEART'] || 5556
|
PBOTVM_HEALTH = ENV['PBOTVM_HEALTH'] || 5556
|
||||||
PBOTVM_NAME = ENV['PBOTVM_NAME'] || 'pbot-vagrant-vm'
|
PBOTVM_DOMAIN = ENV['PBOTVM_DOMAIN'] || 'pbot-vm'
|
||||||
|
|
||||||
Vagrant.configure("2") do |config|
|
Vagrant.configure("2") do |config|
|
||||||
# Every Vagrant development environment requires a box. You can search for
|
# Every Vagrant development environment requires a box. You can search for
|
||||||
|
@ -9,47 +9,73 @@ section, then return to this guide.
|
|||||||
|
|
||||||
To install vagrant on openSUSE, use:
|
To install vagrant on openSUSE, use:
|
||||||
|
|
||||||
zypper install --no-recommends vagrant vagrant-libvirt
|
zypper install --no-recommends vagrant
|
||||||
|
|
||||||
Otherwise see https://vagrant-libvirt.github.io/vagrant-libvirt/installation.html for installation instructions for your platform.
|
Otherwise see https://vagrant-libvirt.github.io/vagrant-libvirt/installation.html for installation instructions for your platform.
|
||||||
|
|
||||||
### Install vagrant-libvirt
|
### Install vagrant-libvirt
|
||||||
|
|
||||||
If your distribution does not have a `vagrant-libvirt` package or if you need an up-to-date version use Vagrant's plugin manager:
|
|
||||||
|
|
||||||
vagrant plugin install vagrant-libvirt
|
vagrant plugin install vagrant-libvirt
|
||||||
|
|
||||||
### Start Vagrant Box
|
### Start Vagrant Box
|
||||||
|
|
||||||
To start a virtual machine, `cd` into one of the PBot-VM Vagrant sub-directories and run the following command. This will download
|
To start a virtual machine, `cd` into one of the PBot-VM Vagrant sub-directories and run the following command. This will download
|
||||||
the appropriate virtual machine image and automatically configure it as a PBot VM Guest.
|
the appropriate virtual machine image and automatically configure it as the default PBot VM Guest, `pbot-vm` described by
|
||||||
|
[`host/config/vm-exec.json`](../host/config/vm-exec.json):
|
||||||
|
|
||||||
vagrant up
|
vagrant up
|
||||||
|
|
||||||
You may pass optional environment variables to override pbot-vm default configuration (see [PBot VM Environment Variables](../../../doc/VirtualMachine.md#environment-variables)):
|
You may pass optional environment variables to override pbot-vm default configuration (see [PBot VM Environment Variables](../../../doc/VirtualMachine.md#environment-variables)).
|
||||||
|
For example, to create `pbot-test-vm` described by [`host/config/vm-exec.json`](../host/config/vm-exec.json):
|
||||||
|
|
||||||
PBOTVM_SERIAL=7777 PBOTVM_HEART=7778 vagrant up
|
PBOTVM_DOMAIN=pbot-test-vm PBOTVM_SERIAL=7777 PBOTVM_HEALTH=7778 vagrant up
|
||||||
|
|
||||||
### Connect to Vagrant Box
|
### Connect to Vagrant Box
|
||||||
|
|
||||||
|
Use SSH to connect to the PBot VM Guest:
|
||||||
|
|
||||||
vagrant ssh
|
vagrant ssh
|
||||||
|
|
||||||
|
If you specified a `PBOTVM_DOMAIN`, e.g. `pbot-test-vm`, you must specify it:
|
||||||
|
|
||||||
|
PBOTVM_DOMAIN=pbot-test-vm vagrant ssh
|
||||||
|
|
||||||
### Start PBot VM Guest Server
|
### Start PBot VM Guest Server
|
||||||
|
|
||||||
sudo guest-server
|
Once connected to the PBot VM Guest via SSH, start `guest-server` in the background:
|
||||||
|
|
||||||
|
sudo nohup guest-server &> log &
|
||||||
|
|
||||||
Some distributions may require you to specify the full path:
|
Some distributions may require you to specify the full path:
|
||||||
|
|
||||||
sudo /usr/local/bin/guest-server
|
sudo nohup /usr/local/bin/guest-server &> log &
|
||||||
|
|
||||||
|
### Disconnect from Vagrant Box
|
||||||
|
|
||||||
|
Now you can type `logout` to exit the PBot VM Guest.
|
||||||
|
|
||||||
|
### Create snapshot of PBot VM Guest
|
||||||
|
|
||||||
|
After you've logged out of the PBot VM Guest with `guest-server` running in the background, create a snapshot. This allows PBot to revert to a known good state when a command times out.
|
||||||
|
If a `PBOTVM_DOMAIN` was defined, replace `pbot-vm` with that name.
|
||||||
|
|
||||||
|
virsh -c qemu:///system snapshot-create-as pbot-vm 1
|
||||||
|
|
||||||
|
### Edit vm-exec.json
|
||||||
|
|
||||||
|
If you used `vagrant up` without specifying a `PBOTVM_DOMAIN`, you must edit the [`../host/config/vm-exec.json`](../host/config/vm-exec.json)
|
||||||
|
configuration file to set the `vagrant` value to `1` for the `pbot-vm` machine.
|
||||||
|
|
||||||
|
If you have specified a `PBOTVM_DOMAIN`, ensure the appropriate entries exist in the `vm-exec.json` configuration file.
|
||||||
|
|
||||||
|
By default, `pbot-test-vm` already has `vagrant` set to `1`.
|
||||||
|
|
||||||
### Start PBot VM Host Server
|
### Start PBot VM Host Server
|
||||||
|
|
||||||
After starting the guest-server, you must now start the host server.
|
cd ../host/bin/
|
||||||
|
./vm-server
|
||||||
../host/bin/vm-server
|
|
||||||
|
|
||||||
### Test PBot VM
|
### Test PBot VM
|
||||||
|
|
||||||
In your instance of PBot, the `sh` and `cc`, etc, commands should now produce output:
|
In your instance of PBot, the `sh` and `cc`, etc, commands should now produce output:
|
||||||
|
|
||||||
<pragma-> sh echo Hello world!
|
<pragma-> sh echo Hello world!
|
||||||
|
@ -4,15 +4,18 @@
|
|||||||
Vagrant.configure("2") do |config|
|
Vagrant.configure("2") do |config|
|
||||||
config.vm.box_check_update = false
|
config.vm.box_check_update = false
|
||||||
|
|
||||||
config.vm.hostname = PBOTVM_NAME
|
config.vm.define PBOTVM_DOMAIN
|
||||||
|
config.vm.hostname = PBOTVM_DOMAIN
|
||||||
|
|
||||||
config.vm.provider :libvirt do |libvirt|
|
config.vm.provider :libvirt do |libvirt|
|
||||||
|
libvirt.title = PBOTVM_DOMAIN
|
||||||
|
libvirt.default_prefix = ""
|
||||||
libvirt.qemuargs :value => "-chardev"
|
libvirt.qemuargs :value => "-chardev"
|
||||||
libvirt.qemuargs :value => "socket,id=charserial1,host=127.0.0.1,port=#{PBOTVM_SERIAL},server=on,wait=off"
|
libvirt.qemuargs :value => "socket,id=charserial1,host=127.0.0.1,port=#{PBOTVM_SERIAL},server=on,wait=off"
|
||||||
libvirt.qemuargs :value => "-device"
|
libvirt.qemuargs :value => "-device"
|
||||||
libvirt.qemuargs :value => '{"driver":"isa-serial","chardev":"charserial1","id":"serial1","index":2}'
|
libvirt.qemuargs :value => '{"driver":"isa-serial","chardev":"charserial1","id":"serial1","index":2}'
|
||||||
libvirt.qemuargs :value => "-chardev"
|
libvirt.qemuargs :value => "-chardev"
|
||||||
libvirt.qemuargs :value => "socket,id=charserial2,host=127.0.0.1,port=#{PBOTVM_HEART},server=on,wait=off"
|
libvirt.qemuargs :value => "socket,id=charserial2,host=127.0.0.1,port=#{PBOTVM_HEALTH},server=on,wait=off"
|
||||||
libvirt.qemuargs :value => "-device"
|
libvirt.qemuargs :value => "-device"
|
||||||
libvirt.qemuargs :value => '{"driver":"isa-serial","chardev":"charserial2","id":"serial2","index":3}'
|
libvirt.qemuargs :value => '{"driver":"isa-serial","chardev":"charserial2","id":"serial2","index":3}'
|
||||||
end
|
end
|
||||||
|
@ -4,8 +4,8 @@
|
|||||||
ENV['VAGRANT_DEFAULT_PROVIDER'] = 'libvirt'
|
ENV['VAGRANT_DEFAULT_PROVIDER'] = 'libvirt'
|
||||||
|
|
||||||
PBOTVM_SERIAL = ENV['PBOTVM_SERIAL'] || 5555
|
PBOTVM_SERIAL = ENV['PBOTVM_SERIAL'] || 5555
|
||||||
PBOTVM_HEART = ENV['PBOTVM_HEART'] || 5556
|
PBOTVM_HEALTH = ENV['PBOTVM_HEALTH'] || 5556
|
||||||
PBOTVM_NAME = ENV['PBOTVM_NAME'] || 'pbot-vagrant-vm'
|
PBOTVM_DOMAIN = ENV['PBOTVM_DOMAIN'] || 'pbot-vm'
|
||||||
|
|
||||||
Vagrant.configure("2") do |config|
|
Vagrant.configure("2") do |config|
|
||||||
# Every Vagrant development environment requires a box. You can search for
|
# Every Vagrant development environment requires a box. You can search for
|
||||||
|
@ -353,7 +353,8 @@
|
|||||||
* [Initial virtual machine set-up complete](VirtualMachine.md#initial-virtual-machine-set-up-complete)
|
* [Initial virtual machine set-up complete](VirtualMachine.md#initial-virtual-machine-set-up-complete)
|
||||||
* [Start PBot VM Host](VirtualMachine.md#start-pbot-vm-host)
|
* [Start PBot VM Host](VirtualMachine.md#start-pbot-vm-host)
|
||||||
* [Test PBot](VirtualMachine.md#test-pbot)
|
* [Test PBot](VirtualMachine.md#test-pbot)
|
||||||
* [QEMU command from libvirt](VirtualMachine.md#qemu-command-from-libvirt)
|
* [Adding additional VMs](VirtualMachine.md#adding-additional-vms)
|
||||||
|
* [QEMU command from libvirt](VirtualMachine.md#qemu-command-from-libvirt)
|
||||||
<!-- md-toc-end -->
|
<!-- md-toc-end -->
|
||||||
<!-- md-toc-begin -->
|
<!-- md-toc-begin -->
|
||||||
* [Frequently Asked Questions](FAQ.md#frequently-asked-questions)
|
* [Frequently Asked Questions](FAQ.md#frequently-asked-questions)
|
||||||
|
File diff suppressed because one or more lines are too long
@ -25,8 +25,8 @@ use PBot::Imports;
|
|||||||
# These are set by the /misc/update_version script
|
# These are set by the /misc/update_version script
|
||||||
use constant {
|
use constant {
|
||||||
BUILD_NAME => "PBot",
|
BUILD_NAME => "PBot",
|
||||||
BUILD_REVISION => 4740,
|
BUILD_REVISION => 4741,
|
||||||
BUILD_DATE => "2024-04-07",
|
BUILD_DATE => "2024-04-10",
|
||||||
};
|
};
|
||||||
|
|
||||||
sub initialize {}
|
sub initialize {}
|
||||||
|
Loading…
Reference in New Issue
Block a user