Commit 6ef1d8cc authored by Matthieu Kermagoret's avatar Matthieu Kermagoret
Browse files

Add the --code flag to run some Perl code directly when launching

the Connector. This fixes #5732.
parent 7a671aed
......@@ -264,6 +264,12 @@ if (WITH_TESTING)
"${TEST_DIR}/connector/execute_multiple_scripts.cc")
target_link_libraries("${TEST_NAME}" ${TEST_LIBRARIES})
add_test("${TEST_NAME}" "${TEST_NAME}")
# Additional code.
set(TEST_NAME "connector_execute_with_additional_code")
add_executable("${TEST_NAME}"
"${TEST_DIR}/connector/execute_with_additional_code.cc")
target_link_libraries("${TEST_NAME}" ${TEST_LIBRARIES})
add_test("${TEST_NAME}" "${TEST_NAME}")
# Module loading from script.
set(TEST_NAME "connector_execute_module_loading")
add_executable("${TEST_NAME}"
......
/*
** Copyright 2011-2013 Merethis
** Copyright 2011-2014 Merethis
**
** This file is part of Centreon Perl Connector.
**
......@@ -43,7 +43,11 @@ class embedded_perl {
public:
~embedded_perl();
static embedded_perl& instance();
static void load(int* argc, char*** argv, char*** env);
static void load(
int* argc,
char*** argv,
char*** env,
char const* code = NULL);
pid_t run(std::string const& cmd, int fds[3]);
static void unload();
......@@ -51,9 +55,11 @@ private:
embedded_perl(
int* argc,
char*** argv,
char*** env);
char*** env,
char const* code = NULL);
embedded_perl(embedded_perl const& ep);
embedded_perl& operator=(embedded_perl const& ep);
void _write(char const* data, size_t len);
umap<std::string, SV*> _parsed;
static char const* const _script;
......
/*
** Copyright 2011-2013 Merethis
** Copyright 2011-2014 Merethis
**
** This file is part of Centreon Perl Connector.
**
......@@ -20,6 +20,7 @@
#include <cstdlib>
#include <iostream>
#include <list>
#include <unistd.h>
#include <EXTERN.h>
#include <perl.h>
......@@ -80,10 +81,15 @@ embedded_perl& embedded_perl::instance() {
* @param[in] argc Argument count.
* @param[in] argv Argument values.
* @param[in] env Program environment.
* @param[in] code Additional code to run by interpreter.
*/
void embedded_perl::load(int* argc, char*** argv, char*** env) {
void embedded_perl::load(
int* argc,
char*** argv,
char*** env,
char const* code) {
if (!_instance)
_instance = new embedded_perl(argc, argv, env);
_instance = new embedded_perl(argc, argv, env, code);
return ;
}
......@@ -255,13 +261,18 @@ void embedded_perl::unload() {
**************************************/
/**
* Default constructor.
* Constructor.
*
* @param[in] argc Argument count.
* @param[in] argv Argument values.
* @param[in] env Program environment.
* @param[in] code Additional code to run by interpreter.
*/
embedded_perl::embedded_perl(int* argc, char*** argv, char*** env) {
embedded_perl::embedded_perl(
int* argc,
char*** argv,
char*** env,
char const* code) {
// Do not warn if unused by PERL_SYS_INIT3 macro.
(void)argc;
(void)argv;
......@@ -285,19 +296,30 @@ embedded_perl::embedded_perl(int* argc, char*** argv, char*** env) {
<< "temporary script path is " << script_path;
// Write embedded script.
char const* data(_script);
size_t len(strlen(data));
while (len > 0) {
ssize_t wb(write(script_fd, data, len));
if (wb <= 0) {
char const* msg(strerror(errno));
close(script_fd);
unlink(script_path);
throw (basic_error()
<< "could not write embedded script: " << msg);
std::list<char const*> l;
l.push_back(_script);
if (code) {
l.push_back(code);
l.push_back("\n");
}
for (std::list<char const*>::const_iterator
it(l.begin()), end(l.end());
it != end;
++it) {
char const* data(*it);
size_t len(strlen(data));
while (len > 0) {
ssize_t wb(write(script_fd, data, len));
if (wb <= 0) {
char const* msg(strerror(errno));
close(script_fd);
unlink(script_path);
throw (basic_error()
<< "could not write embedded script: " << msg);
}
len -= wb;
data += wb;
}
len -= wb;
data += wb;
}
fsync(script_fd);
close(script_fd);
......
/*
** Copyright 2011-2013 Merethis
** Copyright 2011-2014 Merethis
**
** This file is part of Centreon Perl Connector.
**
......@@ -125,7 +125,13 @@ int main(int argc, char** argv, char** env) {
signal(SIGTERM, term_handler);
// Load Embedded Perl.
embedded_perl::load(&argc, &argv, &env);
embedded_perl::load(
&argc,
&argv,
&env,
(opts.get_argument("code").get_is_set()
? opts.get_argument("code").get_value().c_str()
: NULL));
// Program policy.
policy p;
......
/*
** Copyright 2011-2013 Merethis
** Copyright 2011-2014 Merethis
**
** This file is part of Centreon Perl Connector.
**
......@@ -24,6 +24,8 @@
using namespace com::centreon::connector::perl;
// Options descriptions.
static char const* const code_description
= "Argument is some Perl code that will be executed by the embedded interpreter.";
static char const* const debug_description
= "If this flag is specified, print all logs messages.";
static char const* const help_description
......@@ -79,7 +81,8 @@ std::string options::help() const {
oss << "centreon_connector_perl [args]\n"
<< " --debug " << debug_description << "\n"
<< " --help " << help_description << "\n"
<< " --version " << version_description << "\n";
<< " --version " << version_description << "\n"
<< " --code " << code_description << "\n";
// << "\n"
// << "Commands must be sent on the connector's standard input.\n"
// << "They must be sent using Centreon Connector protocol version\n"
......@@ -120,6 +123,15 @@ std::string options::usage() const {
* Init argument table.
*/
void options::_init() {
// Code.
{
misc::argument& arg(_arguments['c']);
arg.set_name('c');
arg.set_long_name("code");
arg.set_description(code_description);
arg.set_has_value(true);
}
// Debug.
{
misc::argument& arg(_arguments['d']);
......
/*
** Copyright 2011-2013 Merethis
** Copyright 2011-2014 Merethis
**
** This file is part of Centreon Perl Connector.
**
......@@ -108,4 +108,4 @@ char const* const com::centreon::connector::perl::embedded_perl::_script =
" die \"could not run '$filename': $@\";\n" \
" }\n" \
" return ($res);\n" \
"}\n";
"}\n\n";
/*
** Copyright 2012-2014 Merethis
**
** This file is part of Centreon Perl Connector.
**
** Centreon Perl Connector is free software: you can redistribute it
** and/or modify it under the terms of the GNU Affero General Public
** License as published by the Free Software Foundation, either version
** 3 of the License, or (at your option) any later version.
**
** Centreon Perl Connector 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
** Affero General Public License for more details.
**
** You should have received a copy of the GNU Affero General Public
** License along with Centreon Perl Connector. If not, see
** <http://www.gnu.org/licenses/>.
*/
#include <cstdio>
#include <cstring>
#include <iostream>
#include <sstream>
#include <string>
#include "com/centreon/clib.hh"
#include "com/centreon/io/file_stream.hh"
#include "com/centreon/process.hh"
#include "com/centreon/exceptions/basic.hh"
#include "test/connector/misc.hh"
#include "test/connector/paths.hh"
using namespace com::centreon;
#define CMD1 "2\0" \
"4242\0" \
"5\0" \
"123456789\0"
#define CMD2 "\0\0\0\0"
#define RESULT "3\0" \
"4242\0" \
"1\0" \
"0\0" \
" \0" \
"Merethis is wonderful\n\0\0\0\0"
/**
* Check that connector can execute a script.
*
* @return 0 on success.
*/
int main() {
clib::load();
// Write Perl script.
std::string script_path(io::file_stream::temp_path());
write_file(
script_path.c_str(),
"#!/usr/bin/perl\n" \
"\n" \
"print \"$Merethis::Test::company is $Merethis::Test::attribute\\n\";\n" \
"exit 0;\n");
// Process.
process p;
p.enable_stream(process::in, true);
p.enable_stream(process::out, true);
p.exec(CONNECTOR_PERL_BINARY " --code 'package Merethis::Test; our $company=\"Merethis\"; our $attribute=\"wonderful\";'");
// Write command.
std::ostringstream oss;
oss.write(CMD1, sizeof(CMD1) - 1);
oss << script_path;
oss.write(CMD2, sizeof(CMD2) - 1);
std::string cmd(oss.str());
char const* ptr(cmd.c_str());
unsigned int size(cmd.size());
while (size > 0) {
unsigned int rb(p.write(ptr, size));
size -= rb;
ptr += rb;
}
p.enable_stream(process::in, false);
// Read reply.
std::string output;
while (true) {
std::string buffer;
p.read(buffer);
if (buffer.empty())
break;
output.append(buffer);
}
// Wait for process termination.
int retval(1);
if (!p.wait(5000)) {
p.terminate();
p.wait();
}
else
retval = (p.exit_code() != 0);
// Remove temporary files.
remove(script_path.c_str());
clib::unload();
try {
if (retval)
throw (basic_error() << "invalid return code: " << retval);
if (output.size() != (sizeof(RESULT) - 1)
|| memcmp(output.c_str(), RESULT, sizeof(RESULT) - 1))
throw (basic_error()
<< "invalid output: size=" << output.size()
<< ", output=" << replace_null(output));
}
catch (std::exception const& e) {
retval = 1;
std::cerr << "error: " << e.what() << std::endl;
}
return (retval);
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment