From 326ff47eddb0e2a89dec8a0b045ef8e25c0b6c8c Mon Sep 17 00:00:00 2001 From: Manuel Aranda Date: Wed, 14 May 2025 13:25:57 +0200 Subject: [PATCH 01/10] Some improvements --- CHANGELOG.md | 14 +++-- migrations/Version20250514051344.php | 31 +++++++++++ migrations/Version20250514101117.php | 31 +++++++++++ .../RunScheduledCommandTasksCommand.php | 23 ++++----- src/Controller/OgAgent/RunScriptAction.php | 4 +- .../OgBoot/PxeBootFile/DeleteAction.php | 41 +++++++++++++++ .../OgBoot/PxeBootFile/GetAction.php | 4 +- src/Dto/Input/ImageRepositoryInput.php | 1 - src/Dto/Input/PxeTemplateInput.php | 2 + src/Entity/Client.php | 15 ++++++ src/Entity/Command.php | 3 ++ src/Entity/CommandTask.php | 22 ++++---- src/EventListener/ClientMacListener.php | 51 +++++++++++++++++++ .../Constraints/PxeTemplateUniqueDefault.php | 23 +++++++++ .../PxeTemplateUniqueDefaultValidator.php | 46 +++++++++++++++++ translations/validators.en.yaml | 1 + translations/validators.es.yaml | 1 + 17 files changed, 281 insertions(+), 32 deletions(-) create mode 100644 migrations/Version20250514051344.php create mode 100644 migrations/Version20250514101117.php create mode 100644 src/Controller/OgBoot/PxeBootFile/DeleteAction.php create mode 100644 src/EventListener/ClientMacListener.php create mode 100644 src/Validator/Constraints/PxeTemplateUniqueDefault.php create mode 100644 src/Validator/Constraints/PxeTemplateUniqueDefaultValidator.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 9422a7c..f0e75b4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog -<<<<<<< HEAD +## [0.12.1] - 2025-05-14 +### Improved +- Se ha eliminado la restriccion en el formulario de crear/editar repositorio, que hacia que la comprobara el formato de IP. Ahora tambien puede ser DNS. +- Mejora en el script de ejecutar tareas. +- Ahora al editar la mac de un cliente, se borra el fichero de arranque antiguo. +- Se ha añadido una restriccion en plantillas para que tan solo haya 1 por defecto + +--- + ## [0.12.0] - 2025-05-13 ### Added - Se ha añadido nueva API para poder gestionar las tareas y acciones programadas. @@ -12,11 +20,11 @@ ## Fixed - Se ha corregido el bug en la creacion de clientes masivos donde no se le asignaba la plantilla PXE. - Se ha corregido un bug en el DTO de clientes, que hacia que PHP diera un timeout por bucle infinito. -======= + +--- ## [0.11.2] - 2025-04-23 ### Fixed - Se ha cambiado la forma en guardar la fecha al recibir "ping" de los clientes. ->>>>>>> main --- ## [0.11.1] - 2025-04-16 diff --git a/migrations/Version20250514051344.php b/migrations/Version20250514051344.php new file mode 100644 index 0000000..47baece --- /dev/null +++ b/migrations/Version20250514051344.php @@ -0,0 +1,31 @@ +addSql('ALTER TABLE client ADD token VARCHAR(255) DEFAULT NULL'); + } + + public function down(Schema $schema): void + { + // this down() migration is auto-generated, please modify it to your needs + $this->addSql('ALTER TABLE client DROP token'); + } +} diff --git a/migrations/Version20250514101117.php b/migrations/Version20250514101117.php new file mode 100644 index 0000000..e203294 --- /dev/null +++ b/migrations/Version20250514101117.php @@ -0,0 +1,31 @@ +addSql('CREATE UNIQUE INDEX UNIQ_IDENTIFIER_NAME ON command (name)'); + } + + public function down(Schema $schema): void + { + // this down() migration is auto-generated, please modify it to your needs + $this->addSql('DROP INDEX UNIQ_IDENTIFIER_NAME ON command'); + } +} diff --git a/src/Command/RunScheduledCommandTasksCommand.php b/src/Command/RunScheduledCommandTasksCommand.php index 06e9971..3a5e7c5 100644 --- a/src/Command/RunScheduledCommandTasksCommand.php +++ b/src/Command/RunScheduledCommandTasksCommand.php @@ -10,6 +10,7 @@ use App\Dto\Input\CommandExecuteInput; use App\Dto\Input\DeployImageInput; use App\Dto\Output\ClientOutput; use App\Entity\CommandTask; +use App\Model\ClientStatus; use App\Repository\CommandTaskRepository; use Doctrine\ORM\EntityManagerInterface; use Symfony\Component\Console\Attribute\AsCommand; @@ -59,22 +60,20 @@ class RunScheduledCommandTasksCommand extends Command usort($scripts, fn($a, $b) => $a->getExecutionOrder() <=> $b->getExecutionOrder()); foreach ($scripts as $script) { - try { - $output->writeln(" - Ejecutando script de tipo {$script->getType()} con orden {$script->getExecutionOrder()}"); + $output->writeln(" - Ejecutando script de tipo {$script->getType()} con orden {$script->getExecutionOrder()}"); - if ($script->getType() === 'run-script') { - $input = new CommandExecuteInput(); + if ($script->getType() === 'run-script') { + $input = new CommandExecuteInput(); - foreach ($task->getOrganizationalUnit()?->getClients() as $client) { - $input->clients[] = new ClientOutput($client); + foreach ($task->getOrganizationalUnit()?->getClients() as $client) { + if ($client->getStatus() !== ClientStatus::OG_LIVE) { + continue; } - $input->script = $script->getContent(); - - $this->runScriptAction->__invoke($input); + $input->clients[] = new ClientOutput($client); } - } catch (TransportExceptionInterface $e) { - $output->writeln("Error ejecutando script: " . $e->getMessage()); - continue; + $input->script = $script->getContent(); + + $this->runScriptAction->__invoke($input); } } diff --git a/src/Controller/OgAgent/RunScriptAction.php b/src/Controller/OgAgent/RunScriptAction.php index 0282f3a..e4a999c 100644 --- a/src/Controller/OgAgent/RunScriptAction.php +++ b/src/Controller/OgAgent/RunScriptAction.php @@ -54,10 +54,10 @@ class RunScriptAction extends AbstractController ], 'json' => $data, ]); - $this->logger->info('Rebooting client', ['client' => $client->getId()]); + $this->logger->info('Executing run-script', ['client' => $client->getId(), 'response' => $response->getContent()]); } catch (TransportExceptionInterface $e) { - $this->logger->error('Error rebooting client', ['client' => $client->getId(), 'error' => $e->getMessage()]); + $this->logger->error('Error executing run-script', ['client' => $client->getId(), 'error' => $e->getMessage()]); return new JsonResponse( data: ['error' => $e->getMessage()], status: Response::HTTP_INTERNAL_SERVER_ERROR diff --git a/src/Controller/OgBoot/PxeBootFile/DeleteAction.php b/src/Controller/OgBoot/PxeBootFile/DeleteAction.php new file mode 100644 index 0000000..884bd11 --- /dev/null +++ b/src/Controller/OgBoot/PxeBootFile/DeleteAction.php @@ -0,0 +1,41 @@ +httpClient->request('DELETE', 'http://'.$this->ogBootApiUrl.'/ogboot/v1/pxes/'.$mac, [ + 'headers' => [ + 'accept' => 'application/json', + ], + ]); + } catch (TransportExceptionInterface $e) { + 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); + + } +} \ No newline at end of file diff --git a/src/Controller/OgBoot/PxeBootFile/GetAction.php b/src/Controller/OgBoot/PxeBootFile/GetAction.php index 4f4fb02..e2efc0d 100644 --- a/src/Controller/OgBoot/PxeBootFile/GetAction.php +++ b/src/Controller/OgBoot/PxeBootFile/GetAction.php @@ -24,10 +24,10 @@ class GetAction extends AbstractOgBootController * @throws RedirectionExceptionInterface * @throws ClientExceptionInterface */ - public function __invoke(Client $client, HttpClientInterface $httpClient): JsonResponse + public function __invoke(Client $client): JsonResponse { try { - $response = $httpClient->request('GET', 'http://'.$this->ogBootApiUrl.'/ogboot/v1/pxes/'.$client->getMac(), [ + $response = $this->httpClient->request('GET', 'http://'.$this->ogBootApiUrl.'/ogboot/v1/pxes/'.$client->getMac(), [ 'headers' => [ 'accept' => 'application/json', ], diff --git a/src/Dto/Input/ImageRepositoryInput.php b/src/Dto/Input/ImageRepositoryInput.php index 56623e1..f4e9089 100644 --- a/src/Dto/Input/ImageRepositoryInput.php +++ b/src/Dto/Input/ImageRepositoryInput.php @@ -22,7 +22,6 @@ final class ImageRepositoryInput public ?string $name = null; #[Assert\NotBlank] - #[Assert\Ip] #[Groups(['repository:write'])] #[ApiProperty(description: 'The IP of the repository', example: "")] public ?string $ip = null; diff --git a/src/Dto/Input/PxeTemplateInput.php b/src/Dto/Input/PxeTemplateInput.php index 58d4946..e221edd 100644 --- a/src/Dto/Input/PxeTemplateInput.php +++ b/src/Dto/Input/PxeTemplateInput.php @@ -4,9 +4,11 @@ namespace App\Dto\Input; use ApiPlatform\Metadata\ApiProperty; use App\Entity\PxeTemplate; +use App\Validator\Constraints\PxeTemplateUniqueDefault; use Symfony\Component\Serializer\Annotation\Groups; use Symfony\Component\Validator\Constraints as Assert; +#[PxeTemplateUniqueDefault] final class PxeTemplateInput { #[Assert\NotBlank(message: 'validators.pxe_template.name.not_blank')] diff --git a/src/Entity/Client.php b/src/Entity/Client.php index 023fcf8..889d9c2 100644 --- a/src/Entity/Client.php +++ b/src/Entity/Client.php @@ -89,6 +89,9 @@ class Client extends AbstractEntity #[ORM\Column(length: 255, nullable: true)] private ?string $firmwareType = null; + #[ORM\Column(length: 255, nullable: true)] + private ?string $token = null; + public function __construct() { parent::__construct(); @@ -354,4 +357,16 @@ class Client extends AbstractEntity return $this; } + + public function getToken(): ?string + { + return $this->token; + } + + public function setToken(?string $token): static + { + $this->token = $token; + + return $this; + } } diff --git a/src/Entity/Command.php b/src/Entity/Command.php index ab5d4bb..1aa5024 100644 --- a/src/Entity/Command.php +++ b/src/Entity/Command.php @@ -7,8 +7,11 @@ use Doctrine\DBAL\Types\Types; use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\Collection; use Doctrine\ORM\Mapping as ORM; +use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity; #[ORM\Entity(repositoryClass: CommandRepository::class)] +#[ORM\UniqueConstraint(name: 'UNIQ_IDENTIFIER_NAME', fields: ['name'])] +#[UniqueEntity(fields: ['name'], message: 'validators.command.name.unique')] class Command extends AbstractEntity { use NameableTrait; diff --git a/src/Entity/CommandTask.php b/src/Entity/CommandTask.php index f572155..8bb719c 100644 --- a/src/Entity/CommandTask.php +++ b/src/Entity/CommandTask.php @@ -227,19 +227,17 @@ class CommandTask extends AbstractEntity if ($type === 'none') { $execDate = $schedule->getExecutionDate(); - if ($execDate !== null && $execDate > $now) { - if ($executionTime !== null) { - $execDateTime = \DateTime::createFromFormat( - 'Y-m-d H:i:s', - $execDate->format('Y-m-d') . ' ' . $executionTime->format('H:i:s') - ); - } else { - $execDateTime = $execDate; - } + if ($executionTime !== null) { + $execDateTime = \DateTime::createFromFormat( + 'Y-m-d H:i:s', + $execDate->format('Y-m-d') . ' ' . $executionTime->format('H:i:s') + ); + } else { + $execDateTime = $execDate; + } - if ($closestDateTime === null || $execDateTime < $closestDateTime) { - $closestDateTime = $execDateTime; - } + if ($closestDateTime === null || $execDateTime < $closestDateTime) { + $closestDateTime = $execDateTime; } } else { $details = $schedule->getRecurrenceDetails(); diff --git a/src/EventListener/ClientMacListener.php b/src/EventListener/ClientMacListener.php new file mode 100644 index 0000000..dc21532 --- /dev/null +++ b/src/EventListener/ClientMacListener.php @@ -0,0 +1,51 @@ +getObjectManager(); + $uow = $em->getUnitOfWork(); + $changeSet = $uow->getEntityChangeSet($client); + + if (!array_key_exists('mac', $changeSet)) { + return; + } + + $oldMac = isset($changeSet['mac'][0]) ? $changeSet['mac'][0] : null; + + if ($oldMac === null) { + return; + } + + $this->deleteAction->__invoke($oldMac); + } + +} \ No newline at end of file diff --git a/src/Validator/Constraints/PxeTemplateUniqueDefault.php b/src/Validator/Constraints/PxeTemplateUniqueDefault.php new file mode 100644 index 0000000..97f2e24 --- /dev/null +++ b/src/Validator/Constraints/PxeTemplateUniqueDefault.php @@ -0,0 +1,23 @@ +message = 'Ya hay un oglive marcado como predeterminado.'; + } + + public function getTargets(): string + { + return self::CLASS_CONSTRAINT; + } +} \ No newline at end of file diff --git a/src/Validator/Constraints/PxeTemplateUniqueDefaultValidator.php b/src/Validator/Constraints/PxeTemplateUniqueDefaultValidator.php new file mode 100644 index 0000000..e7b7bb3 --- /dev/null +++ b/src/Validator/Constraints/PxeTemplateUniqueDefaultValidator.php @@ -0,0 +1,46 @@ +requestStack->getCurrentRequest(); + + if (!$value instanceof PxeTemplateInput) { + return; + } + + if ($value->isDefault === false) { + return; + } + + $ogLiveDefault = $this->entityManager->getRepository(PxeTemplate::class) + ->findOneBy([ + 'isDefault' => true, + ]); + + if ($ogLiveDefault) { + $this->context->buildViolation($constraint->message)->addViolation(); + } + + } +} \ No newline at end of file diff --git a/translations/validators.en.yaml b/translations/validators.en.yaml index 2ea7718..2c58ac9 100644 --- a/translations/validators.en.yaml +++ b/translations/validators.en.yaml @@ -11,6 +11,7 @@ validators: command: name: not_blank: 'The name should not be blank.' + unique: 'The name should be unique.' script: not_blank: 'The script should not be blank.' diff --git a/translations/validators.es.yaml b/translations/validators.es.yaml index d3b821e..93dcaef 100644 --- a/translations/validators.es.yaml +++ b/translations/validators.es.yaml @@ -11,6 +11,7 @@ validators: command: name: not_blank: 'El nombre no debería estar vacío.' + unique: 'El nombre debería ser único. Ya existe un comando con ese nombre.' script: not_blank: 'El script no debería estar vacío.' From 527383bce16c1a7033beeda74373d1b28fc620b2 Mon Sep 17 00:00:00 2001 From: Manuel Aranda Date: Wed, 14 May 2025 13:28:02 +0200 Subject: [PATCH 02/10] solve conflicts --- CHANGELOG.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9422a7c..cc07a70 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,4 @@ # Changelog -<<<<<<< HEAD ## [0.12.0] - 2025-05-13 ### Added - Se ha añadido nueva API para poder gestionar las tareas y acciones programadas. @@ -12,11 +11,11 @@ ## Fixed - Se ha corregido el bug en la creacion de clientes masivos donde no se le asignaba la plantilla PXE. - Se ha corregido un bug en el DTO de clientes, que hacia que PHP diera un timeout por bucle infinito. -======= + +--- ## [0.11.2] - 2025-04-23 ### Fixed - Se ha cambiado la forma en guardar la fecha al recibir "ping" de los clientes. ->>>>>>> main --- ## [0.11.1] - 2025-04-16 From 0396085249f832493ac3a2c472a03e1cfbb0fb65 Mon Sep 17 00:00:00 2001 From: Manuel Aranda Date: Mon, 19 May 2025 08:05:08 +0200 Subject: [PATCH 03/10] refs #2031. Added secret in Client. Refactor ogAgent TLS --- docker/default.conf | 9 ++- ogagent.conf | 0 .../OgAgent/AbstractOgAgentController.php | 79 +++++++++++++++++++ src/Controller/OgAgent/CreateImageAction.php | 43 ++++------ src/Controller/OgAgent/DeployImageAction.php | 39 +++------ src/Controller/OgAgent/LoginAction.php | 44 +++++------ .../OgAgent/PartitionAssistantAction.php | 45 +++++------ src/Controller/OgAgent/PowerOffAction.php | 46 +++++------ src/Controller/OgAgent/RebootAction.php | 46 +++++------ src/Controller/OgAgent/RunScriptAction.php | 49 ++++++------ src/Controller/OgAgent/StatusAction.php | 79 +++++++------------ .../OgAgent/Webhook/AgentController.php | 1 + src/Service/UDS/UDSClient.php | 8 +- 13 files changed, 247 insertions(+), 241 deletions(-) create mode 100644 ogagent.conf create mode 100644 src/Controller/OgAgent/AbstractOgAgentController.php diff --git a/docker/default.conf b/docker/default.conf index f10f718..ec66a09 100644 --- a/docker/default.conf +++ b/docker/default.conf @@ -12,10 +12,8 @@ server { root /var/www/html/public; index index.html index.php; - ssl_certificate /etc/nginx/certs/ogcore.uds-test.net.crt.pem; - ssl_certificate_key /etc/nginx/certs/ogcore.uds-test.net.key.pem; - - + ssl_certificate /opt/opengnsys/ogcore/etc/certificates/ogcore.crt; + ssl_certificate_key /opt/opengnsys/ogcore/etc/certificates/ogcore.key; location /opengnsys/rest/ous// { rewrite ^/opengnsys/rest/ous//([0-9]+)/images /opengnsys/rest/ous/$1/images; @@ -44,6 +42,9 @@ server { error_log /var/log/nginx/error.log debug; access_log /var/log/nginx/access.log; + + ssl_client_certificate /opt/opengnsys/ogcore/etc/certificates/ca.crt; + ssl_verify_client on; } server { diff --git a/ogagent.conf b/ogagent.conf new file mode 100644 index 0000000..e69de29 diff --git a/src/Controller/OgAgent/AbstractOgAgentController.php b/src/Controller/OgAgent/AbstractOgAgentController.php new file mode 100644 index 0000000..a6ada4b --- /dev/null +++ b/src/Controller/OgAgent/AbstractOgAgentController.php @@ -0,0 +1,79 @@ + [ + 'accept' => 'application/json', + 'Content-Type' => 'application/json', + 'Authorization' => $token, + ], + 'verify_peer' => false, + 'verify_host' => false, + 'timeout' => 10 + ]); + + + if ($this->sslEnabled === 'true') { + $params['verify_peer'] = true; + $params['verify_host'] = false; + $params['cafile'] = '/opt/opengnsys/ogcore/etc/certificates/ca.crt'; + $params['local_cert'] = '/opt/opengnsys/ogcore/etc/certificates/ogcore.crt'; + $params['local_pk'] = '/opt/opengnsys/ogcore/etc/certificates/ogcore.key'; + } + + try { + $response = $this->httpClient->request($method, $url, $params); + return json_decode($response->getContent(), true); + } catch (ClientExceptionInterface | ServerExceptionInterface $e) { + $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(), + ]; + } + } +} \ No newline at end of file diff --git a/src/Controller/OgAgent/CreateImageAction.php b/src/Controller/OgAgent/CreateImageAction.php index ed3bb96..907a0f9 100644 --- a/src/Controller/OgAgent/CreateImageAction.php +++ b/src/Controller/OgAgent/CreateImageAction.php @@ -34,19 +34,8 @@ use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface; use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface; use Symfony\Contracts\HttpClient\HttpClientInterface; -class CreateImageAction extends AbstractController +class CreateImageAction extends AbstractOgAgentController { - public function __construct( - protected readonly EntityManagerInterface $entityManager, - protected readonly HttpClientInterface $httpClient, - protected readonly CreateService $createService, - protected readonly LoggerInterface $logger, - protected readonly CreateRepositoryAction $createRepositoryAction, - protected readonly CreateTagAction $createTagAction, - ) - { - } - /** * @throws TransportExceptionInterface * @throws ServerExceptionInterface @@ -147,29 +136,25 @@ class CreateImageAction extends AbstractController throw new Exception("El tipo de partición '$partitionCode' no se encontró en la lista."); } - try { + $client = $client ?? $image->getClient(); + $this->logger->info('Creating image', ['image' => $image->getId()]); - $client = $client ?? $image->getClient(); - $this->logger->info('Creating image', ['image' => $image->getId()]); - $response = $this->httpClient->request('POST', 'https://'.$client->getIp().':8000/opengnsys/CrearImagen', [ - 'verify_peer' => false, - 'verify_host' => false, - 'headers' => [ - 'Content-Type' => 'application/json', - ], + $response = $this->createRequest( + method: 'POST', + url: 'https://'.$client->getIp().':8000/opengnsys/CrearImagen', + params: [ 'json' => $data, - ]); + ], + token: $client->getToken(), + ); + $this->logger->info('Creating image', ['image' => $imageImageRepository->getName(), 'repository' => $repository->getIp()]); - } catch (TransportExceptionInterface $e) { - $this->logger->error('Error creating image', ['image' => $image->getId(), 'error' => $e->getMessage()]); - return new JsonResponse( - data: ['error' => $e->getMessage()], - status: Response::HTTP_INTERNAL_SERVER_ERROR - ); + if (isset($response['error']) && $response['code'] === Response::HTTP_INTERNAL_SERVER_ERROR) { + throw new ValidatorException('Error creating image'); } - $jobId = json_decode($response->getContent(), true)['job_id']; + $jobId = $response['job_id']; $client->setStatus(ClientStatus::BUSY); $this->entityManager->persist($client); diff --git a/src/Controller/OgAgent/DeployImageAction.php b/src/Controller/OgAgent/DeployImageAction.php index fe35468..2ab9d01 100644 --- a/src/Controller/OgAgent/DeployImageAction.php +++ b/src/Controller/OgAgent/DeployImageAction.php @@ -29,17 +29,8 @@ use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface; use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface; use Symfony\Contracts\HttpClient\HttpClientInterface; -class DeployImageAction extends AbstractController +class DeployImageAction extends AbstractOgAgentController { - public function __construct( - protected readonly EntityManagerInterface $entityManager, - protected readonly HttpClientInterface $httpClient, - protected readonly CreateService $createService, - protected readonly LoggerInterface $logger, - ) - { - } - /** * @throws RedirectionExceptionInterface * @throws ClientExceptionInterface @@ -91,26 +82,22 @@ class DeployImageAction extends AbstractController 'ids' => '0' ]; - try { - $response = $this->httpClient->request('POST', 'https://'.$client->getIp().':8000/opengnsys/RestaurarImagen', [ - 'verify_peer' => false, - 'verify_host' => false, - 'headers' => [ - 'Content-Type' => 'application/json', - ], + $response = $this->createRequest( + method: 'POST', + url: 'https://'.$client->getIp().':8000/opengnsys/RestaurarImagen', + params: [ 'json' => $data, - ]); - $this->logger->info('Deploying image', ['image' => $image->getId()]); + ], + token: $client->getToken(), + ); - $jobId = json_decode($response->getContent(), true)['job_id']; - } catch (ClientExceptionInterface | ServerExceptionInterface | TransportExceptionInterface | TransportException $e) { - $this->logger->error('Error deploying image', [ - 'image' => $image->getId() ?? 'unknown', - 'error' => $e->getMessage() - ]); - return null; + $this->logger->info('Deploying image', [ 'image' => $imageImageRepository->getName(), 'repository' => $repository->getIp()]); + + if (isset($response['error']) && $response['code'] === Response::HTTP_INTERNAL_SERVER_ERROR) { + throw new ValidatorException('Error deploying image'); } + $jobId = $response['job_id']; $client->setStatus(ClientStatus::BUSY); $this->entityManager->persist($client); diff --git a/src/Controller/OgAgent/LoginAction.php b/src/Controller/OgAgent/LoginAction.php index 42fd7e1..a6d798f 100644 --- a/src/Controller/OgAgent/LoginAction.php +++ b/src/Controller/OgAgent/LoginAction.php @@ -27,17 +27,14 @@ use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface; use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface; use Symfony\Contracts\HttpClient\HttpClientInterface; -class LoginAction extends AbstractController +class LoginAction extends AbstractOgAgentController { - public function __construct( - protected readonly EntityManagerInterface $entityManager, - protected readonly HttpClientInterface $httpClient, - protected readonly CreateService $createService, - protected readonly LoggerInterface $logger, - ) - { - } - + /** + * @throws TransportExceptionInterface + * @throws ServerExceptionInterface + * @throws RedirectionExceptionInterface + * @throws ClientExceptionInterface + */ public function __invoke(MultipleClientsInput $input): JsonResponse { foreach ($input->clients as $clientEntity) { @@ -60,26 +57,21 @@ class LoginAction extends AbstractController 'ids' => '0' ]; - try { - $response = $this->httpClient->request('POST', 'https://' . $client->getIp() . ':8000/ogAdmClient/IniciarSesion', [ - 'verify_peer' => false, - 'verify_host' => false, - 'headers' => [ - 'Content-Type' => 'application/json', - ], + $response = $this->createRequest( + method: 'POST', + url: 'http://'.$client->getIp().':8000/opengnsys/IniciarSesion', + params: [ 'json' => $data, - ]); - $this->logger->info('Login client', ['client' => $client->getId()]); + ] + ); - } catch (TransportExceptionInterface $e) { - $this->logger->error('Login rebooting client', ['client' => $client->getId(), 'error' => $e->getMessage()]); - return new JsonResponse( - data: ['error' => $e->getMessage()], - status: Response::HTTP_INTERNAL_SERVER_ERROR - ); + if (isset($response['error']) && $response['code'] === Response::HTTP_INTERNAL_SERVER_ERROR) { + throw new ValidatorException('Error logging in: '.$response['error']); } - $jobId = json_decode($response->getContent(), true)['job_id']; + $this->logger->info('Login client', ['client' => $client->getId()]); + + $jobId = $response['job_id']; $client->setStatus(ClientStatus::INITIALIZING); $this->entityManager->persist($client); diff --git a/src/Controller/OgAgent/PartitionAssistantAction.php b/src/Controller/OgAgent/PartitionAssistantAction.php index 5dfe433..d69dba9 100644 --- a/src/Controller/OgAgent/PartitionAssistantAction.php +++ b/src/Controller/OgAgent/PartitionAssistantAction.php @@ -28,17 +28,14 @@ use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface; use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface; use Symfony\Contracts\HttpClient\HttpClientInterface; -class PartitionAssistantAction extends AbstractController +class PartitionAssistantAction extends AbstractOgAgentController { - public function __construct( - protected readonly EntityManagerInterface $entityManager, - protected readonly HttpClientInterface $httpClient, - protected readonly CreateService $createService, - protected readonly LoggerInterface $logger, - ) - { - } - + /** + * @throws TransportExceptionInterface + * @throws ServerExceptionInterface + * @throws RedirectionExceptionInterface + * @throws ClientExceptionInterface + */ public function __invoke(PartitionPostInput $input): JsonResponse { $partitions = $input->partitions; @@ -101,28 +98,28 @@ class PartitionAssistantAction extends AbstractController "ids" => "0" ]; - try { - $response = $this->httpClient->request('POST', 'https://' . $client->getIp() . ':8000/opengnsys/Configurar', [ - 'verify_peer' => false, - 'verify_host' => false, - 'headers' => [ - 'Content-Type' => 'application/json', - ], + $response = $this->createRequest( + method: 'POST', + url: 'https://'.$client->getIp().':8000/opengnsys/Configurar', + params: [ 'json' => $result, - ]); - $this->logger->info('Partitioning disk', ['client' => $client->getId(), 'disk' => $diskNumber]); - } catch (TransportExceptionInterface $e) { - $this->logger->error('Error partitioning disk', ['client' => $client->getId(), 'disk' => $diskNumber, 'error' => $e->getMessage()]); - continue; + ], + token: $client->getToken(), + ); + + $this->logger->info('Partition assistant', ['client' => $client->getId()]); + + if (isset($response['error']) && $response['code'] === Response::HTTP_INTERNAL_SERVER_ERROR) { + throw new ValidatorException('Error occurred while partitioning'); } - $jobId = json_decode($response->getContent(), true)['job_id']; + $jobId = $response['job_id']; $client->setStatus(ClientStatus::BUSY); $this->entityManager->persist($client); $this->entityManager->flush(); - $this->createService->__invoke($client, CommandTypes::PARTITION_AND_FORMAT, TraceStatus::IN_PROGRESS, $jobId, []); + $this->createService->__invoke($client, CommandTypes::PARTITION_AND_FORMAT, TraceStatus::IN_PROGRESS, $jobId, $data); } } diff --git a/src/Controller/OgAgent/PowerOffAction.php b/src/Controller/OgAgent/PowerOffAction.php index 8cde198..ed8c913 100644 --- a/src/Controller/OgAgent/PowerOffAction.php +++ b/src/Controller/OgAgent/PowerOffAction.php @@ -28,17 +28,14 @@ use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface; use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface; use Symfony\Contracts\HttpClient\HttpClientInterface; -class PowerOffAction extends AbstractController +class PowerOffAction extends AbstractOgAgentController { - public function __construct( - protected readonly EntityManagerInterface $entityManager, - protected readonly HttpClientInterface $httpClient, - protected readonly CreateService $createService, - protected readonly LoggerInterface $logger, - ) - { - } - + /** + * @throws TransportExceptionInterface + * @throws ServerExceptionInterface + * @throws RedirectionExceptionInterface + * @throws ClientExceptionInterface + */ public function __invoke(MultipleClientsInput $input): JsonResponse { foreach ($input->clients as $clientEntity) { @@ -60,26 +57,23 @@ class PowerOffAction extends AbstractController 'ids' => '0' ]; - try { - $response = $this->httpClient->request('POST', 'https://' . $client->getIp() . ':8000/'.$endpoint, [ - 'verify_peer' => false, - 'verify_host' => false, - 'headers' => [ - 'Content-Type' => 'application/json', - ], + $response = $this->createRequest( + method: 'POST', + url: 'https://'.$client->getIp().':8000/'.$endpoint, + params: [ 'json' => $data, - ]); - $this->logger->info('Powering off client', ['client' => $client->getId()]); - $jobId = json_decode($response->getContent(), true)['job_id']; + ], + token: $client->getToken(), + ); - } catch (ClientExceptionInterface | ServerExceptionInterface | TransportExceptionInterface | TransportException $e) { - $this->logger->error('Error power off client', [ - 'image' => $client->getIp(), - 'error' => $e->getMessage() - ]); - continue; + if (isset($response['error']) && $response['code'] === Response::HTTP_INTERNAL_SERVER_ERROR) { + throw new ValidatorException('Error deploying image'); } + $this->logger->info('Powering off client', ['client' => $client->getId()]); + + $jobId = $response['job_id']; + $client->setStatus(ClientStatus::TURNING_OFF); $this->entityManager->persist($client); $this->entityManager->flush(); diff --git a/src/Controller/OgAgent/RebootAction.php b/src/Controller/OgAgent/RebootAction.php index 0be2163..b83af31 100644 --- a/src/Controller/OgAgent/RebootAction.php +++ b/src/Controller/OgAgent/RebootAction.php @@ -27,17 +27,14 @@ use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface; use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface; use Symfony\Contracts\HttpClient\HttpClientInterface; -class RebootAction extends AbstractController +class RebootAction extends AbstractOgAgentController { - public function __construct( - protected readonly EntityManagerInterface $entityManager, - protected readonly HttpClientInterface $httpClient, - protected readonly CreateService $createService, - protected readonly LoggerInterface $logger, - ) - { - } - + /** + * @throws TransportExceptionInterface + * @throws ServerExceptionInterface + * @throws RedirectionExceptionInterface + * @throws ClientExceptionInterface + */ public function __invoke(MultipleClientsInput $input): JsonResponse { foreach ($input->clients as $clientEntity) { @@ -56,27 +53,22 @@ class RebootAction extends AbstractController 'ids' => '0' ]; - try { - $response = $this->httpClient->request('POST', 'https://' . $client->getIp() . ':8000/'.$endpoint, [ - 'verify_peer' => false, - 'verify_host' => false, - 'headers' => [ - 'Content-Type' => 'application/json', - ], + $response = $this->createRequest( + method: 'POST', + url: 'http://'.$client->getIp().':8000/'.$endpoint, + params: [ 'json' => $data, - ]); + ], + token: $client->getToken(), + ); - $this->logger->info('Rebooting client', ['client' => $client->getId()]); - - } catch (TransportExceptionInterface $e) { - $this->logger->error('Error rebooting client', ['client' => $client->getId(), 'error' => $e->getMessage()]); - return new JsonResponse( - data: ['error' => $e->getMessage()], - status: Response::HTTP_INTERNAL_SERVER_ERROR - ); + if (isset($response['error']) && $response['code'] === Response::HTTP_INTERNAL_SERVER_ERROR) { + throw new ValidatorException('Error deploying image'); } - $jobId = json_decode($response->getContent(), true)['job_id']; + $this->logger->info('Rebooting client', ['client' => $client->getId()]); + + $jobId = $response['job_id']; $client->setStatus(ClientStatus::INITIALIZING); $this->entityManager->persist($client); diff --git a/src/Controller/OgAgent/RunScriptAction.php b/src/Controller/OgAgent/RunScriptAction.php index e4a999c..840e6d2 100644 --- a/src/Controller/OgAgent/RunScriptAction.php +++ b/src/Controller/OgAgent/RunScriptAction.php @@ -15,24 +15,25 @@ use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Validator\Exception\ValidatorException; +use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface; +use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface; +use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface; use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface; use Symfony\Contracts\HttpClient\HttpClientInterface; -class RunScriptAction extends AbstractController +class RunScriptAction extends AbstractOgAgentController { - public function __construct( - protected readonly EntityManagerInterface $entityManager, - protected readonly HttpClientInterface $httpClient, - protected readonly CreateService $createService, - protected readonly LoggerInterface $logger, - ) - { - } - + /** + * @throws TransportExceptionInterface + * @throws ServerExceptionInterface + * @throws RedirectionExceptionInterface + * @throws ClientExceptionInterface + */ public function __invoke(CommandExecuteInput $input): JsonResponse { /** @var Client $clientEntity */ foreach ($input->clients as $clientEntity) { + /** @var Client $client */ $client = $clientEntity->getEntity(); if (!$client->getIp()) { @@ -45,26 +46,22 @@ class RunScriptAction extends AbstractController 'ids' => '0' ]; - try { - $response = $this->httpClient->request('POST', 'https://' . $client->getIp() . ':8000/opengnsys/EjecutarScript', [ - 'verify_peer' => false, - 'verify_host' => false, - 'headers' => [ - 'Content-Type' => 'application/json', - ], + $response = $this->createRequest( + method: 'POST', + url: 'https://'.$client->getIp().':8000/opengnsys/EjecutarScript', + params: [ 'json' => $data, - ]); - $this->logger->info('Executing run-script', ['client' => $client->getId(), 'response' => $response->getContent()]); + ], + token: $client->getToken(), + ); - } catch (TransportExceptionInterface $e) { - $this->logger->error('Error executing run-script', ['client' => $client->getId(), 'error' => $e->getMessage()]); - return new JsonResponse( - data: ['error' => $e->getMessage()], - status: Response::HTTP_INTERNAL_SERVER_ERROR - ); + if (isset($response['error']) && $response['code'] === Response::HTTP_INTERNAL_SERVER_ERROR) { + throw new ValidatorException('Error deploying image'); } - $jobId = json_decode($response->getContent(), true)['job_id']; + $this->logger->info('Powering off client', ['client' => $client->getId()]); + + $jobId = $response['job_id']; $this->entityManager->persist($client); $this->entityManager->flush(); diff --git a/src/Controller/OgAgent/StatusAction.php b/src/Controller/OgAgent/StatusAction.php index dde6331..4a450af 100644 --- a/src/Controller/OgAgent/StatusAction.php +++ b/src/Controller/OgAgent/StatusAction.php @@ -24,15 +24,8 @@ use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface; use Symfony\Contracts\HttpClient\HttpClientInterface; #[AsController] -class StatusAction extends AbstractController +class StatusAction extends AbstractOgAgentController { - public function __construct( - protected readonly EntityManagerInterface $entityManager, - protected readonly HttpClientInterface $httpClient, - protected readonly CreatePartitionService $createPartitionService, - protected readonly LoggerInterface $logger, - ) {} - /** * @throws TransportExceptionInterface * @throws ServerExceptionInterface @@ -66,37 +59,28 @@ class StatusAction extends AbstractController ); } + /** + * @throws TransportExceptionInterface + * @throws ServerExceptionInterface + * @throws RedirectionExceptionInterface + * @throws ClientExceptionInterface + */ public function getOgLiveStatus (Client $client): JsonResponse|int|string { $this->logger->info('Checking client status', ['client' => $client->getId()]); $params = [ - 'full-config' => false, + 'json' => [ + 'full-config' => false + ] ]; - try { - $response = $this->httpClient->request('POST', 'https://' . $client->getIp() . ':8000/opengnsys/status', [ - 'verify_peer' => false, - 'verify_host' => false, - 'timeout' => 10, - 'headers' => [ - 'Content-Type' => 'application/json', - ], - 'json' => $params, - ]); - $statusCode = $response->getStatusCode(); - $client->setStatus($statusCode === Response::HTTP_OK ? ClientStatus::OG_LIVE : ClientStatus::OFF); - - } catch (TransportExceptionInterface $e) { - $this->logger->error('Error checking client status', ['client' => $client->getId(), 'error' => $e->getMessage()]); - $client->setStatus(ClientStatus::OFF); - $this->entityManager->persist($client); - $this->entityManager->flush(); - - return $e->getMessage(); - } - - $data = json_decode($response->getContent(), true); + $data = $this->createRequest( + method: 'POST', + url: 'https://' . $client->getIp() . ':8000/opengnsys/status', + params: $params, + token: $client->getToken(), + ); if (isset($data['cfg'])) { $this->logger->info('Creating partitions', ['data' => $data['cfg']]); @@ -109,25 +93,22 @@ class StatusAction extends AbstractController return Response::HTTP_OK; } + /** + * @throws TransportExceptionInterface + * @throws ServerExceptionInterface + * @throws RedirectionExceptionInterface + * @throws ClientExceptionInterface + */ public function getSOStatus (Client $client): JsonResponse|int { - try { - $response = $this->httpClient->request('POST', 'https://' . $client->getIp() . ':8000/opengnsys/status', [ - 'verify_peer' => false, - 'verify_host' => false, - 'timeout' => 10, - 'headers' => [ - 'Content-Type' => 'application/json', - ], - 'json' => [], - ]); - } catch (TransportExceptionInterface $e) { - $client->setStatus(ClientStatus::OFF); - $this->logger->error('Error checking client status', ['client' => $client->getId(), 'error' => $e->getMessage()]); - return Response::HTTP_INTERNAL_SERVER_ERROR; - } - - $data = json_decode($response->getContent(), true); + $data = $this->createRequest( + method: 'POST', + url: 'https://' . $client->getIp() . ':8000/opengnsys/status', + params: [ + 'full-config' => false, + ], + token: $client->getToken(), + ); if (isset($data['cfg'])) { $this->createPartitionService->__invoke($data, $client); diff --git a/src/Controller/OgAgent/Webhook/AgentController.php b/src/Controller/OgAgent/Webhook/AgentController.php index 017a4f1..4f4fb48 100644 --- a/src/Controller/OgAgent/Webhook/AgentController.php +++ b/src/Controller/OgAgent/Webhook/AgentController.php @@ -49,6 +49,7 @@ class AgentController extends AbstractController } $clientEntity->setStatus(ClientStatus::OG_LIVE); + $clientEntity->setToken($data['secret'] ?? null); $this->entityManager->persist($clientEntity); if (isset($data['cfg'])) { diff --git a/src/Service/UDS/UDSClient.php b/src/Service/UDS/UDSClient.php index fe6dbad..5842986 100644 --- a/src/Service/UDS/UDSClient.php +++ b/src/Service/UDS/UDSClient.php @@ -25,13 +25,13 @@ class UDSClient public function __construct( private HttpClientInterface $httpClient, private readonly EntityManagerInterface $entityManager, - #[Autowire(env: 'UDS_URL')] + #[Autowire(env: 'REMOTE_PC_URL')] private readonly string $udsAPIurl, - #[Autowire(env: 'UDS_AUTH_LOGIN')] + #[Autowire(env: 'REMOTE_PC_AUTH_LOGIN')] private readonly string $udsAuthLogin, - #[Autowire(env: 'UDS_AUTH_USERNAME')] + #[Autowire(env: 'REMOTE_PC_AUTH_USERNAME')] private readonly string $udsAuthUsername, - #[Autowire(env: 'UDS_AUTH_PASSWORD')] + #[Autowire(env: 'REMOTE_PC_AUTH_PASSWORD')] private readonly string $udsAuthPassword, ) { From 684d25c8d36cd68756b3177239a33857f71d6d8f Mon Sep 17 00:00:00 2001 From: Manuel Aranda Date: Mon, 19 May 2025 08:15:10 +0200 Subject: [PATCH 04/10] Docker certs volume --- docker-compose.yaml | 4 +++- env.json | 11 ++++++----- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/docker-compose.yaml b/docker-compose.yaml index c15177a..45a5841 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -26,7 +26,8 @@ services: - 8443:443 # Añadir el puerto 443 volumes: - ./public:/var/www/html/public:cached - - ./docker/certs:/etc/nginx/certs # Montar certificados en Nginx + - ./docker/certs:/etc/nginx/certs + - ./certs:/opt/opengnsys/ogcore/etc/certificates networks: - ogcore-network @@ -37,6 +38,7 @@ services: dockerfile: ./docker/Dockerfile-php volumes: - ./:/var/www/html + - ./certs:/opt/opengnsys/ogcore/etc/certificates depends_on: - database networks: diff --git a/env.json b/env.json index a9b8660..d77f392 100644 --- a/env.json +++ b/env.json @@ -1,12 +1,13 @@ { "vars": { - "OG_BOOT_API_URL": "192.168.68.51:8082", - "OG_DHCP_API_URL": "192.168.68.51:8081", - "OG_CORE_IP": "192.168.68.62", - "OG_LOG_IP": "192.168.68.51", + "OG_BOOT_API_URL": "127.0.0.1:8082", + "OG_DHCP_API_URL": "127.0.0.1:8081", + "OG_CORE_IP": "127.0.0.1", + "OG_LOG_IP": "127.0.0.1", "UDS_AUTH_LOGIN": "test", "UDS_AUTH_USERNAME": "test", "UDS_AUTH_PASSWORD": "test", - "UDS_URL": "https:\/\/localhost:8087\/uds\/rest\/" + "UDS_URL": "https:\/\/localhost:8087\/uds\/rest\/", + "SSL_ENABLED": "true" } } \ No newline at end of file From 6425e4aaa68a6aa14e3ea97b42737328eb3a83ea Mon Sep 17 00:00:00 2001 From: Manuel Aranda Date: Mon, 19 May 2025 11:11:14 +0200 Subject: [PATCH 05/10] Fixed docker default.conf nginx file --- docker/default.conf | 10 ++++++---- src/Controller/AuthValidatorController.php | 8 ++++++++ 2 files changed, 14 insertions(+), 4 deletions(-) create mode 100644 src/Controller/AuthValidatorController.php diff --git a/docker/default.conf b/docker/default.conf index ec66a09..f990570 100644 --- a/docker/default.conf +++ b/docker/default.conf @@ -12,8 +12,10 @@ server { root /var/www/html/public; index index.html index.php; - ssl_certificate /opt/opengnsys/ogcore/etc/certificates/ogcore.crt; - ssl_certificate_key /opt/opengnsys/ogcore/etc/certificates/ogcore.key; + #ssl_certificate /opt/opengnsys/ogcore/etc/certificates/ogcore.crt; + #ssl_certificate_key /opt/opengnsys/ogcore/etc/certificates/ogcore.key; + ssl_certificate /etc/nginx/certs/ogcore.uds-test.net.crt.pem; + ssl_certificate_key /etc/nginx/certs/ogcore.uds-test.net.key.pem; location /opengnsys/rest/ous// { rewrite ^/opengnsys/rest/ous//([0-9]+)/images /opengnsys/rest/ous/$1/images; @@ -43,8 +45,8 @@ server { error_log /var/log/nginx/error.log debug; access_log /var/log/nginx/access.log; - ssl_client_certificate /opt/opengnsys/ogcore/etc/certificates/ca.crt; - ssl_verify_client on; + #ssl_client_certificate /opt/opengnsys/ogcore/etc/certificates/ca.crt; + #ssl_verify_client on; } server { diff --git a/src/Controller/AuthValidatorController.php b/src/Controller/AuthValidatorController.php new file mode 100644 index 0000000..84d0a40 --- /dev/null +++ b/src/Controller/AuthValidatorController.php @@ -0,0 +1,8 @@ + Date: Mon, 19 May 2025 16:13:08 +0200 Subject: [PATCH 06/10] Improvements --- src/Controller/AuthValidatorController.php | 52 +++++++++++++++++-- .../OgRepository/Image/SyncAction.php | 2 + src/Service/CreatePartitionService.php | 18 ++++--- 3 files changed, 62 insertions(+), 10 deletions(-) diff --git a/src/Controller/AuthValidatorController.php b/src/Controller/AuthValidatorController.php index 84d0a40..d22151b 100644 --- a/src/Controller/AuthValidatorController.php +++ b/src/Controller/AuthValidatorController.php @@ -2,7 +2,53 @@ namespace App\Controller; -class AuthValidatorController -{ +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\Routing\Annotation\Route; +use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; +use Lexik\Bundle\JWTAuthenticationBundle\Services\JWTTokenManagerInterface; +use Symfony\Component\Security\Core\Exception\AuthenticationException; -} \ No newline at end of file +class AuthValidatorController extends AbstractController +{ + private JWTTokenManagerInterface $jwtManager; + + public function __construct(JWTTokenManagerInterface $jwtManager) + { + $this->jwtManager = $jwtManager; + } + + #[Route('/validate', name: 'auth_validate', methods: ['POST'])] + public function validate(Request $request): Response + { + $sslClientVerify = $request->headers->get('SSL_CLIENT_VERIFY'); + $clientCertOk = $sslClientVerify === 'SUCCESS'; + + $authHeader = $request->headers->get('Authorization'); + $hasValidJwt = $this->validateJwtToken($authHeader); + + if ($clientCertOk || $hasValidJwt) { + return new Response('Authorized', Response::HTTP_OK); + } + + return new Response('Unauthorized', Response::HTTP_UNAUTHORIZED); + } + + private function validateJwtToken(?string $authHeader): bool + { + if (!$authHeader || !str_starts_with($authHeader, 'Bearer ')) { + return false; + } + + $token = substr($authHeader, 7); + + try { + $payload = $this->jwtManager->parse($token); + + return true; + + } catch (\Exception $e) { + return false; + } + } +} diff --git a/src/Controller/OgRepository/Image/SyncAction.php b/src/Controller/OgRepository/Image/SyncAction.php index 027693c..0c34fd7 100644 --- a/src/Controller/OgRepository/Image/SyncAction.php +++ b/src/Controller/OgRepository/Image/SyncAction.php @@ -51,6 +51,7 @@ class SyncAction extends AbstractOgRepositoryController $imageEntity->setName($image['name']); $imageEntity->setRemotePc(false); $imageEntity->setIsGlobal(false); + $imageEntity->setType('monolithic'); $this->entityManager->persist($imageEntity); } @@ -59,6 +60,7 @@ class SyncAction extends AbstractOgRepositoryController $imageImageRepositoryEntity = new ImageImageRepository(); } + $imageImageRepositoryEntity->setName($image['name']); $imageImageRepositoryEntity->setImageFullsum($image['fullsum']); $imageImageRepositoryEntity->setDatasize($image['datasize']); $imageImageRepositoryEntity->setStatus(ImageStatus::SUCCESS); diff --git a/src/Service/CreatePartitionService.php b/src/Service/CreatePartitionService.php index f5153b1..f48acfd 100644 --- a/src/Service/CreatePartitionService.php +++ b/src/Service/CreatePartitionService.php @@ -49,15 +49,19 @@ class CreatePartitionService $partitionEntity->setOperativeSystem(null); if (isset($cfg['soi']) && $cfg['soi'] !== '') { - $operativeSystem = $this->entityManager->getRepository(OperativeSystem::class) - ->findOneBy(['name' => $cfg['soi']]); + if ($cfg['soi'] === 'DATA') { + $partitionEntity->setImage(null); + } else { + $operativeSystem = $this->entityManager->getRepository(OperativeSystem::class) + ->findOneBy(['name' => $cfg['soi']]); - if (!$operativeSystem) { - $operativeSystem = new OperativeSystem(); - $operativeSystem->setName($cfg['soi']); - $this->entityManager->persist($operativeSystem); + if (!$operativeSystem) { + $operativeSystem = new OperativeSystem(); + $operativeSystem->setName($cfg['soi']); + $this->entityManager->persist($operativeSystem); + } + $partitionEntity->setOperativeSystem($operativeSystem); } - $partitionEntity->setOperativeSystem($operativeSystem); } $partitionEntity->setClient($clientEntity); From 294a9c5d40297d4d3add4c5efd93b5dc5dd761a9 Mon Sep 17 00:00:00 2001 From: Manuel Aranda Date: Mon, 19 May 2025 16:42:22 +0200 Subject: [PATCH 07/10] Improvements --- src/Controller/OgAgent/AbstractOgAgentController.php | 8 ++++++++ src/Controller/OgAgent/StatusAction.php | 8 ++++++++ 2 files changed, 16 insertions(+) diff --git a/src/Controller/OgAgent/AbstractOgAgentController.php b/src/Controller/OgAgent/AbstractOgAgentController.php index a6ada4b..97ed83d 100644 --- a/src/Controller/OgAgent/AbstractOgAgentController.php +++ b/src/Controller/OgAgent/AbstractOgAgentController.php @@ -69,6 +69,14 @@ abstract class AbstractOgAgentController extends AbstractController } catch (ClientExceptionInterface | ServerExceptionInterface $e) { $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) { + $this->logger->error(sprintf('Transport error in request to %s: %s', $url, $e->getMessage())); + return [ 'code' => Response::HTTP_INTERNAL_SERVER_ERROR, 'error' => 'Client/Server error', diff --git a/src/Controller/OgAgent/StatusAction.php b/src/Controller/OgAgent/StatusAction.php index 4a450af..d188bd7 100644 --- a/src/Controller/OgAgent/StatusAction.php +++ b/src/Controller/OgAgent/StatusAction.php @@ -82,6 +82,14 @@ class StatusAction extends AbstractOgAgentController token: $client->getToken(), ); + if (isset($data['error']) && $data['code'] === Response::HTTP_INTERNAL_SERVER_ERROR) { + $this->logger->error('Error checking client status', ['client' => $client->getId()]); + $client->setStatus(ClientStatus::OFF); + $this->entityManager->persist($client); + $this->entityManager->flush(); + throw new ValidatorException('Error deploying image'); + } + if (isset($data['cfg'])) { $this->logger->info('Creating partitions', ['data' => $data['cfg']]); $this->createPartitionService->__invoke($data, $client); From 1a232e93c7e181d7cef8bc40036072c8b69a254a Mon Sep 17 00:00:00 2001 From: Manuel Aranda Date: Mon, 19 May 2025 16:48:13 +0200 Subject: [PATCH 08/10] Added changelog --- CHANGELOG.md | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 71e10df..9016ae9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,15 @@ # Changelog +## [0.13.0] - 2025-05-20 +### Added +- Se ha creado la base para la comunicacion TLS con el agente. + +### Improved +- Refactorizacion de la API para la gestion de llamadas al agente + +### Fixed +- Se ha corregido un bug que hacia que no se eliminara la imagen al particionar. + +--- ## [0.12.1] - 2025-05-14 ### Improved - Se ha eliminado la restriccion en el formulario de crear/editar repositorio, que hacia que la comprobara el formato de IP. Ahora tambien puede ser DNS. @@ -13,10 +24,10 @@ - Se ha añadido un nuevo campo en plantillas (defecto) el cual nos permite tener una plantilla por defecto en caso de que se elimine una. - Se ha comenzado la integracion con ogGit. -## Improved +### Improved - Mejorado el comportamiento de la API al crear una imagen. Ahora se guardan datos del pc de origen. -## Fixed +### Fixed - Se ha corregido el bug en la creacion de clientes masivos donde no se le asignaba la plantilla PXE. - Se ha corregido un bug en el DTO de clientes, que hacia que PHP diera un timeout por bucle infinito. From a3f271a9aef2c87d32f3bdaf39fefc47fddf38e4 Mon Sep 17 00:00:00 2001 From: Manuel Aranda Date: Tue, 20 May 2025 16:25:54 +0200 Subject: [PATCH 09/10] Added trace date filter --- config/api_platform/Trace.yaml | 2 ++ config/services/api_platform.yaml | 5 +++++ 2 files changed, 7 insertions(+) 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/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: From 76a90d11297156a0f05ebc01882022ee6cc47f99 Mon Sep 17 00:00:00 2001 From: Manuel Aranda Date: Thu, 22 May 2025 18:29:19 +0200 Subject: [PATCH 10/10] refs #2084. New env to ogBoot --- env.json | 5 ++- .../OgBoot/AbstractOgBootController.php | 31 ++++++++++++++----- src/Controller/OgBoot/OgLive/GetAction.php | 6 +++- .../OgBoot/OgLive/GetCollectionAction.php | 6 +++- .../OgBoot/OgLive/GetDefaultAction.php | 7 ++++- .../OgBoot/OgLive/GetIsosAction.php | 2 +- .../OgBoot/OgLive/InstallAction.php | 6 +++- .../OgBoot/OgLive/SetDefaultAction.php | 6 +++- src/Controller/OgBoot/OgLive/SyncAction.php | 6 +++- .../OgBoot/OgLive/UninstallAction.php | 6 +++- .../OgBoot/PxeBootFile/DeleteAction.php | 10 ++---- .../OgBoot/PxeBootFile/GetAction.php | 10 ++---- .../PxeBootFile/GetCollectionAction.php | 2 +- .../OgBoot/PxeBootFile/PostAction.php | 12 ++++--- .../OgBoot/PxeTemplate/DeleteAction.php | 7 ++++- .../OgBoot/PxeTemplate/GetAction.php | 10 ++---- .../PxeTemplate/GetCollectionAction.php | 17 ++++------ .../OgBoot/PxeTemplate/PostAction.php | 7 ++++- .../OgBoot/PxeTemplate/SyncAction.php | 8 +++-- src/Dto/Input/BootClientsInput.php | 8 +++++ src/Service/OgBoot/StatusService.php | 14 ++++++--- 21 files changed, 123 insertions(+), 63 deletions(-) create mode 100644 src/Dto/Input/BootClientsInput.php diff --git a/env.json b/env.json index d77f392..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": "true" + "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/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..d2c8df1 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']); 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..4852896 100644 --- a/src/Controller/OgBoot/PxeBootFile/DeleteAction.php +++ b/src/Controller/OgBoot/PxeBootFile/DeleteAction.php @@ -23,13 +23,9 @@ 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 ($response->getStatusCode() !== Response::HTTP_OK) { return new JsonResponse( data: 'An error occurred', status: Response::HTTP_INTERNAL_SERVER_ERROR); } diff --git a/src/Controller/OgBoot/PxeBootFile/GetAction.php b/src/Controller/OgBoot/PxeBootFile/GetAction.php index e2efc0d..9639f52 100644 --- a/src/Controller/OgBoot/PxeBootFile/GetAction.php +++ b/src/Controller/OgBoot/PxeBootFile/GetAction.php @@ -26,13 +26,9 @@ 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 ($response->getStatusCode() !== Response::HTTP_OK) { return new JsonResponse( data: 'An error occurred', status: Response::HTTP_INTERNAL_SERVER_ERROR); } 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..71f892c 100644 --- a/src/Controller/OgBoot/PxeBootFile/PostAction.php +++ b/src/Controller/OgBoot/PxeBootFile/PostAction.php @@ -28,7 +28,7 @@ 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(); @@ -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/Dto/Input/BootClientsInput.php b/src/Dto/Input/BootClientsInput.php new file mode 100644 index 0000000..4bc68b0 --- /dev/null +++ b/src/Dto/Input/BootClientsInput.php @@ -0,0 +1,8 @@ + 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', ],