Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow AII to use netcat to send logfiles to kickstart syslog server #51

Merged
merged 34 commits into from Apr 24, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
82fbe03
extended kickstart tests with services
stdweird Apr 16, 2014
73e597f
modify the kickstart services
stdweird Apr 16, 2014
4fb21a6
install keyword followed by installtype
stdweird Apr 16, 2014
50df657
add end_script_field to packages section
stdweird Apr 16, 2014
1fea9de
add tests for kickstart_commands
stdweird Apr 16, 2014
1fabe77
fix typo
stdweird Apr 16, 2014
38e9312
Add pxelinux unittests
stdweird Apr 16, 2014
ce1e887
whitespace cleanup
stdweird Apr 16, 2014
28c91b6
add console and netcat logging boolean to AII ks schema
stdweird Apr 8, 2014
ff92771
use variables for logfiles, cleanup fail/success functions
stdweird Apr 8, 2014
6df6a51
factor out logaction, define extra perl variables to avoid confusing
stdweird Apr 8, 2014
acfbcf3
echo begin and end of section and ks-post-reboot
stdweird Apr 8, 2014
25a616b
add netcat log sending to syslog server
stdweird Apr 8, 2014
9a42e26
set syslogheader
stdweird Apr 10, 2014
4519759
add nc and initscripts to packages to install when netcat logging is …
stdweird Apr 10, 2014
37288a6
use awk and introduce 50ms of sleep between each line, enough to let …
stdweird Apr 10, 2014
6098c0d
add enough sleep before end to let the logger flush it all in case of…
stdweird Apr 10, 2014
6c69bea
fix typo in let usage
stdweird Apr 10, 2014
084b76a
netcat logging requires early network test
stdweird Apr 10, 2014
0daaf4f
add entry to schema for bash /dev/tcp
stdweird Apr 15, 2014
7cf5a78
add bash /dev/tcp support
stdweird Apr 15, 2014
b17941c
rework the pxe append line
stdweird Apr 15, 2014
354a72a
move generation of the append list to proper sub
stdweird Apr 15, 2014
a63789a
generate the pxe syslog and loglevel append values based on the
stdweird Apr 15, 2014
148260e
add logging kickstart unittests
stdweird Apr 17, 2014
b1c609b
add pxelinux logging unittests
stdweird Apr 17, 2014
2d9b9dc
new schema, allows to mix and match method and protocol, with single
stdweird Apr 17, 2014
a5883d3
rework code to allow mix and match protocol and method
stdweird Apr 17, 2014
88980b8
extend the logging tests
stdweird Apr 17, 2014
6690ec4
the send_aiilogs is optional (and fixes bug)
stdweird Apr 17, 2014
e6bd762
new schema makes new options mandatory but with defaults; code treats
stdweird Apr 17, 2014
9c07c0d
update the pod file
stdweird Apr 17, 2014
cb151ec
add wait_for_network unittest
stdweird Apr 17, 2014
310db92
use constant for awk command
stdweird Apr 20, 2014
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
12 changes: 12 additions & 0 deletions aii-ks/src/main/pan/quattor/aii/ks/schema.pan
Expand Up @@ -32,10 +32,22 @@ type structure_ks_ksfirewall = {
};

# Information needed for logging into syslog
# Anaconda syslog uses UDP
type structure_ks_logging = {
"host" : type_hostname
"port" : type_port = 514
"level" ? string with match(SELF, "^(debug|warning|error|critical|info)$")

"console" : boolean = true # redirect AII ks logfile to console

# send AII ks logfile to host/port
"send_aiilogs" : boolean = false

# use legacy defaults
# via bash or netcat
"method" : string = 'netcat' with match(SELF, '^(bash|netcat)$')
# via tcp or udp
"protocol" : string = 'udp' with match(SELF, '^(tcp|udp)$')
};

