Merge pull request #235 from ClusterLabs/anvil-tools-dev

Anvil tools dev
main
Digimer 2 years ago committed by GitHub
commit 64458198b3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 3
      Anvil/Tools.pm
  2. 2
      Anvil/Tools/DRBD.pm
  3. 10
      Anvil/Tools/Database.pm
  4. 18
      Anvil/Tools/Get.pm
  5. 4175
      Anvil/Tools/Network.pm
  6. 31
      Anvil/Tools/Server.pm
  7. 2
      Anvil/Tools/Storage.pm
  8. 314
      Anvil/Tools/System.pm
  9. 65
      notes
  10. 70
      ocf/alteeve/server
  11. 5
      scancore-agents/Makefile.am
  12. 13
      scancore-agents/scan-server/scan-server
  13. 34
      share/words.xml
  14. 15
      tools/Makefile.am
  15. 9
      tools/anvil-daemon
  16. 358
      tools/anvil-manage-firewall
  17. 4
      tools/anvil-migrate-server
  18. 6
      tools/anvil-provision-server
  19. 15
      tools/striker-parse-oui
  20. 113
      tools/striker-prep-database

@ -1043,6 +1043,7 @@ sub _set_paths
pxe_grub => "/var/lib/tftpboot/grub.cfg",
postfix_main => "/etc/postfix/main.cf",
postfix_relay_password => "/etc/postfix/relay_password",
'qemu.conf' => "/etc/libvirt/qemu.conf",
ssh_config => "/etc/ssh/ssh_config",
'type.striker' => "/etc/anvil/type.striker",
'type.dr' => "/etc/anvil/type.dr",
@ -1169,7 +1170,7 @@ sub _set_paths
ip => "/usr/sbin/ip",
'ipmi-oem' => "/usr/sbin/ipmi-oem",
ipmitool => "/usr/bin/ipmitool",
### NOTE: When System->manage_firewall() is done, search for and replace all
### NOTE: When Network->manage_firewall() is done, search for and replace all
### instances where iptables is called and replace with firewall-cmd
### calls
iptables => "/usr/sbin/iptables",

@ -2023,7 +2023,7 @@ sub manage_resource
}
}
# If we 'adjust'ed abovem this will likely complain that the backing disk already exists, and that's
# If we 'adjust'ed above, this will likely complain that the backing disk already exists, and that's
# fine.
my $shell_call = $anvil->data->{path}{exe}{drbdadm}." ".$task." ".$resource;
my $output = "";

@ -1154,12 +1154,7 @@ sub configure_pgsql
}
# Make sure the psql TCP port is open.
$anvil->data->{database}{$uuid}{port} = 5432 if not $anvil->data->{database}{$uuid}{port};
my $port_status = $anvil->System->manage_firewall({
task => "open",
port_number => $anvil->data->{database}{$uuid}{port},
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { port_status => $port_status }});
$anvil->Network->manage_firewall({debug => $debug});
return(0);
}
@ -14322,8 +14317,9 @@ sub load_database
my $start_time = time;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { start_time => $start_time }});
### TODO: Replace this with System->manage_firewall().
# Throw up the firewall. Have the open call ready in case we hit an error.
$anvil->Network->manage_firewall({debug => $debug});
### TODO: Delete this when done with manage_firewall().
my $block_call = $anvil->data->{path}{exe}{iptables}." -I INPUT -p tcp --dport 5432 -j REJECT";
my $open_call = $anvil->data->{path}{exe}{iptables}." -D INPUT -p tcp --dport 5432 -j REJECT";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { block_call => $block_call }});

