From cd4914ed55dcea72ec2e3c3f59b9ce72695e460a Mon Sep 17 00:00:00 2001 From: root Date: Sun, 4 Sep 2022 15:57:05 +0200 Subject: [PATCH] v220904 --- ansible_commit | 18 +++++++ ansible_outfilter | 87 ++++++++++++++++++++++++++++++ ansible_role | 29 ++++++++++ dynhosts | 135 ++++++++++++++++++++++++++++++++++++++++++++++ gather_facts | 16 ++++++ uptime_alarm | 14 +++++ 6 files changed, 299 insertions(+) create mode 100755 ansible_commit create mode 100755 ansible_outfilter create mode 100755 ansible_role create mode 100755 dynhosts create mode 100755 gather_facts create mode 100755 uptime_alarm diff --git a/ansible_commit b/ansible_commit new file mode 100755 index 0000000..e108c77 --- /dev/null +++ b/ansible_commit @@ -0,0 +1,18 @@ +#!/bin/bash + +QUIET=0 + +cd /etc/ansible +svn st | perl -ne '/\?\s+(.*)/ && print "$1\0"' | xargs -0 -r -L 1 svn add +svn st | perl -ne '/!\s+(.*)/ && print "$1\0"' | xargs -0 -r -L 1 svn rm + +if [[ $QUIET -gt 0 ]]; then + SVNQUIET="-q" +else + SVNQUIET="" + svn diff +fi + +svn ci $SVNQUIET -m "auto ansible_commit" + +# vim: set tabstop=4 shiftwidth=4 expandtab smarttab: diff --git a/ansible_outfilter b/ansible_outfilter new file mode 100755 index 0000000..63c6496 --- /dev/null +++ b/ansible_outfilter @@ -0,0 +1,87 @@ +#!/usr/bin/perl +use strict; use warnings; +use Getopt::Long qw(:config no_ignore_case bundling); + +my %opts = ( + no_changed => 0, + no_unreach => 0, + no_failed => 0, + ); +my $usage = < 0 + --no-unreachable|-u don't show where unreachable > 0 + --no-failed|-f don't show where failed > 0 +EOT + +GetOptions( + "no-changed|c" => \$opts{no_changed}, + "no-unreachable|u" => \$opts{no_unreach}, + "no-failed|f" => \$opts{no_failed}, + "help|h" => sub {print $usage; exit 0} + ) or die $usage; + +my $play = 'n/a'; +my $play_printed = 0; +my $section = 'n/a'; +my $section_printed = 0; +my $recap = 'n/a'; +my $recap_found = 0; +my $recap_printed = 0; + +while (my $line = ) { + if ($line =~ /^PLAY RECAP \**/) { + $recap_found = 1; + $recap = $line; + last; + } elsif ($line =~ /^PLAY /) { + $play = $line; + $play_printed = 0; + $section = 'n/a'; + $section_printed = 0; + } elsif ($line =~ /^(TASK|RUNNING HANDLER) /) { + $section = $line; + $section_printed = 0; + } elsif ($line =~ /^(ok|skipping|included): /) { + # skip + } elsif ($line !~ /\S/) { + # skip + } else { + if (!$play_printed) { + print "\n", $play; + $play_printed = 1; + } + if (!$section_printed) { + print "\n", $section; + $section_printed = 1; + } + print $line; + } +} +if (!$recap_found) { + die "\nNo 'PLAY RECAP' found or not an ansible-playbook's output.\n"; +} +while (my $line = ) { + next if $line !~ /\S/; + if ($line =~ /:\s+ok=\d+\s+changed=(\d+)\s+unreachable=(\d+)\s+failed=(\d+)/) { + my ($changed, $unreachable, $failed) = ($1, $2, $3); + my $ok = 1; + if ($changed and !$opts{no_changed}) { + $ok = 0; + } + if ($unreachable and !$opts{no_unreach}) { + $ok = 0; + } + if ($failed and !$opts{no_failed}) { + $ok = 0; + } + next if $ok; + } + if (!$recap_printed) { + print "\n\n$recap\n"; + $recap_printed = 1; + } + print $line; +} +# vim: set tabstop=4 shiftwidth=4 expandtab smarttab: diff --git a/ansible_role b/ansible_role new file mode 100755 index 0000000..c837aab --- /dev/null +++ b/ansible_role @@ -0,0 +1,29 @@ +#!/bin/bash + +if [[ $# < 2 ]]; then + cat < [ansible-playbook options] + +Examples: + $0 dest_host my_role + $0 custom_host my_role -i 'custom_host,' -vv --check +HELP + exit 1 +fi + +HOST_PATTERN=$1 +shift +ROLE=$1 +shift + +echo "Trying to apply role \"$ROLE\" to host/group \"$HOST_PATTERN\"..." + +ansible-playbook "$@" /dev/stdin < 0 + ); +my $usage = < \$opts{list}, + "help|h" => sub {print $usage; exit 0} + ) or die $usage; + + +my @inventory = read_file("$FindBin::Bin/../inventory"); +my %groups; +my %hostvars; +my %blockvars; +my @blockgroups; +for (my $i = 0; $i <= $#inventory; $i++) { + my $line = $inventory[$i]; + chomp $line; + next if $line =~ /^\s*#/; + $line =~ s/\s*$//; + if ($line =~ /^\s+/) { + print STDERR "Syntax error (leading whitespace) in line ". ($i + 1) . + ": $line\n"; + next; + } + next if $line !~ /\S/; + # continuation lines (leading whitespace): + while ($i + 1 <= $#inventory) { + last if $inventory[$i + 1] !~ /^\s+([^# ].*)/; + $i++; + my $cont = $1; + $cont =~ s/\s*$//; + $line .= " ". $cont; + } + # group definition: [group < parent + group < parent...] default_vars... + if ($line =~ /^\[([a-z0-9_< +]+)\](\s*.*)/i) { + my ($grouptext, $vars) = ($1, $2); + @blockgroups = (); + for my $x (split /\+/, $grouptext) { + if ($x !~ /^\s*([a-z0-9_]+)(\s*<\s*([a-z0-9_]+))?\s*$/) { + print STDERR "Invalid group definition in line ". ($i + 1) . + ": $line\n"; + next; + } + my ($group, $parent) = ($1, $3); + push @blockgroups, $group; + $groups{$group} = {hosts => []} if !exists $groups{$group}; + if ($parent) { + $groups{$parent} = {hosts => []} if !exists $groups{$parent}; + $groups{$parent}->{children} = [] + if !exists $groups{$parent}->{children}; + push @{$groups{$parent}->{children}}, $group; + } + } + %blockvars = (); + if ($vars) { + while ($vars =~ /\s+([a-z0-9_]+)=(\S*)/gci) { + my ($a, $v) = ($1, $2); + $blockvars{$a} = $v; + } + if (length $vars != pos $vars) { + print STDERR "Invalid parameters in line ". ($i + 1) . + ": $line\n"; + } + } + next; + } + if ($line !~ /^(\S+)\s+(\S+)(\s+\[(\S+)\])?(\s+.*)?/) { + print STDERR "Syntax error in line ". ($i + 1) .": $line\n"; + next; + } + my ($name, $addr, $gr, $rest) = ($1, $2, $4, $5); + + my @gr; + @gr = split /,/, $gr if $gr; + push @gr, @blockgroups; + for my $g (@gr) { + push @{$groups{$g}->{hosts}}, $name; + } + if (exists $hostvars{$name}) { + print STDERR "Duplicate host definition in line ". ($i + 1) .": $line\n"; + } + $hostvars{$name} = { %blockvars }; + $hostvars{$name}->{ansible_host} = $addr; + if ($rest and $rest =~ s/\s+(\{.*\})//) { + my $jsonstring = $1; + my $jo = JSON::PP->new->relaxed->allow_singlequote->allow_barekey; + my $data; + eval { + $data = $jo->decode($jsonstring); + }; + if ($@) { + print STDERR "Invalid JSON in line ". ($i + 1) .": $jsonstring\n"; + } + for my $k (keys %$data) { + $hostvars{$name}->{$k} = $data->{$k}; + } + + } + if ($rest) { + while ($rest =~ /\s+([a-z0-9_]+)=(\S*)/gci) { + my ($a, $v) = ($1, $2); + $hostvars{$name}->{$a} = $v; + } + if (length $rest != pos $rest) { + print STDERR "Invalid parameters in line ". ($i + 1) .": $line\n"; + } + } +} + +$groups{_meta}->{hostvars} = \%hostvars; + + +if ($opts{list}) { + my $json = JSON->new->canonical->pretty; + print $json->encode(\%groups); +} else { + printf "%i hosts in %i groups.\n", + scalar keys %hostvars, (scalar keys %groups) - 1; +} + +__END__ +# vim: set tabstop=4 shiftwidth=4 expandtab smarttab: diff --git a/gather_facts b/gather_facts new file mode 100755 index 0000000..a0dacf2 --- /dev/null +++ b/gather_facts @@ -0,0 +1,16 @@ +#!/bin/bash + +ANSIBLE_DIR=/etc/ansible +OUTPUT=/var/www/def/public/facts.html + +rm $ANSIBLE_DIR/gathered_facts/* +ansible '!off,linux,windows' -m setup -f 5 --task-timeout 30 --tree $ANSIBLE_DIR/gathered_facts >/dev/null + +INV="" +if [[ -r $ANSIBLE_DIR/cmdb-inventory ]]; then + INV="-i $ANSIBLE_DIR/cmdb-inventory" +fi + +/usr/local/bin/ansible-cmdb $INV -t html_fancy_split_overview $ANSIBLE_DIR/gathered_facts > $OUTPUT + +# vim: set tabstop=4 shiftwidth=4 expandtab smarttab: diff --git a/uptime_alarm b/uptime_alarm new file mode 100755 index 0000000..4895082 --- /dev/null +++ b/uptime_alarm @@ -0,0 +1,14 @@ +#!/bin/bash +minimum=${1:-86400} +cd /etc/ansible/gathered_facts +for f in *; do + g=$(grep ansible_uptime_seconds $f) + if [[ $? > 0 ]]; then + continue + fi + up=$(echo "$g" | sed -e 's/.*"ansible_uptime_seconds":\s*\([0-9]\+\).*/\1/') + if [[ $up -lt $minimum ]]; then + echo $f uptime is $((up / 3600)) hours $(($up % 3600 / 60)) minutes + fi +done +# vim: set tabstop=4 shiftwidth=4 expandtab smarttab: