feat(apps::vmware::vsphere8::vcenter::plugin): new plugin (#5608)

Co-authored-by: sdepassio <114986849+sdepassio@users.noreply.github.com>
Refs: CTOR-431
This commit is contained in:
omercier 2025-07-04 15:54:02 +02:00 committed by GitHub
parent eec431c060
commit 226a574d41
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
26 changed files with 2478 additions and 22 deletions

View File

@ -10,8 +10,8 @@ def get_tests_folders(plugin_name):
folder_list = []
pkg_file = open("./packaging/" + plugin_name + "/pkg.json")
packaging = json.load(pkg_file)
for file in packaging["files"]: # loop on "files" array in pkg.json file.
if os.path.isdir("tests/" + file): # check if the path is a directory in the "tests" folder
for file in packaging["files"]: # loop on "files" array in pkg.json file.
if os.path.isdir("tests/" + file): # check if the path is a directory in the "tests" folder
folder_list.append("tests/" + file)
return folder_list
@ -27,8 +27,10 @@ def test_plugin(plugin_name):
print(f"{plugin_name} folders_list : {folders_list}")
if len(folders_list) == 0:
return 0 # no tests present at the moment, but we still have tested the plugin can be installed.
robot_results = subprocess.run("robot --exclude notauto -v ''CENTREON_PLUGINS:" + get_plugin_full_path(plugin_name) + " " + " ".join(folders_list),
shell=True, check=False)
robot_results = subprocess.run(
"robot --exclude notauto -v ''CENTREON_PLUGINS:" + get_plugin_full_path(plugin_name) + " " + " ".join(
folders_list),
shell=True, check=False)
return robot_results.returncode
@ -52,12 +54,13 @@ def launch_snmp_sim():
snmpsim_cmd = "snmpsim-command-responder --logging-method=null --agent-udpv4-endpoint=127.0.0.1:2024 --process-user=snmp --process-group=snmp --data-dir='./tests' &"
try_command(cmd=snmpsim_cmd, error="can't launch snmp sim daemon.")
def refresh_packet_manager(archi):
with open('/var/log/robot-plugins-installation-tests.log', "a") as outfile:
if archi == "deb":
outfile.write("apt-get update\n")
output_status = (subprocess.run(
"apt-get update",
"apt-get update",
shell=True, check=False, stderr=subprocess.STDOUT, stdout=outfile)).returncode
elif archi == "rpm":
return 0
@ -66,17 +69,20 @@ def refresh_packet_manager(archi):
exit(1)
return output_status
def install_plugin(plugin, archi):
with open('/var/log/robot-plugins-installation-tests.log', "a") as outfile:
if archi == "deb":
outfile.write("apt-get install -o 'Binary::apt::APT::Keep-Downloaded-Packages=1;' -y ./" + plugin.lower() + "*.deb\n")
outfile.write(
"apt-get install -o 'Binary::apt::APT::Keep-Downloaded-Packages=1;' -y ./" + plugin.lower() + "*.deb\n")
output_status = (subprocess.run(
"apt-get install -o 'Binary::apt::APT::Keep-Downloaded-Packages=1;' -y ./" + plugin.lower() + "*.deb",
"apt-get install -o 'Binary::apt::APT::Keep-Downloaded-Packages=1;' -y ./" + plugin.lower() + "*.deb",
shell=True, check=False, stderr=subprocess.STDOUT, stdout=outfile)).returncode
elif archi == "rpm":
outfile.write("dnf install --setopt=keepcache=True -y ./" + plugin + "*.rpm\n")
output_status = (subprocess.run("dnf install --setopt=keepcache=True -y ./" + plugin + "*.rpm", shell=True, check=False,
stderr=subprocess.STDOUT, stdout=outfile)).returncode
output_status = (
subprocess.run("dnf install --setopt=keepcache=True -y ./" + plugin + "*.rpm", shell=True, check=False,
stderr=subprocess.STDOUT, stdout=outfile)).returncode
else:
print(f"Unknown architecture, expected deb or rpm, got {archi}. Exiting.")
exit(1)
@ -86,17 +92,19 @@ def install_plugin(plugin, archi):
def remove_plugin(plugin, archi):
with open('/var/log/robot-plugins-installation-tests.log', "a") as outfile:
if archi == "deb":
outfile.write("apt-get -o 'Binary::apt::APT::Keep-Downloaded-Packages=1;' autoremove -y " + plugin.lower() + "\n")
outfile.write(
"export SUDO_FORCE_REMOVE=yes; apt-get -o 'Binary::apt::APT::Keep-Downloaded-Packages=1;' autoremove -y "
+ plugin.lower() + "\n")
output_status = (subprocess.run(
"apt-get -o 'Binary::apt::APT::Keep-Downloaded-Packages=1;' autoremove -y " + plugin.lower(),
"export SUDO_FORCE_REMOVE=yes; apt-get -o 'Binary::apt::APT::Keep-Downloaded-Packages=1;' autoremove -y " + plugin.lower(),
shell=True, check=False, stderr=subprocess.STDOUT, stdout=outfile)).returncode
# -o 'Binary::apt::APT::Keep-Downloaded-Packages=1;' is an option to force apt to keep the package in
# /var/cache/apt/archives, so it do not re download them for every installation.
# 'autoremove', contrary to 'remove' all dependancy while removing the original package.
elif archi == "rpm":
outfile.write("dnf remove --setopt=keepcache=True -y " + plugin + "\n")
output_status = (subprocess.run("dnf remove --setopt=keepcache=True -y " + plugin, shell=True, check=False,
outfile.write("dnf remove --setopt=protected_packages= --setopt=keepcache=True -y " + plugin + "\n")
output_status = (subprocess.run("dnf remove --setopt=protected_packages= --setopt=keepcache=True -y " + plugin, shell=True, check=False,
stderr=subprocess.STDOUT, stdout=outfile)).returncode
else:
print(f"Unknown architecture, expected deb or rpm, got {archi}. Exiting.")
@ -153,7 +161,7 @@ if __name__ == '__main__':
error_purge += tmp
print(f"{nb_plugins} plugins tested.\n there was {error_install} installation error, {error_tests} test "
f"errors, and {error_purge} removal error list of error : {list_plugin_error}",)
f"errors, and {error_purge} removal error list of error : {list_plugin_error}", )
if error_install != 0 or error_tests != 0 or error_purge != 0:
exit(1)

View File

@ -0,0 +1,5 @@
{
"dependencies": [
"libjson-perl"
]
}

View File

@ -0,0 +1,10 @@
{
"pkg_name": "centreon-plugin-Virtualization-Vmware8-Vcenter-Restapi",
"pkg_summary": "Centreon Plugin to monitor VMware vCenter using vSphere 8 REST API",
"plugin_name": "centreon_vmware8_vcenter_restapi.pl",
"files": [
"centreon/plugins/script_custom.pm",
"apps/vmware/vsphere8/vcenter/",
"apps/vmware/vsphere8/custom/"
]
}

View File

@ -0,0 +1,5 @@
{
"dependencies": [
"perl(JSON)"
]
}

View File

@ -203,7 +203,7 @@ sub try_request_api {
}
my $decoded = ($method eq 'GET') ? centreon::plugins::misc::json_decode($content) : {};
my $decoded = ($method eq 'GET') ? centreon::plugins::misc::json_decode($content, booleans_as_strings => 1) : {};
return $decoded;
}

View File

@ -20,7 +20,7 @@
package apps::vmware::vsphere8::esx::mode;
use strict;
use warnings FATAL => 'all';
use warnings;
use base qw(centreon::plugins::templates::counter);

View File

@ -0,0 +1,170 @@
#
# Copyright 2025 Centreon (http://www.centreon.com/)
#
# Centreon is a full-fledged industry-strength solution that meets
# the needs in IT infrastructure and application monitoring for
# service performance.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
package apps::vmware::vsphere8::vcenter::mode;
use strict;
use warnings;
use base qw(centreon::plugins::templates::counter);
sub new {
my ($class, %options) = @_;
my $self = $class->SUPER::new(package => __PACKAGE__, %options, force_new_perfdata => 1);
$options{options}->add_options(
arguments => {}
);
$options{options}->add_help(package => __PACKAGE__, sections => 'VMWARE 8 VCENTER OPTIONS', once => 1);
return $self;
}
sub get_vms {
my ($self, %options) = @_;
# Retrieve the data
return $options{custom}->request_api('endpoint' => '/vcenter/vm', 'method' => 'GET');
}
sub get_datastore {
my ($self, %options) = @_;
# if a datastore_id option is given, prepare to append it to the endpoint path
my $datastore_param = defined($options{datastore_id}) ? '/' . $options{datastore_id} : '';
# Retrieve the data
return $options{custom}->request_api('endpoint' => '/vcenter/datastore' . $datastore_param, 'method' => 'GET');
}
sub get_cluster {
my ($self, %options) = @_;
# if a cluster_id option is given, prepare to append it to the endpoint path
my $cluster_param = defined($options{cluster_id}) ? '/' . $options{cluster_id} : '';
# Retrieve the data
return $options{custom}->request_api('endpoint' => '/vcenter/cluster' . $cluster_param, 'method' => 'GET');
}
sub request_api {
my ($self, %options) = @_;
return $options{custom}->request_api(%options);
}
sub check_options {
my ($self, %options) = @_;
$self->SUPER::check_options(%options);
}
1;
__END__
=head1 VMWARE 8 VCENTER OPTIONS
=over 4
No specific options for vCenter modes.
=back
=cut
=head1 NAME
apps::vmware::vsphere8::vcenter::mode - Template for modes monitoring VMware vCenter
=head1 SYNOPSIS
use base apps::vmware::vsphere8::vcenter::mode;
sub set_counters {...}
sub manage_selection {
my ($self, %options) = @_;
$self->set_options(option_results => $option_results);
$self->check_options();
my $vm_data = $self->get_vms(%options);
my $datastore_data = $self->get_datastore(%options);
}
=head1 DESCRIPTION
This module provides methods to interact with the VMware vSphere 8 REST API. It handles generic API requests and VMs GET requests.
=head1 METHODS
=head2 get_datastore
my $all_datastores = $self->get_datastore(%options);
my $one_datastore = $self->get_datastore(%options, datastore_id => 'datastore-35');
Retrieves the vCenter's datastores or only one datastore's specifics in case the `datastore_id` option is provided.
=over 4
=item * C<%options> - A hash of options. The following keys are supported:
=over 8
=item * C<custom> - The custom_mode object, defined in C<api.pm> and declared in C<plugin.pm> (mandatory).
=item * C<datastore_id> - The C<datastore_id> of a datastore (optional).
=back
=back
=head2 get_vms
my $all_vms = $self->get_vms(%options);
Retrieves the vCenter's virtual machines list.
=over 4
=item * C<%options> - A hash of options. The following keys are supported:
=over 8
=item * C<custom> - The custom_mode object, defined in C<api.pm> and declared in C<plugin.pm> (mandatory).
=back
=back
Returns the list of all the virtual machines with the following attributes for each VM:
=over 4
=item * C<vm>: ID of the virtual machine.
=item * C<name>: name of the virtual machine.
=item * C<cpu_count>: number of vCPU.
=item * C<power_state>: state of the VM. Can be POWERED_ON, POWERED_OFF, SUSPENDED.
=item * C<memory_size_MiB>: amount of memory allocated to the virtual machine.
=back
=cut

View File

@ -0,0 +1,167 @@
#
# Copyright 2025 Centreon (http://www.centreon.com/)
#
# Centreon is a full-fledged industry-strength solution that meets
# the needs in IT infrastructure and application monitoring for
# service performance.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
package apps::vmware::vsphere8::vcenter::mode::clusterstatus;
use base qw(apps::vmware::vsphere8::vcenter::mode);
use strict;
use warnings;
use centreon::plugins::templates::catalog_functions qw(catalog_status_threshold_ng);
sub custom_ha_status_output {
my ($self, %options) = @_;
my $ha = ($self->{result_values}->{ha_enabled} eq 'true') ? 'enabled' : 'disabled';
return "'" . $self->{result_values}->{name} . "' has HA " . $ha;
}
sub custom_drs_status_output {
my ($self, %options) = @_;
my $drs = ($self->{result_values}->{drs_enabled} eq 'true') ? 'enabled' : 'disabled';
return "'" . $self->{result_values}->{name} . "' has DRS " . $drs;
}
sub set_counters {
my ($self, %options) = @_;
$self->{maps_counters_type} = [
{ name => 'cluster', type => 1, cb_prefix_output => 'prefix_cluster_output', message_multiple => 'All clusters are ok', skipped_code => { -10 => 1 } }
];
$self->{maps_counters}->{cluster} = [
{
label => 'ha-status',
type => 2,
warning_default => '%{ha_enabled} ne "true"',
set => {
key_values => [ { name => 'name' }, { name => 'cluster' }, { name => 'ha_enabled' } ],
closure_custom_output => $self->can('custom_ha_status_output'),
closure_custom_threshold_check => \&catalog_status_threshold_ng
}
},
{
label => 'drs-status',
type => 2,
warning_default => '%{drs_enabled} ne "true"',
set => {
key_values => [ { name => 'name' }, { name => 'drs_enabled' }, { name => 'cluster' } ],
closure_custom_output => $self->can('custom_drs_status_output'),
closure_custom_threshold_check => \&catalog_status_threshold_ng
}
}
];
}
sub new {
my ($class, %options) = @_;
my $self = $class->SUPER::new(package => __PACKAGE__, %options, force_new_perfdata => 1);
$options{options}->add_options(
arguments => {
'include-name:s' => { name => 'include_name', default => '' },
'exclude-name:s' => { name => 'exclude_name', default => '' }
}
);
$options{options}->add_help(package => __PACKAGE__, sections => 'MODE', once => 1);
return $self;
}
sub manage_selection {
my ($self, %options) = @_;
# get the list of clusters response from /api/vcenter/cluster endpoint
my $response = $self->get_cluster(%options);
for my $cluster (@{$response}) {
# exclude cluster if not whitelisted
if (centreon::plugins::misc::is_excluded($cluster->{name}, $self->{option_results}->{include_name}, $self->{option_results}->{exclude_name})) {
$self->{output}->output_add(long_msg => "skipping excluded cluster '" . $cluster->{name} . "'", debug => 1);
next;
}
# and now we store the information
$self->{cluster}->{$cluster->{cluster}} = {
name => $cluster->{name},
cluster => $cluster->{cluster},
drs_enabled => $cluster->{drs_enabled},
ha_enabled => $cluster->{ha_enabled}
};
}
if (!defined($self->{cluster}) || keys(%{$self->{cluster}}) == 0) {
$self->{output}->output_add(
severity => 'UNKNOWN',
short_msg => 'No clusters found.'
);
}
}
1;
__END__
=head1 MODE
Monitor the status of a vSphere cluster through vSphere 8 REST API.
=over 8
=item B<--include-name>
Filter by including only the clusters whose name matches the regular expression provided after this parameter.
Example : C<--include-name='^Prod.*'>
=item B<--exclude-name>
Filter by excluding the clusters whose name matches the regular expression provided after this parameter.
Example : C<--exclude-name='^Sandbox.*'>
=item B<--warning-ha-status>
Define the conditions to match for the status to be WARNING. You can use the following variables: C<%{name}>, C<%{ha_enabled}>,
C<%{cluster}>.
Default: C<%{ha_enabled} ne "true">
=item B<--critical-ha-status>
Define the conditions to match for the status to be CRITICAL. You can use the following variables: C<%{name}>, C<%{ha_enabled}>,
C<%{cluster}>.
=item B<--warning-drs-status>
Define the conditions to match for the status to be WARNING. You can use the following variables: C<%{name}>, C<%{drs_enabled}>,
C<%{cluster}>.
Default: C<%{drs_enabled} ne "true">
=item B<--critical-drs-status>
Define the conditions to match for the status to be CRITICAL. You can use the following variables: C<%{name}>, C<%{drs_enabled}>,
C<%{cluster}>.
=back
=cut

View File

@ -0,0 +1,229 @@
#
# Copyright 2025 Centreon (http://www.centreon.com/)
#
# Centreon is a full-fledged industry-strength solution that meets
# the needs in IT infrastructure and application monitoring for
# service performance.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
package apps::vmware::vsphere8::vcenter::mode::datastoreusage;
use base qw(apps::vmware::vsphere8::vcenter::mode);
use strict;
use warnings;
use centreon::plugins::templates::catalog_functions qw(catalog_status_threshold_ng);
sub custom_status_output {
my ($self, %options) = @_;
return "'" . $self->{result_values}->{display} . "' accessible" if ($self->{result_values}->{accessible} eq 'true');
return "'" . $self->{result_values}->{display} . "' NOT accessible" if ($self->{result_values}->{accessible} ne 'true');
}
sub custom_usage_output {
my ($self, %options) = @_;
my ($total_size_value, $total_size_unit) = $self->{perfdata}->change_bytes(value => $self->{result_values}->{total_space});
my ($total_used_value, $total_used_unit) = $self->{perfdata}->change_bytes(value => $self->{result_values}->{used_space});
my ($total_free_value, $total_free_unit) = $self->{perfdata}->change_bytes(value => $self->{result_values}->{free_space});
my $msg = sprintf(
'Used: %s (%.2f%%) - Free: %s (%.2f%%) - Total: %s',
$total_used_value . " " . $total_used_unit, $self->{result_values}->{prct_used_space},
$total_free_value . " " . $total_free_unit, $self->{result_values}->{prct_free_space},
$total_size_value . " " . $total_size_unit
);
return $msg;
}
sub set_counters {
my ($self, %options) = @_;
$self->{maps_counters_type} = [
{ name => 'datastore', type => 1, cb_prefix_output => 'prefix_datastore_output', message_multiple => 'All datastores are ok', skipped_code => { -10 => 1 } }
];
$self->{maps_counters}->{datastore} = [
{
label => 'status',
type => 2,
critical_default => '%{accessible} ne "true"',
set => {
key_values => [ { name => 'accessible' }, { name => 'display' },
{ name => 'thin_provisioning_supported' }, { name => 'multiple_host_access' } ],
closure_custom_output => $self->can('custom_status_output'),
closure_custom_threshold_check => \&catalog_status_threshold_ng
}
},
{
label => 'usage',
nlabel => 'datastore.space.usage.bytes',
type => 1,
set => {
key_values => [
{ name => 'used_space' }, { name => 'free_space' }, { name => 'prct_used_space' },
{ name => 'prct_free_space' }, { name => 'total_space' }, { name => 'display' }
],
closure_custom_output => $self->can('custom_usage_output'),
perfdatas => [
{ label => 'used', template => '%d', min => 0, max => 'total_space',
unit => 'B', cast_int => 1, label_extra_instance => 1, instance_use => 'display' }
]
}
},
{
label => 'usage-free',
nlabel => 'datastore.space.free.bytes',
display_ok => 0,
type => 1,
set => {
key_values => [
{ name => 'free_space' }, { name => 'used_space' }, { name => 'prct_used_space' },
{ name => 'prct_free_space' }, { name => 'total_space' }, { name => 'display' } ],
closure_custom_output => $self->can('custom_usage_output'),
perfdatas => [
{ label => 'free', template => '%d', min => 0, max => 'total_space',
unit => 'B', cast_int => 1, label_extra_instance => 1, instance_use => 'display' }
]
}
},
{
label => 'usage-prct',
nlabel => 'datastore.space.usage.percentage',
display_ok => 0,
type => 1,
set => {
key_values => [
{ name => 'prct_used_space' }, { name => 'free_space' }, { name => 'used_space' },
{ name => 'prct_free_space' }, { name => 'total_space' }, { name => 'display' }
],
closure_custom_output => $self->can('custom_usage_output'),
perfdatas => [
{ label => 'used_prct', template => '%.2f', min => 0, max => 100,
unit => '%', label_extra_instance => 1, instance_use => 'display' }
]
}
}
];
}
sub new {
my ($class, %options) = @_;
my $self = $class->SUPER::new(package => __PACKAGE__, %options, force_new_perfdata => 1);
$options{options}->add_options(
arguments => {
'include-name:s' => { name => 'include_name', default => '' },
'exclude-name:s' => { name => 'exclude_name', default => '' }
}
);
$options{options}->add_help(package => __PACKAGE__, sections => 'MODE', once => 1);
return $self;
}
sub manage_selection {
my ($self, %options) = @_;
# get the list of datastores response from /api/vcenter/datastore endpoint
my $response = $self->get_datastore(%options);
for my $ds (@{$response}) {
# exclude datastores not whitelisted
if ( centreon::plugins::misc::is_excluded($ds->{name}, $self->{option_results}->{include_name}, $self->{option_results}->{exclude_name}) ) {
$self->{output}->output_add(long_msg => "skipping excluded datastore '" . $ds->{name} . "'", debug => 1);
next;
}
# at this point the current datastore must be monitored
# let's get the missing data for the current datastore with a new API request
my $detail = $self->get_datastore(%options, datastore_id => $ds->{datastore});
# and now we store the information
$self->{datastore}->{$ds->{datastore}} = {
display => $ds->{name},
type => $ds->{type},
free_space => $ds->{free_space},
total_space => $ds->{capacity},
used_space => $ds->{capacity} - $ds->{free_space},
prct_used_space => 100 * ($ds->{capacity} - $ds->{free_space}) / $ds->{capacity},
prct_free_space => 100 * $ds->{free_space} / $ds->{capacity},
thin_provisioning_supported => $detail->{thin_provisioning_supported},
accessible => $detail->{accessible},
multiple_host_access => $detail->{multiple_host_access}
};
}
}
1;
__END__
=head1 MODE
Monitor the usage of a vCenter's datastores through vSphere 8 REST API.
=over 8
=item B<--include-name>
Filter by including only the VMs whose name matches the regular expression provided after this parameter.
Example : C<--include-name='^prod.*'>
=item B<--exclude-name>
Filter by excluding the VMs whose name matches the regular expression provided after this parameter.
Example : C<--exclude-name='^sandbox.*'>
=item B<--warning-status>
Define the conditions to match for the status to be WARNING. You can use the following variables: C<%{accessible}>,
C<%{display}>, C<%{thin_provisioning_supported}>, C<%{multiple_host_access}>.
=item B<--critical-status>
Define the conditions to match for the status to be CRITICAL. You can use the following variables: C<%{accessible}>,
C<%{display}>, C<%{thin_provisioning_supported}>, C<%{multiple_host_access}>.
Default: C<%{accessible} ne "true">
=item B<--warning-usage>
Threshold in bytes.
=item B<--critical-usage>
Threshold in bytes.
=item B<--warning-usage-free>
Threshold in bytes.
=item B<--critical-usage-free>
Threshold in bytes.
=item B<--warning-usage-prct>
Threshold in percentage.
=item B<--critical-usage-prct>
Threshold in percentage.
=back
=cut

View File

@ -0,0 +1,95 @@
#
# Copyright 2025 Centreon (http://www.centreon.com/)
#
# Centreon is a full-fledged industry-strength solution that meets
# the needs in IT infrastructure and application monitoring for
# service performance.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
package apps::vmware::vsphere8::vcenter::mode::listclusters;
use base qw(apps::vmware::vsphere8::vcenter::mode);
use strict;
use warnings;
sub new {
my ($class, %options) = @_;
my $self = $class->SUPER::new(package => __PACKAGE__, %options);
bless $self, $class;
$options{options}->add_options(arguments => {});
return $self;
}
sub check_options {
my ($self, %options) = @_;
$self->SUPER::init(%options);
}
sub run {
my ($self, %options) = @_;
my $response = $self->get_cluster(%options);
for my $cluster (@{$response}) {
$self->{output}->output_add(
long_msg => sprintf(" %s [id=%s] [drs_enabled=%s] [ha_enabled=%s]",
$cluster->{name},
$cluster->{cluster},
$cluster->{drs_enabled},
$cluster->{ha_enabled})
);
}
$self->{output}->output_add(severity => 'OK',
short_msg => 'List clusters:');
$self->{output}->display(nolabel => 1, force_ignore_perfdata => 1, force_long_output => 1);
$self->{output}->exit();
}
sub disco_format {
my ($self, %options) = @_;
$self->{output}->add_disco_format(elements => ['name', 'cluster', 'drs_enabled', 'ha_enabled']);
}
sub disco_show {
my ($self, %options) = @_;
my $response = $self->get_cluster(%options);
for my $ds (@{$response}) {
$self->{output}->add_disco_entry(
drs_enabled => $ds->{drs_enabled},
cluster => $ds->{cluster},
name => $ds->{name},
ha_enabled => $ds->{ha_enabled}
);
}
}
1;
__END__
=head1 MODE
List clusters for service discovery.
=over 8
=back
=cut

View File

@ -0,0 +1,96 @@
#
# Copyright 2025 Centreon (http://www.centreon.com/)
#
# Centreon is a full-fledged industry-strength solution that meets
# the needs in IT infrastructure and application monitoring for
# service performance.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
package apps::vmware::vsphere8::vcenter::mode::listdatastores;
use base qw(apps::vmware::vsphere8::vcenter::mode);
use strict;
use warnings;
sub new {
my ($class, %options) = @_;
my $self = $class->SUPER::new(package => __PACKAGE__, %options);
bless $self, $class;
$options{options}->add_options(arguments => {});
return $self;
}
sub check_options {
my ($self, %options) = @_;
$self->SUPER::init(%options);
}
sub run {
my ($self, %options) = @_;
my $response = $self->get_datastore(%options);
for my $ds (@{$response}) {
$self->{output}->output_add(long_msg => sprintf(" %s [%s] [%s] [%s free over %s]",
$ds->{name},
$ds->{type},
$ds->{datastore},
$ds->{free_space},
$ds->{capacity},
));
}
$self->{output}->output_add(severity => 'OK',
short_msg => 'List datastore(s):');
$self->{output}->display(nolabel => 1, force_ignore_perfdata => 1, force_long_output => 1);
$self->{output}->exit();
}
sub disco_format {
my ($self, %options) = @_;
$self->{output}->add_disco_format(elements => ['name', 'datastore', 'free_space', 'capacity', 'type']);
}
sub disco_show {
my ($self, %options) = @_;
my $response = $self->get_datastore(%options);
for my $ds (@{$response}) {
$self->{output}->add_disco_entry(
name => $ds->{name},
datastore => $ds->{datastore},
free_space => $ds->{free_space},
capacity => $ds->{capacity},
type => $ds->{type}
);
}
}
1;
__END__
=head1 MODE
List datastores for service discovery.
=over 8
=back
=cut

View File

@ -0,0 +1,218 @@
#
# Copyright 2025 Centreon (http://www.centreon.com/)
#
# Centreon is a full-fledged industry-strength solution that meets
# the needs in IT infrastructure and application monitoring for
# service performance.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
package apps::vmware::vsphere8::vcenter::mode::vmcount;
use base qw(apps::vmware::vsphere8::vcenter::mode);
use strict;
use warnings;
sub set_counters {
my ($self, %options) = @_;
$self->{maps_counters_type} = [
{ name => 'global', type => 0 }
];
$self->{maps_counters}->{global} = [
{
label => 'on-count',
nlabel => 'vm.poweredon.count',
type => 1,
set => {
key_values => [ { name => 'POWERED_ON' }, { name => 'total' } ],
output_template => '%s VM(s) powered on',
perfdatas => [
{ label => 'POWERED_ON', template => '%s', min => 0, max => 'total' }
]
}
},
{
label => 'off-count',
nlabel => 'vm.poweredoff.count',
type => 1,
set => {
key_values => [ { name => 'POWERED_OFF' }, { name => 'total' } ],
output_template => '%s VM(s) powered off',
perfdatas => [
{ label => 'POWERED_OFF', template => '%s', min => 0, max => 'total' }
]
}
},
{
label => 'suspended-count',
nlabel => 'vm.suspended.count',
type => 1,
set => {
key_values => [ { name => 'SUSPENDED' }, { name => 'total' } ],
output_template => '%s VM(s) suspended',
perfdatas => [
{ label => 'SUSPENDED', template => '%s', min => 0, max => 'total' }
]
}
},
{
label => 'total-count',
nlabel => 'vm.total.count',
type => 1,
warning_default => '1:',
set => {
key_values => [ { name => 'total' } ],
output_template => '%s VM(s) in total',
perfdatas => [
{ label => 'total', template => '%s', min => 0 }
]
}
}
];
}
sub new {
my ($class, %options) = @_;
my $self = $class->SUPER::new(package => __PACKAGE__, %options, force_new_perfdata => 1);
$options{options}->add_options(
arguments => {
'include-name:s' => { name => 'include_name', default => '' },
'exclude-name:s' => { name => 'exclude_name', default => '' },
'include-state:s' => { name => 'include_state', default => '' },
'exclude-state:s' => { name => 'exclude_state', default => '' },
}
);
$options{options}->add_help(package => __PACKAGE__, sections => 'VMWARE 8 VCENTER OPTIONS', once => 1);
return $self;
}
sub manage_selection {
my ($self, %options) = @_;
# get the response from /api/vcenter/vm endpoint
my $response = $self->get_vms(%options);
$self->{global} = {
'POWERED_ON' => 0,
'POWERED_OFF' => 0,
'SUSPENDED' => 0,
'total' => 0,
'UNKNOWN' => 0
};
for my $vm (@{$response}) {
# avoid undef values
my $entry = {
vm => $vm->{vm},
name => $vm->{name},
cpu_count => $vm->{cpu_count} // 0,
power_state => $vm->{power_state} // 'UNKNOWN',
memory_size_MiB => $vm->{memory_size_MiB} // 0
};
my $entry_desc = sprintf(
"VM '%s' (%s) which is %s, has %d CPUs and %d MiB of RAM",
$entry->{name},
$entry->{vm},
$entry->{power_state},
$entry->{cpu_count},
$entry->{memory_size_MiB}
);
if ( centreon::plugins::misc::is_excluded($entry->{name}, $self->{option_results}->{include_name}, $self->{option_results}->{exclude_name})
|| centreon::plugins::misc::is_excluded($entry->{power_state}, $self->{option_results}->{include_state}, $self->{option_results}->{exclude_state}) ) {
$self->{output}->output_add(long_msg => "skipping VM " . $entry_desc . " (excluded)", debug => 1);
next;
}
$self->{output}->output_add(long_msg => $entry_desc);
$self->{global}->{ $entry->{power_state} }++;
$self->{global}->{total}++;
}
}
1;
__END__
=head1 MODE
Monitor the number of VMware VMs through vSphere 8 REST API.
=over 8
=item B<--include-name>
Filter by including only the VMs whose name matches the regular expression provided after this parameter.
Example : C<--include-name='^prod.*'>
=item B<--exclude-name>
Filter by excluding the VMs whose name matches the regular expression provided after this parameter.
Example : C<--exclude-name='^sandbox.*'>
=item B<--include-state>
Filter by including only the VMs whose power state matches the regular expression provided after this parameter.
Example : C<--include-name='^POWERED_ON$'>
=item B<--exclude-state>
Filter by excluding the VMs whose state matches the regular expression provided after this parameter.
Example : C<--exclude-name='^POWERED_OFF|SUSPENDED$'>
=item B<--warning-on-count>
Threshold.
=item B<--critical-on-count>
Threshold.
=item B<--warning-off-count>
Threshold.
=item B<--critical-off-count>
Threshold.
=item B<--warning-suspended-count>
Threshold.
=item B<--critical-suspended-count>
Threshold.
=item B<--warning-total-count>
Threshold.
=item B<--critical-total-count>
Threshold.
=back
=cut

View File

@ -0,0 +1,53 @@
#
# Copyright 2025 Centreon (http://www.centreon.com/)
#
# Centreon is a full-fledged industry-strength solution that meets
# the needs in IT infrastructure and application monitoring for
# service performance.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
package apps::vmware::vsphere8::vcenter::plugin;
use strict;
use warnings;
use base qw(centreon::plugins::script_custom);
sub new {
my ($class, %options) = @_;
my $self = $class->SUPER::new(package => __PACKAGE__, %options);
bless $self, $class;
$self->{version} = '0.1';
$self->{modes} = {
'cluster-status' => 'apps::vmware::vsphere8::vcenter::mode::clusterstatus',
'datastore-usage' => 'apps::vmware::vsphere8::vcenter::mode::datastoreusage',
'list-clusters' => 'apps::vmware::vsphere8::vcenter::mode::listclusters',
'list-datastores' => 'apps::vmware::vsphere8::vcenter::mode::listdatastores',
'vm-count' => 'apps::vmware::vsphere8::vcenter::mode::vmcount',
};
$self->{custom_modes}->{api} = 'apps::vmware::vsphere8::custom::api';
return $self;
}
1;
__END__
=head1 PLUGIN DESCRIPTION
Monitor VMware physical hosts through vSphere 8 REST API.
=cut

View File

@ -767,18 +767,30 @@ sub check_security_whitelist {
}
sub json_decode {
my ($content) = @_;
my ($content, %options) = @_;
$content =~ s/\r//mg;
my $object;
my $decoder = JSON::XS->new->utf8;
# this option
if ($options{booleans_as_strings}) {
# boolean_values() is not available on old versions of JSON::XS (Alma 8 still provides v3.04)
if (JSON::XS->can('boolean_values')) {
$decoder = $decoder->boolean_values("false", "true");
} else {
# if boolean_values is not available, perform a dirty substitution of booleans
$content =~ s/"(\w+)"\s*:\s*(true|false)(\s*,?)/"$1": "$2"$3/gm;
}
}
eval {
$object = JSON::XS->new->utf8->decode($content);
$object = $decoder->decode($content);
};
if ($@) {
print STDERR "Cannot decode JSON string: $@" . "\n";
return undef;
}
return $object;
}
@ -798,6 +810,15 @@ sub json_encode {
return $encoded;
}
# function to assess if a string has to be excluded given an include regexp and an exclude regexp
sub is_excluded {
my ($string, $include_regexp, $exclude_regexp) = @_;
return 1 unless defined($string);
return 1 if (defined($exclude_regexp) && $exclude_regexp ne '' && $string =~ /$exclude_regexp/);
return 0 if (!defined($include_regexp) || $include_regexp eq '' || $string =~ /$include_regexp/);
return 1;
}
1;
@ -1287,7 +1308,7 @@ Checks if a command is in the security whitelist.
=head2 json_decode
my $decoded = centreon::plugins::misc::json_decode($content);
my $decoded = centreon::plugins::misc::json_decode($content, %options);
Decodes a JSON string.
@ -1295,6 +1316,15 @@ Decodes a JSON string.
=item * C<$content> - The JSON string to decode and transform into an object.
=item * C<%options> - Options passed to the function.
=over 4
=item * C<booleans_as_strings> - Defines whether booleans must be converted to C<true>/C<false> strings instead of
JSON:::PP::Boolean values. C<1> => strings, C<0> => booleans.
=back
=back
=head2 json_encode
@ -1309,6 +1339,28 @@ Encodes an object to a JSON string.
=back
=head2 is_excluded
my $excluded = is_excluded($string, $include_regexp, $exclude_regexp);
Determines whether a string should be excluded based on include and exclude regular expressions.
=over 4
=item * C<$string> - The string to evaluate. If undefined, the function returns 1 (excluded).
=item * C<$include_regexp> - A regular expression to include the string.
=item * C<$exclude_regexp> - A regular expression to exclude the string. If defined and matches the string, the function returns 1 (excluded).
=back
Returns 1 if the string is excluded, 0 if it is included.
The string is excluded if $exclude_regexp is defined and matches the string, or if $include_regexp is defined and does
not match the string. The string will also be excluded if it is undefined.
=cut
=head1 AUTHOR
Centreon

View File

@ -0,0 +1,41 @@
*** Settings ***
Resource ${CURDIR}${/}..${/}..${/}..${/}..${/}resources/import.resource
Suite Setup Start Mockoon ${MOCKOON_JSON}
Suite Teardown Stop Mockoon
Test Timeout 120s
Test Setup Ctn Cleanup Cache
*** Variables ***
${MOCKOON_JSON} ${CURDIR}${/}mockoon.json
${CMD} ${CENTREON_PLUGINS} --plugin=apps::vmware::vsphere8::vcenter::plugin
... --mode=cluster-status
... --password=C3POR2P2
... --username=obi-wan
... --hostname=127.0.0.1
... --proto=http
... --port=3000
*** Test Cases ***
Cluster-Status ${tc}
[Tags] apps api vmware vsphere8 vcenter
${command} Catenate ${CMD} ${extraoptions}
Ctn Run Command And Check Result As Strings ${command} ${expected_result}
Examples: tc extraoptions expected_result --
... 1 ${EMPTY} WARNING: 'EXT-CLU01' has DRS disabled
... 2 --warning-drs-status='\\\%{drs_enabled} ne "true"' WARNING: 'EXT-CLU01' has DRS disabled
... 3 --critical-drs-status='\\\%{drs_enabled} ne "true"' CRITICAL: 'EXT-CLU01' has DRS disabled
... 4 --warning-drs-status=0 OK: 'EXT-CLU01' has HA enabled, 'EXT-CLU01' has DRS disabled
... 5 --warning-ha-status='\\\%{ha_enabled} ne "true"' WARNING: 'EXT-CLU01' has DRS disabled
... 6 --warning-ha-status='\\\%{ha_enabled} eq "true"' WARNING: 'EXT-CLU01' has HA enabled, 'EXT-CLU01' has DRS disabled
... 7 --critical-ha-status='\\\%{ha_enabled} ne "true"' WARNING: 'EXT-CLU01' has DRS disabled
... 8 --critical-ha-status='\\\%{ha_enabled} eq "true"' CRITICAL: 'EXT-CLU01' has HA enabled, 'EXT-CLU01' has DRS disabled
... 9 --include-name='EXT-CLU01' WARNING: 'EXT-CLU01' has DRS disabled
... 10 --exclude-name='EXT-CLU01' UNKNOWN: No clusters found.
... 11 --include-name='no match' UNKNOWN: No clusters found.

View File

@ -0,0 +1,42 @@
*** Settings ***
Resource ${CURDIR}${/}..${/}..${/}..${/}..${/}resources/import.resource
Suite Setup Start Mockoon ${MOCKOON_JSON}
Suite Teardown Stop Mockoon
Test Timeout 120s
Test Setup Ctn Cleanup Cache
*** Variables ***
${MOCKOON_JSON} ${CURDIR}${/}mockoon.json
${CMD} ${CENTREON_PLUGINS} --plugin=apps::vmware::vsphere8::vcenter::plugin
... --mode=datastore-usage
... --password=C3POR2P2
... --username=obi-wan
... --hostname=127.0.0.1
... --proto=http
... --port=3000
*** Test Cases ***
Datastore-Usage ${tc}
[Tags] apps api vmware vsphere8 vcenter
${command_curl} Catenate ${CMD} --http-backend=curl ${extraoptions}
${command_lwp} Catenate ${CMD} --http-backend=lwp ${extraoptions}
Ctn Run Command And Check Result As Strings ${command_curl} ${expected_result}
Ctn Run Command And Check Result As Strings ${command_lwp} ${expected_result}
Examples: tc extraoptions expected_result --
... 1 --include-name=Prod OK: 'Datastore - Production' accessible, Used: 637.46 GB (52.66%) - Free: 573.04 GB (47.34%) - Total: 1.18 TB | 'Datastore - Production#datastore.space.usage.bytes'=684471615488B;;;0;1299764477952 'Datastore - Production#datastore.space.free.bytes'=615292862464B;;;0;1299764477952 'Datastore - Production#datastore.space.usage.percentage'=52.66%;;;0;100
... 2 --include-name=Prod --warning-usage=5 WARNING: Used: 637.46 GB (52.66%) - Free: 573.04 GB (47.34%) - Total: 1.18 TB | 'Datastore - Production#datastore.space.usage.bytes'=684471615488B;0:5;;0;1299764477952 'Datastore - Production#datastore.space.free.bytes'=615292862464B;;;0;1299764477952 'Datastore - Production#datastore.space.usage.percentage'=52.66%;;;0;100
... 3 --include-name=Prod --critical-usage=5 CRITICAL: Used: 637.46 GB (52.66%) - Free: 573.04 GB (47.34%) - Total: 1.18 TB | 'Datastore - Production#datastore.space.usage.bytes'=684471615488B;;0:5;0;1299764477952 'Datastore - Production#datastore.space.free.bytes'=615292862464B;;;0;1299764477952 'Datastore - Production#datastore.space.usage.percentage'=52.66%;;;0;100
... 4 --include-name=Prod --warning-usage-free=1000000000000: WARNING: Used: 637.46 GB (52.66%) - Free: 573.04 GB (47.34%) - Total: 1.18 TB | 'Datastore - Production#datastore.space.usage.bytes'=684471615488B;;;0;1299764477952 'Datastore - Production#datastore.space.free.bytes'=615292862464B;1000000000000:;;0;1299764477952 'Datastore - Production#datastore.space.usage.percentage'=52.66%;;;0;100
... 5 --include-name=Prod --critical-usage-free=1000000000000: CRITICAL: Used: 637.46 GB (52.66%) - Free: 573.04 GB (47.34%) - Total: 1.18 TB | 'Datastore - Production#datastore.space.usage.bytes'=684471615488B;;;0;1299764477952 'Datastore - Production#datastore.space.free.bytes'=615292862464B;;1000000000000:;0;1299764477952 'Datastore - Production#datastore.space.usage.percentage'=52.66%;;;0;100
... 6 --filter-counters=status CRITICAL: 'Datastore - Developpement 7200' NOT accessible
... 7 --filter-counters=status --critical-status=0 OK: All datastores are ok
... 8 --filter-counters=status --critical-status=0 --warning-status=1 WARNING: 'Datastore - Systeme' accessible - 'Datastore - ESX02' accessible - 'Datastore - ESX03' accessible - 'Datastore - Developpement 15000' accessible - 'Datastore - Developpement 7200' NOT accessible - 'Datastore - ESX01' accessible - 'Datastore - Developpement' accessible - 'Datastore - Production' accessible
... 9 --include-name=Prod --warning-usage-prct=5 WARNING: Used: 637.46 GB (52.66%) - Free: 573.04 GB (47.34%) - Total: 1.18 TB | 'Datastore - Production#datastore.space.usage.bytes'=684471615488B;;;0;1299764477952 'Datastore - Production#datastore.space.free.bytes'=615292862464B;;;0;1299764477952 'Datastore - Production#datastore.space.usage.percentage'=52.66%;0:5;;0;100
... 10 --include-name=Prod --critical-usage-prct=5 CRITICAL: Used: 637.46 GB (52.66%) - Free: 573.04 GB (47.34%) - Total: 1.18 TB | 'Datastore - Production#datastore.space.usage.bytes'=684471615488B;;;0;1299764477952 'Datastore - Production#datastore.space.free.bytes'=615292862464B;;;0;1299764477952 'Datastore - Production#datastore.space.usage.percentage'=52.66%;;0:5;0;100

View File

@ -0,0 +1,72 @@
*** Settings ***
Resource ${CURDIR}${/}..${/}..${/}..${/}..${/}resources/import.resource
Suite Setup Start Mockoon ${MOCKOON_JSON}
Suite Teardown Stop Mockoon
Test Timeout 120s
Test Setup Ctn Cleanup Cache
*** Variables ***
${MOCKOON_JSON} ${CURDIR}${/}mockoon.json
${CMD} ${CENTREON_PLUGINS} --plugin=apps::vmware::vsphere8::vcenter::plugin
... --mode=list-clusters
... --password=C3POR2P2
... --username=obi-wan
... --hostname=127.0.0.1
... --proto=http
... --port=3000
*** Test Cases ***
List-Datastores
[Tags] apps api vmware vsphere8 vcenter
${command} Catenate ${CMD} --http-backend=curl --disco-show
# expected disco-show
#<?xml version="1.0" encoding="utf-8"?>
#<data>
# <label cluster="domain-c18" name="AQU-CLU01" ha_enabled="true" drs_enabled="false"/>
#</data>
${root}= Ctn Run Command And Return Parsed XML ${command}
${nb_clusters}= Get Element Count ${root} label
# First check: are there 8 datastores as expected
Should Be Equal As Integers ${nb_clusters} 1 Number of clusters do not match
# Get the list of cluster IDs
@{elem_list}= Get Elements ${root} label
@{found_clusters}= Create List
FOR ${item} IN @{elemList}
${clusters_id}= Get Element Attribute ${item} cluster
Append To List ${found_clusters} ${clusters_id}
END
# Here is what is expected
@{expected_clusters}= Create List domain-c18
# Compare obtained list with expected list
Lists Should Be Equal ${found_clusters} ${expected_clusters}
Disco-format
${command} Catenate ${CMD} --disco-format
${root}= Ctn Run Command And Return Parsed XML ${command}
# expected disco-format
#<?xml version="1.0" encoding="utf-8"?>
#<data>
# <element>name</element>
# <element>cluster</element>
# <element>drs_enabled</element>
# <element>ha_enabled</element>
#</data>
# Get the list of cluster IDs
@{elem_list}= Get Elements ${root} element
@{found_macros}= Create List
FOR ${item} IN @{elemList}
${macro_name}= Get Element Text ${item}
Append To List ${found_macros} ${macro_name}
END
# Here is what is expected
@{expected_macros}= Create List name cluster drs_enabled ha_enabled
# Compare obtained list with expected list
Lists Should Be Equal ${found_macros} ${expected_macros}

View File

@ -0,0 +1,53 @@
*** Settings ***
Resource ${CURDIR}${/}..${/}..${/}..${/}..${/}resources/import.resource
Suite Setup Start Mockoon ${MOCKOON_JSON}
Suite Teardown Stop Mockoon
Test Timeout 120s
Test Setup Ctn Cleanup Cache
*** Variables ***
${MOCKOON_JSON} ${CURDIR}${/}mockoon.json
${CMD} ${CENTREON_PLUGINS} --plugin=apps::vmware::vsphere8::vcenter::plugin
... --mode=list-datastores
... --password=C3POR2P2
... --username=obi-wan
... --hostname=127.0.0.1
... --proto=http
... --port=3000
*** Test Cases ***
List-Datastores
[Tags] apps api vmware vsphere8 vcenter
${command_curl} Catenate ${CMD} --http-backend=curl --disco-show
#<?xml version="1.0" encoding="utf-8"?>
#<data>
# <label datastore="datastore-14" type="VMFS" name="Datastore - Systeme" free_space="610635087872" capacity="799937658880"/>
# <label datastore="datastore-25" capacity="341986770944" name="Datastore - ESX02" free_space="340472627200" type="VMFS"/>
# <label capacity="341986770944" type="VMFS" free_space="340472627200" name="Datastore - ESX03" datastore="datastore-31"/>
# <label datastore="datastore-38" free_space="5586639912960" name="Datastore - Developpement 15000" type="VMFS" capacity="7794560335872"/>
# <label datastore="datastore-39" type="VMFS" free_space="5422671986688" name="Datastore - Developpement 7200" capacity="5516885491712"/>
# <label datastore="datastore-40" free_space="340472627200" name="Datastore - ESX01" type="VMFS" capacity="341986770944"/>
# <label datastore="datastore-45" capacity="7499818205184" free_space="4376304287744" name="Datastore - Developpement" type="VMFS"/>
# <label type="VMFS" free_space="615292862464" name="Datastore - Production" capacity="1299764477952" datastore="datastore-46"/>
#</data>
${root}= Ctn Run Command And Return Parsed XML ${command_curl}
${nb_ds}= Get Element Count ${root} label
# First check: are there 8 datastores as expected
Should Be Equal As Integers ${nb_ds} 8 Number of datastores do not match
# Get the list of datastore IDs
@{elem_list}= Get Elements ${root} label
@{found_ds}= Create List
FOR ${item} IN @{elemList}
${ds_id}= Get Element Attribute ${item} datastore
Append To List ${found_ds} ${ds_id}
END
# Here is what is expected
@{expected_ds}= Create List datastore-14 datastore-25 datastore-31 datastore-38 datastore-39 datastore-40 datastore-45 datastore-46
# Compare obtained list with expected list
Lists Should Be Equal ${found_ds} ${expected_ds}

View File

@ -0,0 +1,907 @@
{
"uuid": "dd7d9589-c42b-42e9-8790-f11c8a0f344d",
"lastMigration": 33,
"name": "Vmware8 restapi.mockoon",
"endpointPrefix": "",
"latency": 0,
"port": 3000,
"hostname": "",
"folders": [],
"routes": [
{
"uuid": "24bee589-6166-4849-bc82-937ea7a5480c",
"type": "http",
"documentation": "",
"method": "post",
"endpoint": "api/session",
"responses": [
{
"uuid": "d037b485-9952-467c-985c-415b9033e4d9",
"body": "\"32c9819179813376a9bbda43e9c84165\"",
"latency": 0,
"statusCode": 201,
"label": "",
"headers": [
{
"key": "access-control-allow-headers",
"value": "Content-Type, Origin, Accept, Authorization, Content-Length, X-Requested-With"
},
{
"key": "access-control-allow-methods",
"value": "GET,POST,PUT,PATCH,DELETE,HEAD,OPTIONS"
},
{
"key": "access-control-allow-origin",
"value": "*"
},
{
"key": "content-security-policy",
"value": "default-src 'none'"
},
{
"key": "content-type",
"value": "text/html; charset=utf-8"
},
{
"key": "x-content-type-options",
"value": "nosniff"
}
],
"bodyType": "INLINE",
"filePath": "",
"databucketID": "",
"sendFileAsBody": false,
"rules": [],
"rulesOperator": "OR",
"disableTemplating": false,
"fallbackTo404": false,
"default": false,
"crudKey": "id",
"callbacks": []
}
],
"responseMode": null,
"streamingMode": null,
"streamingInterval": 0
},
{
"uuid": "68acba14-1ccf-4597-a90c-69264b07d558",
"type": "http",
"documentation": "",
"method": "get",
"endpoint": "api/vcenter/host",
"responses": [
{
"uuid": "cc160130-c765-4a8a-ba09-0ad544ef956f",
"latency": 0,
"statusCode": 200,
"label": "",
"headers": [
{
"key": "access-control-allow-headers",
"value": "Content-Type, Origin, Accept, Authorization, Content-Length, X-Requested-With"
},
{
"key": "access-control-allow-methods",
"value": "GET,POST,PUT,PATCH,DELETE,HEAD,OPTIONS"
},
{
"key": "access-control-allow-origin",
"value": "*"
},
{
"key": "content-security-policy",
"value": "default-src 'none'"
},
{
"key": "content-type",
"value": "text/html; charset=utf-8"
},
{
"key": "x-content-type-options",
"value": "nosniff"
}
],
"bodyType": "DATABUCKET",
"filePath": "",
"databucketID": "7kak",
"sendFileAsBody": false,
"rules": [],
"rulesOperator": "OR",
"disableTemplating": false,
"fallbackTo404": false,
"default": false,
"crudKey": "id",
"callbacks": [],
"body": "{}"
}
],
"responseMode": null,
"streamingMode": null,
"streamingInterval": 0
},
{
"uuid": "31f2da05-1f2f-41fb-ae1e-b4f2ee277055",
"type": "http",
"documentation": "",
"method": "get",
"endpoint": "api/vcenter/vm",
"responses": [
{
"uuid": "96a6828b-5fa1-496d-bd7f-84df9a152f78",
"body": "[\n {\n \"memory_size_MiB\": 2048,\n \"vm\": \"vm-5678\",\n \"name\": \"my_other_vm\",\n \"power_state\": \"POWERED_OFF\",\n \"cpu_count\": 2\n },\n {\n \"memory_size_MiB\": 4096,\n \"vm\": \"vm-1234\",\n \"name\": \"my_favourite_vm\",\n \"power_state\": \"POWERED_ON\",\n \"cpu_count\": 4\n },\n {\n \"memory_size_MiB\": 4096,\n \"vm\": \"vm-12345\",\n \"name\": \"my_suspended_vm\",\n \"power_state\": \"SUSPENDED\",\n \"cpu_count\": 4\n }\n]",
"latency": 0,
"statusCode": 200,
"label": "",
"headers": [
{
"key": "access-control-allow-headers",
"value": "Content-Type, Origin, Accept, Authorization, Content-Length, X-Requested-With"
},
{
"key": "access-control-allow-methods",
"value": "GET,POST,PUT,PATCH,DELETE,HEAD,OPTIONS"
},
{
"key": "access-control-allow-origin",
"value": "*"
},
{
"key": "content-security-policy",
"value": "default-src 'none'"
},
{
"key": "content-type",
"value": "text/html; charset=utf-8"
},
{
"key": "x-content-type-options",
"value": "nosniff"
}
],
"bodyType": "INLINE",
"filePath": "",
"databucketID": "",
"sendFileAsBody": false,
"rules": [],
"rulesOperator": "OR",
"disableTemplating": false,
"fallbackTo404": false,
"default": false,
"crudKey": "id",
"callbacks": []
}
],
"responseMode": null,
"streamingMode": null,
"streamingInterval": 0
},
{
"uuid": "84be4ae5-fc86-4ed1-8066-e9c46cef691d",
"type": "http",
"documentation": "",
"method": "get",
"endpoint": "api/vcenter/datastore",
"responses": [
{
"uuid": "e8adb942-d389-4265-85ad-b20c728095bd",
"body": "[\n {\n \"datastore\": \"datastore-14\",\n \"name\": \"Datastore - Systeme\",\n \"type\": \"VMFS\",\n \"free_space\": 610635087872,\n \"capacity\": 799937658880\n },\n {\n \"datastore\": \"datastore-25\",\n \"name\": \"Datastore - ESX02\",\n \"type\": \"VMFS\",\n \"free_space\": 340472627200,\n \"capacity\": 341986770944\n },\n {\n \"datastore\": \"datastore-31\",\n \"name\": \"Datastore - ESX03\",\n \"type\": \"VMFS\",\n \"free_space\": 340472627200,\n \"capacity\": 341986770944\n },\n {\n \"datastore\": \"datastore-38\",\n \"name\": \"Datastore - Developpement 15000\",\n \"type\": \"VMFS\",\n \"free_space\": 5586639912960,\n \"capacity\": 7794560335872\n },\n {\n \"datastore\": \"datastore-39\",\n \"name\": \"Datastore - Developpement 7200\",\n \"type\": \"VMFS\",\n \"free_space\": 5422671986688,\n \"capacity\": 5516885491712\n },\n {\n \"datastore\": \"datastore-40\",\n \"name\": \"Datastore - ESX01\",\n \"type\": \"VMFS\",\n \"free_space\": 340472627200,\n \"capacity\": 341986770944\n },\n {\n \"datastore\": \"datastore-45\",\n \"name\": \"Datastore - Developpement\",\n \"type\": \"VMFS\",\n \"free_space\": 4376304287744,\n \"capacity\": 7499818205184\n },\n {\n \"datastore\": \"datastore-46\",\n \"name\": \"Datastore - Production\",\n \"type\": \"VMFS\",\n \"free_space\": 615292862464,\n \"capacity\": 1299764477952\n }\n]",
"latency": 0,
"statusCode": 200,
"label": "",
"headers": [
{
"key": "access-control-allow-headers",
"value": "Content-Type, Origin, Accept, Authorization, Content-Length, X-Requested-With"
},
{
"key": "access-control-allow-methods",
"value": "GET,POST,PUT,PATCH,DELETE,HEAD,OPTIONS"
},
{
"key": "access-control-allow-origin",
"value": "*"
},
{
"key": "content-security-policy",
"value": "default-src 'none'"
},
{
"key": "content-type",
"value": "text/html; charset=utf-8"
},
{
"key": "x-content-type-options",
"value": "nosniff"
}
],
"bodyType": "INLINE",
"filePath": "",
"databucketID": "",
"sendFileAsBody": false,
"rules": [],
"rulesOperator": "OR",
"disableTemplating": false,
"fallbackTo404": false,
"default": false,
"crudKey": "id",
"callbacks": []
}
],
"responseMode": null,
"streamingMode": null,
"streamingInterval": 0
},
{
"uuid": "7b842f35-687c-45e7-8ffc-192a71cb1210",
"type": "http",
"documentation": "",
"method": "get",
"endpoint": "api/vcenter/datastore/datastore-45",
"responses": [
{
"uuid": "495c38c5-1618-4ecf-b4b4-c31960cc96fd",
"body": "{\n \"accessible\": true,\n \"multiple_host_access\": true,\n \"name\": \"Datastore - Developpement\",\n \"type\": \"VMFS\",\n \"free_space\": 4376304287744,\n \"thin_provisioning_supported\": true\n} \n",
"latency": 0,
"statusCode": 200,
"label": "",
"headers": [
{
"key": "access-control-allow-headers",
"value": "Content-Type, Origin, Accept, Authorization, Content-Length, X-Requested-With"
},
{
"key": "access-control-allow-methods",
"value": "GET,POST,PUT,PATCH,DELETE,HEAD,OPTIONS"
},
{
"key": "access-control-allow-origin",
"value": "*"
},
{
"key": "content-security-policy",
"value": "default-src 'none'"
},
{
"key": "content-type",
"value": "text/html; charset=utf-8"
},
{
"key": "x-content-type-options",
"value": "nosniff"
}
],
"bodyType": "INLINE",
"filePath": "",
"databucketID": "",
"sendFileAsBody": false,
"rules": [],
"rulesOperator": "OR",
"disableTemplating": false,
"fallbackTo404": false,
"default": false,
"crudKey": "id",
"callbacks": []
}
],
"responseMode": null,
"streamingMode": null,
"streamingInterval": 0
},
{
"uuid": "8254cc34-56f6-45b7-b941-df16dc6ef757",
"type": "http",
"documentation": "",
"method": "get",
"endpoint": "api/vcenter/datastore/datastore-14",
"responses": [
{
"uuid": "b7d8fde6-32e1-45eb-b0b5-6ca3640dcb44",
"body": "{\n \"accessible\": true,\n \"multiple_host_access\": true,\n \"name\": \"Datastore - Systeme\",\n \"type\": \"VMFS\",\n \"free_space\": 610635087872,\n \"thin_provisioning_supported\": true\n}",
"latency": 0,
"statusCode": 200,
"label": "",
"headers": [
{
"key": "access-control-allow-headers",
"value": "Content-Type, Origin, Accept, Authorization, Content-Length, X-Requested-With"
},
{
"key": "access-control-allow-methods",
"value": "GET,POST,PUT,PATCH,DELETE,HEAD,OPTIONS"
},
{
"key": "access-control-allow-origin",
"value": "*"
},
{
"key": "content-security-policy",
"value": "default-src 'none'"
},
{
"key": "content-type",
"value": "text/html; charset=utf-8"
},
{
"key": "x-content-type-options",
"value": "nosniff"
}
],
"bodyType": "INLINE",
"filePath": "",
"databucketID": "",
"sendFileAsBody": false,
"rules": [],
"rulesOperator": "OR",
"disableTemplating": false,
"fallbackTo404": false,
"default": false,
"crudKey": "id",
"callbacks": []
}
],
"responseMode": null,
"streamingMode": null,
"streamingInterval": 0
},
{
"uuid": "9a4bba96-1d68-4930-ad3e-d1f581df5b54",
"type": "http",
"documentation": "",
"method": "get",
"endpoint": "api/vcenter/datastore/datastore-25",
"responses": [
{
"uuid": "71a226a2-b39e-48fa-b135-67ffd533fb2e",
"body": "{\n \"accessible\": true,\n \"multiple_host_access\": false,\n \"name\": \"Datastore - ESX02\",\n \"type\": \"VMFS\",\n \"free_space\": 340472627200,\n \"thin_provisioning_supported\": true\n} \n",
"latency": 0,
"statusCode": 200,
"label": "",
"headers": [
{
"key": "access-control-allow-headers",
"value": "Content-Type, Origin, Accept, Authorization, Content-Length, X-Requested-With"
},
{
"key": "access-control-allow-methods",
"value": "GET,POST,PUT,PATCH,DELETE,HEAD,OPTIONS"
},
{
"key": "access-control-allow-origin",
"value": "*"
},
{
"key": "content-security-policy",
"value": "default-src 'none'"
},
{
"key": "content-type",
"value": "text/html; charset=utf-8"
},
{
"key": "x-content-type-options",
"value": "nosniff"
}
],
"bodyType": "INLINE",
"filePath": "",
"databucketID": "",
"sendFileAsBody": false,
"rules": [],
"rulesOperator": "OR",
"disableTemplating": false,
"fallbackTo404": false,
"default": false,
"crudKey": "id",
"callbacks": []
}
],
"responseMode": null,
"streamingMode": null,
"streamingInterval": 0
},
{
"uuid": "78ced1c5-7ba2-414b-954f-115dd614c163",
"type": "http",
"documentation": "",
"method": "get",
"endpoint": "api/vcenter/datastore/datastore-39",
"responses": [
{
"uuid": "973dd70a-aa17-4ae7-b2d0-0dc0c792a2a7",
"body": "{\n \"accessible\": false,\n \"multiple_host_access\": true,\n \"name\": \"Datastore - Developpement 7200\",\n \"type\": \"VMFS\",\n \"free_space\": 5422671986688,\n \"thin_provisioning_supported\": true\n} \n",
"latency": 0,
"statusCode": 200,
"label": "",
"headers": [
{
"key": "access-control-allow-headers",
"value": "Content-Type, Origin, Accept, Authorization, Content-Length, X-Requested-With"
},
{
"key": "access-control-allow-methods",
"value": "GET,POST,PUT,PATCH,DELETE,HEAD,OPTIONS"
},
{
"key": "access-control-allow-origin",
"value": "*"
},
{
"key": "content-security-policy",
"value": "default-src 'none'"
},
{
"key": "content-type",
"value": "text/html; charset=utf-8"
},
{
"key": "x-content-type-options",
"value": "nosniff"
}
],
"bodyType": "INLINE",
"filePath": "",
"databucketID": "",
"sendFileAsBody": false,
"rules": [],
"rulesOperator": "OR",
"disableTemplating": false,
"fallbackTo404": false,
"default": false,
"crudKey": "id",
"callbacks": []
}
],
"responseMode": null,
"streamingMode": null,
"streamingInterval": 0
},
{
"uuid": "dbafe65e-fe59-43c8-b072-a9a363c1d375",
"type": "http",
"documentation": "",
"method": "get",
"endpoint": "api/vcenter/datastore/datastore-46",
"responses": [
{
"uuid": "4d33cd7a-3919-43cb-9b7e-0ee4c797b8d6",
"body": "{\n \"accessible\": true,\n \"multiple_host_access\": true,\n \"name\": \"Datastore - Production\",\n \"type\": \"VMFS\",\n \"free_space\": 615292862464,\n \"thin_provisioning_supported\": true\n} \n",
"latency": 0,
"statusCode": 200,
"label": "",
"headers": [
{
"key": "access-control-allow-headers",
"value": "Content-Type, Origin, Accept, Authorization, Content-Length, X-Requested-With"
},
{
"key": "access-control-allow-methods",
"value": "GET,POST,PUT,PATCH,DELETE,HEAD,OPTIONS"
},
{
"key": "access-control-allow-origin",
"value": "*"
},
{
"key": "content-security-policy",
"value": "default-src 'none'"
},
{
"key": "content-type",
"value": "text/html; charset=utf-8"
},
{
"key": "x-content-type-options",
"value": "nosniff"
}
],
"bodyType": "INLINE",
"filePath": "",
"databucketID": "",
"sendFileAsBody": false,
"rules": [],
"rulesOperator": "OR",
"disableTemplating": false,
"fallbackTo404": false,
"default": false,
"crudKey": "id",
"callbacks": []
}
],
"responseMode": null,
"streamingMode": null,
"streamingInterval": 0
},
{
"uuid": "689a3103-dca3-416c-a720-0a71a2011ca0",
"type": "http",
"documentation": "",
"method": "get",
"endpoint": "api/vcenter/datastore/datastore-40",
"responses": [
{
"uuid": "95cc3c0e-58ef-4a51-9d8f-e34e5c2ca3b7",
"body": "{\n \"accessible\": true,\n \"multiple_host_access\": false,\n \"name\": \"Datastore - ESX01\",\n \"type\": \"VMFS\",\n \"free_space\": 340472627200,\n \"thin_provisioning_supported\": true\n} \n",
"latency": 0,
"statusCode": 200,
"label": "",
"headers": [
{
"key": "access-control-allow-headers",
"value": "Content-Type, Origin, Accept, Authorization, Content-Length, X-Requested-With"
},
{
"key": "access-control-allow-methods",
"value": "GET,POST,PUT,PATCH,DELETE,HEAD,OPTIONS"
},
{
"key": "access-control-allow-origin",
"value": "*"
},
{
"key": "content-security-policy",
"value": "default-src 'none'"
},
{
"key": "content-type",
"value": "text/html; charset=utf-8"
},
{
"key": "x-content-type-options",
"value": "nosniff"
}
],
"bodyType": "INLINE",
"filePath": "",
"databucketID": "",
"sendFileAsBody": false,
"rules": [],
"rulesOperator": "OR",
"disableTemplating": false,
"fallbackTo404": false,
"default": false,
"crudKey": "id",
"callbacks": []
}
],
"responseMode": null,
"streamingMode": null,
"streamingInterval": 0
},
{
"uuid": "f15307ab-2c42-4b06-bd36-a6562051ebe3",
"type": "http",
"documentation": "",
"method": "get",
"endpoint": "api/vcenter/datastore/datastore-38",
"responses": [
{
"uuid": "140e5e4a-b54a-4adb-a83a-7d456fcdb672",
"body": "{\n \"accessible\": true,\n \"multiple_host_access\": true,\n \"name\": \"Datastore - Developpement 15000\",\n \"type\": \"VMFS\",\n \"free_space\": 5586639912960,\n \"thin_provisioning_supported\": true\n} \n",
"latency": 0,
"statusCode": 200,
"label": "",
"headers": [
{
"key": "access-control-allow-headers",
"value": "Content-Type, Origin, Accept, Authorization, Content-Length, X-Requested-With"
},
{
"key": "access-control-allow-methods",
"value": "GET,POST,PUT,PATCH,DELETE,HEAD,OPTIONS"
},
{
"key": "access-control-allow-origin",
"value": "*"
},
{
"key": "content-security-policy",
"value": "default-src 'none'"
},
{
"key": "content-type",
"value": "text/html; charset=utf-8"
},
{
"key": "x-content-type-options",
"value": "nosniff"
}
],
"bodyType": "INLINE",
"filePath": "",
"databucketID": "",
"sendFileAsBody": false,
"rules": [],
"rulesOperator": "OR",
"disableTemplating": false,
"fallbackTo404": false,
"default": false,
"crudKey": "id",
"callbacks": []
}
],
"responseMode": null,
"streamingMode": null,
"streamingInterval": 0
},
{
"uuid": "f7b2be2f-8055-4619-bee3-c81c12d4ca71",
"type": "http",
"documentation": "",
"method": "get",
"endpoint": "api/vcenter/datastore/datastore-31",
"responses": [
{
"uuid": "23576cfa-8eb7-4862-b6f5-2125c058da55",
"body": "{\n \"accessible\": true,\n \"multiple_host_access\": false,\n \"name\": \"Datastore - ESX03\",\n \"type\": \"VMFS\",\n \"free_space\": 340472627200,\n \"thin_provisioning_supported\": true\n} \n",
"latency": 0,
"statusCode": 200,
"label": "",
"headers": [
{
"key": "access-control-allow-headers",
"value": "Content-Type, Origin, Accept, Authorization, Content-Length, X-Requested-With"
},
{
"key": "access-control-allow-methods",
"value": "GET,POST,PUT,PATCH,DELETE,HEAD,OPTIONS"
},
{
"key": "access-control-allow-origin",
"value": "*"
},
{
"key": "content-security-policy",
"value": "default-src 'none'"
},
{
"key": "content-type",
"value": "text/html; charset=utf-8"
},
{
"key": "x-content-type-options",
"value": "nosniff"
}
],
"bodyType": "INLINE",
"filePath": "",
"databucketID": "",
"sendFileAsBody": false,
"rules": [],
"rulesOperator": "OR",
"disableTemplating": false,
"fallbackTo404": false,
"default": false,
"crudKey": "id",
"callbacks": []
}
],
"responseMode": null,
"streamingMode": null,
"streamingInterval": 0
},
{
"uuid": "621ad4eb-05f8-4976-a236-a1e70c7714eb",
"type": "http",
"documentation": "",
"method": "get",
"endpoint": "api/vcenter/cluster",
"responses": [
{
"uuid": "ea14a01e-c806-4110-b444-a80d6267914f",
"body": "[\n {\n \"drs_enabled\": false,\n \"cluster\": \"domain-c18\",\n \"name\": \"EXT-CLU01\",\n \"ha_enabled\": true\n }\n]",
"latency": 0,
"statusCode": 200,
"label": "",
"headers": [
{
"key": "access-control-allow-headers",
"value": "Content-Type, Origin, Accept, Authorization, Content-Length, X-Requested-With"
},
{
"key": "access-control-allow-methods",
"value": "GET,POST,PUT,PATCH,DELETE,HEAD,OPTIONS"
},
{
"key": "access-control-allow-origin",
"value": "*"
},
{
"key": "content-security-policy",
"value": "default-src 'none'"
},
{
"key": "content-type",
"value": "text/html; charset=utf-8"
},
{
"key": "x-content-type-options",
"value": "nosniff"
}
],
"bodyType": "INLINE",
"filePath": "",
"databucketID": "",
"sendFileAsBody": false,
"rules": [],
"rulesOperator": "OR",
"disableTemplating": false,
"fallbackTo404": false,
"default": false,
"crudKey": "id",
"callbacks": []
}
],
"responseMode": null,
"streamingMode": null,
"streamingInterval": 0
},
{
"uuid": "f6e866b7-ede9-4bec-8f69-0513a88b730e",
"type": "http",
"documentation": "",
"method": "get",
"endpoint": "api/vcenter/cluster/domain-c18",
"responses": [
{
"uuid": "d015157a-edef-4496-ab71-ca2a930daede",
"body": "{\n \"name\": \"EXT-CLU01\",\n \"resource_pool\": \"resgroup-19\"\n}",
"latency": 0,
"statusCode": 200,
"label": "",
"headers": [
{
"key": "access-control-allow-headers",
"value": "Content-Type, Origin, Accept, Authorization, Content-Length, X-Requested-With"
},
{
"key": "access-control-allow-methods",
"value": "GET,POST,PUT,PATCH,DELETE,HEAD,OPTIONS"
},
{
"key": "access-control-allow-origin",
"value": "*"
},
{
"key": "content-security-policy",
"value": "default-src 'none'"
},
{
"key": "content-type",
"value": "text/html; charset=utf-8"
},
{
"key": "x-content-type-options",
"value": "nosniff"
}
],
"bodyType": "INLINE",
"filePath": "",
"databucketID": "",
"sendFileAsBody": false,
"rules": [],
"rulesOperator": "OR",
"disableTemplating": false,
"fallbackTo404": false,
"default": false,
"crudKey": "id",
"callbacks": []
}
],
"responseMode": null,
"streamingMode": null,
"streamingInterval": 0
}
],
"rootChildren": [
{
"type": "route",
"uuid": "24bee589-6166-4849-bc82-937ea7a5480c"
},
{
"type": "route",
"uuid": "68acba14-1ccf-4597-a90c-69264b07d558"
},
{
"type": "route",
"uuid": "31f2da05-1f2f-41fb-ae1e-b4f2ee277055"
},
{
"type": "route",
"uuid": "84be4ae5-fc86-4ed1-8066-e9c46cef691d"
},
{
"type": "route",
"uuid": "7b842f35-687c-45e7-8ffc-192a71cb1210"
},
{
"type": "route",
"uuid": "8254cc34-56f6-45b7-b941-df16dc6ef757"
},
{
"type": "route",
"uuid": "9a4bba96-1d68-4930-ad3e-d1f581df5b54"
},
{
"type": "route",
"uuid": "78ced1c5-7ba2-414b-954f-115dd614c163"
},
{
"type": "route",
"uuid": "dbafe65e-fe59-43c8-b072-a9a363c1d375"
},
{
"type": "route",
"uuid": "689a3103-dca3-416c-a720-0a71a2011ca0"
},
{
"type": "route",
"uuid": "f15307ab-2c42-4b06-bd36-a6562051ebe3"
},
{
"type": "route",
"uuid": "f7b2be2f-8055-4619-bee3-c81c12d4ca71"
},
{
"type": "route",
"uuid": "621ad4eb-05f8-4976-a236-a1e70c7714eb"
},
{
"type": "route",
"uuid": "f6e866b7-ede9-4bec-8f69-0513a88b730e"
}
],
"proxyMode": false,
"proxyHost": "",
"proxyRemovePrefix": false,
"tlsOptions": {
"enabled": false,
"type": "CERT",
"pfxPath": "",
"certPath": "",
"keyPath": "",
"caPath": "",
"passphrase": ""
},
"cors": true,
"headers": [
{
"key": "Content-Type",
"value": "application/json"
},
{
"key": "Access-Control-Allow-Origin",
"value": "*"
},
{
"key": "Access-Control-Allow-Methods",
"value": "GET,POST,PUT,PATCH,DELETE,HEAD,OPTIONS"
},
{
"key": "Access-Control-Allow-Headers",
"value": "Content-Type, Origin, Accept, Authorization, Content-Length, X-Requested-With"
}
],
"proxyReqHeaders": [
{
"key": "",
"value": ""
}
],
"proxyResHeaders": [
{
"key": "",
"value": ""
}
],
"data": [
{
"uuid": "a438d9f3-8360-49c3-9d1f-d2f6d202513d",
"id": "7kak",
"name": "/api/vcenter/host",
"documentation": "Complete response",
"value": "[{\"host\":\"host-22\",\"name\":\"esx1.acme.com\",\"connection_state\":\"CONNECTED\",\"power_state\":\"POWERED_ON\"},{\"host\":\"host-28\",\"name\":\"esx2.acme.com\",\"connection_state\":\"CONNECTED\",\"power_state\":\"POWERED_OFF\"},{\"host\":\"host-35\",\"name\":\"esx3.acme.com\",\"connection_state\":\"DISCONNECTED\",\"power_state\":\"POWERED_ON\"}]\n"
}
],
"callbacks": []
}

View File

@ -0,0 +1,54 @@
*** Settings ***
Resource ${CURDIR}${/}..${/}..${/}..${/}..${/}resources/import.resource
Suite Setup Start Mockoon ${MOCKOON_JSON}
Suite Teardown Stop Mockoon
Test Timeout 120s
Test Setup Ctn Cleanup Cache
*** Variables ***
${MOCKOON_JSON} ${CURDIR}${/}mockoon.json
${CMD} ${CENTREON_PLUGINS} --plugin=apps::vmware::vsphere8::vcenter::plugin
... --mode=vm-count
... --password=C3POR2P2
... --username=obi-wan
... --hostname=127.0.0.1
... --proto=http
... --port=3000
*** Test Cases ***
Vm-Count ${tc}
[Tags] apps api vmware vsphere8 esx
${command_curl} Catenate ${CMD} --http-backend=curl ${extraoptions}
${command_lwp} Catenate ${CMD} --http-backend=lwp ${extraoptions}
Ctn Run Command And Check Result As Strings ${command_curl} ${expected_result}
Ctn Run Command And Check Result As Strings ${command_lwp} ${expected_result}
Examples: tc extraoptions expected_result --
... 1 ${EMPTY} OK: 1 VM(s) powered on, 1 VM(s) powered off, 1 VM(s) suspended, 3 VM(s) in total | 'vm.poweredon.count'=1;;;0;3 'vm.poweredoff.count'=1;;;0;3 'vm.suspended.count'=1;;;0;3 'vm.total.count'=3;1:;;0;
... 2 --include-name=toto WARNING: 0 VM(s) in total | 'vm.poweredon.count'=0;;;0;0 'vm.poweredoff.count'=0;;;0;0 'vm.suspended.count'=0;;;0;0 'vm.total.count'=0;1:;;0;
... 3 --include-name=fav OK: 1 VM(s) powered on, 0 VM(s) powered off, 0 VM(s) suspended, 1 VM(s) in total | 'vm.poweredon.count'=1;;;0;1 'vm.poweredoff.count'=0;;;0;1 'vm.suspended.count'=0;;;0;1 'vm.total.count'=1;1:;;0;
... 4 --warning-on-count=1: OK: 1 VM(s) powered on, 1 VM(s) powered off, 1 VM(s) suspended, 3 VM(s) in total | 'vm.poweredon.count'=1;1:;;0;3 'vm.poweredoff.count'=1;;;0;3 'vm.suspended.count'=1;;;0;3 'vm.total.count'=3;1:;;0;
... 5 --critical-on-count=1: OK: 1 VM(s) powered on, 1 VM(s) powered off, 1 VM(s) suspended, 3 VM(s) in total | 'vm.poweredon.count'=1;;1:;0;3 'vm.poweredoff.count'=1;;;0;3 'vm.suspended.count'=1;;;0;3 'vm.total.count'=3;1:;;0;
... 6 --warning-on-count=2: WARNING: 1 VM(s) powered on | 'vm.poweredon.count'=1;2:;;0;3 'vm.poweredoff.count'=1;;;0;3 'vm.suspended.count'=1;;;0;3 'vm.total.count'=3;1:;;0;
... 7 --critical-on-count=2: CRITICAL: 1 VM(s) powered on | 'vm.poweredon.count'=1;;2:;0;3 'vm.poweredoff.count'=1;;;0;3 'vm.suspended.count'=1;;;0;3 'vm.total.count'=3;1:;;0;
... 8 --exclude-name=.* WARNING: 0 VM(s) in total | 'vm.poweredon.count'=0;;;0;0 'vm.poweredoff.count'=0;;;0;0 'vm.suspended.count'=0;;;0;0 'vm.total.count'=0;1:;;0;
... 9 --exclude-name=fav OK: 0 VM(s) powered on, 1 VM(s) powered off, 1 VM(s) suspended, 2 VM(s) in total | 'vm.poweredon.count'=0;;;0;2 'vm.poweredoff.count'=1;;;0;2 'vm.suspended.count'=1;;;0;2 'vm.total.count'=2;1:;;0;
... 10 --warning-off-count=1: OK: 1 VM(s) powered on, 1 VM(s) powered off, 1 VM(s) suspended, 3 VM(s) in total | 'vm.poweredon.count'=1;;;0;3 'vm.poweredoff.count'=1;1:;;0;3 'vm.suspended.count'=1;;;0;3 'vm.total.count'=3;1:;;0;
... 11 --critical-off-count=1: OK: 1 VM(s) powered on, 1 VM(s) powered off, 1 VM(s) suspended, 3 VM(s) in total | 'vm.poweredon.count'=1;;;0;3 'vm.poweredoff.count'=1;;1:;0;3 'vm.suspended.count'=1;;;0;3 'vm.total.count'=3;1:;;0;
... 12 --warning-off-count=2: WARNING: 1 VM(s) powered off | 'vm.poweredon.count'=1;;;0;3 'vm.poweredoff.count'=1;2:;;0;3 'vm.suspended.count'=1;;;0;3 'vm.total.count'=3;1:;;0;
... 13 --critical-off-count=2: CRITICAL: 1 VM(s) powered off | 'vm.poweredon.count'=1;;;0;3 'vm.poweredoff.count'=1;;2:;0;3 'vm.suspended.count'=1;;;0;3 'vm.total.count'=3;1:;;0;
... 14 --warning-total-count=4: WARNING: 3 VM(s) in total | 'vm.poweredon.count'=1;;;0;3 'vm.poweredoff.count'=1;;;0;3 'vm.suspended.count'=1;;;0;3 'vm.total.count'=3;4:;;0;
... 15 --critical-total-count=4: CRITICAL: 3 VM(s) in total | 'vm.poweredon.count'=1;;;0;3 'vm.poweredoff.count'=1;;;0;3 'vm.suspended.count'=1;;;0;3 'vm.total.count'=3;1:;4:;0;
... 16 --warning-total-count=2: OK: 1 VM(s) powered on, 1 VM(s) powered off, 1 VM(s) suspended, 3 VM(s) in total | 'vm.poweredon.count'=1;;;0;3 'vm.poweredoff.count'=1;;;0;3 'vm.suspended.count'=1;;;0;3 'vm.total.count'=3;2:;;0;
... 17 --critical-total-count=2: OK: 1 VM(s) powered on, 1 VM(s) powered off, 1 VM(s) suspended, 3 VM(s) in total | 'vm.poweredon.count'=1;;;0;3 'vm.poweredoff.count'=1;;;0;3 'vm.suspended.count'=1;;;0;3 'vm.total.count'=3;1:;2:;0;
... 18 --warning-suspended-count=1: OK: 1 VM(s) powered on, 1 VM(s) powered off, 1 VM(s) suspended, 3 VM(s) in total | 'vm.poweredon.count'=1;;;0;3 'vm.poweredoff.count'=1;;;0;3 'vm.suspended.count'=1;1:;;0;3 'vm.total.count'=3;1:;;0;
... 19 --critical-suspended-count=1: OK: 1 VM(s) powered on, 1 VM(s) powered off, 1 VM(s) suspended, 3 VM(s) in total | 'vm.poweredon.count'=1;;;0;3 'vm.poweredoff.count'=1;;;0;3 'vm.suspended.count'=1;;1:;0;3 'vm.total.count'=3;1:;;0;
... 20 --warning-suspended-count=2: WARNING: 1 VM(s) suspended | 'vm.poweredon.count'=1;;;0;3 'vm.poweredoff.count'=1;;;0;3 'vm.suspended.count'=1;2:;;0;3 'vm.total.count'=3;1:;;0;
... 21 --critical-suspended-count=2: CRITICAL: 1 VM(s) suspended | 'vm.poweredon.count'=1;;;0;3 'vm.poweredoff.count'=1;;;0;3 'vm.suspended.count'=1;;2:;0;3 'vm.total.count'=3;1:;;0;
... 22 --critical-suspended-count=2: --warning-on-count=2: --critical-total-count=4: --warning-off-count=2: CRITICAL: 1 VM(s) powered on, 1 VM(s) powered off, 1 VM(s) suspended, 3 VM(s) in total | 'vm.poweredon.count'=1;2:;;0;3 'vm.poweredoff.count'=1;2:;;0;3 'vm.suspended.count'=1;;2:;0;3 'vm.total.count'=3;1:;4:;0;

View File

@ -0,0 +1,100 @@
use strict;
use warnings;
use Test2::V0;
use Test2::Tools::Compare qw{is like match};
use FindBin;
use lib "$FindBin::RealBin/../../../../src";
use centreon::plugins::misc;
sub test {
my @tests = (
{
string => undef,
include_regexp => undef,
exclude_regexp => undef,
expected_boolean => 1,
msg => 'Test undef string with undef include and exclude regexp'
},
{
string => undef,
include_regexp => 'test',
exclude_regexp => undef,
expected_boolean => 1,
msg => 'Test undef string with non-empty include and undef exclude regexp'
},
{
string => 'test',
include_regexp => undef,
exclude_regexp => undef,
expected_boolean => 0,
msg => 'Test string with undef include and exclude regexp'
},
{
string => 'test',
include_regexp => '^t.*t$',
exclude_regexp => undef,
expected_boolean => 0,
msg => 'Test string with include regexp and undef exclude regexp'
},
{
string => 'test',
include_regexp => undef,
exclude_regexp => '^t.*t$',
expected_boolean => 1,
msg => 'Test string with undef include regex and non-empty exclude regexp'
},
{
string => '',
include_regexp => '',
exclude_regexp => '',
expected_boolean => 0,
msg => 'Test empty string with empty include and exclude regexp'
},
{
string => '',
include_regexp => 'test',
exclude_regexp => '',
expected_boolean => 1,
msg => 'Test empty string with non-empty include and empty exclude regexp'
},
{
string => 'test',
include_regexp => '',
exclude_regexp => '',
expected_boolean => 0,
msg => 'Test string with empty include and exclude regexp'
},
{
string => 'test',
include_regexp => '^t.*t$',
exclude_regexp => '',
expected_boolean => 0,
msg => 'Test string with include regexp and empty exclude regexp'
},
{
string => 'test',
include_regexp => '',
exclude_regexp => '^t.*t$',
expected_boolean => 1,
msg => 'Test string with empty include regex and non-empty exclude regexp'
},
{
string => 'test',
include_regexp => '^t.*t$',
exclude_regexp => '^t.*t$',
expected_boolean => 1,
msg => 'Test string with both include and exclude regexp matching the string'
},
);
for my $test (@tests) {
my $is_excluded = centreon::plugins::misc::is_excluded($test->{string}, $test->{include_regexp}, $test->{exclude_regexp});
is($is_excluded, $test->{expected_boolean}, $test->{msg});
}
}
test();
done_testing();

View File

@ -0,0 +1,65 @@
use strict;
use warnings;
use Test2::V0;
use Test2::Tools::Compare qw{is like match};
use FindBin;
use lib "$FindBin::RealBin/../../../../src";
use centreon::plugins::misc;
use centreon::plugins::output;
use centreon::plugins::options;
sub test {
my $mock_output = mock 'centreon::plugins::output'; # this is from Test2::Tools::Mock, included by Test2::V0
my $option = centreon::plugins::options->new();
my $output = centreon::plugins::output->new(options => $option);
my @tests = (
{
json_string => '[ { "datastore": "datastore-14", "name": "Datastore - Systeme", "type": "VMFS", "free_space": 610635087872, "capacity": 799937658880 }]',
expected_object => [ { 'name' => 'Datastore - Systeme', 'capacity' => '799937658880', 'datastore' => 'datastore-14', 'free_space' => '610635087872', 'type' => 'VMFS' } ],
booleans_as_strings => 0,
msg => 'Objects without booleans'
},
{
json_string => '[ { "datastore": "datastore-14", "name": "Datastore - Systeme", "type": "VMFS", "free_space": 610635087872, "capacity": 799937658880 }, { "datastore": "datastore-25", "name": "Datastore - ESX02", "type": "VMFS", "free_space": 340472627200, "capacity": 341986770944 }, { "datastore": "datastore-31", "name": "Datastore - ESX03", "type": "VMFS", "free_space": 340472627200, "capacity": 341986770944 }, { "datastore": "datastore-38", "name": "Datastore - Developpement 15000", "type": "VMFS", "free_space": 5586639912960, "capacity": 7794560335872 }, { "datastore": "datastore-39", "name": "Datastore - Developpement 7200", "type": "VMFS", "free_space": 5422671986688, "capacity": 5516885491712 }, { "datastore": "datastore-40", "name": "Datastore - ESX01", "type": "VMFS", "free_space": 340472627200, "capacity": 341986770944 }, { "datastore": "datastore-45", "name": "Datastore - Developpement", "type": "VMFS", "free_space": 4376304287744, "capacity": 7499818205184 }, { "datastore": "datastore-46", "name": "Datastore - Production", "type": "VMFS", "free_space": 615292862464, "capacity": 1299764477952 }]',
expected_object => [ { 'name' => 'Datastore - Systeme', 'capacity' => '799937658880', 'datastore' => 'datastore-14', 'free_space' => '610635087872', 'type' => 'VMFS' }, { 'free_space' => '340472627200', 'type' => 'VMFS', 'name' => 'Datastore - ESX02', 'capacity' => '341986770944', 'datastore' => 'datastore-25' }, { 'name' => 'Datastore - ESX03', 'capacity' => '341986770944', 'datastore' => 'datastore-31', 'free_space' => '340472627200', 'type' => 'VMFS' }, { 'free_space' => '5586639912960', 'type' => 'VMFS', 'name' => 'Datastore - Developpement 15000', 'capacity' => '7794560335872', 'datastore' => 'datastore-38' }, { 'capacity' => '5516885491712', 'name' => 'Datastore - Developpement 7200', 'datastore' => 'datastore-39', 'type' => 'VMFS', 'free_space' => '5422671986688' }, { 'capacity' => '341986770944', 'name' => 'Datastore - ESX01', 'datastore' => 'datastore-40', 'type' => 'VMFS', 'free_space' => '340472627200' }, { 'datastore' => 'datastore-45', 'capacity' => '7499818205184', 'name' => 'Datastore - Developpement', 'free_space' => '4376304287744', 'type' => 'VMFS' }, { 'capacity' => '1299764477952', 'name' => 'Datastore - Production', 'datastore' => 'datastore-46', 'free_space' => '615292862464', 'type' => 'VMFS' } ],
booleans_as_strings => 1,
msg => 'Objects without booleans'
},
{
json_string => '{ "accessible": false, "multiple_host_access": true, "name": "Datastore - Developpement 7200", "type": "VMFS", "free_space": 5422671986688, "thin_provisioning_supported": true } ',
expected_object => { 'multiple_host_access' => bless( do{\(my $o = 1)}, 'JSON::PP::Boolean' ), 'thin_provisioning_supported' => bless( do{\(my $o = 1)}, 'JSON::PP::Boolean' ), 'name' => 'Datastore - Developpement 7200', 'free_space' => '5422671986688', 'type' => 'VMFS', 'accessible' => bless( do{\(my $o = 0)}, 'JSON::PP::Boolean' ) },
booleans_as_strings => 0,
msg => 'Object with booleans as booleans'
},
{
json_string => '{ "accessible": false, "multiple_host_access": true, "name": "Datastore - Developpement 7200", "type": "VMFS", "free_space": 5422671986688, "thin_provisioning_supported": true } ',
expected_object => { 'multiple_host_access' => 'true', 'thin_provisioning_supported' => 'true', 'name' => 'Datastore - Developpement 7200', 'free_space' => '5422671986688', 'type' => 'VMFS', 'accessible' => 'false' },
booleans_as_strings => 1,
msg => 'Object with booleans as strings'
},
{
json_string => '{ "accessible": false, "multiple_host_access": true, "name": "Trick: true, we\'re still in the string Developpement 7200", "type": "VMFS", "free_space": 5422671986688, "thin_provisioning_supported": true } ',
expected_object => { 'multiple_host_access' => 'true', 'thin_provisioning_supported' => 'true', 'name' => 'Trick: true, we\'re still in the string Developpement 7200', 'free_space' => '5422671986688', 'type' => 'VMFS', 'accessible' => 'false' },
booleans_as_strings => 1,
msg => 'Object with tricky booleans as strings'
},
{
json_string => '{ "accessible": false, "multiple_host_access": true, "name": ": true, we\'re still in the string Developpement 7200", "type": "VMFS", "free_space": 5422671986688, "thin_provisioning_supported": true } ',
expected_object => { 'multiple_host_access' => 'true', 'thin_provisioning_supported' => 'true', 'name' => ': true, we\'re still in the string Developpement 7200', 'free_space' => '5422671986688', 'type' => 'VMFS', 'accessible' => 'false' },
booleans_as_strings => 1,
msg => 'Object with more tricky booleans as strings'
}
);
for my $test (@tests) {
my ($object, $exit_code) = centreon::plugins::misc::json_decode($test->{json_string}, booleans_as_strings => $test->{booleans_as_strings});
is($object, $test->{expected_object}, $test->{msg});
}
}
test();
done_testing();

View File

@ -5,7 +5,7 @@ use Test2::V0;
use Test2::Plugin::NoWarnings echo => 1;
use FindBin;
use lib "$FindBin::RealBin/../../../src";
use lib "$FindBin::RealBin/../../../../src";
use centreon::plugins::perfdata;
my $perfdata = centreon::plugins::perfdata->new();

View File

@ -6,4 +6,5 @@ Library DateTime
Library OperatingSystem
Library String
Library XML
Library Collections
Resource resources.resource

View File

@ -95,3 +95,10 @@ Ctn Run Command And Check Result As Json
${json_expected}= evaluate json.loads('''${expected}''') json
Dictionaries Should Be Equal ${json_output} ${json_expected} ignore_keys=['end_time', 'start_time', 'duration']
Log Dictionary ${json_output}
Ctn Run Command And Return Parsed XML
[Arguments] ${command}
${output} Run ${command}
${output} Strip String ${output}
${parsed}= Parse XML ${output}
RETURN ${parsed}

View File

@ -57,6 +57,8 @@ CX
Cyberoam
Datacore
datasource
datastore
datastores
dBm
DC4
dcdiag
@ -308,12 +310,16 @@ v1
v2
v2c
v3
vCenter
VCENTER
vCPU
vdom
vdomain
VDSL2
Veeam
VeloCloud
VM
VMs
VMware
VMWARE
vpn