@ -769,7 +769,9 @@ sub bridges
my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3;
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0125", variables => { method => "Get->bridges()" }});
my ($output, $return_code) = $anvil->System->call({shell_call => $anvil->data->{path}{exe}{bridge}." -json -details link show"});
my $shell_call = $anvil->data->{path}{exe}{bridge}." -json -details link show";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { shell_call => $shell_call }});
my ($output, $return_code) = $anvil->System->call({shell_call => $shell_call});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
output => $output,
return_code => $return_code,
@ -899,13 +901,19 @@ sub bridges
my $type = "interface";
my $interface = $hash_ref->{ifname};
my $master_bridge = $hash_ref->{master};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
interface => $interface,
master_bridge => $master_bridge,
}});
$anvil->data->{$host}{network}{bridges}{bridge}{$master_bridge}{found} = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"${host}::network::bridges::bridge::${master_bridge}::found" => $anvil->data->{$host}{network}{bridges}{bridge}{$master_bridge}{found},
}});
if ($interface eq $master_bridge)
{
$type = "bridge";
$anvil->data->{$host}{network}{bridges}{bridge}{$interface}{found} = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"${host}::network::bridges::bridge::${interface}::found" => $anvil->data->{$host}{network}{bridges}{bridge}{$interface}{found},
}});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { type => $type }});
}
else
{

File diff suppressed because it is too large Load Diff

@ -200,6 +200,9 @@ sub boot_virsh
host => $anvil->data->{server}{location}{$server}{host_name},
}});
# Make sure the VNC port is open.
$anvil->Network->manage_firewall({debug => $debug});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "sys::database::connections" => $anvil->data->{sys}{database}{connections} }});
if ($anvil->data->{sys}{database}{connections})
{
@ -1102,6 +1105,34 @@ WHERE
}
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { migration_command => $migration_command }});
# Register a job for the peer so it can update its firewall once the target is created.
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"sys::database::connections" => $anvil->data->{sys}{database}{connections}
}});
if ($anvil->data->{sys}{database}{connections})
{
my $target_host_uuid = $anvil->Get->host_uuid_from_name({
debug => $debug,
host_name => $target,
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { target_host_uuid => $target_host_uuid }});
if ($target_host_uuid)
{
my ($job_uuid) = $anvil->Database->insert_or_update_jobs({
file => $THIS_FILE,
line => __LINE__,
job_command => $anvil->data->{path}{exe}{'anvil-manage-firewall'}.$anvil->Log->switches,
job_data => "server=".$server,
job_name => "manage::firewall",
job_title => "job_0399",
job_description => "job_0400",
job_progress => 0,
job_host_uuid => $target_host_uuid,
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { job_uuid => $job_uuid }});
}
}
# Call the migration now
my ($output, $return_code) = $anvil->System->call({shell_call => $migration_command});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {

@ -3607,7 +3607,7 @@ This is the name of the file to read. When reading from a remote machine, it mus
=head3 force_read (optional, default '1')
This is an otpional parameter that, if set to C<< 0 >>, will allow an existing cached copy of the file to be used instead of actually reading the file from disk (again).
This is an optional parameter that, if set to C<< 0 >>, will allow an existing cached copy of the file to be used instead of actually reading the file from disk (again).
=head3 password (optional)

@ -3475,6 +3475,7 @@ sub check_firewall
# Show live or permanent rules? Permanent is default
my $permanent = defined $parameter->{permanent} ? $parameter->{permanent} : 1;
my $start = defined $parameter->{start} ? $parameter->{start} : 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { permanent => $permanent }});
# Read in /etc/firewalld/firewalld.conf and parse the 'DefaultZone' variable.
@ -3654,319 +3655,6 @@ sub manage_authorized_keys
return(0);
}
=head2 manage_firewall
This method manages a firewalld firewall.
B<NOTE>: This is pretty basic at this time. Capabilities will be added over time so please expect changes to this method.
Parameters;
=head3 task (optional)
If set to C<< open >>, it will open the corresponding C<< port >>. If set to C<< close >>, it will close the corresponding C<< port >>. If set to c<< check >>, the state of the given C<< port >> is returned.
The default is C<< check >>.
=head3 port_number (required)
This is the port number to work on.
If not specified, C<< service >> is required.
=head3 protocol (optional)
This can be c<< tcp >> or C<< upd >> and is used to specify what protocol to use with the C<< port >>, when specified. The default is C<< tcp >>.
=cut
### TODO: This is slooooow. We need to be able to get more data per system call.
### - Getting better...
sub manage_firewall
{
my $self = shift;
my $parameter = shift;
my $anvil = $self->parent;
my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3;
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0125", variables => { method => "System->manage_firewall()" }});
my $task = defined $parameter->{task} ? $parameter->{task} : "check";
my $port_number = defined $parameter->{port_number} ? $parameter->{port_number} : "";
my $protocol = defined $parameter->{protocol} ? $parameter->{protocol} : "tcp";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
task => $task,
port_number => $port_number,
protocol => $protocol,
}});
### NOTE: Disabled during development
return(0);
# Make sure we have a port or service.
if (not $port_number)
{
# ...
return("!!error!!");
}
if (($protocol ne "tcp") && ($protocol ne "udp"))
{
# Bad protocol
return("!!error!!");
}
# This will be set if the port is found to be open.
my $open = 0;
# Checking the iptables rules in memory is very fast, relative to firewall-cmd. So we'll do an
# initial check there to see if the port in question is listed.
my $shell_call = $anvil->data->{path}{exe}{'iptables-save'};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { shell_call => $shell_call }});
my ($iptables, $return_code) = $anvil->System->call({debug => $debug, shell_call => $shell_call});
foreach my $line (split/\n/, $iptables)
{
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { line => $line }});
if (($line =~ /-m $protocol /) && ($line =~ /--dport $port_number /) && ($line =~ /ACCEPT/))
{
$open = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { 'open' => $open }});
last;
}
}
# If the port is open and the task is 'check' or 'open', we're done and can return now and save a lot
# of time.
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { 'task' => $task, 'open' => $open }});
if ((($task eq "check") or ($task eq "open")) && ($open))
{
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { 'open' => $open }});
return($open);
}
# Make sure firewalld is running.
my $firewalld_running = $anvil->System->check_daemon({daemon => $anvil->data->{sys}{daemon}{firewalld}});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { firewalld_running => $firewalld_running }});
if (not $firewalld_running)
{
if ($anvil->data->{sys}{daemons}{restart_firewalld})
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0127"});
my $return_code = $anvil->System->start_daemon({daemon => $anvil->data->{sys}{daemon}{firewalld}});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { return_code => $return_code }});
if ($return_code)
{
# non-0 means something went wrong.
return("!!error!!");
}
}
else
{
# We've been asked to leave it off.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0128"});
return(0);
}
}
# Before we do anything, what zone is active?
my $active_zone = "";
if (not $active_zone)
{
my $shell_call = $anvil->data->{path}{exe}{'firewall-cmd'}." --get-active-zones";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { shell_call => $shell_call }});
my ($output, $return_code) = $anvil->System->call({debug => $debug, shell_call => $shell_call});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { output => $output, return_code => $return_code }});
foreach my $line (split/\n/, $output)
{
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { line => $line }});
if ($line !~ /\s/)
{
$active_zone = $line;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { active_zone => $active_zone }});
}
last;
}
}
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { active_zone => $active_zone }});
# If I still don't know what the active zone is, we're done.
if (not $active_zone)
{
return("!!error!!");
}
# If we have an active zone, see if the requested port is open.
my $zone_file = $anvil->data->{path}{directories}{firewalld_zones}."/".$active_zone.".xml";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { zone_file => $zone_file }});
if (not -e $zone_file)
{
#...
return($open);
}
# Read the XML to see what services are opened already and translate those into port numbers and
# protocols.
local $@;
my $open_services = [];
my $xml = XML::Simple->new();
my $body = "";
my $test = eval { $body = $xml->XMLin($zone_file, KeyAttr => { language => 'name', key => 'name' }, ForceArray => [ 'service' ]) };
if (not $test)
{
chomp $@;
my $error = "[ Error ] - The was a problem reading: [$zone_file]. The error was:\n";
$error .= "===========================================================\n";
$error .= $@."\n";
$error .= "===========================================================\n";
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", raw => $error});
# Clear the error so it doesn't propogate out to a future 'die' and confuse things.
$@ = '';
}
else
{
# Parse the already-opened services
foreach my $hash_ref (@{$body->{service}})
{
# Load the details of this service.
my $service = $hash_ref->{name};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { service => $service }});
$anvil->System->_load_specific_firewalld_zone({service => $hash_ref->{name}});
push @{$open_services}, $service;
}
# Now loop through the open services, protocols and ports looking for the one passed in by
# the caller. If found, the port is already open.
foreach my $service (sort {$a cmp $b} @{$open_services})
{
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { service => $service }});
foreach my $this_protocol ("tcp", "udp")
{
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { this_protocol => $this_protocol }});
foreach my $this_port (sort {$a cmp $b} @{$anvil->data->{firewalld}{zones}{by_name}{$service}{tcp}})
{
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { this_port => $this_port }});
if (($port_number eq $this_port) && ($this_protocol eq $protocol))
{
# Opened already (as the recorded service).
$open = $service;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { 'open' => $open }});
last if $open;
}
last if $open;
}
last if $open;
}
last if $open;
}
}
# We're done if we were just checking. However, if we've been asked to open a currently closed port,
# or vice versa, make the change before returning.
my $changed = 0;
if (($task eq "open") && (not $open))
{
# Map the port to a service, if possible.
my $service = $anvil->System->_match_port_to_service({port => $port_number});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { service => $service }});
# Open the port
if ($service)
{
my $shell_call = $anvil->data->{path}{exe}{'firewall-cmd'}." --permanent --add-service ".$service;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { shell_call => $shell_call }});
my ($output, $return_code) = $anvil->System->call({debug => $debug, shell_call => $shell_call});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { output => $output, return_code => $return_code }});
if ($output eq "success")
{
$open = 1;
$changed = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { 'open' => $open, changed => $changed }});
}
else
{
# Something went wrong...
return("!!error!!");
}
}
else
{
my $shell_call = $anvil->data->{path}{exe}{'firewall-cmd'}." --permanent --add-port ".$port_number."/".$protocol;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { shell_call => $shell_call }});
my ($output, $return_code) = $anvil->System->call({debug => $debug, shell_call => $shell_call});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { output => $output, return_code => $return_code }});
if ($output eq "success")
{
$open = 1;
$changed = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { 'open' => $open, changed => $changed }});
}
else
{
# Something went wrong...
return("!!error!!");
}
}
}
elsif (($task eq "close") && ($open))
{
# Map the port to a service, if possible.
my $service = $anvil->System->_match_port_to_service({port => $port_number});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { service => $service }});
# Close the port
if ($service)
{
my $shell_call = $anvil->data->{path}{exe}{'firewall-cmd'}." --permanent --remove-service ".$service;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { shell_call => $shell_call }});
my ($output, $return_code) = $anvil->System->call({debug => $debug, shell_call => $shell_call});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { output => $output, return_code => $return_code }});
if ($output eq "success")
{
$open = 0;
$changed = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { 'open' => $open, changed => $changed }});
}
else
{
# Something went wrong...
return("!!error!!");
}
}
else
{
my $shell_call = $anvil->data->{path}{exe}{'firewall-cmd'}." --permanent --remove-port ".$port_number."/".$protocol;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { shell_call => $shell_call }});
my ($output, $return_code) = $anvil->System->call({debug => $debug, shell_call => $shell_call});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { output => $output, return_code => $return_code }});
if ($output eq "success")
{
$open = 0;
$changed = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { 'open' => $open, changed => $changed }});
}
else
{
# Something went wrong...
return("!!error!!");
}
}
}
# If we made a change, reload.
if ($changed)
{
$anvil->System->reload_daemon({daemon => $anvil->data->{sys}{daemon}{firewalld}});
}
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { 'open' => $open }});
return($open);
}
=head2 pids
This parses C<< ps aux >> and stores the information about running programs in C<< pids::<pid_number>::<data> >>. If called against a remote host, the data is stored in C<< remote_pids::<pid_number>::<data> >>.

