1## OpenXPKI::Server::Notification::Connector 2## Notifier that sends the compiled message using a Connector 3 4package OpenXPKI::Server::Notification::Connector; 5 6use strict; 7use warnings; 8use English; 9 10use Data::Dumper; 11 12use JSON; 13use YAML::Loader; 14use DateTime; 15use OpenXPKI::Server::Context qw( CTX ); 16use OpenXPKI::Exception; 17use OpenXPKI::Debug; 18 19use Moose; 20 21extends 'OpenXPKI::Server::Notification::Base'; 22 23has 'backend' => ( 24 is => 'ro', 25 isa => 'Object', 26 reader => '_backend', 27 builder => '_init_backend', 28 lazy => 1, 29); 30 31has '_json' => ( 32 is => 'ro', 33 isa => 'JSON', 34 default => sub { return JSON->new(); }, 35 lazy => 1, 36); 37 38sub _init_backend { 39 40 my $self = shift; 41 42 ##! 8: 'creating transport' 43 my $cfg = CTX('config')->get_hash( $self->config() . '.backend' ); 44 45 my $class = $cfg->{connector}; 46 delete $cfg->{class}; # this is the notify package name 47 delete $cfg->{connector}; # this is the connector package name 48 49 eval "use $class;1" or OpenXPKI::Exception->throw( 50 message => 'Unable to load connector backend class', 51 params => { 52 class => $class, 53 error => $@, 54 }); 55 56 my $conn; 57 eval{ $conn = $class->new(%{$cfg}); }; 58 if ($EVAL_ERROR || !$conn) { 59 OpenXPKI::Exception->throw( 60 message => 'Unable to initialize connector backend class', 61 params => { 62 class => $class, 63 error => $@, 64 }); 65 } 66 67 return $conn; 68} 69 70=head1 Functions 71=head2 notify 72see @OpenXPKI::Server::Notification::Base 73=cut 74sub notify { 75 76 ##! 1: 'start' 77 78 my $self = shift; 79 my $args = shift; 80 81 my $msg = $args->{MESSAGE}; 82 my $token = $args->{TOKEN}; 83 my $template_vars = $args->{VARS}; 84 85 my $msgconfig = $self->config().'.message.'.$msg; 86 87 # Test if there is an entry for this kind of message 88 my @handles = CTX('config')->get_keys( $msgconfig ); 89 90 ##! 8: 'Starting message ' . $msg 91 92 ##! 16: 'Found handles ' . Dumper @handles 93 94 ##! 32: 'Template vars: ' . Dumper $template_vars 95 96 if (!@handles) { 97 CTX('log')->system()->debug("No notifcations to send for $msgconfig"); 98 return 0; 99 } 100 101 # Walk through the handles 102 QUEUE_HANDLE: 103 foreach my $handle (@handles) { 104 105 my $pi = $token->{$handle}; 106 107 ##! 16: 'Starting handle '.$handle.', PI: ' . Dumper $pi 108 109 # We do the eval per handle 110 eval { 111 my @path = CTX('config')->get_scalar_as_list( "$msgconfig.$handle.path" ); 112 113 # template defines a YAML file that is rendered using TT 114 my $template_file = CTX('config')->get( "$msgconfig.$handle.template" ); 115 116 my $data; 117 if ($template_file) { 118 ##! 32: "Using template file $template_file" 119 my $yaml = $self->_render_template_file( $template_file.'.yaml', $template_vars ); 120 ##! 64: $yaml 121 $data = YAML::Loader->new->load($yaml); 122 } elsif (my $content = CTX('config')->get_hash( "$msgconfig.$handle.content" )) { 123 my %vars = %{$template_vars}; 124 ##! 32: "Using content hash with key " . join(", ", keys %($content)) 125 ##! 64: $content 126 # we use template toolkit on any scalar value that contains a % sign 127 foreach my $key (keys %{$content}) { 128 my $value = $content->{$key} || ''; 129 if (!ref $value && ($value =~ m{%})) { 130 $value = $self->_render_template( $value, \%vars ); 131 } 132 $data->{$key} = $value; 133 } 134 } 135 136 if (!$data) { 137 CTX('log')->system()->warn("Unable to generate message for $handle - no data"); 138 next QUEUE_HANDLE; 139 } 140 141 ##! 32: $data 142 ##! 64: "Notify to path " . join(".", @path) 143 ##! 64: $data 144 CTX('log')->system()->trace(sprintf("Notify to %s with payload %s", 145 join(".", @path), Dumper $data)) if (CTX('log')->system()->is_trace()); 146 147 my $json = $self->_json()->encode($data); 148 die "Unable to encode to json" unless($json); 149 $self->_backend()->set(\@path, $json); 150 151 }; 152 if ($EVAL_ERROR) { 153 CTX('log')->system()->error("Notify for $msgconfig/$handle failed with $EVAL_ERROR"); 154 } 155 } # end handle 156 157 return $token; 158 159} 160 161sub _cleanup { 162 163} 164 1651; 166 167=head1 Name 168 169OpenXPKI::Server::Notification::Connector - Notification via Connector 170 171=head1 Description 172 173This class implements a notifier that sends out notifications via the "set" 174method of a Connector backend. The payload can be created in different ways. 175 176For now this backend supports creation of a data structure directly as a hash 177from the config or by rendering a YAML file using Template Toolkit and parsing 178the yaml afterwards. 179 180The only supported output format for now is JSON. 181 182=head1 Configuration 183 184# Sample configuration using a JSON based REST API via HTTP 185 186backend: 187 class: OpenXPKI::Server::Notification::Connector 188 connector: Connector::Proxy::HTTP 189 LOCATION: https://api.acme.org/v2/ 190 content_type: application/json 191 http_method: POST 192 header: 193 Authorization: MyAuthToken 194 195# template settings 196template: 197 dir: /usr/local/etc/openxpki/template/alerts/ 198 199message: 200 cert_expiry: 201 default: 202 path: alert 203 # the template file must end on .yaml and generate a hash 204 template: cert_expiry 205 206 cert_issued: 207 default: 208 path: info 209 content: 210 title: A new certificate for [% cert_subject %] has been created 211 message: | 212 A new certificate for [% cert_subject %] has been created. 213 You can find more details on the PKI WebUI. 214 priority: info 215