diff --git a/CHANGELOG.md b/CHANGELOG.md index f57f4cc..edbd977 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,19 @@ # Changelog +## [0.14.0] - 2025-06-02 +### Added +- Se ha añadido la funcionalidad de mover equipos entre aulas y grupos. +- Se ha añadido la funcionalidad para eliminar imagen cache. +- Se ha añadido la funcionalidad para iniciar sesion. + +### Improved +- Se ha cambiado la restriccion que comprobaba los puertos de MULTICAST. +- Se ha modificado el tiempo en el script, que se encarga de comprobar el estado de los equipos. Ahora es de 1 min en lugar de 3. + +### Fixed +- Se ha corregido un bug que hacia que al modificar un cliente o eliminarlo, no se actualizaba su estado en la subred. +- Se ha corregido un bug que hacia que al modificar un cliente, no se actualizara su fichero de arranque. + +--- ## [0.13.1] - 2025-05-23 ### Fixed - Variable de entorno "SSl_ENABLED" desactivada por defecto. diff --git a/config/api_platform/Client.yaml b/config/api_platform/Client.yaml index ad274d0..3882d9c 100644 --- a/config/api_platform/Client.yaml +++ b/config/api_platform/Client.yaml @@ -32,7 +32,7 @@ resources: class: ApiPlatform\Metadata\Post method: POST input: App\Dto\Input\ChangeOrganizationalUnitInput - uriTemplate: /clients/change-organizational-units + uriTemplate: /clients/change-organizational-unit controller: App\Controller\ChangeOrganizationalUnitAction agent_status: @@ -50,13 +50,20 @@ resources: uriTemplate: /clients/server/{uuid}/get-pxe controller: App\Controller\OgBoot\PxeBootFile\GetAction - login_client: + boot_client: class: ApiPlatform\Metadata\Post method: POST - input: App\Dto\Input\MultipleClientsInput - uriTemplate: /clients/server/login-client + input: App\Dto\Input\BootClientsInput + uriTemplate: /clients/server/boot-client controller: App\Controller\OgAgent\LoginAction + remove_cache_image: + class: ApiPlatform\Metadata\Post + method: POST + input: App\Dto\Input\BootClientsInput + uriTemplate: /clients/server/remove-cache-image + controller: App\Controller\OgAgent\RemoveCacheImageAction + reboot_client: class: ApiPlatform\Metadata\Post method: POST diff --git a/config/api_platform/Partition.yaml b/config/api_platform/Partition.yaml index 7ec5daa..200c8e3 100644 --- a/config/api_platform/Partition.yaml +++ b/config/api_platform/Partition.yaml @@ -4,6 +4,7 @@ resources: input: App\Dto\Input\PartitionPostInput output: App\Dto\Output\PartitionOutput order: + diskNumber: 'ASC' partitionNumber: 'ASC' normalizationContext: groups: ['default', 'partition:read'] diff --git a/config/api_platform/Trace.yaml b/config/api_platform/Trace.yaml index 65a6a32..3d64fa4 100644 --- a/config/api_platform/Trace.yaml +++ b/config/api_platform/Trace.yaml @@ -9,6 +9,8 @@ resources: filters: - 'api_platform.filter.trace.order' - 'api_platform.filter.trace.search' + - 'api_platform.filter.trace.date' + ApiPlatform\Metadata\Get: provider: App\State\Provider\TraceProvider diff --git a/config/packages/security.yaml b/config/packages/security.yaml index 8d142bc..6466847 100644 --- a/config/packages/security.yaml +++ b/config/packages/security.yaml @@ -33,6 +33,7 @@ security: - { path: ^/og-repository/webhook, roles: PUBLIC_ACCESS } - { path: ^/og-lives/install/webhook, roles: PUBLIC_ACCESS } - { path: ^/auth/refresh, roles: PUBLIC_ACCESS } + - { path: ^/validate, roles: PUBLIC_ACCESS } - { path: ^/menu-browser, roles: PUBLIC_ACCESS } - { path: ^/menu/, roles: PUBLIC_ACCESS } - { path: ^/, roles: IS_AUTHENTICATED_FULLY } diff --git a/config/services/api_platform.yaml b/config/services/api_platform.yaml index 2a7b829..0f70054 100644 --- a/config/services/api_platform.yaml +++ b/config/services/api_platform.yaml @@ -304,6 +304,11 @@ services: $orderParameterName: 'order' tags: [ 'api_platform.filter' ] + api_platform.filter.trace.date: + parent: 'api_platform.doctrine.orm.date_filter' + arguments: [ { 'executedAt': ~, 'createdAt': ~ } ] + tags: [ 'api_platform.filter' ] + api_platform.filter.user.order: parent: 'api_platform.doctrine.orm.order_filter' arguments: diff --git a/env.json b/env.json index b20cad5..9020b33 100644 --- a/env.json +++ b/env.json @@ -8,6 +8,9 @@ "UDS_AUTH_USERNAME": "test", "UDS_AUTH_PASSWORD": "test", "UDS_URL": "https:\/\/localhost:8087\/uds\/rest\/", - "SSL_ENABLED": "false" + "SSL_ENABLED": "true", + "OG_BOOT_IP": "127.0.0.1", + "OG_BOOT_API_PORT": "8082", + "OG_BOOT_PXE_PORT": "8085" } } \ No newline at end of file diff --git a/src/Command/CheckClientAvailability.php b/src/Command/CheckClientAvailability.php index bf7419e..fb63a9f 100644 --- a/src/Command/CheckClientAvailability.php +++ b/src/Command/CheckClientAvailability.php @@ -20,7 +20,7 @@ use Symfony\Component\Mercure\Update; #[AsCommand(name: 'opengnsys:check-client-availability', description: 'Check client availability')] class CheckClientAvailability extends Command { - const int THRESHOLD_MINUTES = 3; + const int THRESHOLD_MINUTES = 1; public function __construct( private readonly HubInterface $hub, @@ -34,16 +34,18 @@ class CheckClientAvailability extends Command { $io = new SymfonyStyle($input, $output); $threshold = (new \DateTime())->modify(' - '.self::THRESHOLD_MINUTES . ' minutes'); - $startQueryTime = microtime(true); + $validStatuses = [ClientStatus::OG_LIVE, ClientStatus::WINDOWS, ClientStatus::LINUX, ClientStatus::MACOS]; + $query = $this->entityManager->createQuery( 'UPDATE App\Entity\Client c - SET c.status = :status - WHERE c.status = :currentStatus AND c.updatedAt < :threshold' + SET c.status = :status + WHERE c.status IN (:currentStatuses) + AND c.updatedAt < :threshold' ); $query->setParameter('status', ClientStatus::DISCONNECTED); - $query->setParameter('currentStatus', ClientStatus::OG_LIVE); + $query->setParameter('currentStatuses', $validStatuses); $query->setParameter('threshold', $threshold); $updatedCount = $query->execute(); diff --git a/src/Controller/ChangeOrganizationalUnitAction.php b/src/Controller/ChangeOrganizationalUnitAction.php index 4d0609b..66e3ec1 100644 --- a/src/Controller/ChangeOrganizationalUnitAction.php +++ b/src/Controller/ChangeOrganizationalUnitAction.php @@ -2,7 +2,9 @@ namespace App\Controller; +use App\Controller\OgBoot\PxeBootFile\PostAction; use App\Dto\Input\ChangeOrganizationalUnitInput; +use App\Dto\Output\ClientOutput; use App\Entity\Client; use App\Repository\ClientRepository; use Doctrine\ORM\EntityManagerInterface; @@ -10,29 +12,37 @@ use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; +use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface; +use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface; +use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface; +use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface; class ChangeOrganizationalUnitAction extends AbstractController { public function __construct( - private readonly ClientRepository $clientRepository, - private readonly EntityManagerInterface $entityManager + private readonly EntityManagerInterface $entityManager, + private PostAction $postAction, ) { } + /** + * @throws TransportExceptionInterface + * @throws ServerExceptionInterface + * @throws RedirectionExceptionInterface + * @throws ClientExceptionInterface + */ public function __invoke(ChangeOrganizationalUnitInput $input): JsonResponse { foreach ($input->clients as $client) { - /** @var Client $client */ - $clientEntity = $this->clientRepository->find($client->getEntity()->getId()); - if (!$clientEntity) { - throw new NotFoundHttpException('Client not found'); - } + /** @var Client $clientEntity */ + $clientEntity = $client->getEntity(); $organizationalUnit = $input->organizationalUnit->getEntity(); $clientEntity->setOrganizationalUnit($organizationalUnit); $this->entityManager->persist($clientEntity); + $this->postAction->__invoke($clientEntity, $clientEntity->getTemplate()); } $this->entityManager->flush(); diff --git a/src/Controller/OgAgent/LoginAction.php b/src/Controller/OgAgent/LoginAction.php index a6d798f..260f02f 100644 --- a/src/Controller/OgAgent/LoginAction.php +++ b/src/Controller/OgAgent/LoginAction.php @@ -4,10 +4,12 @@ declare(strict_types=1); namespace App\Controller\OgAgent; +use App\Dto\Input\BootClientsInput; use App\Dto\Input\MultipleClientsInput; use App\Entity\Client; use App\Entity\Command; use App\Entity\Image; +use App\Entity\Partition; use App\Entity\Trace; use App\Model\ClientStatus; use App\Model\CommandTypes; @@ -35,8 +37,11 @@ class LoginAction extends AbstractOgAgentController * @throws RedirectionExceptionInterface * @throws ClientExceptionInterface */ - public function __invoke(MultipleClientsInput $input): JsonResponse + public function __invoke(BootClientsInput $input): JsonResponse { + /** @var Partition $partition */ + $partition = $input->partition->getEntity(); + foreach ($input->clients as $clientEntity) { /** @var Client $client */ $client = $clientEntity->getEntity(); @@ -52,17 +57,18 @@ class LoginAction extends AbstractOgAgentController $data = [ 'nfn' => 'IniciarSesion', - 'dsk' => '1', - 'par' => '1', + 'dsk' => (string) $partition->getDiskNumber(), + 'par' => (string) $partition->getPartitionNumber(), 'ids' => '0' ]; $response = $this->createRequest( method: 'POST', - url: 'http://'.$client->getIp().':8000/opengnsys/IniciarSesion', + url: 'https://'.$client->getIp().':8000/opengnsys/IniciarSesion', params: [ 'json' => $data, - ] + ], + token: $client->getToken(), ); if (isset($response['error']) && $response['code'] === Response::HTTP_INTERNAL_SERVER_ERROR) { @@ -77,7 +83,7 @@ class LoginAction extends AbstractOgAgentController $this->entityManager->persist($client); $this->entityManager->flush(); - $this->createService->__invoke($client, CommandTypes::REBOOT, TraceStatus::SUCCESS, $jobId, []); + $this->createService->__invoke($client, CommandTypes::LOGIN, TraceStatus::SUCCESS, $jobId, []); } return new JsonResponse(data: [], status: Response::HTTP_OK); diff --git a/src/Controller/OgAgent/RebootAction.php b/src/Controller/OgAgent/RebootAction.php index b83af31..410bba6 100644 --- a/src/Controller/OgAgent/RebootAction.php +++ b/src/Controller/OgAgent/RebootAction.php @@ -55,7 +55,7 @@ class RebootAction extends AbstractOgAgentController $response = $this->createRequest( method: 'POST', - url: 'http://'.$client->getIp().':8000/'.$endpoint, + url: 'https://'.$client->getIp().':8000/'.$endpoint, params: [ 'json' => $data, ], diff --git a/src/Controller/OgAgent/RemoveCacheImageAction.php b/src/Controller/OgAgent/RemoveCacheImageAction.php new file mode 100644 index 0000000..769453f --- /dev/null +++ b/src/Controller/OgAgent/RemoveCacheImageAction.php @@ -0,0 +1,85 @@ +partition->getEntity(); + + foreach ($input->clients as $clientEntity) { + /** @var Client $client */ + $client = $clientEntity->getEntity(); + + if (!$partition->getImage()) { + throw new ValidatorException('Image is required'); + } + + if (!$client->getIp()) { + throw new ValidatorException('IP is required'); + } + + if ($client->getStatus() !== ClientStatus::OG_LIVE) { + throw new ValidatorException('Client is not in OG_LIVE status'); + } + + $script = `rm%20-r%20/opt/opengnsys/cache/opt/opengnsys/images/{$partition->getImage()->getName()}.*@'`; + + $data = [ + 'nfn' => 'EjecutarScript', + 'scp' => base64_encode($script), + 'ids' => '0' + ]; + + $response = $this->createRequest( + method: 'POST', + url: 'https://'.$client->getIp().':8000/opengnsys/EjecutarScript', + params: [ + 'json' => $data, + ], + token: $client->getToken(), + ); + + if (isset($response['error']) && $response['code'] === Response::HTTP_INTERNAL_SERVER_ERROR) { + throw new ValidatorException('Error logging in: '.$response['error']); + } + + $this->logger->info('Login client', ['client' => $client->getId()]); + + $jobId = $response['job_id']; + + $this->entityManager->persist($client); + $this->entityManager->flush(); + + $inputData = [ + 'script' => $script, + ]; + + $this->createService->__invoke($client, CommandTypes::RUN_SCRIPT, TraceStatus::SUCCESS, $jobId, $inputData); + } + + return new JsonResponse(data: [], status: Response::HTTP_OK); + } +} \ No newline at end of file diff --git a/src/Controller/OgBoot/AbstractOgBootController.php b/src/Controller/OgBoot/AbstractOgBootController.php index c85e0fd..18f6bea 100644 --- a/src/Controller/OgBoot/AbstractOgBootController.php +++ b/src/Controller/OgBoot/AbstractOgBootController.php @@ -9,6 +9,7 @@ use App\Service\Trace\CreateService; use App\Service\Utils\ExtractOgLiveFilenameDateService; use App\Service\Utils\SimplifyOgLiveFilenameService; use Doctrine\ORM\EntityManagerInterface; +use Psr\Log\LoggerInterface; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\DependencyInjection\Attribute\Autowire; use Symfony\Component\HttpFoundation\JsonResponse; @@ -25,8 +26,12 @@ use Symfony\Contracts\HttpClient\HttpClientInterface; abstract class AbstractOgBootController extends AbstractController { public function __construct( - #[Autowire(env: 'OG_BOOT_API_URL')] - protected string $ogBootApiUrl, + #[Autowire(env: 'OG_BOOT_IP')] + protected string $ogBootIp, + #[Autowire(env: 'OG_BOOT_PXE_PORT')] + protected string $ogBootPxePort, + #[Autowire(env: 'OG_BOOT_API_PORT')] + protected string $ogBootApiPort, #[Autowire(env: 'OG_CORE_IP')] protected string $ogCoreIP, #[Autowire(env: 'OG_LOG_IP')] @@ -36,6 +41,8 @@ abstract class AbstractOgBootController extends AbstractController protected readonly CreateService $createService, protected readonly SimplifyOgLiveFilenameService $simplifyOgLiveFilenameService, protected readonly ExtractOgLiveFilenameDateService $extractOgLiveFilenameDateService, + protected readonly LoggerInterface $logger, + ) { } @@ -56,15 +63,25 @@ abstract class AbstractOgBootController extends AbstractController ]); try { - $response = $this->httpClient->request($method, $url, $params); + $response = $this->httpClient->request($method, 'http://'.$this->ogBootIp.':'.$this->ogBootApiPort.$url, $params); return json_decode($response->getContent(), true); } catch (ClientExceptionInterface | ServerExceptionInterface $e) { - $response = $e->getResponse(); - $content = json_decode($response->getContent(false), true); - throw new HttpException($response->getStatusCode(), $content['error'] ?? 'An error occurred'); + $this->logger->error(sprintf('Client/Server error in request to %s: %s', $url, $e->getMessage())); + + return [ + 'code' => Response::HTTP_INTERNAL_SERVER_ERROR, + 'error' => 'Client/Server error', + 'details' => $e->getMessage(), + ]; } catch (TransportExceptionInterface $e) { - throw new HttpException(Response::HTTP_INTERNAL_SERVER_ERROR, $e->getMessage()); + $this->logger->error(sprintf('Transport error in request to %s: %s', $url, $e->getMessage())); + + return [ + 'code' => Response::HTTP_INTERNAL_SERVER_ERROR, + 'error' => 'Transport error', + 'details' => $e->getMessage(), + ]; } } } diff --git a/src/Controller/OgBoot/OgLive/GetAction.php b/src/Controller/OgBoot/OgLive/GetAction.php index 0417416..296d4bd 100644 --- a/src/Controller/OgBoot/OgLive/GetAction.php +++ b/src/Controller/OgBoot/OgLive/GetAction.php @@ -29,7 +29,11 @@ class GetAction extends AbstractOgBootController throw new ValidatorException('Checksum is required'); } - $content = $this->createRequest('GET', 'http://'.$this->ogBootApiUrl.'/ogboot/v1/oglives/'.$data->getChecksum()); + $content = $this->createRequest('GET', '/ogboot/v1/oglives/'.$data->getChecksum()); + + if (isset($content['error']) && $content['error'] === Response::HTTP_INTERNAL_SERVER_ERROR ) { + throw new ValidatorException('An error occurred: ' . $content['error']); + } return new JsonResponse(data: $content, status: Response::HTTP_OK); } diff --git a/src/Controller/OgBoot/OgLive/GetCollectionAction.php b/src/Controller/OgBoot/OgLive/GetCollectionAction.php index 91204ac..2427f49 100644 --- a/src/Controller/OgBoot/OgLive/GetCollectionAction.php +++ b/src/Controller/OgBoot/OgLive/GetCollectionAction.php @@ -23,7 +23,11 @@ class GetCollectionAction extends AbstractOgBootController */ public function __invoke(): JsonResponse { - $content = $this->createRequest('GET', 'http://'.$this->ogBootApiUrl.'/ogboot/v1/oglives'); + $content = $this->createRequest('GET', '/ogboot/v1/oglives'); + + if (isset($content['error']) && $content['error'] === Response::HTTP_INTERNAL_SERVER_ERROR ) { + throw new ValidatorException('An error occurred: ' . $content['error']); + } return new JsonResponse(data: $content, status: Response::HTTP_OK); } diff --git a/src/Controller/OgBoot/OgLive/GetDefaultAction.php b/src/Controller/OgBoot/OgLive/GetDefaultAction.php index e5ef4f5..7b6ef5a 100644 --- a/src/Controller/OgBoot/OgLive/GetDefaultAction.php +++ b/src/Controller/OgBoot/OgLive/GetDefaultAction.php @@ -6,6 +6,7 @@ use App\Controller\OgBoot\AbstractOgBootController; use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Attribute\AsController; +use Symfony\Component\Validator\Exception\ValidatorException; use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface; use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface; use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface; @@ -22,7 +23,11 @@ class GetDefaultAction extends AbstractOgBootController */ public function __invoke(): JsonResponse { - $content = $this->createRequest('GET', 'http://'.$this->ogBootApiUrl.'/ogboot/v1/oglives/default'); + $content = $this->createRequest('GET', '/ogboot/v1/oglives/default'); + + if (isset($content['error']) && $content['error'] === Response::HTTP_INTERNAL_SERVER_ERROR ) { + throw new ValidatorException('An error occurred: ' . $content['error']); + } return new JsonResponse(status: Response::HTTP_OK); } diff --git a/src/Controller/OgBoot/OgLive/GetIsosAction.php b/src/Controller/OgBoot/OgLive/GetIsosAction.php index f451d88..52e08c6 100644 --- a/src/Controller/OgBoot/OgLive/GetIsosAction.php +++ b/src/Controller/OgBoot/OgLive/GetIsosAction.php @@ -23,7 +23,7 @@ class GetIsosAction extends AbstractOgBootController */ public function __invoke(): JsonResponse { - $content = $this->createRequest('GET', 'http://'.$this->ogBootApiUrl.'/ogboot/v1/oglives/isos'); + $content = $this->createRequest('GET', '/ogboot/v1/oglives/isos'); if (!isset($content['message']) || !is_array($content['message'])) { return new JsonResponse(data: ['error' => 'Invalid response'], status: Response::HTTP_BAD_REQUEST); diff --git a/src/Controller/OgBoot/OgLive/InstallAction.php b/src/Controller/OgBoot/OgLive/InstallAction.php index f736f13..95c4e91 100644 --- a/src/Controller/OgBoot/OgLive/InstallAction.php +++ b/src/Controller/OgBoot/OgLive/InstallAction.php @@ -45,7 +45,11 @@ class InstallAction extends AbstractOgBootController 'uuid' => 'InstallOgLive_'.$data->getUuid() ]; - $content = $this->createRequest('POST', 'http://'.$this->ogBootApiUrl.'/ogboot/v1/oglives/install', $params); + $content = $this->createRequest('POST', '/ogboot/v1/oglives/install', $params); + + if (isset($content['error']) && $content['error'] === Response::HTTP_INTERNAL_SERVER_ERROR ) { + throw new ValidatorException('An error occurred: ' . $content['error']); + } $this->createService->__invoke(null, CommandTypes::INSTALL_OGLIVE, TraceStatus::IN_PROGRESS, 'InstallOgLive_'.$data->getUuid(), $inputData); diff --git a/src/Controller/OgBoot/OgLive/SetDefaultAction.php b/src/Controller/OgBoot/OgLive/SetDefaultAction.php index 94bf7b1..d148b1b 100644 --- a/src/Controller/OgBoot/OgLive/SetDefaultAction.php +++ b/src/Controller/OgBoot/OgLive/SetDefaultAction.php @@ -36,7 +36,11 @@ class SetDefaultAction extends AbstractOgBootController ] ]; - $content = $this->createRequest('PUT', 'http://'.$this->ogBootApiUrl.'/ogboot/v1/oglives/default', $params); + $content = $this->createRequest('PUT', '/ogboot/v1/oglives/default', $params); + + if (isset($content['error']) && $content['error'] === Response::HTTP_INTERNAL_SERVER_ERROR ) { + throw new ValidatorException('An error occurred: ' . $content['error']); + } $oldDefaultOgLive = $this->entityManager->getRepository(OgLive::class)->findBy(['isDefault' => true]); diff --git a/src/Controller/OgBoot/OgLive/SyncAction.php b/src/Controller/OgBoot/OgLive/SyncAction.php index 69cabd0..13d790c 100644 --- a/src/Controller/OgBoot/OgLive/SyncAction.php +++ b/src/Controller/OgBoot/OgLive/SyncAction.php @@ -30,7 +30,11 @@ class SyncAction extends AbstractOgBootController */ public function __invoke(): JsonResponse { - $content = $this->createRequest('GET', 'http://'.$this->ogBootApiUrl . '/ogboot/v1/oglives'); + $content = $this->createRequest('GET', '/ogboot/v1/oglives'); + + if (isset($content['error']) && $content['error'] === Response::HTTP_INTERNAL_SERVER_ERROR ) { + throw new ValidatorException('An error occurred: ' . $content['error']); + } $allOgLives = $this->entityManager->getRepository(OgLive::class)->findAll(); $apiChecksums = array_map(fn($ogLive) => $ogLive['id'], $content['message']['installed_ogLives']); @@ -76,7 +80,9 @@ class SyncAction extends AbstractOgBootController */ private function extracted(OgLive $ogLiveEntity, mixed $ogLive): void { - $ogLiveEntity->setName($this->simplifyOgLiveFilenameService->__invoke(str_replace(self::OG_BOOT_DIRECTORY, '', $ogLive['directory']))); + $name = $this->simplifyOgLiveFilenameService->__invoke(str_replace(self::OG_BOOT_DIRECTORY, '', $ogLive['directory'])); + + $ogLiveEntity->setName($name ? $name : str_replace(self::OG_BOOT_DIRECTORY, '', $ogLive['directory'])); $ogLiveEntity->setDate(new \DateTime($this->extractOgLiveFilenameDateService->__invoke(str_replace(self::OG_BOOT_DIRECTORY, '', $ogLive['directory'])))); $ogLiveEntity->setInstalled(true); $ogLiveEntity->setArchitecture($ogLive['architecture']); diff --git a/src/Controller/OgBoot/OgLive/UninstallAction.php b/src/Controller/OgBoot/OgLive/UninstallAction.php index fe64ce8..4d72aee 100644 --- a/src/Controller/OgBoot/OgLive/UninstallAction.php +++ b/src/Controller/OgBoot/OgLive/UninstallAction.php @@ -31,7 +31,11 @@ class UninstallAction extends AbstractOgBootController throw new ValidatorException('Checksum is required'); } - $content = $this->createRequest( 'DELETE', 'http://'.$this->ogBootApiUrl.'/ogboot/v1/oglives/'.$data->getChecksum()); + $content = $this->createRequest( 'DELETE', '/ogboot/v1/oglives/'.$data->getChecksum()); + + if (isset($content['error']) && $content['error'] === Response::HTTP_INTERNAL_SERVER_ERROR ) { + throw new ValidatorException('An error occurred: ' . $content['error']); + } $this->entityManager->remove($data); $this->entityManager->flush(); diff --git a/src/Controller/OgBoot/PxeBootFile/DeleteAction.php b/src/Controller/OgBoot/PxeBootFile/DeleteAction.php index 884bd11..0a957a8 100644 --- a/src/Controller/OgBoot/PxeBootFile/DeleteAction.php +++ b/src/Controller/OgBoot/PxeBootFile/DeleteAction.php @@ -23,19 +23,13 @@ class DeleteAction extends AbstractOgBootController */ public function __invoke(string $mac): JsonResponse { - try { - $response = $this->httpClient->request('DELETE', 'http://'.$this->ogBootApiUrl.'/ogboot/v1/pxes/'.$mac, [ - 'headers' => [ - 'accept' => 'application/json', - ], - ]); - } catch (TransportExceptionInterface $e) { + $response = $this->createRequest('DELETE', '/ogboot/v1/pxes/'.$mac); + + if (isset($content['error']) && $content['code'] === Response::HTTP_INTERNAL_SERVER_ERROR) { return new JsonResponse( data: 'An error occurred', status: Response::HTTP_INTERNAL_SERVER_ERROR); } - $data = json_decode($response->getContent(), true); - - return new JsonResponse( data: $data, status: Response::HTTP_OK); + return new JsonResponse( data: [], status: Response::HTTP_OK); } } \ No newline at end of file diff --git a/src/Controller/OgBoot/PxeBootFile/GetAction.php b/src/Controller/OgBoot/PxeBootFile/GetAction.php index e2efc0d..7c35630 100644 --- a/src/Controller/OgBoot/PxeBootFile/GetAction.php +++ b/src/Controller/OgBoot/PxeBootFile/GetAction.php @@ -26,18 +26,12 @@ class GetAction extends AbstractOgBootController */ public function __invoke(Client $client): JsonResponse { - try { - $response = $this->httpClient->request('GET', 'http://'.$this->ogBootApiUrl.'/ogboot/v1/pxes/'.$client->getMac(), [ - 'headers' => [ - 'accept' => 'application/json', - ], - ]); - } catch (TransportExceptionInterface $e) { + $response = $this->createRequest('GET', '/ogboot/v1/pxes/'.$client->getName()); + + if (isset($content['error']) && $content['code'] === Response::HTTP_INTERNAL_SERVER_ERROR) { return new JsonResponse( data: 'An error occurred', status: Response::HTTP_INTERNAL_SERVER_ERROR); } - $data = json_decode($response->getContent(), true); - - return new JsonResponse( data: $data, status: Response::HTTP_OK); + return new JsonResponse( data: $response, status: Response::HTTP_OK); } } \ No newline at end of file diff --git a/src/Controller/OgBoot/PxeBootFile/GetCollectionAction.php b/src/Controller/OgBoot/PxeBootFile/GetCollectionAction.php index 211d548..8a10792 100644 --- a/src/Controller/OgBoot/PxeBootFile/GetCollectionAction.php +++ b/src/Controller/OgBoot/PxeBootFile/GetCollectionAction.php @@ -26,7 +26,7 @@ class GetCollectionAction extends AbstractOgBootController */ public function __invoke(HttpClientInterface $httpClient): JsonResponse { - $content = $this->createRequest('GET', 'http://'.$this->ogBootApiUrl.'/ogboot/v1/pxes'); + $content = $this->createRequest('GET', '/ogboot/v1/pxes'); return new JsonResponse(data: $content, status: Response::HTTP_OK); } diff --git a/src/Controller/OgBoot/PxeBootFile/PostAction.php b/src/Controller/OgBoot/PxeBootFile/PostAction.php index 75a30c3..28e4b8a 100644 --- a/src/Controller/OgBoot/PxeBootFile/PostAction.php +++ b/src/Controller/OgBoot/PxeBootFile/PostAction.php @@ -28,13 +28,13 @@ class PostAction extends AbstractOgBootController */ public function __invoke(Client $client, PxeTemplate $pxeTemplate): JsonResponse { - $ogRepoIp = $this->ogBootApiUrl; + $ogRepoIp = $this->ogBootIp; $ogRepoIp = $client->getRepository()?->getIp() ?? $client->getOrganizationalUnit()?->getNetworkSettings()?->getRepository()?->getIp(); $ogLive = $client->getOgLive()?->getFilename() - ?? $client->getOrganizationalUnit()?->getNetworkSettings()?->getOgLive()->getFilename(); + ?? $client->getOrganizationalUnit()?->getNetworkSettings()?->getOgLive()?->getFilename(); $params = [ 'json' => [ @@ -42,7 +42,9 @@ class PostAction extends AbstractOgBootController 'mac' => strtolower($client->getMac()), 'lang' => 'es_ES.UTF-8', 'ip' => $client->getIp(), - 'server_ip' => $this->ogBootApiUrl, + 'server_ip' => $this->ogBootIp, + 'server_api_port' => $this->ogBootApiPort, + 'server_pxe_port' => $this->ogBootPxePort, 'router' => $client->getOrganizationalUnit()->getNetworkSettings()->getRouter(), 'netmask' => $client->getOrganizationalUnit()->getNetworkSettings() ? $client->getOrganizationalUnit()->getNetworkSettings()->getNetmask() : '255.255.255.0', 'computer_name' => $client->getName(), @@ -50,10 +52,10 @@ class PostAction extends AbstractOgBootController 'group' => $client->getOrganizationalUnit()->getName(), 'ogrepo' => $ogRepoIp, 'ogcore' => $this->ogCoreIP, - 'oglive' => $this->ogBootApiUrl, + 'oglive' => $this->ogBootIp, 'oglog' => $this->ogLogIp, 'ogshare' => $client->getOrganizationalUnit()->getNetworkSettings()?->getOgShare() - ? $client->getOrganizationalUnit()->getNetworkSettings()?->getOgShare(): $this->ogBootApiUrl, + ? $client->getOrganizationalUnit()->getNetworkSettings()?->getOgShare(): $this->ogBootIp, 'oglivedir' => $ogLive, 'ogprof' => 'false', 'hardprofile' => $client->getHardwareProfile() ? $client->getHardwareProfile()->getDescription() : 'default', @@ -64,7 +66,7 @@ class PostAction extends AbstractOgBootController ] ]; - $content = $this->createRequest('POST', 'http://'.$this->ogBootApiUrl.'/ogboot/v1/pxes', $params); + $content = $this->createRequest('POST', '/ogboot/v1/pxes', $params); $client->setPxeSync(true); $this->entityManager->persist($client); diff --git a/src/Controller/OgBoot/PxeTemplate/DeleteAction.php b/src/Controller/OgBoot/PxeTemplate/DeleteAction.php index c816365..f319303 100644 --- a/src/Controller/OgBoot/PxeTemplate/DeleteAction.php +++ b/src/Controller/OgBoot/PxeTemplate/DeleteAction.php @@ -10,6 +10,7 @@ use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Attribute\AsController; +use Symfony\Component\Validator\Exception\ValidatorException; use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface; use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface; use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface; @@ -30,7 +31,11 @@ class DeleteAction extends AbstractOgBootController $this->entityManager->remove($data); $this->entityManager->flush(); - $content = $this->createRequest('DELETE', 'http://'.$this->ogBootApiUrl.'/ogboot/v1/pxe-templates/'.$data->getName()); + $content = $this->createRequest('DELETE', '/ogboot/v1/pxe-templates/'.$data->getName()); + + if (isset($content['error']) && $content['error'] === Response::HTTP_INTERNAL_SERVER_ERROR ) { + throw new ValidatorException('An error occurred: ' . $content['error']); + } $defaultTemplateEntity = $this->entityManager->getRepository(PxeTemplate::class)->findOneBy(['isDefault' => true]); diff --git a/src/Controller/OgBoot/PxeTemplate/GetAction.php b/src/Controller/OgBoot/PxeTemplate/GetAction.php index 6a61c17..cc94c2c 100644 --- a/src/Controller/OgBoot/PxeTemplate/GetAction.php +++ b/src/Controller/OgBoot/PxeTemplate/GetAction.php @@ -25,13 +25,9 @@ class GetAction extends AbstractOgBootController */ public function __invoke(PxeTemplate $template, HttpClientInterface $httpClient): JsonResponse { - try { - $response = $httpClient->request('GET', 'http://'.$this->ogBootApiUrl.'/ogboot/v1/pxe-templates/'.$template->getName(), [ - 'headers' => [ - 'accept' => 'application/json', - ], - ]); - } catch (TransportExceptionInterface $e) { + $response = $this->createRequest('GET', '/ogboot/v1/pxe-templates/'.$template->getName()); + + if ($response->getStatusCode() !== Response::HTTP_OK) { return new JsonResponse( data: 'An error occurred', status: Response::HTTP_INTERNAL_SERVER_ERROR); } diff --git a/src/Controller/OgBoot/PxeTemplate/GetCollectionAction.php b/src/Controller/OgBoot/PxeTemplate/GetCollectionAction.php index 623c8d3..936f2b4 100644 --- a/src/Controller/OgBoot/PxeTemplate/GetCollectionAction.php +++ b/src/Controller/OgBoot/PxeTemplate/GetCollectionAction.php @@ -7,6 +7,7 @@ use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Attribute\AsController; +use Symfony\Component\Validator\Exception\ValidatorException; use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface; use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface; use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface; @@ -24,18 +25,12 @@ class GetCollectionAction extends AbstractOgBootController */ public function __invoke(HttpClientInterface $httpClient): JsonResponse { - try { - $response = $httpClient->request('GET', 'http://'.$this->ogBootApiUrl.'/ogboot/v1/pxe-templates', [ - 'headers' => [ - 'accept' => 'application/json', - ], - ]); - } catch (TransportExceptionInterface $e) { - return new JsonResponse( data: 'An error occurred', status: Response::HTTP_INTERNAL_SERVER_ERROR); + $content = $this->createRequest('GET', '/ogboot/v1/pxe-templates'); + + if (isset($content['error']) && $content['error'] === Response::HTTP_INTERNAL_SERVER_ERROR ) { + throw new ValidatorException('An error occurred: ' . $content['error']); } - $data = json_decode($response->getContent(), true); - - return new JsonResponse( data: $data, status: Response::HTTP_OK); + return new JsonResponse( data: $content, status: Response::HTTP_OK); } } \ No newline at end of file diff --git a/src/Controller/OgBoot/PxeTemplate/PostAction.php b/src/Controller/OgBoot/PxeTemplate/PostAction.php index 2ad106c..42ff754 100644 --- a/src/Controller/OgBoot/PxeTemplate/PostAction.php +++ b/src/Controller/OgBoot/PxeTemplate/PostAction.php @@ -9,6 +9,7 @@ use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Attribute\AsController; +use Symfony\Component\Validator\Exception\ValidatorException; use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface; use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface; use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface; @@ -33,7 +34,11 @@ class PostAction extends AbstractOgBootController ] ]; - $content = $this->createRequest('POST', 'http://'.$this->ogBootApiUrl.'/ogboot/v1/pxe-templates' , $params); + $content = $this->createRequest('POST', '/ogboot/v1/pxe-templates' , $params); + + if (isset($content['error']) && $content['error'] === Response::HTTP_INTERNAL_SERVER_ERROR ) { + throw new ValidatorException('An error occurred: ' . $content['error']); + } $data->setSynchronized(true); $this->entityManager->persist($data); diff --git a/src/Controller/OgBoot/PxeTemplate/SyncAction.php b/src/Controller/OgBoot/PxeTemplate/SyncAction.php index 4988b84..1d9e2b6 100644 --- a/src/Controller/OgBoot/PxeTemplate/SyncAction.php +++ b/src/Controller/OgBoot/PxeTemplate/SyncAction.php @@ -28,7 +28,7 @@ class SyncAction extends AbstractOgBootController */ public function __invoke(): JsonResponse { - $content = $this->createRequest('GET', 'http://' . $this->ogBootApiUrl . '/ogboot/v1/pxe-templates'); + $content = $this->createRequest('GET', '/ogboot/v1/pxe-templates'); $templateNamesFromApi = $content['message']; $existingTemplates = $this->entityManager->getRepository(PxeTemplate::class)->findAll(); @@ -49,7 +49,11 @@ class SyncAction extends AbstractOgBootController $templateEntity->setName($templateName); } - $templateContent = $this->createRequest('GET', 'http://' . $this->ogBootApiUrl . '/ogboot/v1/pxe-templates/' . $templateEntity->getName()); + $templateContent = $this->createRequest('GET', '/ogboot/v1/pxe-templates/' . $templateEntity->getName()); + + if (isset($templateContent['error']) && $templateContent['error'] === Response::HTTP_INTERNAL_SERVER_ERROR ) { + throw new ValidatorException('An error occurred: ' . $templateContent['error']); + } $templateEntity->setTemplateContent($templateContent['template_content']); $templateEntity->setSynchronized(true); diff --git a/src/Controller/OgDhcp/Subnet/DeleteAction.php b/src/Controller/OgDhcp/Subnet/DeleteAction.php index 6a184f3..4d1b5db 100644 --- a/src/Controller/OgDhcp/Subnet/DeleteAction.php +++ b/src/Controller/OgDhcp/Subnet/DeleteAction.php @@ -7,6 +7,7 @@ use App\Entity\Subnet; use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Attribute\AsController; +use Symfony\Component\HttpKernel\Exception\HttpException; use Symfony\Component\Validator\Exception\ValidatorException; use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface; use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface; @@ -29,11 +30,23 @@ class DeleteAction extends AbstractOgDhcpController throw new ValidatorException('Data Id is required'); } - $content = $this->createRequest('DELETE', 'http://'.$this->ogDhcpApiUrl.'/ogdhcp/v1/subnets/'.$data->getServerId()); + try { + $content = $this->createRequest( + 'DELETE', + 'http://' . $this->ogDhcpApiUrl . '/ogdhcp/v1/subnets/' . $data->getServerId() + ); + } catch (HttpException $e) { + if ($e->getStatusCode() === 404) { + $content = ['message' => 'Subnet not found on external API, proceeding with local deletion']; + } else { + throw $e; + } + } $this->entityManager->remove($data); $this->entityManager->flush(); return new JsonResponse(data: $content, status: Response::HTTP_OK); } + } \ No newline at end of file diff --git a/src/Controller/OgDhcp/Subnet/PostHostAction.php b/src/Controller/OgDhcp/Subnet/PostHostAction.php index ba9de31..4b518c2 100644 --- a/src/Controller/OgDhcp/Subnet/PostHostAction.php +++ b/src/Controller/OgDhcp/Subnet/PostHostAction.php @@ -53,17 +53,15 @@ class PostHostAction extends AbstractOgDhcpController $params ); - // Guardar resultado exitoso $success[] = [ 'client' => $clientEntity->getName(), 'response' => $content ]; - // Persistir solo si la llamada fue exitosa $subnet->addClient($clientEntity); $this->entityManager->persist($subnet); $this->entityManager->flush(); - } catch (\Throwable $e) { // Capturar cualquier error sin interrumpir + } catch (\Throwable $e) { $errors[] = [ 'client' => $clientEntity->getName(), 'error' => $e->getMessage() diff --git a/src/Controller/OgDhcp/Subnet/PutHostAction.php b/src/Controller/OgDhcp/Subnet/PutHostAction.php index cf89d25..d7b6a45 100644 --- a/src/Controller/OgDhcp/Subnet/PutHostAction.php +++ b/src/Controller/OgDhcp/Subnet/PutHostAction.php @@ -24,26 +24,23 @@ class PutHostAction extends AbstractOgDhcpController * @throws RedirectionExceptionInterface * @throws ClientExceptionInterface */ - public function __invoke(SubnetAddHostInput $input, Subnet $subnet): JsonResponse + public function __invoke(string $mac, Client $client): JsonResponse { - $clients = $input->clients; + $subnet = $client->getSubnet(); - foreach ($clients as $client) { - /** @var Client $clientEntity */ - $clientEntity = $client->getEntity(); - $data = [ - 'host' => $clientEntity->getName(), - 'oldMacAddress' => '', - 'macAddress' => '', - 'address' => '', - ]; + /** @var Client $clientEntity */ + $data = [ + 'hostname' => $client->getName(), + 'oldMacAddress' => strtolower($mac), + 'macAddress' => strtolower($client->getMac()), + 'address' => $client->getIp(), + ]; - $params = [ - 'json' => $data - ]; + $params = [ + 'json' => $data + ]; - $content = $this->createRequest('PUT', 'http://'.$this->ogDhcpApiUrl.'/ogdhcp/v1/subnets/'.$subnet->getId().'/hosts', $params); - } + $content = $this->createRequest('PUT', 'http://'.$this->ogDhcpApiUrl.'/ogdhcp/v1/subnets/'.$subnet->getServerId().'/hosts', $params); return new JsonResponse(status: Response::HTTP_OK); } diff --git a/src/Dto/Input/BootClientsInput.php b/src/Dto/Input/BootClientsInput.php new file mode 100644 index 0000000..a430967 --- /dev/null +++ b/src/Dto/Input/BootClientsInput.php @@ -0,0 +1,21 @@ +putHostAction->__invoke($oldMac, $client); $this->deleteAction->__invoke($oldMac); } - } \ No newline at end of file diff --git a/src/EventSubscriber/ClientSubscriber.php b/src/EventSubscriber/ClientSubscriber.php index 7c652c2..ed08088 100644 --- a/src/EventSubscriber/ClientSubscriber.php +++ b/src/EventSubscriber/ClientSubscriber.php @@ -4,8 +4,11 @@ namespace App\EventSubscriber; use ApiPlatform\Symfony\EventListener\EventPriorities; use App\Controller\OgBoot\PxeBootFile\PostAction; +use App\Controller\OgDhcp\Subnet\PutHostAction; use App\Dto\Output\ClientOutput; use App\Entity\Client; +use App\Entity\PxeTemplate; +use Doctrine\ORM\EntityManagerInterface; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\Event\ViewEvent; @@ -18,7 +21,9 @@ use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface; final readonly class ClientSubscriber implements EventSubscriberInterface { public function __construct( + private readonly EntityManagerInterface $entityManager, private PostAction $postAction, + private PutHostAction $putHostAction, ) { @@ -49,14 +54,19 @@ final readonly class ClientSubscriber implements EventSubscriberInterface /** @var Client $client */ $client = $clientOutput->getEntity(); - $template = !$client->getTemplate() ? + $template = $client->getTemplate() ? $client->getTemplate() : $client->getOrganizationalUnit()?->getNetworkSettings()?->getPxeTemplate(); if ($template === null) { - return; + $template = $this->entityManager->getRepository(PxeTemplate::class)->findOneBy(['isDefault' => true]); + + if ($template === null) { + return; + } } $this->postAction->__invoke($client, $template); + $this->putHostAction->__invoke($client->getMac(), $client); } } \ No newline at end of file diff --git a/src/EventSubscriber/MercureSubscriber.php b/src/EventSubscriber/MercureSubscriber.php index aaf1b3d..fe44ef7 100644 --- a/src/EventSubscriber/MercureSubscriber.php +++ b/src/EventSubscriber/MercureSubscriber.php @@ -63,15 +63,25 @@ class MercureSubscriber implements EventSubscriberInterface 'status' => $client->getStatus(), ]; - $update = new Update( - 'clients', - json_encode($data) - ); - $this->hub->publish($update); + try { + $update = new Update( + 'clients', + json_encode($data) + ); - $this->logger->info('Evento Mercure disparado', [ - 'method' => $method, - 'path' => $request->getPathInfo() - ]); + $this->hub->publish($update); + + $this->logger->info('Evento Mercure disparado', [ + 'method' => $method, + 'path' => $request->getPathInfo() + ]); + } catch (\Exception $e) { + $this->logger->error('Error setting method for Mercure update', [ + 'method' => $method, + 'path' => $request->getPathInfo(), + 'error' => $e->getMessage(), + ]); + return; + } } } diff --git a/src/Service/OgBoot/StatusService.php b/src/Service/OgBoot/StatusService.php index 740e95e..f11fb10 100644 --- a/src/Service/OgBoot/StatusService.php +++ b/src/Service/OgBoot/StatusService.php @@ -16,8 +16,12 @@ use Symfony\Component\HttpClient\HttpClient; readonly class StatusService { public function __construct( - #[Autowire(env: 'OG_BOOT_API_URL')] - private string $ogBootApiUrl + #[Autowire(env: 'OG_BOOT_IP')] + protected string $ogBootIp, + #[Autowire(env: 'OG_BOOT_PXE_PORT')] + protected string $ogBootPxePort, + #[Autowire(env: 'OG_BOOT_API_PORT')] + protected string $ogBootApiPort, ) { } @@ -31,12 +35,12 @@ readonly class StatusService public function __invoke() { $httpClient = HttpClient::create([ - 'verify_peer' => false, // Ignorar la verificación del certificado SSL - 'verify_host' => false, // Ignorar la verificación del nombre del host + 'verify_peer' => false, + 'verify_host' => false, ]); try { - $response = $httpClient->request('GET', 'http://'.$this->ogBootApiUrl.'/ogboot/v1/status', [ + $response = $httpClient->request('GET', 'http://'.$this->ogBootIp.':'.$this->ogBootApiPort.'/ogboot/v1/status', [ 'headers' => [ 'accept' => 'application/json', ], diff --git a/src/State/Processor/ClientProcessor.php b/src/State/Processor/ClientProcessor.php index 76605ff..69c07e4 100644 --- a/src/State/Processor/ClientProcessor.php +++ b/src/State/Processor/ClientProcessor.php @@ -9,18 +9,34 @@ use ApiPlatform\Metadata\Post; use ApiPlatform\Metadata\Put; use ApiPlatform\State\ProcessorInterface; use ApiPlatform\Validator\ValidatorInterface; +use App\Controller\OgBoot\PxeBootFile\DeleteAction; +use App\Controller\OgDhcp\Subnet\DeleteHostAction; use App\Dto\Input\ClientInput; use App\Dto\Output\ClientOutput; use App\Dto\Output\UserGroupOutput; +use App\Entity\OgLive; +use App\Entity\PxeTemplate; use App\Repository\ClientRepository; use App\Repository\MenuRepository; +use App\Repository\OgLiveRepository; +use App\Repository\PxeTemplateRepository; +use Symfony\Component\HttpKernel\KernelInterface; +use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface; +use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface; +use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface; +use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface; readonly class ClientProcessor implements ProcessorInterface { public function __construct( - private ClientRepository $clientRepository, - private MenuRepository $menuRepository, - private ValidatorInterface $validator + private ClientRepository $clientRepository, + private MenuRepository $menuRepository, + private PxeTemplateRepository $pxeTemplateRepository, + private OgLiveRepository $ogLiveRepository, + private ValidatorInterface $validator, + private DeleteHostAction $deleteHostAction, + private DeleteAction $deletePxeAction, + private KernelInterface $kernel, ) { } @@ -55,6 +71,8 @@ readonly class ClientProcessor implements ProcessorInterface } $defaultMenu = $this->menuRepository->findOneBy(['isDefault' => true]); + $defaultPxe = $this->pxeTemplateRepository->findOneBy(['isDefault' => true]); + $defaultPxeOgLive = $this->ogLiveRepository->findOneBy(['isDefault' => true]); $client = $data->createOrUpdateEntity($entity); @@ -62,16 +80,35 @@ readonly class ClientProcessor implements ProcessorInterface $client->setMenu($defaultMenu); } + if ($defaultPxe) { + $client->setTemplate($defaultPxe); + } + + if ($defaultPxeOgLive) { + $client->setOgLive($defaultPxeOgLive); + } + $this->validator->validate($client); $this->clientRepository->save($client); return new ClientOutput($client); } + /** + * @throws TransportExceptionInterface + * @throws ServerExceptionInterface + * @throws RedirectionExceptionInterface + * @throws ClientExceptionInterface + */ private function processDelete($data, Operation $operation, array $uriVariables = [], array $context = []): null { - $user = $this->clientRepository->findOneByUuid($uriVariables['uuid']); - $this->clientRepository->delete($user); + $client = $this->clientRepository->findOneByUuid($uriVariables['uuid']); + $this->clientRepository->delete($client); + + if ($this->kernel->getEnvironment() !== 'test') { + $this->deleteHostAction->__invoke($client->getSubnet(), $client->getUuid()); + $this->deletePxeAction->__invoke($client->getUuid()); + } return null; } diff --git a/src/Validator/Constraints/OrganizationalUnitMulticastPortValidator.php b/src/Validator/Constraints/OrganizationalUnitMulticastPortValidator.php index 6baabda..38ef7ab 100644 --- a/src/Validator/Constraints/OrganizationalUnitMulticastPortValidator.php +++ b/src/Validator/Constraints/OrganizationalUnitMulticastPortValidator.php @@ -9,8 +9,8 @@ use Symfony\Component\Validator\ConstraintValidator; class OrganizationalUnitMulticastPortValidator extends ConstraintValidator { - CONST int minPort = 9000; - CONST int maxPort = 9050; + public const int minPort = 9000; + public const int maxPort = 9098; public function validate($value, Constraint $constraint): void { @@ -18,9 +18,14 @@ class OrganizationalUnitMulticastPortValidator extends ConstraintValidator return; } - if (!(self::minPort <= $value) && ($value <= self::maxPort)) { + if ($value % 2 !== 0) { + $this->context->buildViolation('El puerto debe ser un número par y encontrarse entre el 9000 y el 9098.')->addViolation(); + return; + } + + if ($value < self::minPort || $value > self::maxPort) { $this->context->buildViolation($constraint->message)->addViolation(); return; } } -} \ No newline at end of file +}