65
notes

@ -7,6 +7,24 @@ dnf -y update && dnf -y install https://www.alteeve.com/an-repo/m3/anvil-release
dnf -y update && dnf -y install https://www.alteeve.com/an-repo/m3/anvil-release-latest.noarch.rpm && alteeve-repo-setup -y && dnf -y install anvil-dr --allowerasing
### Currently set default zone;
# Doesn't seem to matter - /etc/firewalld/firewalld.conf:6:DefaultZone=public
firewall-cmd --get-default-zone
# public
firewall-cmd --permanent --set-default-zone=IFN1
firewall-cmd --permanent --new-zone="IFN1"
firewall-cmd --permanent --zone=IFN1 --set-description="Internet-Facing Network 1"
firewall-cmd --permanent --zone=IFN1 --set-short="IFN1"
firewall-cmd --permanent --zone=IFN1 --add-interface=ifn1_bond1
firewall-cmd --permanent --zone=IFN1 --add-service=ssh
firewall-cmd --permanent --zone=IFN1 --add-service=postgresql
firewall-cmd --permanent --zone=IFN1 --add-port=22869/tcp
firewall-cmd --reload
# Configure APC PDUs and UPSes
tcpip -i 10.201.2.3 -s 255.255.0.0 -g 10.201.255.254
web -h enable
@ -15,6 +33,13 @@ snmp -S enable -c1 private -a1 writeplus
snmp -S enable -c2 public -a2 writeplus
/root/ci-tools/ci-destroy-anvil-bm-vm
/root/ci-tools/ci-setup-anvil-bm-vm rhel-8 ci ci
watch 'echo "striker 1"; ssh root@an-striker01 "grep ^database /etc/anvil/anvil.conf | grep host"; echo "striker 2"; ssh root@an-striker02 "grep ^database /etc/anvil/anvil.conf | grep host"; echo "node 1"; ssh root@an-a01n01 "grep ^database /etc/anvil/anvil.conf | grep host"; echo "node 2"; ssh root@an-a01n02 "grep ^database /etc/anvil/anvil.conf | grep host"; echo "dr 1"; ssh root@an-a01dr01 "grep ^database /etc/anvil/anvil.conf | grep host";'
Anvil! to Anvil! live migration;
1. Create LVs
2. Make sure /etc/hosts is populated
@ -66,18 +91,6 @@ export python=python3
============
DISABLE KSM!
- https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/7/html/virtualization_tuning_and_optimization_guide/chap-ksm
NEXT; -
RHEL 8 package changes:
chrony replaces ntp
cockpit replaces virt-manager (deprecated)
e1000e replaces e1000 driver
tmux replaces screen
iproute2 replaces bridge-utils (See "ip link" and man bridge.)
==] UEFI Setup [======================================================================
ignoredisk --only-use=vdb,vda
@ -120,6 +133,9 @@ x = Network;
- SN = 100 + network
ie: SN1 = 10.101.y.z
SN2 = 10.102.y.z
- MN = 199 (only 1, always back-to-back between nodes 1 and 2)
ie: MN1 = 10.199.y.z
y = Device Type.
Foudation Pack;
@ -149,14 +165,29 @@ RHEL 8 Firewall
=============================
### Nodes
* BCN Ports
TCP 22 sshd
TCP 2224 pcsd It is crucial to open port 2224 in such a way that pcs from any node can talk to all nodes in the cluster, including itself.
UDP 5404 corosync Required on corosync nodes if corosync is configured for multicast UDP
UDP 5405 corosync Required on all corosync nodes (needed by corosync)
TCP 5900+ vnc
TCP 49152-49215 virsh live migration - migration_port_min and migration_port_max attributes in the /etc/libvirt/qemu.conf
* SN Ports (Pull ports from DRBD resource config)
TCP 7788+ drbd 1 port per resource
* IFN Ports
TCP 22 sshd
MN Ports
TCP 49152-49215 virsh mn live migration - migration_port_min and migration_port_max attributes in the /etc/libvirt/qemu.conf
Ports we care about
Porto Number Used by Nets Description
TCP 2224 pcsd bcn It is crucial to open port 2224 in such a way that pcs from any node can talk to all nodes in the cluster, including itself.
UDP 5404 corosync bcn Required on corosync nodes if corosync is configured for multicast UDP
UDP 5405 corosync bcn Required on all corosync nodes (needed by corosync)
TCP 7788+ drbd sn 1 port per resource
TCP 49152-49215 virsh bcn live migration - migration_port_min and migration_port_max attributes in the /etc/libvirt/qemu.conf
NOTE: DHCP listens to raw sockets and ignores firewalld rules. We need to stop dhcpd directly - https://kb.isc.org/docs/aa-00378

@ -260,7 +260,11 @@ if ($anvil->data->{switches}{migrate_to})
}
elsif ($anvil->data->{switches}{migrate_from})
{
# This is called after a migration is complete, so we're basically just doing a status check.
# This is called after a migration is complete, so we're basically just doing a status check. In case
# the TCP port isn't open in the firewall yet though, we'll check that now.
$anvil->Network->manage_firewall();
# Now do the status check.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0529", variables => { server => $anvil->data->{environment}{OCF_RESKEY_name} }});
server_status($anvil);
}
@ -748,6 +752,9 @@ sub start_drbd_resource
}
# If auto-promote isn't set, promote the resource.
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"drbd::config::${local_host}::auto-promote" => $anvil->data->{drbd}{config}{$local_host}{'auto-promote'},
}});
if (not $anvil->data->{drbd}{config}{$local_host}{'auto-promote'})
{
foreach my $resource (sort {$a cmp $b} keys %{$anvil->data->{server}{$local_host}{$server}{resource}})
@ -756,6 +763,7 @@ sub start_drbd_resource
server => $server,
resource => $resource,
}});
# Make the local resource primary.
$anvil->DRBD->manage_resource({
resource => $resource,
@ -765,39 +773,42 @@ sub start_drbd_resource
}
}
### NOTE: We always check the peer now, in case it's resource is down and ours happens to be up.
# See if we're inconsistent and, if so, if we can connect our peers.
sleep 2;
$anvil->DRBD->get_status({debug => 3});
my $peer_startup_needed = 1;
foreach my $resource (sort {$a cmp $b} keys %{$anvil->data->{server}{$local_host}{$server}{resource}})
if (0)
{
# Is the current resource up locally already?
my $role = defined $anvil->data->{drbd}{status}{$host}{resource}{$resource}{role} ? $anvil->data->{drbd}{status}{$host}{resource}{$resource}{role} : "";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
's1:resource' => $resource,
's2:role' => $role,
}});
# Check all volumes.
foreach my $volume (sort {$a cmp $b} keys %{$anvil->data->{drbd}{status}{$host}{resource}{$resource}{devices}{volume}})
sleep 2;
$anvil->DRBD->get_status({debug => 3});
my $peer_startup_needed = 1;
foreach my $resource (sort {$a cmp $b} keys %{$anvil->data->{server}{$local_host}{$server}{resource}})
{
my $disk_state = defined $anvil->data->{drbd}{status}{$host}{resource}{$resource}{devices}{volume}{$volume}{'disk-state'} ? $anvil->data->{drbd}{status}{$host}{resource}{$resource}{devices}{volume}{$volume}{'disk-state'} : "";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { disk_state => $disk_state }});
# Is the current resource up locally already?
my $role = defined $anvil->data->{drbd}{status}{$host}{resource}{$resource}{role} ? $anvil->data->{drbd}{status}{$host}{resource}{$resource}{role} : "";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
's1:resource' => $resource,
's2:role' => $role,
}});
if ((lc($disk_state) eq "consistent") or
(lc($disk_state) eq "outdated") or
(lc($disk_state) eq "failed") or
(not $disk_state))
# Check all volumes.
foreach my $volume (sort {$a cmp $b} keys %{$anvil->data->{drbd}{status}{$host}{resource}{$resource}{devices}{volume}})
{
# This will trigger trying to ssh into peer(s) and up'ing their resource.
$peer_startup_needed = 0;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { peer_startup_needed => $peer_startup_needed }});
last;
my $disk_state = defined $anvil->data->{drbd}{status}{$host}{resource}{$resource}{devices}{volume}{$volume}{'disk-state'} ? $anvil->data->{drbd}{status}{$host}{resource}{$resource}{devices}{volume}{$volume}{'disk-state'} : "";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { disk_state => $disk_state }});
if ((lc($disk_state) eq "consistent") or
(lc($disk_state) eq "outdated") or
(lc($disk_state) eq "failed") or
(not $disk_state))
{
# This will trigger trying to ssh into peer(s) and up'ing their resource.
$peer_startup_needed = 0;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { peer_startup_needed => $peer_startup_needed }});
last;
}
}
}
}
### NOTE: We always check the peer now, in case it's resource is down and ours happens to be up.
# Do we need to start the resource on our peers?
#$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { peer_startup_needed => $peer_startup_needed }});
#if (not $peer_startup_needed)
@ -806,7 +817,7 @@ sub start_drbd_resource
# return(0);
#}
# Start DRBD on the peer(s).
# Start DRBD on the peer(s), if we can.
foreach my $resource (sort {$a cmp $b} keys %{$anvil->data->{server}{$local_host}{$server}{resource}})
{
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { resource => $resource }});
@ -867,7 +878,7 @@ sub start_drbd_resource
my $all_resources_ok = 1;
foreach my $resource (sort {$a cmp $b} keys %{$anvil->data->{server}{$local_host}{$server}{resource}})
{
# This is set to '1' is either the volumes are UpToDate or Sync'ing.
# This is set to '1' if either the volumes are UpToDate or Sync'ing.
$anvil->data->{drbd}{status}{$local_host}{resource}{$resource}{ok} = 0;
foreach my $volume (sort {$a cmp $b} keys %{$anvil->data->{drbd}{status}{$local_host}{resource}{$resource}{devices}{volume}})
{
@ -878,7 +889,7 @@ sub start_drbd_resource
$disk_state = "" if not defined $disk_state;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { disk_state => $disk_state }});
if ($disk_state ne "uptodate")
if ($disk_state eq "uptodate")
{
$anvil->data->{drbd}{status}{$local_host}{resource}{$resource}{devices}{volume}{$volume}{ok} = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
@ -892,7 +903,7 @@ sub start_drbd_resource
# See if we're a SyncTarget
foreach my $connection (sort {$a cmp $b} keys %{$anvil->data->{drbd}{status}{$local_host}{resource}{$resource}{connection}})
{
my $connection_state = $anvil->data->{drbd}{status}{$local_host}{resource}{$resource}{connection}{'connection-state'};
my $connection_state = $anvil->data->{drbd}{status}{$local_host}{resource}{$resource}{connection}{$connection}{'connection-state'};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
connection => $connection,
connection_state => $connection_state,
@ -948,6 +959,7 @@ sub start_drbd_resource
}
}
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { all_resources_ok => $all_resources_ok }});
if ($all_resources_ok)
{
$waiting = 0;

@ -66,6 +66,11 @@ dist_lvm_DATA = \
dist_lvm_SCRIPTS = \
scan-lvm/scan-lvm
networkdir = ${targetdir}/scan-network
dist_network_DATA = \
scan-network/scan-network.sql \
scan-network/scan-network.xml
serverdir = ${targetdir}/scan-server
dist_server_DATA = \
scan-server/scan-server.sql \

@ -311,7 +311,7 @@ sub collect_data
* Server states;
running - The domain is currently running on a CPU
idle - The domain is idle, and not running or runnable. This can be caused because the domain is waiting on IO (a traditional wait state) or has gone to sleep because there was nothing else for it to do.
paused - The domain has been paused, usually occurring through the administrator running virsh suspend. When in a paused state the domain will still consume allocated resources like memory, but will not be eligible for scheduling by the hypervisor.
paused - The domain has been paused. This can happen when a server is migrating to this host, or through the administrator running virsh suspend. When in a paused state the domain will still consume allocated resources like memory, but will not be eligible for scheduling by the hypervisor.
in shutdown - The domain is in the process of shutting down, i.e. the guest operating system has been notified and should be in the process of stopping its operations gracefully.
shut off - The domain is not running. Usually this indicates the domain has been shut down completely, or has not been started.
crashed - The domain has crashed, which is always a violent ending. Usually this state can only occur if the domain has been configured not to restart on crash.
@ -419,6 +419,9 @@ DELETED - Marks a server as no longer existing
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { server_definition_uuid => $server_definition_uuid }});
# Make sure the firewall is updated.
$anvil->Network->manage_firewall();
# Reload the servers.
$anvil->Database->get_servers();
$anvil->Database->get_server_definitions();
@ -701,6 +704,14 @@ DELETED - Marks a server as no longer existing
server_boot_time => $server_boot_time." (".$anvil->Get->date_and_time({use_time => $server_boot_time}).")",
}});
}
# If the server was migrated or booted, update the firewall. With luck, this happened
# already, so this is a back-stop mainly.
if (($old_server_state eq "migrating") or ($old_server_state eq "shut off"))
{
# Make sure the firewall is updated.
$anvil->Network->manage_firewall();
}
}
if ($server_boot_time ne $old_server_boot_time)
{

@ -1320,6 +1320,11 @@ Note: This will connect the DR host until the disk(s) on DR are (all) UpToDate.
<key name="job_0396">Still sync'ing from: [#!variable!sync_source!#] at a rate of: [#!variable!sync_speed!#/sec]. Estimated time remaining is: [#!variable!time_to_sync!#].</key>
<key name="job_0397">Sync'ed! Bringing the resource back down now.</key>
<key name="job_0398">Waiting for the connection to come up...</key>
<key name="job_0399">Manage Firewall</key>
<key name="job_0400">This will wait for the named server to appear, then update the firewall to ensure needed ports are open for access to the server's desktop.</key>
<key name="job_0401">Waiting until the server: [#!variable!server!#] appears.</key>
<key name="job_0402">[ Error ] - Timed out waiting for the server: [#!variable!server!#] to appear!</key>
<key name="job_0403">Waiting for the server: [#!variable!server!#] to appear. Will wait: [#!variable!time_left!#] more seconds.</key>
<!-- Log entries -->
<key name="log_0001">Starting: [#!variable!program!#].</key>
@ -2090,7 +2095,7 @@ The file: [#!variable!file!#] needs to be updated. The difference is:
<key name="log_0666"><![CDATA[[ Error ] - The method Database->query() was asked to query the database with UUID: [#!variable!old_uuid!#] but there is no file handle open to the database. Switched the read to: [#!variable!new_uuid!#].]]></key>
<key name="log_0667">Opening the firewall zone: [#!variable!zone!#] to allow the service: [#!variable!service!#].</key>
<key name="log_0668">No password for the database on the host with UUID: [#!variable!uuid!#], skipping it.</key>
<key name="log_0669">The firewalld daemon isn't running, skipping firewall setup.</key>
<key name="log_0669">The firewalld daemon isn't running, skipping firewall setup. Is 'sys::daemon::firewalld' set to '0' in anvil.conf?</key>
<key name="log_0670">The postgresql server is installed.</key>
<key name="log_0671">The host: [#!variable!host_name!#] was powered off for an unknown reason, and 'feature::scancore::disable::boot-unknown-stop' is set to: [#!data!feature::scancore::disable::boot-unknown-stop!#]. Will not boot this host.</key>
<key name="log_0672">The host: [#!variable!host_name!#] was powered off for an unknown reason, and 'feature::scancore::disable::boot-unknown-stop' is set to: [#!data!feature::scancore::disable::boot-unknown-stop!#]. If power and temperature looks good, we'll boot it.</key>
@ -2127,6 +2132,17 @@ The file: [#!variable!file!#] needs to be updated. The difference is:
<key name="log_0703">The timestamp has been updated from: [#!variable!old_time!#] to: [#!variable!new_time!#].</key>
<key name="log_0704"><![CDATA[[ Error ] - The method Database->read_state() was called but both the 'state_name' and 'state_uuid' parameters were not passed or both were empty.]]></key>
<key name="log_0705">Forcing the dailing resync and checking to clear records in the history schema no longer in public schema.</key>
<key name="log_0706">Updating the OUI list will happen after the system has been up for at least an hour. You can force an update now by running 'striker-parse-oui --force' at the command line.</key>
<key name="log_0707">Updated: [#!data!path::configs::firewalld.conf!#] to disable 'AllowZoneDrifting'. See: https://firewalld.org/2020/01/allowzonedrifting</key>
<key name="log_0708">Created the firewall zone: [#!variable!zone!#].</key>
<key name="log_0709">Added the interface: [#!variable!interface!#] to the firewall zone: [#!variable!zone!#].</key>
<key name="log_0710">Opening the firewall service: [#!variable!service!#] for the zone: [#!variable!zone!#]!</key>
<key name="log_0711">Closing the firewall service: [#!variable!service!#] for the zone: [#!variable!zone!#]!</key>
<key name="log_0712">Opening the firewall port: [#!variable!port!#/#!variable!protocol!#] for the zone: [#!variable!zone!#]!</key>
<key name="log_0713">Opening the firewall port range: [#!variable!port!#/#!variable!protocol!#] for the zone: [#!variable!zone!#]!</key>
<key name="log_0714">Closing the firewall port: [#!variable!port!#/#!variable!protocol!#] for the zone: [#!variable!zone!#]!</key>
<key name="log_0715">Closing the firewall port range: [#!variable!port!#/#!variable!protocol!#] for the zone: [#!variable!zone!#]!</key>
<key name="log_0716">Changes were made to the firewall, reloading now.</key>
<!-- Messages for users (less technical than log entries), though sometimes used for logs, too. -->
<key name="message_0001">The host name: [#!variable!target!#] does not resolve to an IP address.</key>
@ -2548,6 +2564,11 @@ Available options;
<key name="message_0289">#!variable!cores!#c (#!variable!threads!#t)</key>
<key name="message_0290">-=] Server Usage and Anvil! Node Resource Availability</key>
<key name="message_0291">This program is currently disabled, please see NOTE in the header for more information.</key>
<key name="message_0292"># NOTE: This was added by the Anvil!, as per firewalld's warning below.
# WARNING: AllowZoneDrifting is enabled. This is considered an insecure
# configuration option. It will be removed in a future release.
# Please consider disabling it now.</key>
<key name="message_0293">Migration Network</key>
<!-- Success messages shown to the user -->
<key name="ok_0001">Saved the mail server information successfully!</key>
@ -3225,6 +3246,17 @@ We will sleep a bit and try again.
<key name="warning_0143">[ Warning ] - While evaluating database shutdown, the host UUID: [#!variable!host_uuid!#] was not yet found in the database on host: [#!variable!db_uuid!#]. DB shutdown will not happen until all hosts are in all DBs.</key>
<key name="warning_0144">[ Warning ] - While preparing to record the state: [#!variable!state_info!#], the host UUID: [#!variable!host_uuid!#] was not yet found in the database on host: [#!variable!db_uuid!#]. NOT recording the state!</key>
<key name="warning_0145">[ Warning ] - The daemon: [#!variable!daemon!#] was found running. It shouldn't be, and will now be stopped and disabled.</key>
<key name="warning_0146">[ Warning ] - Failed to parse the firewall zone file: [#!variable!file!#]. The body of the file was:
========
#!variable!body!#
========
The error was:
========
#!variable!error!#
========
</key>
<!-- The entries below here are not sequential, but use a key to find the entry. -->
<!-- Run 'striker-parse-os-list to find new entries. -->

@ -17,8 +17,10 @@ dist_sbin_SCRIPTS = \
anvil-get-server-screenshot \
anvil-join-anvil \
anvil-maintenance-mode \
anvil-manage-dr \
anvil-manage-files \
anvil-manage-firewall \
anvil-manage-host \
anvil-manage-keys \
anvil-manage-power \
anvil-manage-server \
@ -26,16 +28,25 @@ dist_sbin_SCRIPTS = \
anvil-parse-fence-agents \
anvil-provision-server \
anvil-rename-server \
anvil-report-usage \
anvil-safe-start \
anvil-safe-stop \
anvil-scan-network \
anvil-show-local-ips \
anvil-shutdown-server \
anvil-sync-shared \
anvil-test-alerts \
anvil-update-definition \
anvil-update-issue \
anvil-update-states \
anvil-update-system \
anvil-watch-bonds \
scancore \
striker-auto-initialize-all \
striker-boot-machine \
striker-db-report \
striker-db-status \
striker-file-manager \
striker-get-peer-data \
striker-initialize-host \
striker-manage-install-target \
@ -47,9 +58,7 @@ dist_sbin_SCRIPTS = \
striker-prep-database \
striker-purge-target \
striker-scan-network \
striker-show-db-counts \
striker-auto-initialize-all \
striker-db-status
striker-show-db-counts
fencedir = ${FASEXECPREFIX}/sbin

@ -698,8 +698,8 @@ sub handle_periodic_tasks
# Now check to see if it's time to run daily tasks.
if ($now_time >= $anvil->data->{timing}{next_daily_check})
{
# Make sure ksm and ksmtuned are disabled.
foreach my $daemon ("ksm.service", "ksmtuned.service")
# Make sure ksm, ksmtuned and tuned are disabled.
foreach my $daemon ("ksm.service", "ksmtuned.service", "tuned.service")
{
my $status = $anvil->System->check_daemon({daemon => $daemon});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
@ -977,6 +977,9 @@ sub run_once
{
my ($anvil) = @_;
# Make sure the firewall is configured.
$anvil->Network->manage_firewall();
# Check that the database is ready.
prep_database($anvil);
@ -985,7 +988,7 @@ sub run_once
# Check the ssh stuff.
# NOTE: This actually runs again in the minutes tasks, but needs to run on boot as well.
$anvil->System->check_ssh_keys({debug => 2});
$anvil->System->check_ssh_keys();
# Check setuid wrappers
check_setuid_wrappers($anvil);

@ -9,9 +9,6 @@
# 2 = Failed to write or update a file.
#
# TODO:
# - TEMP: During development, firewalling is disabled.
# - Add support for enabling/disabling MASQ'ing the BCN
# - Add support for listening for NTP queries based on /etc/chrony.conf's Server entries (map them to networks / zones).
#
# # Allow routing/masq'ing through the IFN1 (provide net access to the BCN)
# firewall-cmd --zone=IFN1 --add-masquerade
@ -51,28 +48,48 @@ if (not $anvil->data->{sys}{manage}{firewall})
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 3, secure => 0, key => "log_0115", variables => { program => $THIS_FILE }});
# Read switches
$anvil->data->{switches}{'y'} = "";
$anvil->data->{switches}{'job-uuid'} = "";
$anvil->data->{switches}{server} = "";
$anvil->Get->switches;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
'switches::job-uuid' => $anvil->data->{switches}{'job-uuid'},
'switches::server' => $anvil->data->{switches}{server},
}});
# For now, we just disable the firewall, if it is enabled.
my $firewall_running = $anvil->System->check_daemon({daemon => "firewalld", debug => 3});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { firewall_running => $firewall_running }});
if ($firewall_running eq "1")
{
# Disable it.
$anvil->System->stop_daemon({daemon => "firewalld", debug => 2});
$anvil->System->disable_daemon({daemon => "firewalld", debug => 2});
}
$anvil->nice_exit({exit_code => 0});
# Log our start.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "message_0134"});
# If we've been passed a job UUID, pick up the details.
if ($anvil->data->{switches}{'job-uuid'})
{
$anvil->Job->clear();
$anvil->Job->get_job_details();
$anvil->Job->update_progress({
progress => 1,
job_picked_up_by => $$,
job_picked_up_at => time,
message => "message_0134",
});
if ($anvil->data->{jobs}{job_data} =~ /server=(.*)$/)
{
$anvil->data->{switches}{server} = $1 if not $anvil->data->{switches}{server};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
'switches::server' => $anvil->data->{switches}{server},
}});
wait_for_server($anvil);
}
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 2, key => "message_0134"});
check_initial_setup($anvil);
}
# Restart, if needed.
if ($anvil->data->{firewall}{reload})
# This used to do all the work, but that's now moved to the method below. So all we do here now is call it.
$anvil->Network->manage_firewall();
if ($anvil->data->{switches}{'job-uuid'})
{
restart_firewall($anvil);
$anvil->Job->update_progress({
progress => 100,
message => "job_0281",
});
}
# We're done
@ -83,284 +100,71 @@ $anvil->nice_exit({exit_code => 0});
# Private functions. #
#############################################################################################################
sub check_initial_setup
# This simple watches 'virsh list' until the named server appears.
sub wait_for_server
{
my ($anvil) = @_;
# See what we've found... We'll look at what 'check_firewall' finds later to know if any unused zones
# need to be removed.
my $needed_zones = [];
# This will get set if we need to restart the firewalld daemon.
$anvil->data->{firewall}{reload} = 0;
# Get a list of networks.
$anvil->Network->get_ips({debug => 3});
# Get the list of existing zones from iptables/firewalld.
$anvil->System->check_firewall({debug => 3});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "firewall::default_zone" => $anvil->data->{firewall}{default_zone} }});
my $internet_zone = "";
my $local_host = $anvil->Get->short_host_name();
foreach my $interface (sort {$a cmp $b} keys %{$anvil->data->{network}{$local_host}{interface}})
{
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { interface => $interface }});
if ($interface =~ /^((bcn|ifn|sn)\d+)_/)
{
# We'll use the start of the string (network type) as the zone, though it should
# always be overridden by the ZONE="" variable in each interface's config.
my $zone = $1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { zone => $zone }});
if ((exists $anvil->data->{network}{$local_host}{interface}{$interface}{variable}{ZONE}) && ($anvil->data->{network}{$local_host}{interface}{$interface}{variable}{ZONE}))
{
$zone = $anvil->data->{network}{$local_host}{interface}{$interface}{variable}{ZONE};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { zone => $zone }});
}
push @{$needed_zones}, $zone;
$anvil->data->{firewall}{zone}{$zone}{interface}{$interface}{ip} = $anvil->data->{network}{$local_host}{interface}{$interface}{ip};
$anvil->data->{firewall}{zone}{$zone}{interface}{$interface}{subnet_mask} = $anvil->data->{network}{$local_host}{interface}{$interface}{subnet_mask};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"firewall::zone::${zone}::interface::${interface}::ip" => $anvil->data->{firewall}{zone}{$zone}{interface}{$interface}{ip},
"firewall::zone::${zone}::interface::${interface}::subnet_mask" => $anvil->data->{firewall}{zone}{$zone}{interface}{$interface}{subnet_mask},
"network::${local_host}::interface::${interface}::default_gateway" => $anvil->data->{network}{$local_host}{interface}{$interface}{default_gateway},
}});
if ($anvil->data->{network}{$local_host}{interface}{$interface}{default_gateway})
{
$internet_zone = $zone;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { internet_zone => $internet_zone }});
if ((not $anvil->data->{firewall}{default_zone}) or ($anvil->data->{firewall}{default_zone} eq "public"))
{
$anvil->data->{firewall}{default_zone} = $zone;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "firewall::default_zone" => $anvil->data->{firewall}{default_zone} }});
}
}
}
}
# Process the list of existing zones from iptables/firewalld.
foreach my $zone (sort {$a cmp $b} keys %{$anvil->data->{firewall}{zone}})
($anvil) = @_;
$anvil->Job->update_progress({
progress => 25,
message => "job_0401,!!server!".$anvil->data->{switches}{server}."!!",
});
my $wait_until = time + 60;
my $waiting = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
wait_until => $wait_until,
}});
while($waiting)
{
my $file = exists $anvil->data->{firewall}{zone}{$zone}{file} ? $anvil->data->{firewall}{zone}{$zone}{file} : $anvil->data->{path}{directories}{firewalld_zones}."/".$zone.".xml";
my $user_file = $anvil->data->{path}{directories}{firewalld_zones_etc}."/".$zone.".xml";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"s1:zone" => $zone,
"s2:file" => $file,
"s3:user_file" => $user_file,
}});
### NOTE: This is probably overkill.
# Is this a zone I want/need?
my $wanted = 0;
foreach my $needed_zone (sort {$a cmp $b} @{$needed_zones})
{
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"s1:zone" => $zone,
"s2:needed_zone" => $needed_zone,
}});
if ($needed_zone eq $zone)
{
$wanted = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { wanted => $wanted }});
last;
}
}
# Skip if this is a zone I don't care about.
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { wanted => $wanted }});
next if not $wanted;
# Now, skip if the user-land file exists.
if (-e $user_file)
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "message_0143", variables => { zone => $zone, file => $user_file }});
next;
}
# Create or update the zone file, if needed.
my $template = "";
my $description = "";
if ($zone =~ /bcn(\d+)/i)
{
my $number = $1;
$template = "bcn_zone";
$description = $anvil->Words->string({key => "message_0131", variables => { number => $number }});
}
elsif ($zone =~ /sn(\d+)/i)
{
my $number = $1;
$template = "sn_zone";
$description = $anvil->Words->string({key => "message_0132", variables => { number => $number }});
}
elsif ($zone =~ /ifn(\d+)/i)
{
my $number = $1;
$template = "ifn_zone";
$description = $anvil->Words->string({key => "message_0133", variables => { number => $number }});
}
else
{
# This should never be hit, but it's a fail-safe in we're in a zone we don't manage.
next;
}
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"s1:template" => $template,
"s2:description" => $description,
}});
my $shell_call = $anvil->data->{path}{exe}{virsh}." list --name";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { shell_call => $shell_call }});
my $new_zone_body = $anvil->Template->get({debug => 3, file => "firewall.txt", show_name => 0, name => $template, variables => {
zone => $zone,
description => $description,
my ($output, $return_code) = $anvil->System->call({debug => 3, shell_call => $shell_call});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
's1:output' => $output,
's2:return_code' => $return_code,
}});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_zone_body => $new_zone_body }});
# This is another fail safe, don't edit unless we have a new file body.
if (not $new_zone_body)
foreach my $server (split/\n/, $output)
{
next;
}
$server = $anvil->Words->clean_spaces({string => $server});
next if not $server;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { server => $server }});
# If there isn't a body, see if the file exists. If it doesn't, create it. If it does, read it.
my $update_file = 0;
my $old_zone_body = exists $anvil->data->{firewall}{zone}{$zone}{body} ? $anvil->data->{firewall}{zone}{$zone}{body} : "";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { old_zone_body => $old_zone_body }});
if (-e $file)
{
# Has it changed?
my $diff = diff \$old_zone_body, \$new_zone_body, { STYLE => 'Unified' };
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { diff => $diff }});
if ($diff)
if ($server eq $anvil->data->{switches}{server})
{
# Update it
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "message_0136", variables => { zone => $zone, file => $file }});
$update_file = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { update_file => $update_file }});
# Found it.
$waiting = 0;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { waiting => $waiting }});
}
}
else
{
# Create it
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "message_0137", variables => { zone => $zone, file => $file }});
$update_file = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { update_file => $update_file }});
}
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { update_file => $update_file }});
if ($update_file)
if ($waiting)
{
my $error = $anvil->Storage->write_file({
file => $file,
body => $new_zone_body,
group => "root",
user => "root",
mode => "0644",
overwrite => 1,
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { error => $error }});
if ($error)
if (time > $wait_until)
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, priority => "err", key => "error_0043", variables => { file => $file }});
$anvil->nice_exit({exit_code => 2});
# timed out
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, priority => "err", key => "job_0402", variables => { server => $anvil->data->{switches}{server} }});
$anvil->Job->update_progress({
progress => 75,
message => "job_0402,!!server!".$anvil->data->{switches}{server}."!!",
});
}
else
{
# We need an immediate reload to pick up the new file.
restart_firewall($anvil);
}
}
# Make sure the appropriate interfaces are in this zone.
foreach my $interface (sort {$a cmp $b} keys %{$anvil->data->{firewall}{zone}{$zone}{interface}})
{
my $in_zone = exists $anvil->data->{firewall}{interface}{$interface}{zone} ? $anvil->data->{firewall}{interface}{$interface}{zone} : "";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"s1:interface" => $interface,
"s2:in_zone" => $in_zone,
"s3:zone" => $zone,
}});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { in_zone => $in_zone, zone => $zone }});
if ((not $in_zone) or ($zone ne $in_zone))
{
# Add it
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "message_0138", variables => {
interface => $interface,
zone => $zone,
sleep 3;
my $time_left = $wait_until - time;
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "job_0403", variables => {
server => $anvil->data->{switches}{server},
time_left => $time_left,
}});
my $shell_call = $anvil->data->{path}{exe}{'firewall-cmd'}." --zone=".$zone." --change-interface=".$interface." --permanent";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }});
my ($output, $return_code) = $anvil->System->call({debug => 2, shell_call => $shell_call});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { output => $output, return_code => $return_code }});
$shell_call = $anvil->data->{path}{exe}{'firewall-cmd'}." --zone=".$zone." --change-interface=".$interface;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }});
($output, $return_code) = $anvil->System->call({debug => 2, shell_call => $shell_call});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { output => $output, return_code => $return_code }});
$anvil->data->{firewall}{reload} = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "firewall::reload" => $anvil->data->{firewall}{reload} }});
$anvil->Job->update_progress({
progress => 50,
message => "job_0403,!!server!".$anvil->data->{switches}{server}."!!,!!time_left!".$time_left."!!",
});
}
# Delete it so we know this one has been processed.
delete $anvil->data->{firewall}{interface}{$interface};
}
}
# Do we need to update the default zone?
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
internet_zone => $internet_zone,
"firewall::default_zone" => $anvil->data->{firewall}{default_zone},
}});
if ($anvil->data->{firewall}{default_zone})
{
# What's the current default zone?
my $shell_call = $anvil->data->{path}{exe}{'firewall-cmd'}." --get-default-zone";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }});
my ($default_zone, $return_code) = $anvil->System->call({debug => 3, shell_call => $shell_call});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { default_zone => $default_zone, return_code => $return_code }});
if ($default_zone ne $anvil->data->{firewall}{default_zone})
{
# Update.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "message_0141", variables => { zone => $internet_zone }});
my $shell_call = $anvil->data->{path}{exe}{'firewall-cmd'}." --set-default-zone=".$anvil->data->{firewall}{default_zone};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }});
my ($output, $return_code) = $anvil->System->call({debug => 2, shell_call => $shell_call});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { output => $output, return_code => $return_code }});
$anvil->data->{firewall}{reload} = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "firewall::reload" => $anvil->data->{firewall}{reload} }});
}
}
# NOTE: We may want to do machine-specific stuff down the road.
my $type = $anvil->Get->host_type();
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { type => $type }});
return(0);
}
sub restart_firewall
{
my ($anvil) = @_;
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "message_0139"});
my $shell_call = $anvil->data->{path}{exe}{'firewall-cmd'}." --complete-reload";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }});
my ($output, $return_code) = $anvil->System->call({debug => 3, shell_call => $shell_call});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { output => $output, return_code => $return_code }});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 2, key => "message_0140"});
$anvil->System->restart_daemon({debug => 3, daemon => "firewalld"});
$anvil->data->{firewall}{reload} = 0;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "firewall::reload" => $anvil->data->{firewall}{reload} }});
return(0);
}

@ -7,6 +7,10 @@
# 0 = Normal exit.
# 1 = Any problem that causes an early exit.
#
# NOTE: as per qemu.conf defaults, a maximum of 63 live migrations can happen at the same time. We need to
# to count how many servers there are and, if the number is over 63, update qemu.conf. The current
# range of ports available for live migration can be found here:
# - my ($migration_minimum, $migration_maximum) = $anvil->Network->_get_live_migration_ports();
use strict;
use warnings;

@ -308,6 +308,9 @@ sub run_jobs
# Create the DRBD resource file
create_resource_file($anvil);
# Make sure the DRBD ports are open.
$anvil->Network->manage_firewall();
# Create the DRBD metadata, if needed.
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 'job::initialize_drbd' => $anvil->data->{job}{initialize_drbd} }});
create_md($anvil) if $anvil->data->{job}{initialize_drbd};
@ -328,6 +331,9 @@ sub run_jobs
provision_server($anvil);
}
# Make sure the VNC port is open.
$anvil->Network->manage_firewall();
# Add the server to the cluster.
add_server_to_cluster($anvil);

@ -152,11 +152,24 @@ sub check_if_time
my ($anvil) = @_;
# NOTE: We only scan once a day, unless 'force' is used.
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "switches::force" => $anvil->data->{switches}{force} }});
if ($anvil->data->{switches}{force})
{
return(0);
}
elsif (not $anvil->data->{switches}{'job-uuid'})
# What's the uptime? If the uptime is less than an hour, don't run.
my $uptime = $anvil->Get->uptime;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { uptime => $uptime }});
if ($uptime < 3600)
{
# Don't run.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, 'print' => 1, key => "log_0706"});
update_progress($anvil, 100, "log_0706");
$anvil->nice_exit({exit_code => 1});
}
if (not $anvil->data->{switches}{'job-uuid'})
{
# No job_uuid, so a manual call.
return(0);

@ -541,117 +541,8 @@ sub configure_firewall
{
my ($anvil) = @_;
# What zones are there?
my $in_zone = "";
my $shell_call = $anvil->data->{path}{exe}{'firewall-cmd'}." --get-active-zones";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }});
my ($output, $return_code) = $anvil->System->call({shell_call => $shell_call, debug => 2, source => $THIS_FILE, line => __LINE__});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
output => $output,
return_code => $return_code,
}});
# If the return code was 252, firewalld isn't running.
if ($return_code eq "252")
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0669"});
return(0);
}
foreach my $line (split/\n/, $output)
{
if ($line =~ /^\S/)
{
$in_zone = $line;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { in_zone => $in_zone }});
$anvil->data->{firewall}{zone}{$in_zone}{active} = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"firewall::zone::${in_zone}::active" => $anvil->data->{firewall}{zone}{$in_zone}{active},
}});
}
elsif ($line =~ /^\s+interfaces: (.*)$/)
{
my $interfaces = $1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { interfaces => $interfaces }});
$anvil->data->{firewall}{zone}{$in_zone}{interfaces} = $1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"firewall::zone::${in_zone}::interfaces" => $anvil->data->{firewall}{zone}{$in_zone}{interfaces},
}});
}
}
my $reload = 0;
foreach my $zone (sort {$a cmp $b} keys %{$anvil->data->{firewall}{zone}})
{
my $shell_call = $anvil->data->{path}{exe}{'firewall-cmd'}." --permanent --info-zone=".$zone;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }});
my ($output, $return_code) = $anvil->System->call({shell_call => $shell_call, debug => 2, source => $THIS_FILE, line => __LINE__});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
output => $output,
return_code => $return_code,
}});
foreach my $line (split/\n/, $output)
{
if ($line =~ /^\s+services: (.*)$/)
{
my $services = $1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { services => $services }});
foreach my $service (split/ /, $services)
{
$anvil->data->{firewall}{zone}{$in_zone}{service}{$service} = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"firewall::zone::${in_zone}::service::${service}" => $anvil->data->{firewall}{zone}{$in_zone}{service}{$service},
}});
}
}
}
# Is postgres open?
if ((not exists $anvil->data->{firewall}{zone}{$in_zone}{service}{postgresql}) or (not $anvil->data->{firewall}{zone}{$in_zone}{service}{postgresql}))
{
### TODO: Switch this to System->manage_firewall().
# Enable it.
my $service = "postgresql";
$reload = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
service => $service,
reload => $reload,
}});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0667", variables => {
zone => $zone,
service => $service,
}});
my $shell_call = $anvil->data->{path}{exe}{'firewall-cmd'}." --zone=".$zone." --permanent --add-service=".$service;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }});
my ($output, $return_code) = $anvil->System->call({shell_call => $shell_call, debug => 2, source => $THIS_FILE, line => __LINE__});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
output => $output,
return_code => $return_code,
}});
}
}
# Reload the firewall?
if ($reload)
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "message_0139"});
my $shell_call = $anvil->data->{path}{exe}{'firewall-cmd'}." --reload";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }});
my ($output, $return_code) = $anvil->System->call({shell_call => $shell_call, debug => 2, source => $THIS_FILE, line => __LINE__});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
output => $output,
return_code => $return_code,
}});
}
# All the firewall management is now in the method below.
$anvil->Network->manage_firewall();
return(0);
}

Loading…
Cancel
Save