diff --git a/.github/actions/package/action.yml b/.github/actions/package/action.yml index c753cc054d5..03f6f63ef92 100644 --- a/.github/actions/package/action.yml +++ b/.github/actions/package/action.yml @@ -111,8 +111,8 @@ runs: path: ./*.${{ inputs.package_extension }} key: ${{ inputs.cache_key }} - # Update if condition to true to get packages as artifacts - - if: ${{ false }} + # Add to your PR the label upload-artifacts to get packages as artifacts + - if: ${{ contains(github.event.pull_request.labels.*.name, 'upload-artifacts') }} name: Upload package artifacts uses: actions/upload-artifact@0b2256b8c012f0828dc542b3febcab082c67f72b # v4.3.4 with: diff --git a/.github/workflows/gorgone.yml b/.github/workflows/gorgone.yml index 2c14adf9ab9..7f418cdbe49 100644 --- a/.github/workflows/gorgone.yml +++ b/.github/workflows/gorgone.yml @@ -14,7 +14,6 @@ on: - ready_for_review paths: - "gorgone/**" - - "!gorgone/tests/**" - "!gorgone/veracode.json" - "!gorgone/.veracode-exclusions" push: @@ -25,7 +24,6 @@ on: - "[2-9][0-9].[0-9][0-9].x" paths: - "gorgone/**" - - "!gorgone/tests/**" - "!gorgone/veracode.json" - "!gorgone/.veracode-exclusions" @@ -55,6 +53,52 @@ jobs: docker_registry_id: ${{ secrets.HARBOR_CENTREON_PULL_USERNAME }} docker_registry_passwd: ${{ secrets.HARBOR_CENTREON_PULL_TOKEN }} + gorgone-unit-tests: + strategy: + fail-fast: false + matrix: + image: [unit-tests-alma8, unit-tests-alma9, unit-tests-bullseye, unit-tests-bullseye-arm64, unit-tests-bookworm, unit-tests-jammy] + include: + - runner_name: ubuntu-22.04 + - package_extension: rpm + image: unit-tests-alma8 + distrib: el8 + - package_extension: rpm + image: unit-tests-alma9 + distrib: el9 + - package_extension: deb + image: unit-tests-bullseye + distrib: bullseye + - package_extension: deb + image: unit-tests-bullseye-arm64 + distrib: bullseye-arm64 + runner_name: ["self-hosted", "collect-arm64"] + - package_extension: deb + image: unit-tests-bookworm + distrib: bookworm + + runs-on: ${{ matrix.runner_name }} + container: + image: ${{ vars.DOCKER_INTERNAL_REGISTRY_URL }}/${{ matrix.image }} + credentials: + username: ${{ secrets.DOCKER_REGISTRY_ID }} + password: ${{ secrets.DOCKER_REGISTRY_PASSWD }} + steps: + - name: Checkout sources + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + + - name: Run unit tests + run: yath -L test ./gorgone/tests/unit/ + + - name: Upload logs as artifacts if tests failed + if: failure() + uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 # v4.4.0 + with: + name: gorgone-unit-tests-logs-${{ matrix.distrib }} + path: ./lastlog.jsonl + retention-days: 1 + # end of the unit test for gorgone. + package: needs: [get-environment] if: ${{ needs.get-environment.outputs.stability != 'stable' }} diff --git a/gorgone/gorgone/class/core.pm b/gorgone/gorgone/class/core.pm index b432de30721..7b8408472f1 100644 --- a/gorgone/gorgone/class/core.pm +++ b/gorgone/gorgone/class/core.pm @@ -163,10 +163,17 @@ sub init { $self->{logger}->writeLogError("[core] can't find config file '$self->{config_file}'"); exit(1); } + # before loading the config, we need to load initialize vault. + # Gorgone don't know how to reload for now, but once it will be done, we will need to retry the vault connexion if it failed when starting, and read again the configuration + $self->{vault_file} = defined($self->{vault_file}) ? $self->{vault_file} : '/var/lib/centreon/vault/vault.json'; + $self->{vault} = centreon::common::vault->new(logger => $self->{logger}, 'config_file' => $self->{vault_file}); + $self->{config} = $self->yaml_load_config( - file => $self->{config_file}, + file => $self->{config_file}, + # the filter is used to remove anything from the configuration not related to gorgone or centreon filter => '!($ariane eq "configuration##" || $ariane =~ /^configuration##(?:gorgone|centreon)##/)' ); + $self->init_server_keys(); $self->{config}->{configuration}->{gorgone}->{gorgonecore}->{external_com_zmq_tcp_keepalive} = diff --git a/gorgone/gorgone/class/script.pm b/gorgone/gorgone/class/script.pm index a5891101799..5e48dfac044 100644 --- a/gorgone/gorgone/class/script.pm +++ b/gorgone/gorgone/class/script.pm @@ -56,6 +56,7 @@ sub new { $self->{logger} = gorgone::class::logger->new(); $self->{options} = { 'config=s' => \$self->{config_file}, + 'vault=s' => \$self->{vault_config_file}, 'logfile=s' => \$self->{log_file}, 'severity=s' => \$self->{severity}, 'flushoutput' => \$self->{flushoutput}, @@ -141,6 +142,11 @@ sub run { $self->init(); } +# yaml_get_include: return a flat array of files defined by an !include directive. +# it will resolve the wildcard and return a sorted list of files. +# include: string with the directive. It can be a comma separated list, each element can contain '*' at the start of the string to specify 0 or more character (any character). +# current_dir: current directory to resolve relative path of !include directive. +# if the path is not absolute, it will be prefixed by the binary current path, so the first top level include should be an absolute path. sub yaml_get_include { my ($self, %options) = @_; @@ -151,16 +157,19 @@ sub yaml_get_include { my $dirname = File::Basename::dirname($dir); $dirname = $options{current_dir} . '/' . $dirname if ($dirname !~ /^\//); my $match_files = File::Basename::basename($dir); + # \Q\E is used to escape every special characters in the regex. + # we replace * by .* to match any character and disable \Q\E locally. + # so the extension will correctly match the file. $match_files =~ s/\*/\\E.*\\Q/g; $match_files = '\Q' . $match_files . '\E'; - my @sorted_files = (); my $DIR; + if (!opendir($DIR, $dirname)) { $self->{logger}->writeLogError("config - cannot opendir '$dirname' error: $!"); return (); } - + # opened the directory for the tested file, we will now test every file in the directory to see if they match the pattern. while (readdir($DIR)) { if (-f "$dirname/$_" && eval "/^$match_files\$/") { push @sorted_files, "$dirname/$_"; @@ -170,13 +179,17 @@ sub yaml_get_include { @sorted_files = sort { $a cmp $b } @sorted_files; push @all_files, @sorted_files; } - + # the list can be empty, for exemple if the client disable all the cron or whitelist of gorgone there should not be any error. return @all_files; } - +# yaml_parse_config: recursive function to parse yaml content and honor the inclusion of other files and vault password decryption. +# depending on the type of the yaml object, it will call itself recursively. +# config: yaml object as perl reference (hash, array, scalar, hash of hash...). $YAML::XS::LoadBlessed should be set to 1 to transform !include in blessed reference. +# current_dir: current directory to resolve relative path of !include directive. +# filter: a string to eval to filter the yaml content. you can for exemple return only children of a node. +# ariane: Ariadne's thread to know where we are in the yaml content. It is used by the filter. example : 'configuration##gorgone##gorgonecore##' sub yaml_parse_config { my ($self, %options) = @_; - if (ref(${$options{config}}) eq 'HASH') { foreach (keys %{${$options{config}}}) { my $ariane = $options{ariane} . $_ . '##'; @@ -206,6 +219,7 @@ sub yaml_parse_config { ariane => $ariane ); } + # $YAML::XS::LoadBlessed must be set, when YAML::XS will load a property with !include, it will be a blessed reference instead of a scalar. } elsif (ref(${$options{config}}) eq 'include') { my @files = $self->yaml_get_include( include => ${${$options{config}}}, @@ -236,9 +250,23 @@ sub yaml_parse_config { } else { ${$options{config}} = 'false'; } + + } elsif (ref(${$options{config}}) eq '') { + # this is a scalar value, we check if this is a vault path to replace it. + if ($self->{vault} and $self->{vault}->can('get_secret')) { + ${$options{config}} = $self->{vault}->get_secret( ${$options{config}}); + } + } else { + $self->{logger}->writeLogError("config - unknown type of data: " . ref(${$options{config}})); } } +# yaml_load_config: entry point for yaml parsing. +# can be called by yaml_parse_config if there is !include in the yaml, and will call yaml_parse_config to parse the content of the file. +# file: filename to parse. The file can contain !include directive to include other files. +# filter: is a string to eval to filter the yaml content. you can for exemple return only children of a node named configuration with this filter : +# '$ariane eq "configuration##"' +# arianne: Ariadne's thread to know where we are in the yaml content. It is used by the filter. example : 'configuration##gorgone##gorgonecore##' sub yaml_load_config { my ($self, %options) = @_; diff --git a/gorgone/gorgoned b/gorgone/gorgoned index fdb423af470..8006a14463b 100644 --- a/gorgone/gorgoned +++ b/gorgone/gorgoned @@ -46,6 +46,10 @@ gorgoned [options] Specify the path to the yaml configuration file (default: ''). +=item B<--vault> + +Specify the path to the vault json configuration file (default: '/var/lib/centreon/vault/vault.json'). + =item B<--help> Print a brief help message and exits. diff --git a/gorgone/packaging/centreon-gorgone.yaml b/gorgone/packaging/centreon-gorgone.yaml index 16e86d297b1..a94092299df 100644 --- a/gorgone/packaging/centreon-gorgone.yaml +++ b/gorgone/packaging/centreon-gorgone.yaml @@ -157,6 +157,7 @@ overrides: rpm: depends: - centreon-common + - centreon-perl-libs-common - bzip2 - perl-Libssh-Session >= 0.8 - perl-CryptX @@ -196,6 +197,7 @@ overrides: deb: depends: # those dependencies are taken from centreon-gorgone/packaging/debian/control - centreon-common + - centreon-perl-libs-common - libdatetime-perl - libtime-parsedate-perl - libtry-tiny-perl diff --git a/gorgone/tests/unit/class/config_examples/centreon-gorgone/config.d/30-centreon.yaml b/gorgone/tests/unit/class/config_examples/centreon-gorgone/config.d/30-centreon.yaml new file mode 100644 index 00000000000..abe2baa10b8 --- /dev/null +++ b/gorgone/tests/unit/class/config_examples/centreon-gorgone/config.d/30-centreon.yaml @@ -0,0 +1,12 @@ +name: centreon.yaml +description: Configure Centreon Gorgone to work with Centreon Web. +centreon: + database: + db_configuration: + dsn: "mysql:host=localhost:port=3306;dbname=centreon" + username: "centreon" + password: "password" + db_realtime: + dsn: "mysql:host=localhost:port=3306;dbname=centreon_storage" + username: "centreon" + password: "password" diff --git a/gorgone/tests/unit/class/config_examples/centreon-gorgone/config.d/31-centreon-api.yaml b/gorgone/tests/unit/class/config_examples/centreon-gorgone/config.d/31-centreon-api.yaml new file mode 100644 index 00000000000..4f4ae454f18 --- /dev/null +++ b/gorgone/tests/unit/class/config_examples/centreon-gorgone/config.d/31-centreon-api.yaml @@ -0,0 +1,9 @@ +gorgone: + tpapi: + - name: centreonv2 + base_url: "http://127.0.0.1/centreon/api/latest/" + username: "centreon-gorgone" + password: "webapiPassword!" + - name: clapi + username: "centreon-gorgone" + password: "webapiPassword!" diff --git a/gorgone/tests/unit/class/config_examples/centreon-gorgone/config.d/39-action.yaml b/gorgone/tests/unit/class/config_examples/centreon-gorgone/config.d/39-action.yaml new file mode 100644 index 00000000000..c17385c42e6 --- /dev/null +++ b/gorgone/tests/unit/class/config_examples/centreon-gorgone/config.d/39-action.yaml @@ -0,0 +1,8 @@ +gorgone: + modules: + - name: action + package: "gorgone::modules::core::action::hooks" + enable: true + command_timeout: 30 + whitelist_cmds: true + allowed_cmds: !include whitelist.conf.d/*.yaml diff --git a/gorgone/tests/unit/class/config_examples/centreon-gorgone/config.d/40-gorgoned.yaml b/gorgone/tests/unit/class/config_examples/centreon-gorgone/config.d/40-gorgoned.yaml new file mode 100644 index 00000000000..bcb66cbe241 --- /dev/null +++ b/gorgone/tests/unit/class/config_examples/centreon-gorgone/config.d/40-gorgoned.yaml @@ -0,0 +1,97 @@ +gorgone: + gorgonecore: + privkey: "/var/lib/centreon-gorgone/.keys/rsakey.priv.pem" + pubkey: "/var/lib/centreon-gorgone/.keys/rsakey.pub.pem" + id: 1 + + modules: + - name: httpserver + package: "gorgone::modules::core::httpserver::hooks" + enable: true + address: "0.0.0.0" + port: "8085" + ssl: true + ssl_cert_file: /var/lib/centreon-gorgone/.keys/server_api_cert.pem + ssl_key_file: /var/lib/centreon-gorgone/.keys/server_api_key.pem + auth: + enabled: false + user: web-user-gorgone-api + password: password + allowed_hosts: + enabled: true + subnets: + - 127.0.0.1/32 + + - name: action + package: "gorgone::modules::core::action::hooks" + enable: true + command_timeout: 30 + whitelist_cmds: true + allowed_cmds: + - ^sudo\s+(/bin/)?systemctl\s+(reload|restart)\s+(centengine|centreontrapd|cbd)\s*$ + - ^(sudo\s+)?(/usr/bin/)?service\s+(centengine|centreontrapd|cbd|cbd-sql)\s+(reload|restart)\s*$ + - ^/usr/sbin/centenginestats\s+-c\s+/etc/centreon-engine/centengine\.cfg\s*$ + - ^cat\s+/var/lib/centreon-engine/[a-zA-Z0-9\-]+-stats\.json\s*$ + - ^/usr/lib/centreon/plugins/.*$ + - ^/bin/perl /usr/share/centreon/bin/anomaly_detection --seasonality >> /var/log/centreon/anomaly_detection\.log 2>&1\s*$ + - ^/usr/bin/php -q /usr/share/centreon/cron/centreon-helios\.php >> /var/log/centreon-helios\.log 2>&1\s*$ + - ^centreon + - ^mkdir + - ^/usr/share/centreon/www/modules/centreon-autodiscovery-server/script/run_save_discovered_host + - ^/usr/share/centreon/bin/centreon -u \"centreon-gorgone\" -p \S+ -w -o CentreonWorker -a processQueue$ + + - name: cron + package: "gorgone::modules::core::cron::hooks" + enable: true + cron: !include cron.d/*.yaml + + - name: register + package: "gorgone::modules::core::register::hooks" + enable: true + + - name: nodes + package: "gorgone::modules::centreon::nodes::hooks" + enable: true + + - name: proxy + package: "gorgone::modules::core::proxy::hooks" + enable: true + buffer_size: 10 + pool: 1 + httpserver: + enable: true + token: "^$*ù^é&àérç(é/*-+$$z@ze%r¨£µ~zz" + address: "0.0.0.0" + port: 8099 + + + - name: legacycmd + package: "gorgone::modules::centreon::legacycmd::hooks" + enable: true + buffer_size: 100 + cmd_dir: "/var/lib/centreon/centcore/" + cmd_file: "/var/lib/centreon/centcore.cmd" + cache_dir: "/var/cache/centreon/" + cache_dir_trap: "/etc/snmp/centreon_traps" + remote_dir: "/var/cache/centreon//config/remote-data/" + + - name: engine + package: "gorgone::modules::centreon::engine::hooks" + enable: true + command_file: "/var/lib/centreon-engine/rw/centengine.cmd" + + - name: statistics + package: "gorgone::modules::centreon::statistics::hooks" + enable: true + broker_cache_dir: "/var/cache/centreon//broker-stats/" + cron: + - id: broker_stats + timespec: "*/5 * * * *" + action: BROKERSTATS + parameters: + timeout: 10 + - id: engine_stats + timespec: "*/5 * * * *" + action: ENGINESTATS + parameters: + timeout: 10 diff --git a/gorgone/tests/unit/class/config_examples/centreon-gorgone/config.d/41-autodiscovery.yaml b/gorgone/tests/unit/class/config_examples/centreon-gorgone/config.d/41-autodiscovery.yaml new file mode 100644 index 00000000000..56bae5eb0fb --- /dev/null +++ b/gorgone/tests/unit/class/config_examples/centreon-gorgone/config.d/41-autodiscovery.yaml @@ -0,0 +1,5 @@ +gorgone: + modules: + - name: autodiscovery + package: "gorgone::modules::centreon::autodiscovery::hooks" + enable: true diff --git a/gorgone/tests/unit/class/config_examples/centreon-gorgone/config.d/50-centreon-audit.yaml b/gorgone/tests/unit/class/config_examples/centreon-gorgone/config.d/50-centreon-audit.yaml new file mode 100644 index 00000000000..ae0f8c96c62 --- /dev/null +++ b/gorgone/tests/unit/class/config_examples/centreon-gorgone/config.d/50-centreon-audit.yaml @@ -0,0 +1,5 @@ +gorgone: + modules: + - name: audit + package: "gorgone::modules::centreon::audit::hooks" + enable: true diff --git a/gorgone/tests/unit/class/config_examples/centreon-gorgone/config.d/cron.d/41-service-discovery.yaml b/gorgone/tests/unit/class/config_examples/centreon-gorgone/config.d/cron.d/41-service-discovery.yaml new file mode 100644 index 00000000000..b2796c7d284 --- /dev/null +++ b/gorgone/tests/unit/class/config_examples/centreon-gorgone/config.d/cron.d/41-service-discovery.yaml @@ -0,0 +1,3 @@ +- id: service_discovery + timespec: "30 22 * * *" + action: LAUNCHSERVICEDISCOVERY diff --git a/gorgone/tests/unit/class/config_examples/centreon-gorgone/config.d/whitelist.conf.d/centreon.yaml b/gorgone/tests/unit/class/config_examples/centreon-gorgone/config.d/whitelist.conf.d/centreon.yaml new file mode 100644 index 00000000000..5a7e2cca4e8 --- /dev/null +++ b/gorgone/tests/unit/class/config_examples/centreon-gorgone/config.d/whitelist.conf.d/centreon.yaml @@ -0,0 +1,20 @@ +# Configuration brought by Centreon Gorgone package. +# SHOULD NOT BE EDITED! CREATE YOUR OWN FILE IN WHITELIST.CONF.D DIRECTORY! +- ^sudo\s+(/bin/|/usr/bin/)?systemctl\s+(reload|restart)\s+(centengine|centreontrapd|cbd)\s*$ +- ^(sudo\s+)?(/usr/bin/)?service\s+(centengine|centreontrapd|cbd|cbd-sql)\s+(reload|restart)\s*$ +- ^/usr/sbin/centenginestats\s+-c\s+/etc/centreon-engine/+centengine\.cfg\s*$ +- ^cat\s+/var/lib/centreon-engine/+[a-zA-Z0-9\-]+-stats\.json\s*$ +- ^/usr/lib/centreon/plugins/.*$ +- ^/bin/perl /usr/share/centreon/bin/anomaly_detection --seasonality >> /var/log/centreon/anomaly_detection\.log 2>&1\s*$ +- ^/usr/bin/php -q /usr/share/centreon/cron/centreon-helios\.php >> /var/log/centreon-helios\.log 2>&1\s*$ +- ^centreon +- ^mkdir +- ^/usr/share/centreon/www/modules/centreon-autodiscovery-server/script/run_save_discovered_host +- ^/usr/share/centreon/bin/centreon -u \"centreon-gorgone\" -p \S+ -w -o CentreonWorker -a processQueue$ +- ^/usr/bin/php (-q )?/usr/share/centreon/cron/[\w,\s.-]+ >> /var/log/centreon-gorgone/[\w,\s.-]+\s+2>&1$ +- ^/usr/bin/php -q /usr/share/centreon/www/modules/centreon-bi-server/tools/purgeArchivesFiles\.php >> /var/log/centreon-gorgone/centreon-bi-archive-retention\.log 2>&1$ +- ^/usr/share/centreon/cron/eventReportBuilder --config=/etc/centreon/conf\.pm >> /var/log/centreon-gorgone/eventReportBuilder\.log 2>&1$ +- ^/usr/share/centreon/cron/dashboardBuilder --config=/etc/centreon/conf\.pm >> /var/log/centreon-gorgone/dashboardBuilder\.log 2>&1$ +- ^/usr/share/centreon/www/modules/centreon-dsm/+cron/centreon_dsm_purge\.pl --config=\"/etc/centreon/conf.pm\" --severity=\S+ >> /var/log/centreon-gorgone/centreon_dsm_purge\.log 2>&1\s*$ +- ^/usr/share/centreon-bi-backup/centreon-bi-backup-web\.sh >> /var/log/centreon-gorgone/centreon-bi-backup-web\.log 2>&1$ +- ^/usr/share/centreon/www/modules/centreon-autodiscovery-server/+cron/centreon_autodisco.pl --config='/etc/centreon/conf.pm' --config-extra='/etc/centreon/centreon_autodisco.pm' --severity=\S+ >> /var/log/centreon-gorgone/centreon_service_discovery.log 2>&1$ diff --git a/gorgone/tests/unit/class/config_examples/centreon-gorgone/config.yaml b/gorgone/tests/unit/class/config_examples/centreon-gorgone/config.yaml new file mode 100644 index 00000000000..d843c9b7d46 --- /dev/null +++ b/gorgone/tests/unit/class/config_examples/centreon-gorgone/config.yaml @@ -0,0 +1,3 @@ +name: config.yaml +description: Configuration brought by Centreon Gorgone package. SHOULD NOT BE EDITED! USE CONFIG.D DIRECTORY! +configuration: !include config.d/*.yaml \ No newline at end of file diff --git a/gorgone/tests/unit/class/config_examples/centreon-gorgone/expectedConfiguration.pl b/gorgone/tests/unit/class/config_examples/centreon-gorgone/expectedConfiguration.pl new file mode 100644 index 00000000000..9ebc4aed437 --- /dev/null +++ b/gorgone/tests/unit/class/config_examples/centreon-gorgone/expectedConfiguration.pl @@ -0,0 +1,194 @@ +return { + 'configuration' => { + 'centreon' => { + 'database' => { + 'db_configuration' => { + 'dsn' => 'mysql:host=localhost:port=3306;dbname=centreon', + 'password' => 'password', + 'username' => 'centreon' + }, + 'db_realtime' => { + 'dsn' => 'mysql:host=localhost:port=3306;dbname=centreon_storage', + 'password' => 'password', + 'username' => 'centreon' + } + } + }, + 'gorgone' => { + 'tpapi' => [ + { + 'password' => 'webapiPassword!', + 'base_url' => 'http://127.0.0.1/centreon/api/latest/', + 'name' => 'centreonv2', + 'username' => 'centreon-gorgone' + }, + { + 'username' => 'centreon-gorgone', + 'name' => 'clapi', + 'password' => 'webapiPassword!' + } + ], + 'gorgonecore' => { + 'id' => 1, + 'privkey' => '/var/lib/centreon-gorgone/.keys/rsakey.priv.pem', + 'pubkey' => '/var/lib/centreon-gorgone/.keys/rsakey.pub.pem' + }, + 'modules' => [ + { + 'package' => 'gorgone::modules::core::action::hooks', + 'whitelist_cmds' => 'true', + 'command_timeout' => 30, + 'allowed_cmds' => [ + '^sudo\\s+(/bin/|/usr/bin/)?systemctl\\s+(reload|restart)\\s+(centengine|centreontrapd|cbd)\\s*$', + '^(sudo\\s+)?(/usr/bin/)?service\\s+(centengine|centreontrapd|cbd|cbd-sql)\\s+(reload|restart)\\s*$', + '^/usr/sbin/centenginestats\\s+-c\\s+/etc/centreon-engine/+centengine\\.cfg\\s*$', + '^cat\\s+/var/lib/centreon-engine/+[a-zA-Z0-9\\-]+-stats\\.json\\s*$', + '^/usr/lib/centreon/plugins/.*$', + '^/bin/perl /usr/share/centreon/bin/anomaly_detection --seasonality >> /var/log/centreon/anomaly_detection\\.log 2>&1\\s*$', + '^/usr/bin/php -q /usr/share/centreon/cron/centreon-helios\\.php >> /var/log/centreon-helios\\.log 2>&1\\s*$', + '^centreon', + '^mkdir', + '^/usr/share/centreon/www/modules/centreon-autodiscovery-server/script/run_save_discovered_host', + '^/usr/share/centreon/bin/centreon -u \\"centreon-gorgone\\" -p \\S+ -w -o CentreonWorker -a processQueue$', + '^/usr/bin/php (-q )?/usr/share/centreon/cron/[\\w,\\s.-]+ >> /var/log/centreon-gorgone/[\\w,\\s.-]+\\s+2>&1$', + '^/usr/bin/php -q /usr/share/centreon/www/modules/centreon-bi-server/tools/purgeArchivesFiles\\.php >> /var/log/centreon-gorgone/centreon-bi-archive-retention\\.log 2>&1$', + '^/usr/share/centreon/cron/eventReportBuilder --config=/etc/centreon/conf\\.pm >> /var/log/centreon-gorgone/eventReportBuilder\\.log 2>&1$', + '^/usr/share/centreon/cron/dashboardBuilder --config=/etc/centreon/conf\\.pm >> /var/log/centreon-gorgone/dashboardBuilder\\.log 2>&1$', + '^/usr/share/centreon/www/modules/centreon-dsm/+cron/centreon_dsm_purge\\.pl --config=\\"/etc/centreon/conf.pm\\" --severity=\\S+ >> /var/log/centreon-gorgone/centreon_dsm_purge\\.log 2>&1\\s*$', + '^/usr/share/centreon-bi-backup/centreon-bi-backup-web\\.sh >> /var/log/centreon-gorgone/centreon-bi-backup-web\\.log 2>&1$', + '^/usr/share/centreon/www/modules/centreon-autodiscovery-server/+cron/centreon_autodisco.pl --config=\'/etc/centreon/conf.pm\' --config-extra=\'/etc/centreon/centreon_autodisco.pm\' --severity=\\S+ >> /var/log/centreon-gorgone/centreon_service_discovery.log 2>&1$' + ], + 'name' => 'action', + 'enable' => 'true' + }, + { + 'enable' => 'true', + 'ssl_cert_file' => '/var/lib/centreon-gorgone/.keys/server_api_cert.pem', + 'ssl' => 'true', + 'auth' => { + 'user' => 'web-user-gorgone-api', + 'enabled' => 'false', + 'password' => 'password' + }, + 'name' => 'httpserver', + 'address' => '0.0.0.0', + 'allowed_hosts' => { + 'enabled' => 'true', + 'subnets' => [ + '127.0.0.1/32' + ] + }, + 'port' => '8085', + 'package' => 'gorgone::modules::core::httpserver::hooks', + 'ssl_key_file' => '/var/lib/centreon-gorgone/.keys/server_api_key.pem' + }, + { + 'whitelist_cmds' => 'true', + 'enable' => 'true', + 'package' => 'gorgone::modules::core::action::hooks', + 'allowed_cmds' => [ + '^sudo\\s+(/bin/)?systemctl\\s+(reload|restart)\\s+(centengine|centreontrapd|cbd)\\s*$', + '^(sudo\\s+)?(/usr/bin/)?service\\s+(centengine|centreontrapd|cbd|cbd-sql)\\s+(reload|restart)\\s*$', + '^/usr/sbin/centenginestats\\s+-c\\s+/etc/centreon-engine/centengine\\.cfg\\s*$', + '^cat\\s+/var/lib/centreon-engine/[a-zA-Z0-9\\-]+-stats\\.json\\s*$', + '^/usr/lib/centreon/plugins/.*$', + '^/bin/perl /usr/share/centreon/bin/anomaly_detection --seasonality >> /var/log/centreon/anomaly_detection\\.log 2>&1\\s*$', + '^/usr/bin/php -q /usr/share/centreon/cron/centreon-helios\\.php >> /var/log/centreon-helios\\.log 2>&1\\s*$', + '^centreon', + '^mkdir', + '^/usr/share/centreon/www/modules/centreon-autodiscovery-server/script/run_save_discovered_host', + '^/usr/share/centreon/bin/centreon -u \\"centreon-gorgone\\" -p \\S+ -w -o CentreonWorker -a processQueue$' + ], + 'name' => 'action', + 'command_timeout' => 30 + }, + { + 'enable' => 'true', + 'cron' => [ + { + 'action' => 'LAUNCHSERVICEDISCOVERY', + 'timespec' => '30 22 * * *', + 'id' => 'service_discovery' + } + ], + 'name' => 'cron', + 'package' => 'gorgone::modules::core::cron::hooks' + }, + { + 'package' => 'gorgone::modules::core::register::hooks', + 'name' => 'register', + 'enable' => 'true' + }, + { + 'enable' => 'true', + 'package' => 'gorgone::modules::centreon::nodes::hooks', + 'name' => 'nodes' + }, + { + 'enable' => 'true', + 'httpserver' => { + 'enable' => 'true', + 'port' => 8099, + 'token' => "^\$*\x{f9}^\x{e9}&\x{e0}\x{e9}r\x{e7}(\x{e9}/*-+\$\$z\@ze%r\x{a8}\x{a3}\x{b5}~zz", + 'address' => '0.0.0.0' + }, + 'package' => 'gorgone::modules::core::proxy::hooks', + 'name' => 'proxy', + 'pool' => 1, + 'buffer_size' => 10 + }, + { + 'cmd_dir' => '/var/lib/centreon/centcore/', + 'buffer_size' => 100, + 'cache_dir' => '/var/cache/centreon/', + 'enable' => 'true', + 'name' => 'legacycmd', + 'remote_dir' => '/var/cache/centreon//config/remote-data/', + 'cmd_file' => '/var/lib/centreon/centcore.cmd', + 'cache_dir_trap' => '/etc/snmp/centreon_traps', + 'package' => 'gorgone::modules::centreon::legacycmd::hooks' + }, + { + 'enable' => 'true', + 'command_file' => '/var/lib/centreon-engine/rw/centengine.cmd', + 'name' => 'engine', + 'package' => 'gorgone::modules::centreon::engine::hooks' + }, + { + 'name' => 'statistics', + 'package' => 'gorgone::modules::centreon::statistics::hooks', + 'enable' => 'true', + 'cron' => [ + { + 'action' => 'BROKERSTATS', + 'timespec' => '*/5 * * * *', + 'id' => 'broker_stats', + 'parameters' => { + 'timeout' => 10 + } + }, + { + 'action' => 'ENGINESTATS', + 'id' => 'engine_stats', + 'timespec' => '*/5 * * * *', + 'parameters' => { + 'timeout' => 10 + } + } + ], + 'broker_cache_dir' => '/var/cache/centreon//broker-stats/' + }, + { + 'enable' => 'true', + 'package' => 'gorgone::modules::centreon::autodiscovery::hooks', + 'name' => 'autodiscovery' + }, + { + 'package' => 'gorgone::modules::centreon::audit::hooks', + 'name' => 'audit', + 'enable' => 'true' + } + ] + } + } +}; diff --git a/gorgone/tests/unit/class/config_examples/include_other_files/first_module.yaml b/gorgone/tests/unit/class/config_examples/include_other_files/first_module.yaml new file mode 100644 index 00000000000..767a5f36e7d --- /dev/null +++ b/gorgone/tests/unit/class/config_examples/include_other_files/first_module.yaml @@ -0,0 +1,3 @@ +gorgone: + gorgonecore: + global_variable: "value" \ No newline at end of file diff --git a/gorgone/tests/unit/class/config_examples/include_other_files/main.yaml b/gorgone/tests/unit/class/config_examples/include_other_files/main.yaml new file mode 100644 index 00000000000..fc5b54b1b49 --- /dev/null +++ b/gorgone/tests/unit/class/config_examples/include_other_files/main.yaml @@ -0,0 +1,4 @@ +--- +name: config.yaml +description: simple configuration exemple without other file include. +configuration: !include ./first_module.yaml diff --git a/gorgone/tests/unit/class/config_examples/simple_no_recursion/norecursion.yaml b/gorgone/tests/unit/class/config_examples/simple_no_recursion/norecursion.yaml new file mode 100644 index 00000000000..c903827c7b1 --- /dev/null +++ b/gorgone/tests/unit/class/config_examples/simple_no_recursion/norecursion.yaml @@ -0,0 +1,15 @@ +--- +name: config.yaml +description: simple configuration exemple without other file include. +configuration: + gorgone: + key1: a string with all char &é"'(-è_çà)=!:;,*$^ù%µ£¨/.\e?/§ + key2: + - array1 + - array2 + - array3 + TrueVal: true + FalseVal: false + vault: + badFormat: "secret::hashicorp::thereIsOnlyOneColon" + correctFormat: "secret::hashicorp_vault::SecretPathArg::secretNameFromApiResponse" diff --git a/gorgone/tests/unit/class/core.t b/gorgone/tests/unit/class/core.t new file mode 100644 index 00000000000..b4a3224c44b --- /dev/null +++ b/gorgone/tests/unit/class/core.t @@ -0,0 +1,106 @@ +#!/usr/bin/perl +use strict; +use warnings; + +use Test2::V0; +use Test2::Plugin::NoWarnings echo => 1; +use Test2::Tools::Compare qw{is like match}; +use Data::Dumper; +use FindBin; +use lib "$FindBin::Bin/../../../"; +use gorgone::class::script; +use gorgone::class::core; +use centreon::common::centreonvault; + +sub create_data_set { + my $set = {}; + # as we are in unit test, we can't be sure of our current path, but the tests require that we start from the same directory than the script. + chdir($FindBin::Bin); + $set->{logger} = gorgone::class::logger->new(); + $set->{logger}->severity('debug'); + $set->{vault} = mock 'centreon::common::centreonvault'; # is from Test2::Tools::Mock, included by Test2::V0 + $set->{vault}->override('get_secret' => sub { + if ($_[1] eq 'secret::hashicorp_vault::SecretPathArg::secretNameFromApiResponse') { + return 'VaultSentASecret'; + } + return $_[1]; + }, 'new' => sub { + return bless({}, 'centreon::common::centreonvault'); + }); + + return $set; +} + +sub test_configuration_read { + my $set = shift; + # let's make a simple object and try to industryalize the yaml read configuration. + my $gorgone = gorgone::class::core->new(); + $gorgone->{logger} = $set->{logger}; + $gorgone->{vault} = centreon::common::centreonvault->new(); + + my $tests_cases = [ + { + file => './config_examples/simple_no_recursion/norecursion.yaml', + got => { configuration => { gorgone => { + key1 => 'a string with all char &é"\'(-è_çà)=!:;,*$^ù%µ£¨/.\e?/§', + key2 => ["array1", "array2", "array3"], + TrueVal => 'true', + FalseVal => 'false', + vault => { + badFormat => 'secret::hashicorp::thereIsOnlyOneColon', + correctFormat => 'VaultSentASecret'}, + + } } }, + msg => 'simple configuration without recursion' + }, + { + file => './config_examples/include_other_files/main.yaml', + got => { configuration => { gorgone => { + gorgonecore => { global_variable => "value" } + } } }, + msg => 'simple configuration with !include.' + }, + { # this is a real world exemple with all parameter I could think of. The default configuration don't have all of them. + # this is more an integration test than a unit test, but allow to test the whole configuration. + file => './config_examples/centreon-gorgone/config.yaml', + got => require("./config_examples/centreon-gorgone/expectedConfiguration.pl"), + msg => 'complete configuration with multiples include and many files.' + } + ]; + + for my $test (@$tests_cases) { + my $config = $gorgone->yaml_load_config( + file => $test->{file}, + filter => '!($ariane eq "configuration##" || $ariane =~ /^configuration##(?:gorgone|centreon)##/)' + ); + is($config, $test->{got}, $test->{msg}); + } + +} + +sub test_yaml_get_include { + my $set = shift; + my $gorgone = gorgone::class::core->new(); + $gorgone->{logger} = $set->{logger}; + #$gorgone->{vault} = centreon::common::centreonvault->new(); + my @result = $gorgone->yaml_get_include('include' => '*.yaml', + 'current_dir' => './config_examples/include_other_files', + 'filter' => '!($ariane eq "configuration##" || $ariane =~ /^configuration##(?:gorgone|centreon)##/)'); + my @expected = ("./config_examples/include_other_files/./first_module.yaml", "./config_examples/include_other_files/./main.yaml"); + is(\@result, \@expected, 'found both files of the directory'); + + my @emptyResult = $gorgone->yaml_get_include('include' => '/notAFile.yaml', + 'current_dir' => './config_examples/include_other_files', + 'filter' => '!($ariane eq "configuration##" || $ariane =~ /^configuration##(?:gorgone|centreon)##/)'); + is(scalar(@emptyResult), 0, 'no file found return empty'); +} +sub main { + my $set = create_data_set(); + test_yaml_get_include($set); + test_configuration_read($set); + + print "\n"; + done_testing; +} +&main; +