Commit 33c5c2a9 authored by Adrien Morais-Mestre's avatar Adrien Morais-Mestre Committed by Adrien Morais
Browse files

enh(resources): use new resources tables from monitoring (#11040)



* enh(resources): use new tables resources

* Update src/Centreon/Domain/Monitoring/Icon.php

Co-authored-by: default avatarKevin Duret <kduret@centreon.com>

* Update src/Centreon/Domain/Monitoring/Icon.php

Co-authored-by: default avatarKevin Duret <kduret@centreon.com>

* Update src/Centreon/Infrastructure/Monitoring/Resource/DbReadResourceRepository.php

Co-authored-by: default avatarKevin Duret <kduret@centreon.com>

* Update src/Centreon/Infrastructure/Monitoring/Resource/DbReadResourceRepository.php

Co-authored-by: default avatarKevin Duret <kduret@centreon.com>

* Update src/Centreon/Infrastructure/Monitoring/Resource/DbReadResourceRepository.php

Co-authored-by: default avatarKevin Duret <kduret@centreon.com>

* Update src/Centreon/Infrastructure/Monitoring/Resource/DbReadResourceRepository.php

Co-authored-by: default avatarKevin Duret <kduret@centreon.com>

* Update src/Centreon/Infrastructure/Monitoring/Resource/DbReadResourceRepository.php

Co-authored-by: default avatarKevin Duret <kduret@centreon.com>

* Update src/Centreon/Infrastructure/Monitoring/Resource/DbReadResourceRepository.php

Co-authored-by: default avatarKevin Duret <kduret@centreon.com>

* Update src/Centreon/Infrastructure/Monitoring/Resource/DbReadResourceRepository.php

Co-authored-by: default avatarKevin Duret <kduret@centreon.com>

* Update src/Centreon/Infrastructure/Monitoring/Resource/DbReadResourceRepository.php

Co-authored-by: default avatarKevin Duret <kduret@centreon.com>

* Update src/Centreon/Infrastructure/Monitoring/Resource/DbReadResourceRepository.php

Co-authored-by: default avatarKevin Duret <kduret@centreon.com>

* Update src/Centreon/Infrastructure/Monitoring/Resource/DbReadResourceRepository.php

Co-authored-by: default avatarKevin Duret <kduret@centreon.com>

* Update src/Centreon/Infrastructure/Monitoring/Resource/DbReadResourceRepository.php

Co-authored-by: default avatarKevin Duret <kduret@centreon.com>

* Update src/Centreon/Infrastructure/Monitoring/Resource/DbReadResourceRepository.php

Co-authored-by: default avatarKevin Duret <kduret@centreon.com>

* Update src/Centreon/Infrastructure/Monitoring/Resource/DbReadResourceRepository.php

Co-authored-by: default avatarKevin Duret <kduret@centreon.com>

* Update src/Centreon/Infrastructure/Monitoring/Resource/DbReadResourceRepository.php

Co-authored-by: default avatarKevin Duret <kduret@centreon.com>

* Update src/Centreon/Infrastructure/Monitoring/Resource/DbReadResourceRepository.php

Co-authored-by: default avatarKevin Duret <kduret@centreon.com>

* code-review: from kdu

* code-review: remove unused variable

* code-review: add missing concordances

* add unit tests for factory

* disable new mod for now, waiting for a PR to be merged

* centreon-bot: review

* code-review: callapas feedback

* bind issue if only one icon

Co-authored-by: default avatarKevin Duret <kduret@centreon.com>
parent 559b4d7f
......@@ -252,6 +252,12 @@ services:
- method: setProviders
arguments: [!tagged_iterator 'monitoring.resource.providers']
# Centreon\Domain\Monitoring\Interfaces\ResourceRepositoryInterface:
# class: Centreon\Infrastructure\Monitoring\Resource\DbReadResourceRepository
# calls:
# - method: setSqlRequestTranslator
# arguments: ['@sqlRequestTranslator']
Core\Infrastructure\RealTime\Api\Hypermedia\HypermediaCreator:
class: Core\Infrastructure\RealTime\Api\Hypermedia\HypermediaCreator
calls:
......
......@@ -32,6 +32,11 @@ class Icon
// Groups for serializing
public const SERIALIZER_GROUP_MAIN = 'icon_main';
/**
* @var int|null
*/
private $id;
/**
* @var string|null
*/
......@@ -42,6 +47,25 @@ class Icon
*/
private $url;
/**
* @return int|null
*/
public function getId(): ?int
{
return $this->id;
}
/**
* @param int|null $id
* @return self
*/
public function setId(?int $id): self
{
$this->id = $id;
return $this;
}
/**
* @return string|null
*/
......
......@@ -147,14 +147,14 @@ class Resource
private $acknowledged = false;
/**
* @var bool|null
* @var bool
*/
private $activeChecks;
private $activeChecks = true;
/**
* @var bool|null
* @var bool
*/
private $passiveChecks;
private $passiveChecks = false;
/**
* @var ResourceLinks
......@@ -262,6 +262,11 @@ class Resource
*/
private $notificationEnabled = false;
/**
* @var bool
*/
private $hasGraph = false;
/**
* Resource constructor.
*/
......@@ -396,7 +401,6 @@ class Resource
public function setAlias(?string $alias): self
{
$this->alias = $alias;
return $this;
}
......@@ -647,7 +651,6 @@ class Resource
public function setInDowntime(bool $inDowntime): self
{
$this->inDowntime = $inDowntime;
return $this;
}
......@@ -666,41 +669,40 @@ class Resource
public function setAcknowledged(bool $acknowledged): self
{
$this->acknowledged = $acknowledged;
return $this;
}
/**
* @return bool|null
* @return bool
*/
public function getActiveChecks(): ?bool
public function getActiveChecks(): bool
{
return $this->activeChecks;
}
/**
* @param bool|null $activeChecks
* @param bool $activeChecks
* @return self
*/
public function setActiveChecks(?bool $activeChecks): self
public function setActiveChecks(bool $activeChecks): self
{
$this->activeChecks = $activeChecks;
return $this;
}
/**
* @return bool|null
* @return bool
*/
public function getPassiveChecks(): ?bool
public function getPassiveChecks(): bool
{
return $this->passiveChecks;
}
/**
* @param bool|null $passiveChecks
* @param bool $passiveChecks
* @return self
*/
public function setPassiveChecks(?bool $passiveChecks): self
public function setPassiveChecks(bool $passiveChecks): self
{
$this->passiveChecks = $passiveChecks;
return $this;
......@@ -1084,4 +1086,22 @@ class Resource
return $this;
}
/**
* @param bool $hasGraph
* @return self
*/
public function setHasGraph(bool $hasGraph): self
{
$this->hasGraph = $hasGraph;
return $this;
}
/**
* @return bool
*/
public function hasGraph(): bool
{
return $this->hasGraph;
}
}
......@@ -130,7 +130,10 @@ class ResourceService extends AbstractCentreonService implements ResourceService
$hostId = null;
if ($resource->getType() === ResourceEntity::TYPE_HOST) {
$hostId = (int) $resource->getId();
} elseif ($resource->getType() === ResourceEntity::TYPE_SERVICE) {
} elseif (
$resource->getParent() !== null
&& $resource->getType() === ResourceEntity::TYPE_SERVICE
) {
$hostId = (int) $resource->getParent()->getId();
}
......@@ -146,11 +149,11 @@ class ResourceService extends AbstractCentreonService implements ResourceService
*/
private function replaceMacrosInUrlsForHostResource(ResourceEntity $resource, string $url): string
{
$url = str_replace('$HOSTADDRESS$', $resource->getFqdn(), $url);
$url = str_replace('$HOSTADDRESS$', $resource->getFqdn() ?? '', $url);
$url = str_replace('$HOSTNAME$', $resource->getName(), $url);
$url = str_replace('$HOSTSTATE$', $resource->getStatus()->getName(), $url);
$url = str_replace('$HOSTSTATEID$', (string) $resource->getStatus()->getCode(), $url);
$url = str_replace('$HOSTALIAS$', $resource->getAlias(), $url);
$url = str_replace('$HOSTALIAS$', $resource->getAlias() ?? '', $url);
return $url;
}
......@@ -164,11 +167,11 @@ class ResourceService extends AbstractCentreonService implements ResourceService
*/
private function replaceMacrosInUrlsForServiceResource(ResourceEntity $resource, string $url): string
{
$url = str_replace('$HOSTADDRESS$', $resource->getParent()->getFqdn(), $url);
$url = str_replace('$HOSTNAME$', $resource->getParent()->getName(), $url);
$url = str_replace('$HOSTSTATE$', $resource->getParent()->getStatus()->getName(), $url);
$url = str_replace('$HOSTSTATEID$', (string) $resource->getParent()->getStatus()->getCode(), $url);
$url = str_replace('$HOSTALIAS$', $resource->getParent()->getAlias(), $url);
$url = str_replace('$HOSTADDRESS$', $resource->getParent()?->getFqdn() ?? '', $url);
$url = str_replace('$HOSTNAME$', $resource->getParent()?->getName() ?? '', $url);
$url = str_replace('$HOSTSTATE$', $resource->getParent()?->getStatus()->getName() ?? '', $url);
$url = str_replace('$HOSTSTATEID$', (string) $resource->getParent()?->getStatus()->getCode(), $url);
$url = str_replace('$HOSTALIAS$', $resource->getParent()?->getAlias() ?? '', $url);
$url = str_replace('$SERVICEDESC$', $resource->getName(), $url);
$url = str_replace('$SERVICESTATE$', $resource->getStatus()->getName(), $url);
$url = str_replace('$SERVICESTATEID$', (string) $resource->getStatus()->getCode(), $url);
......@@ -186,7 +189,7 @@ class ResourceService extends AbstractCentreonService implements ResourceService
$notesUrl = ($notesObject !== null) ? $notesObject->getUrl() : null;
$resourceType = $resource->getType();
if ($actionUrl !== null) {
if (! empty($actionUrl)) {
if ($resourceType === ResourceEntity::TYPE_HOST) {
$actionUrl = $this->replaceMacrosInUrlsForHostResource($resource, $actionUrl);
} elseif ($resourceType === ResourceEntity::TYPE_SERVICE) {
......@@ -195,13 +198,13 @@ class ResourceService extends AbstractCentreonService implements ResourceService
$resource->getLinks()->getExternals()->setActionUrl($actionUrl);
}
if ($notesUrl !== null) {
if (! empty($notesUrl)) {
if ($resourceType === ResourceEntity::TYPE_HOST) {
$notesUrl = $this->replaceMacrosInUrlsForHostResource($resource, $notesUrl);
} elseif ($resourceType === ResourceEntity::TYPE_SERVICE) {
$notesUrl = $this->replaceMacrosInUrlsForServiceResource($resource, $notesUrl);
}
$resource->getLinks()->getExternals()->getNotes()->setUrl($notesUrl);
$resource->getLinks()->getExternals()->getNotes()?->setUrl($notesUrl);
}
}
......
......@@ -86,7 +86,7 @@ class ResourceStatus
*/
public function getName(): ?string
{
return $this->name ? _($this->name) : $this->name;
return $this->name;
}
/**
......
<?php
/*
* Copyright 2005 - 2022 Centreon (https://www.centreon.com/)
*
* 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.
*
* For more information : contact@centreon.com
*
*/
declare(strict_types=1);
namespace Centreon\Infrastructure\Monitoring\Resource;
use Centreon\Domain\Security\AccessGroup;
use Centreon\Domain\Monitoring\ResourceFilter;
use Centreon\Infrastructure\DatabaseConnection;
use Centreon\Domain\Repository\RepositoryException;
use Centreon\Domain\Contact\Interfaces\ContactInterface;
use Centreon\Domain\Log\LoggerTrait;
use Centreon\Domain\RequestParameters\RequestParameters;
use Centreon\Infrastructure\Repository\AbstractRepositoryDRB;
use Centreon\Infrastructure\CentreonLegacyDB\StatementCollector;
use Centreon\Domain\Monitoring\Interfaces\ResourceRepositoryInterface;
use Centreon\Infrastructure\RequestParameters\SqlRequestParametersTranslator;
use Centreon\Infrastructure\RequestParameters\RequestParametersTranslatorException;
use Centreon\Domain\Monitoring\Resource as ResourceEntity;
class DbReadResourceRepository extends AbstractRepositoryDRB implements ResourceRepositoryInterface
{
use LoggerTrait;
private const RESOURCE_TYPE_SERVICE = 0,
RESOURCE_TYPE_HOST = 1,
RESOURCE_TYPE_METASERVICE = 2;
/**
* @var SqlRequestParametersTranslator
*/
private $sqlRequestTranslator;
/**
* @var ContactInterface
*/
private $contact;
/**
* @var AccessGroup[]
*/
private $accessGroups = [];
/**
* @var array<string, string>
*/
private $resourceConcordances = [
'id' => 'resources.id',
'name' => 'resources.name',
'alias' => 'resources.alias',
'fqdn' => 'resources.address',
'type' => 'resources.type',
'h.name' => 'parent_resource.name',
'h.alias' => 'parent_resource.alias',
'h.address' => 'parent_resource.address',
's.description' => 'resources.type IN (0,2) AND resources.name',
'status_code' => 'resources.status',
'status_severity_code' => 'resources.status_ordered',
'action_url' => 'resources.action_url',
'parent_name' => 'resources.parent_name',
'parent_alias' => 'parent_resource.alias',
'parent_status' => 'parent_resource.status',
'severity_level' => 'severity_level',
'in_downtime' => 'resources.in_downtime',
'acknowledged' => 'resources.acknowledged',
'last_status_change' => 'resources.last_status_change',
'tries' => 'resources.check_attempts',
'last_check' => 'resources.last_check',
'monitoring_server_name' => 'monitoring_server_name',
'information' => 'resources.output',
];
/**
* @param DatabaseConnection $db
*/
public function __construct(DatabaseConnection $db)
{
$this->db = $db;
}
/**
* Initialized by the dependency injector.
*
* @param SqlRequestParametersTranslator $sqlRequestTranslator
*/
public function setSqlRequestTranslator(SqlRequestParametersTranslator $sqlRequestTranslator): void
{
$this->sqlRequestTranslator = $sqlRequestTranslator;
$this->sqlRequestTranslator
->getRequestParameters()
->setConcordanceStrictMode(RequestParameters::CONCORDANCE_MODE_STRICT)
->setConcordanceErrorMode(RequestParameters::CONCORDANCE_ERRMODE_SILENT);
}
/**
* @inheritDoc
*/
public function setContact(ContactInterface $contact): ResourceRepositoryInterface
{
$this->contact = $contact;
return $this;
}
/**
* @inheritDoc
*/
public function filterByAccessGroups(?array $accessGroups): ResourceRepositoryInterface
{
$this->accessGroups = $accessGroups;
return $this;
}
/**
* @inheritDoc
*/
public function findResources(ResourceFilter $filter): array
{
$resources = [];
if ($this->hasNotEnoughRightsToContinue()) {
return $resources;
}
$collector = new StatementCollector();
$this->sqlRequestTranslator->setConcordanceArray($this->resourceConcordances);
$request = "SELECT SQL_CALC_FOUND_ROWS DISTINCT
resources.resource_id,
resources.name,
resources.alias,
resources.address,
resources.id,
resources.internal_id,
resources.parent_id,
resources.parent_name,
parent_resource.status AS `parent_status`,
parent_resource.alias AS `parent_alias`,
parent_resource.status_ordered AS `parent_status_ordered`,
severities.level AS `severity_level`,
resources.type,
resources.status,
resources.status_ordered,
resources.status_confirmed,
resources.in_downtime,
resources.acknowledged,
resources.passive_checks_enabled,
resources.active_checks_enabled,
resources.notifications_enabled,
resources.last_check,
resources.last_status_change,
resources.check_attempts,
resources.max_check_attempts,
resources.notes,
resources.notes_url,
resources.action_url,
resources.output,
resources.poller_id,
resources.has_graph,
instances.name AS `monitoring_server_name`,
resources.enabled,
resources.icon_id
FROM `:dbstg`.`resources`
LEFT JOIN `:dbstg`.`resources` resource_parent
ON resource_parent.id = resources.parent_id
LEFT JOIN `:dbstg`.`severities`
ON `severities`.severity_id = `resources`.severity_id
LEFT JOIN `:dbstg`.`resources_tags` AS rtags
ON `rtags`.resource_id = `resources`.resource_id
INNER JOIN `:dbstg`.`instances`
ON `instances`.instance_id = `resources`.poller_id";
/**
* Handle search values
*/
$searchSubRequest = null;
$hasWhereCondition = false;
try {
$searchSubRequest .= $this->sqlRequestTranslator->translateSearchParameterToSql();
} catch (RequestParametersTranslatorException $ex) {
throw new RepositoryException($ex->getMessage(), 0, $ex);
}
$request .= !empty($searchSubRequest) ? $searchSubRequest . ' AND ' : ' WHERE ';
$request .= " resources.name NOT LIKE '\_Module\_%'
AND resources.parent_name NOT LIKE '\_Module\_BAM%'
AND resources.enabled = 1";
/**
* Handle ACL
*/
if ($this->contact->isAdmin() === false) {
$accessGroupIds = array_map(
function (AccessGroup $accessGroup) {
return $accessGroup->getId();
},
$this->accessGroups
);
$request .= ' AND EXISTS (
SELECT 1 FROM `:dbstg`.centreon_acl acl WHERE
(resources.type IN (0,2) AND resources.parent_id = acl.host_id AND resources.id = acl.service_id)
OR
(resources.type = 1 AND resources.id = acl.host_id AND acl.service_id IS NULL)
AND acl.group_id IN (' . implode(', ', $accessGroupIds) . ')
LIMIT 1
)';
}
/**
* Resource Type filter
* 'service', 'metaservice', 'host'
*/
$request .= $this->addResourceTypeSubRequest($filter);
/**
* State filter
* 'unhandled_problems', 'resource_problems', 'acknowledged', 'in_downtime'
*/
$request .= $this->addResourceStateSubRequest($filter);
/**
* Status filter
* 'OK', 'WARNING', 'CRITICAL', 'UNKNOWN', 'UP', 'UNREACHABLE', 'DOWN', 'PENDING'
*/
$request .= $this->addResourceStatusSubRequest($filter);
/**
* Status type filter
* 'HARD', 'SOFT'
*/
$request .= $this->addStatusTypeSubRequest($filter);
/**
* Monitoring Server filter
*/
$request .= $this->addMonitoringServerSubRequest($filter, $collector);
/**
* Resource tag filter by name
* - servicegroups
* - hostgroups
* - @todo servicecategories
* - @todo hostcategories
*/
$request .= $this->addResourceTagsSubRequest($filter, $collector);
/**
* Handle sort parameters
*/
$request .= $this->sqlRequestTranslator->translateSortParameterToSql()
?: ' ORDER BY resources.status_ordered DESC, resources.name ASC';
/**
* Handle pagination
*/
$request .= $this->sqlRequestTranslator->translatePaginationToSql();
$statement = $this->db->prepare(
$this->translateDbName($request)
);
foreach ($this->sqlRequestTranslator->getSearchValues() as $key => $data) {
$collector->addValue($key, current($data), key($data));
}
$collector->bind($statement);
$statement->execute();
$result = $this->db->query('SELECT FOUND_ROWS()');
if ($result !== false && ($total = $result->fetchColumn()) !== false) {
$this->sqlRequestTranslator->getRequestParameters()->setTotal((int) $total);
}
while ($resourceRecord = $statement->fetch(\PDO::FETCH_ASSOC)) {
$resources[] = DbResourceFactory::createFromRecord($resourceRecord);
}
/**
* Loop on resources on a private method to get icon ids and add them to the entity
*/
$resources = $this->getIconsForResources($resources);
return $resources;
}
/**
* Only return resources that has performance data available in order to display graphs
*
* @param ResourceEntity[] $resources
* @return ResourceEntity[]
*/
public function extractResourcesWithGraphData(array $resources): array
{
return array_filter(
$resources,
fn(ResourceEntity $resource) => $resource->hasGraph(),
);
}
/**
* @return bool Return FALSE if the contact is an admin or has at least one access group.
*/
private function hasNotEnoughRightsToContinue(): bool
{
return ($this->contact !== null)
? !($this->contact->isAdmin() || count($this->accessGroups) > 0)
: count($this->accessGroups) == 0;
}
/**
* This adds the sub request filter on resource types
*
* @param ResourceFilter $filter
* @return string
*/
private function addResourceTypeSubRequest(ResourceFilter $filter): string
{
$resourceTypes = [];
$subRequest = '';
foreach ($filter->getTypes() as $resourceType) {
if ($resourceType === ResourceEntity::TYPE_HOST) {
$resourceTypes[] = self::RESOURCE_TYPE_HOST;
} elseif ($resourceType === ResourceEntity::TYPE_SERVICE) {