# # obs_notify_generic # # Copyright (c) 2015 Jörg Steffens # # inspired of # https://build.opensuse.org/package/show/isv:B1-Systems:OBS/obs-notfy_email # Copyright (c) 2014 Christian Schneemann, B1 Systems GmbH # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 as # published by the Free Software Foundation. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program (see the file COPYING); if not, write to the # Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA # ################################################################ package obs_notify_generic; use strict; use warnings; #use BSConfig; use lib "/usr/lib/obs/server/plugins/"; use obs_notify_generic_config; use Data::Dumper; use IPC::Run; use Proc::Daemon; use Time::Piece; #use XML::Simple; # stdout goes to /srv/obs/log/src_server.log sub new { my $self = { 'cfg' => ${obs_notify_generic_config::cfg}, 'logfile' => ${obs_notify_generic_config::logfile}, }; if ( not $self->{'logfile'} ) { ##$self->{'logfile'} = "/tmp/notify_generic.log"; $self->{'logfile'} = "/srv/obs/log/notify_generic.log"; } bless $self, shift; return $self; } sub notify { my ( $self, $type, $paramRef ) = @_; $type = "UNKNOWN" unless $type; my $cfg_type; if ( $self->{'cfg'}->{$type} ) { $cfg_type = $self->{'cfg'}->{$type}; } elsif ( $self->{'cfg'}->{'UNKNOWN'} ) { $cfg_type = $self->{'cfg'}->{'UNKNOWN'}; } for my $entry ( @{$cfg_type} ) { my $match = 1; foreach my $key ( keys %{ $entry->{'filter'} } ) { my $value = $entry->{'filter'}->{$key}; #print "key: $key\n"; #print "value: $value\n"; if ( not( exists( $paramRef->{$key} ) ) ) { error_msg( "$type (" . Data::Dumper->new( [$paramRef] )->Indent(0)->Dump . "): filter for '" . $key . "' is invalid" ); $match = 0; # exit loop last; } elsif ( not( $paramRef->{$key} =~ /$value/ ) ) { $match = 0; } } if ($match) { my $extra = undef; if ( $entry->{'action'} ) { if ( $paramRef->{'project'} ) { my $project = $paramRef->{'project'}; $project =~ s/:/:\//g; $paramRef->{'project_path'} = "/srv/obs/repos/" . $project; } # create regex, # test against longest string first to avoid partial replacement ($repo, $repository) my $check = join '|', sort { length($b) <=> length($a) } keys %{$paramRef}; my $action = $entry->{'action'}; $action =~ s/\$($check)/$paramRef->{$1}/g; $extra = { 'action_template' => $entry->{'action'}, 'action' => $action, }; #$self->run_wait( $action, $extra ); $self->run_daemon( $action, $extra ); } if ( $entry->{'log'} ) { $self->log( $type, $paramRef, $extra ); } } else { #print "no match\n"; } } } sub run_wait { my ( $self, $action, $extra ) = @_; my $in = undef; my $out; my $err; my $rc; eval { my $process = IPC::Run::start( [ "sh", "--login", "-c", "HOME=/usr/lib/obs $action", "2>&1" ], \$in, \$out, \$err ); $process->finish(); $rc = $process->result(0); }; if ($@) { #print "eval: ", $@; $out = join( "\n", $@ ); $rc = 127; } chomp($out); $extra->{'returncode'} = $rc; $extra->{'output'} = $out; } sub run_daemon { my ( $self, $action, $extra ) = @_; my $daemon = Proc::Daemon->new(); my $pid = $daemon->Init( { exec_command => "date --rfc-3339=seconds; echo '$action'; $action", child_STDOUT => "+>>" . $self->{'logfile'} . ".out.log", child_STDERR => "+>>" . $self->{'logfile'} . ".out.log", } ); #print $daemon->Status($pid); $extra->{'pid'} = $pid; } sub error_msg { print "FAILED: ", join( " ", @_ ) . "\n"; } sub log { my ( $self, $type, $paramRef, $extra ) = @_; my $fh; my $file_opened = 0; if ( $self->{'logfile'} eq "STDOUT" ) { $fh = *STDOUT; } else { if ( open( $fh, '>>', $self->{'logfile'} ) ) { $file_opened = 1; } else { error_msg( "failed to open log file " . $self->{'logfile'} ); return 1; } } print $fh localtime->strftime("%Y%m%d %H%M%S"), " TYPE=$type"; if ($extra) { print $fh "\n"; print $fh Dumper( { 'param' => $paramRef, 'extra' => $extra } ); print $fh "\n"; } else { print $fh " "; print $fh Data::Dumper->new( [$paramRef] )->Indent(0)->Dump; print $fh "\n"; } if ($file_opened) { close $fh; } } # sub notify_setting { # my ($self, $project) = @_; # my ($xml, $attributes); # # $xml = $self->call_obs_api("/source/$project/_attribute/$notify_email_config::notify_attr"); # # if ($xml) { # $attributes = XMLin($xml, KeyAttr => { }, ForceArray =>0); # } # # return $attributes->{attribute}->{'value'} || 0; # } # sub unique { # my ($self, @a) = @_; # return keys %{{ map { $_ => 1 } @a }}; # } # sub get_obs_maintainer { # my ($self, $project, $package) = @_; # my ($request, @persons, $xml, $meta); # if ($package) { # $request = "/source/$project/$package/_meta"; # $xml = $self->call_obs_api($request); # $meta = XMLin($xml, KeyAttr => {}, ForceArray => [ 'person'] ); # # @persons = grep { $_->{'role'} =~ /$notify_email_config::notified_roles/i } @{$meta->{person}}; # } # $request = "/source/$project/_meta"; # # $xml = $self->call_obs_api($request); # $meta = XMLin($xml, KeyAttr => {}, ForceArray => ['person'] ); # # push @persons, grep { $_->{'role'} =~ /$notify_email_config::notified_roles/i } @{$meta->{person}}; # # @persons = $self->unique(map{ $_->{'userid'} } @persons); # # return @persons; # } # # sub get_obs_email { # my ($self, $user) = @_; # # my $xml = $self->call_obs_api("/person/$user"); # # $xml = XMLin($xml, KeyAttr => {}, ForceArray => 0); # # return $xml->{'email'}; # } # sub call_obs_api { # my ($self, $api_call) = @_; # return `$notify_email_config::curl_binary -k -s -u $notify_email_config::api_user:$notify_email_config::api_pass $notify_email_config::api_url/$api_call`; # } 1;