# Information needed for creating the Kickstart file
Expand Down
200 changes: 153 additions & 47 deletions aii-ks/src/main/perl/ks.pm
Expand Up @@ -77,6 +77,15 @@ use constant { KS => "/system/aii/osinstall/ks",
use constant MODULEBASE => "AII::";
use constant USEMODULE => "use " . MODULEBASE;

# use this syslogheader for remote AII scripts logging:
# 190 = local7.info
use constant LOG_ACTION_SYSLOGHEADER => '<190>AII: ';
# awk command to prefix LOG_ACTION_SYSLOGHEADER and
# to insert sleep (usleep by initscripts), throtlles to 40 lines per sec
use constant LOG_ACTION_AWK =>
"awk '{print \"".LOG_ACTION_SYSLOGHEADER."\"\$0; fflush(); system(\"usleep 25000 >& /dev/null\");}'";


# Configuration variable for the osinstall directory.
use constant KSDIROPT => 'osinstalldir';

Expand Down Expand Up @@ -217,7 +226,8 @@ sub kscommands
my $config = shift;

my $tree = $config->getElement(KS)->getTree;

my @packages = @{$tree->{packages}};

my $installtype = $tree->{installtype};
if ($installtype =~ /http/) {
my ($proxyhost, $proxyport, $proxytype) = proxy($config);
Expand All @@ -232,9 +242,9 @@ sub kscommands
}
print <<EOF;
install
$installtype
text
reboot
$installtype
timezone --utc $tree->{timezone}
rootpw --iscrypted $tree->{rootpw}
EOF
Expand All @@ -252,8 +262,13 @@ EOF
"--port=$tree->{logging}->{port}";
print " --level=$tree->{logging}->{level}" if $tree->{logging}->{level};
print "\n";
if(exists($tree->{logging}->{send_aiilogs}) && $tree->{logging}->{send_aiilogs}) {
# requirement for usleep
push(@packages, 'initscripts');
push(@packages, 'nc') if ($tree->{logging}->{method} eq 'netcat');
}
}
print "bootloader --location=$tree->{bootloader_location}";
print "bootloader --location=$tree->{bootloader_location}";
print " --driveorder=", join(',', @{$tree->{bootdisk_order}})
if exists $tree->{bootdisk_order} && @{$tree->{bootdisk_order}};
print " --append=\"$tree->{bootloader_append}\""
Expand Down Expand Up @@ -301,19 +316,19 @@ EOF
print "ignoredisk --drives=",
join (',', @{$tree->{ignoredisk}}), "\n";
}
print "%packages ", join(" ",@{$tree->{packages_args}}), "\n",
join ("\n", @{$tree->{packages}}), "\n";

## enable services, if any
if (exists($tree->{enable_service}) && @{$tree->{enable_service}}) {
## should be a list of strings
my $services = join(" ",@{$tree->{enable_service}});
if ($services) {
print "services --enabled=",
join (',', @{$tree->{enable_service}}), "\n";;
}
};

## disable and enable services, if any
my @services;
push(@services, "--disabled=".join(',', @{$tree->{disable_service}})) if
(exists($tree->{disable_service}) && @{$tree->{disable_service}});
push(@services, "--enabled=".join(',', @{$tree->{enable_service}})) if
(exists($tree->{enable_service}) && @{$tree->{enable_service}});

print "services ", join (' ', @services), "\n" if (@services);

print "%packages ", join(" ",@{$tree->{packages_args}}), "\n",
join ("\n", @packages), "\n",
$config->getElement(END_SCRIPT_FIELD)->getValue(), "\n";
}

# Writes the mountpoint definitions and LVM and MD settings
Expand Down Expand Up @@ -397,12 +412,69 @@ EOF
kscommands ($config);
}

# Create the action to be taken on the log files
# logfile is the path to the log file
sub log_action {
my ($config, $logfile, $wait_for_network) = @_;

my $tree = $config->getElement(KS)->getTree;
my @logactions;
push(@logactions, "exec >$logfile 2>&1");

my $consolelogging = 1; # default behaviour
if (exists($tree->{logging})) {
$consolelogging = $tree->{logging}->{console} if(exists($tree->{logging}->{console}));

if (exists($tree->{logging}->{send_aiilogs}) && $tree->{logging}->{send_aiilogs}) {
# network must be functional
# (not needed in %pre and %post; we can rely on anaconda for that)
push(@logactions, "wait_for_network $tree->{logging}->{host}")
if ($wait_for_network);

my $method = $tree->{logging}->{method};
my $protocol = $tree->{logging}->{protocol};

my $actioncmd;
if ($method eq 'netcat') {
push(@logactions,'# Send messages to $protocol syslog server via netcat');
# use netcat to log to syslog port
my $nccmd = 'nc';
$nccmd .= ' -u' if ($protocol eq 'udp');

$actioncmd = "| $nccmd $tree->{logging}->{host} $tree->{logging}->{port}";
} elsif ($method eq 'bash') {
push(@logactions,"# Send messages to $protocol syslog server via bash /dev/$protocol");
# use netcat to log to UDP syslog port
# this assumes that the %pre, %post and post-reboot are bash
$actioncmd = "> /dev/$protocol/$tree->{logging}->{host}/$tree->{logging}->{port}";
}

my $action = "(tail -f $logfile | ".LOG_ACTION_AWK." $actioncmd) &";
push(@logactions, $action);

# insert extra sleep to get all started before any output is send
push(@logactions, 'sleep 1');
}
}

if ($consolelogging) {
push(@logactions, '# Make sure messages show up on the serial console',
"tail -f $logfile > /dev/console &");
}

push(@logactions,''); # add trailing newline
return join("\n", @logactions)
}

# Takes care of the pre-install script, in which the
sub pre_install_script
{
my ($self, $config) = @_;

print <<'EOF';
my $logfile = '/tmp/pre-log.log';
my $logaction = log_action($config, $logfile);

print <<EOF;
%pre

# Pre-installation script.
Expand All @@ -414,11 +486,14 @@ sub pre_install_script
# primary, one extended and your /dev/foo4 will be silently renamed to
# /dev/foo5.

# Make sure messages show up on the serial console
exec >/tmp/pre-log.log 2>&1
tail -f /tmp/pre-log.log > /dev/console &
$logaction
echo 'Begin of pre section'
set -x

EOF

print <<'EOF';

# Hack for RHEL 6: force re-reading the partition table
#
# fdisk often fails to re-read the partition table on RHEL 6, so we have to do
Expand Down Expand Up @@ -490,8 +565,11 @@ EOF
# De-activate logical volumes. Needed on RHEL6, see:
# https://bugzilla.redhat.com/show_bug.cgi?id=652417
lvm vgchange -an
echo 'End of pre section'
$end

EOF

}

# Prints the code needed for removing and creating partitions, block
Expand Down Expand Up @@ -602,25 +680,35 @@ sub kspostreboot_header
{
my $config = shift;

# TODO is it ok to rename this logfile?
my $logfile = '/root/ks-post-reboot.log';
my $logaction = log_action($config, $logfile, 1);
$logaction =~ s/\$/\\\$/g;

my $hostname = $config->getElement (HOSTNAME)->getValue;
my $domain = $config->getElement (DOMAINNAME)->getValue;
my $fqdn = "$hostname.$domain";

my $rootmail = $config->getElement (ROOTMAIL)->getValue;

print <<EOF;
#!/bin/bash
# Script to run at the first reboot. It installs the base Quattor RPMs
# and runs the components needed to get the system correctly
# configured.

hostname $fqdn

# Function to be called if there is an error in this phase.
# It sends an e-mail to $rootmail alerting about the failure.
fail() {
echo "Quattor installation on failed: \\\$1"
echo "Quattor installation on $fqdn failed: \\\$1"
sendmail -t <<End_of_sendmail
From: root\@$hostname
From: root\@$fqdn
To: $rootmail
Subject: [\\`date +'%x %R %z'\\`] Quattor installation on $hostname failed: \\\$1
Subject: [\\`date +'%x %R %z'\\`] Quattor installation on $fqdn failed: \\\$1

\\`cat /root/ks-post-install.log\\`
\\`cat $logfile\\`
------------------------------------------------------------
\\`ls -tr /var/log/ncm 2>/dev/null|xargs tail /var/log/spma.log\\`

Expand All @@ -632,37 +720,44 @@ End_of_sendmail
# Function to be called if the installation succeeds. It sends an
# e-mail to $rootmail alerting about the installation success.
success() {
echo "Quattor installation on $fqdn succeeded"
sendmail -t <<End_of_sendmail
From: root\@$hostname
From: root\@$fqdn
To: $rootmail
Subject: [\\`date +'%x %R %z'\\`] Quattor installation on $hostname succeeded
Subject: [\\`date +'%x %R %z'\\`] Quattor installation on $fqdn succeeded

Node $hostname successfully installed.
Node $fqdn successfully installed.
.
End_of_sendmail
}
hostname $hostname.$domain

# Wait for functional network up by testing DNS lookup via nslookup.
wait_for_network () {
# Wait up to 2 minutes until the network comes up
i=0
while ! nslookup \\\$1 > /dev/null
do
sleep 1
let i=\\\$i+1
if [ \\\$i -gt 120 ]
then
fail "Network does not come up (nslookup \\\$1)"
fi
done
}

# Ensure that the log file doesn't exist.
[ -e /root/ks-post-install.log ] && \\
fail "Last installation went wrong. Aborting. See logfile"
[ -e $logfile ] && \\
fail "Last installation went wrong. Aborting. See logfile $logfile."

exec &> /root/ks-post-install.log
tail -f /root/ks-post-install.log &>/dev/console &
$logaction
echo 'Begin of ks-post-reboot'
set -x

# Wait up to 2 minutes until the network comes up
i=0
while ! nslookup \\`hostname\\` > /dev/null
do
sleep 1
let i = \\\$i+1
if [ \\\$i -gt 120 ]
then
fail "Network does not come up"
fi
done
wait_for_network $fqdn

EOF

}

sub ksquattor_config
Expand Down Expand Up @@ -746,6 +841,8 @@ sub kspostreboot_tail

print <<EOF;
rm -f /etc/rc.d/rc3.d/S86ks-post-reboot
echo 'End of ks-post-reboot'
sleep 1
shutdown -r now

EOF
Expand Down Expand Up @@ -993,16 +1090,20 @@ EOF
sub post_install_script
{
my ($self, $config) = @_;

my $logfile='/tmp/post-log.log';
my $logaction = log_action($config, $logfile);

print <<EOF;

%post

set -x
# %post phase. The base system has already been installed. Let's do
# some minor changes and prepare it for being configured.
$logaction
echo 'Begin of post section'
set -x

exec &>/tmp/post-log.log
tail -f /tmp/post-log.log > /dev/console &

EOF

Expand All @@ -1018,7 +1119,7 @@ EOF
ksfix_grub;
}

## disable services, if any
# delete services, if any
if (exists($tree->{disable_service})) {
## should be a list of strings
my $services = join(" ",@{$tree->{disable_service}});
Expand Down Expand Up @@ -1061,7 +1162,12 @@ EOF

ksuserhooks ($config, PREREBOOTHOOK);
my $end = $config->getElement(END_SCRIPT_FIELD)->getValue();
print "$end\n";
print <<EOF;
echo 'End of post section'
sleep 1
$end

EOF

}

Expand Down