From 20c243fb52fba4b000d108ab4581d1cec4f4e5ed Mon Sep 17 00:00:00 2001 From: Manuel Aranda Date: Mon, 27 Jan 2025 13:59:37 +0100 Subject: [PATCH] refs #1353. Added multiple commands logic. Updated endpoints --- config/api_platform/Client.yaml | 8 +- src/Controller/DeployImageAction.php | 96 ++++++------ src/Controller/OgAgent/DeployImageAction.php | 18 +-- .../OgAgent/PartitionAssistantAction.php | 138 ++++++++++-------- src/Controller/OgAgent/PowerOffAction.php | 72 ++++----- src/Controller/OgAgent/RebootAction.php | 76 +++++----- .../OgAgent/Webhook/ClientsController.php | 2 +- .../OgBoot/PxeBootFile/PostAction.php | 12 +- .../OgRepository/Image/DeployImageAction.php | 5 +- src/Dto/Input/DeployImageInput.php | 15 +- src/Dto/Input/MultipleClientsInput.php | 16 ++ src/Dto/Input/PartitionInput.php | 9 -- src/Dto/Input/PartitionPostInput.php | 6 + src/Dto/Output/ClientOutput.php | 13 +- .../ClientsHaveSamePartitionCount.php | 23 +++ ...ClientsHaveSamePartitionCountValidator.php | 39 +++++ 16 files changed, 326 insertions(+), 222 deletions(-) create mode 100644 src/Dto/Input/MultipleClientsInput.php create mode 100644 src/Validator/Constraints/ClientsHaveSamePartitionCount.php create mode 100644 src/Validator/Constraints/ClientsHaveSamePartitionCountValidator.php diff --git a/config/api_platform/Client.yaml b/config/api_platform/Client.yaml index 6078953..f2322f6 100644 --- a/config/api_platform/Client.yaml +++ b/config/api_platform/Client.yaml @@ -52,15 +52,15 @@ resources: reboot_client: class: ApiPlatform\Metadata\Post method: POST - input: false - uriTemplate: /clients/server/{uuid}/reboot + input: App\Dto\Input\MultipleClientsInput + uriTemplate: /clients/server/reboot controller: App\Controller\OgAgent\RebootAction power_off_client: class: ApiPlatform\Metadata\Post method: POST - input: false - uriTemplate: /clients/server/{uuid}/power-off + input: App\Dto\Input\MultipleClientsInput + uriTemplate: /clients/server/power-off controller: App\Controller\OgAgent\PowerOffAction diff --git a/src/Controller/DeployImageAction.php b/src/Controller/DeployImageAction.php index 7b9778a..d414880 100644 --- a/src/Controller/DeployImageAction.php +++ b/src/Controller/DeployImageAction.php @@ -4,6 +4,7 @@ declare(strict_types=1); namespace App\Controller; +use ApiPlatform\Validator\ValidatorInterface; use App\Dto\Input\DeployImageInput; use App\Entity\Command; use App\Entity\Image; @@ -29,6 +30,7 @@ class DeployImageAction extends AbstractController protected readonly EntityManagerInterface $entityManager, protected readonly HttpClientInterface $httpClient, protected readonly CreateService $createService, + protected readonly ValidatorInterface $validator, public readonly \App\Controller\OgAgent\DeployImageAction $deployImageOgAgentAction, public readonly \App\Controller\OgRepository\Image\DeployImageAction $deployImageOgRepositoryAction, ) @@ -42,67 +44,71 @@ class DeployImageAction extends AbstractController */ public function __invoke(DeployImageInput $input, Image $image): JsonResponse { - /** @var Partition $partition */ - $partition = $input->partition->getEntity(); + $this->validator->validate($input); switch ($input->method){ case DeployMethodTypes::UNICAST: case DeployMethodTypes::UNICAST_DIRECT: - $inputData = [ - 'method' => $input->method, - 'client' => $input->client->getEntity()->getUuid(), - 'image' => $image->getUuid(), - 'numDisk' => (string) $partition->getDiskNumber(), - 'numPartition' => (string) $partition->getPartitionNumber(), - ]; + foreach ($input->clients as $client) { + $inputData = [ + 'method' => $input->method, + 'client' => $client->getEntity()->getUuid(), + 'image' => $image->getUuid(), + 'numDisk' => (string) $input->diskNumber, + 'numPartition' => (string) $input->partitionNumber, + ]; - $agentJobId = $this->deployImageOgAgentAction->__invoke($image, $input, DeployMethodTypes::UNICAST); - $this->createService->__invoke($input->client->getEntity(), CommandTypes::DEPLOY_IMAGE, TraceStatus::IN_PROGRESS, $agentJobId, $inputData); + $agentJobId = $this->deployImageOgAgentAction->__invoke($image, $input, $client->getEntity(), DeployMethodTypes::UNICAST); + $this->createService->__invoke($client->getEntity(), CommandTypes::DEPLOY_IMAGE, TraceStatus::IN_PROGRESS, $agentJobId, $inputData); + } + break; - break; case DeployMethodTypes::MULTICAST_UFTP: - case DeployMethodTypes::MULTICAST_UDPCAST: - case DeployMethodTypes::MULTICAST: case DeployMethodTypes::MULTICAST_UFTP_DIRECT: + case DeployMethodTypes::MULTICAST_UDPCAST: case DeployMethodTypes::MULTICAST_UDPCAST_DIRECT: + case DeployMethodTypes::MULTICAST: + foreach ($input->clients as $client) { + $inputData = [ + 'method' => $input->method, + 'client' => $client->getEntity()->getUuid(), + 'image' => $image->getUuid(), + 'mcastIp' => $input->mcastIp, + 'mcastPort' => $input->mcastPort, + 'mcastSpeed' => $input->mcastSpeed, + 'mcastMode' => $input->mcastMode, + 'numDisk' => (string) $input->diskNumber, + 'numPartition' => (string) $input->partitionNumber, + ]; - $inputData = [ - 'method' => $input->method, - 'client' => $input->client->getEntity()->getUuid(), - 'image' => $image->getUuid(), - 'mcastIp' => $input->mcastIp, - 'mcastPort' => $input->mcastPort, - 'mcastSpeed' => $input->mcastSpeed, - 'mcastMode' => $input->mcastMode, - 'numDisk' => (string) $partition->getDiskNumber(), - 'numPartition' => (string) $partition->getPartitionNumber(), - ]; + try { + $this->deployImageOgRepositoryAction->__invoke($input, $image, $client->getEntity(), $this->httpClient); + } catch (\Exception $e) { + //return new JsonResponse(data: ['error' => $e->getMessage()], status: Response::HTTP_INTERNAL_SERVER_ERROR); + continue; + } - try { - $this->deployImageOgRepositoryAction->__invoke($input, $image, $this->httpClient); - } catch (\Exception $e) { - return new JsonResponse(data: ['error' => $e->getMessage()], status: Response::HTTP_INTERNAL_SERVER_ERROR); + $agentJobId = $this->deployImageOgAgentAction->__invoke($image, $input, $client->getEntity(), DeployMethodTypes::MULTICAST); + $this->createService->__invoke($client->getEntity(), CommandTypes::DEPLOY_IMAGE, TraceStatus::IN_PROGRESS, $agentJobId, $inputData); } - - $agentJobId = $this->deployImageOgAgentAction->__invoke($image, $input, DeployMethodTypes::MULTICAST); - $this->createService->__invoke($input->client->getEntity(), CommandTypes::DEPLOY_IMAGE, TraceStatus::IN_PROGRESS, $agentJobId, $inputData); - - break; + break; case DeployMethodTypes::TORRENT: - $inputData = [ - 'method' => $input->method, - 'client' => $input->client->getEntity()->getUuid(), - 'image' => $image->getUuid(), - 'p2pMode' => $input->p2pMode, - 'p2pTime' => $input->p2pTime, - 'numDisk' => (string) $partition->getDiskNumber(), - 'numPartition' => (string) $partition->getPartitionNumber(), - ]; + foreach ($input->clients as $client) { + $inputData = [ + 'method' => $input->method, + 'client' => $client->getEntity()->getUuid(), + 'image' => $image->getUuid(), + 'p2pMode' => $input->p2pMode, + 'p2pTime' => $input->p2pTime, + 'numDisk' => (string) $input->diskNumber, + 'numPartition' => (string) $input->partitionNumber, + ]; - $agentJobId = $this->deployImageOgAgentAction->__invoke($image, $input, DeployMethodTypes::TORRENT); - $this->createService->__invoke($input->client->getEntity(), CommandTypes::DEPLOY_IMAGE, TraceStatus::IN_PROGRESS, $agentJobId, $inputData); + $agentJobId = $this->deployImageOgAgentAction->__invoke($image, $input, $client->getEntity(), DeployMethodTypes::TORRENT); + $this->createService->__invoke($client->getEntity(), CommandTypes::DEPLOY_IMAGE, TraceStatus::IN_PROGRESS, $agentJobId, $inputData); + } break; } diff --git a/src/Controller/OgAgent/DeployImageAction.php b/src/Controller/OgAgent/DeployImageAction.php index 617505c..70e119b 100644 --- a/src/Controller/OgAgent/DeployImageAction.php +++ b/src/Controller/OgAgent/DeployImageAction.php @@ -38,7 +38,7 @@ class DeployImageAction extends AbstractController { } - public function __invoke(Image $image, DeployImageInput $input, string $method) + public function __invoke(Image $image, DeployImageInput $input, Client $client, string $method) { if (!$image->getClient()->getIp()) { throw new ValidatorException('IP is required'); @@ -46,12 +46,6 @@ class DeployImageAction extends AbstractController $partitionInfo = json_decode($image->getPartitionInfo(), true); - /** @var Client $client */ - $client = $input->client->getEntity(); - - /** @var Partition $partition */ - $partition = $input->partition->getEntity(); - $method = match ($input->method) { DeployMethodTypes::MULTICAST_UFTP_DIRECT, DeployMethodTypes::MULTICAST_UDPCAST_DIRECT, => 'multicast-direct', DeployMethodTypes::MULTICAST, DeployMethodTypes::MULTICAST_UFTP, DeployMethodTypes::MULTICAST_UDPCAST => 'multicast', @@ -61,7 +55,7 @@ class DeployImageAction extends AbstractController default => throw new ValidatorException('Invalid method'), }; - $ptcMulticastValue = "$method $input->mcastPort:$input->mcastMode:$input->mcastIp:$input->mcastSpeed:$input->maxClients:$input->maxTime"; + $ptcMulticastValue = "$method $input->mcastPort:$input->mcastMode.'-duplex'.:$input->mcastIp:$input->mcastSpeed.'M'.:$input->maxClients:$input->maxTime"; $ptcTorrentValue = "$method $input->p2pMode:$input->p2pTime"; $ptcUnicastValue = $method; @@ -73,8 +67,8 @@ class DeployImageAction extends AbstractController }; $data = [ - 'dsk' => (string) $partition->getDiskNumber(), - 'par' => (string) $partition->getPartitionNumber(), + 'dsk' => (string) $input->diskNumber, + 'par' => (string) $input->partitionNumber, 'ifs' => "1", 'idi' => $image->getUuid(), 'nci' => $image->getName(), @@ -97,10 +91,6 @@ class DeployImageAction extends AbstractController } catch (TransportExceptionInterface $e) { $this->logger->error('Error deploying image', ['image' => $image->getId(), 'error' => $e->getMessage()]); - return new JsonResponse( - data: ['error' => $e->getMessage()], - status: Response::HTTP_INTERNAL_SERVER_ERROR - ); } $jobId = json_decode($response->getContent(), true)['job_id']; diff --git a/src/Controller/OgAgent/PartitionAssistantAction.php b/src/Controller/OgAgent/PartitionAssistantAction.php index 0044048..7e8021d 100644 --- a/src/Controller/OgAgent/PartitionAssistantAction.php +++ b/src/Controller/OgAgent/PartitionAssistantAction.php @@ -8,6 +8,7 @@ use App\Dto\Input\PartitionPostInput; 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; @@ -46,79 +47,88 @@ class PartitionAssistantAction extends AbstractController throw new ValidatorException('Partitions is required'); } - /** @var Client $client */ - $client = $input->partitions[0]->client->getEntity(); + foreach ($input->clients as $clientInput) { + $client = $clientInput->getEntity(); - $disks = []; - foreach ($partitions as $partition) { - $diskNumber = $partition->diskNumber; + $disks = []; + foreach ($partitions as $partition) { + $diskNumber = $partition->diskNumber; - if (!isset($disks[$diskNumber])) { - $disks[$diskNumber] = [ - 'diskData' => [], - 'partitionData' => [] - ]; - } - - if ($partition->filesystem === 'CACHE') { - $disks[$diskNumber]['diskData'] = [ - 'dis' => (string) $diskNumber, - 'che' => "0", - 'tch' => (string) ($partition->size * 1024), - ]; - } - - $disks[$diskNumber]['partitionData'][] = [ - 'par' => (string) $partition->partitionNumber, - 'cpt' => $partition->partitionCode, - 'sfi' => $partition->filesystem, - 'tam' => (string) (integer) ($partition->size * 1024), - 'ope' => $partition->format ? "1" : "0", - ]; - } - - foreach ($disks as $diskNumber => $diskInfo) { - $data = []; - if (!empty($diskInfo['diskData'])) { - $data[] = $diskInfo['diskData']; - } - $data = array_merge($data, $diskInfo['partitionData']); - - $result = [ - "nfn" => "Configurar", - "dsk" => (string) $diskNumber, - "cfg" => $data, - "ids" => "0" - ]; - - try { - $response = $this->httpClient->request('POST', 'https://' . $client->getIp() . ':8000/CloningEngine/Configurar', [ - 'verify_peer' => false, - 'verify_host' => false, - 'headers' => [ - 'Content-Type' => 'application/json', - ], - 'json' => $result, + $partitionEntity = $this->entityManager->getRepository(Partition::class)->findOneBy([ + 'client' => $client, + 'partitionNumber' => $partition->partitionNumber, + 'diskNumber' => $partition->diskNumber, ]); - $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()]); - return new JsonResponse( - data: ['error' => "Error en disco $diskNumber: " . $e->getMessage()], - status: Response::HTTP_INTERNAL_SERVER_ERROR - ); + + if ($partitionEntity) { + $partitionEntity->setClient($client); + $this->entityManager->persist($partitionEntity); + } + + if (!isset($disks[$diskNumber])) { + $disks[$diskNumber] = [ + 'diskData' => [], + 'partitionData' => [] + ]; + } + + if ($partition->filesystem === 'CACHE') { + $disks[$diskNumber]['diskData'] = [ + 'dis' => (string) $diskNumber, + 'che' => "0", + 'tch' => (string) ($partition->size * 1024), + ]; + } + + $disks[$diskNumber]['partitionData'][] = [ + 'par' => (string) $partition->partitionNumber, + 'cpt' => $partition->partitionCode, + 'sfi' => $partition->filesystem, + 'tam' => (string) (integer) ($partition->size * 1024), + 'ope' => $partition->format ? "1" : "0", + ]; } - $jobId = json_decode($response->getContent(), true)['job_id']; + foreach ($disks as $diskNumber => $diskInfo) { + $data = []; + if (!empty($diskInfo['diskData'])) { + $data[] = $diskInfo['diskData']; + } + $data = array_merge($data, $diskInfo['partitionData']); - $client->setStatus(ClientStatus::BUSY); - $this->entityManager->persist($client); - $this->entityManager->flush(); + $result = [ + "nfn" => "Configurar", + "dsk" => (string) $diskNumber, + "cfg" => $data, + "ids" => "0" + ]; - $this->createService->__invoke($client, CommandTypes::PARTITION_AND_FORMAT, TraceStatus::IN_PROGRESS, $jobId, []); + try { + $response = $this->httpClient->request('POST', 'https://' . $client->getIp() . ':8000/CloningEngine/Configurar', [ + 'verify_peer' => false, + 'verify_host' => false, + 'headers' => [ + 'Content-Type' => 'application/json', + ], + '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; + } + + $jobId = json_decode($response->getContent(), true)['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, []); + } } - return new JsonResponse(data: $client, status: Response::HTTP_OK); + return new JsonResponse(data: [], status: Response::HTTP_OK); } } diff --git a/src/Controller/OgAgent/PowerOffAction.php b/src/Controller/OgAgent/PowerOffAction.php index 766dd91..2f5f0b1 100644 --- a/src/Controller/OgAgent/PowerOffAction.php +++ b/src/Controller/OgAgent/PowerOffAction.php @@ -4,6 +4,7 @@ declare(strict_types=1); namespace App\Controller\OgAgent; +use App\Dto\Input\MultipleClientsInput; use App\Entity\Client; use App\Entity\Command; use App\Entity\Image; @@ -37,44 +38,45 @@ class PowerOffAction extends AbstractController { } - public function __invoke(Client $client): JsonResponse + public function __invoke(MultipleClientsInput $input): JsonResponse { - if (!$client->getIp()) { - throw new ValidatorException('IP is required'); + foreach ($input->clients as $clientEntity) { + $client = $clientEntity->getEntity(); + + if (!$client->getIp()) { + throw new ValidatorException('IP is required'); + } + + $data = [ + 'nfn' => 'Apagar', + 'ids' => '0' + ]; + + try { + $response = $this->httpClient->request('POST', 'https://'.$client->getIp().':8000/ogAdmClient/Apagar', [ + 'verify_peer' => false, + 'verify_host' => false, + 'headers' => [ + 'Content-Type' => 'application/json', + ], + 'json' => $data, + ]); + $this->logger->info('Powering off client', ['client' => $client->getId()]); + + } catch (TransportExceptionInterface $e) { + $this->logger->error('Error powering off client', ['client' => $client->getId(), 'error' => $e->getMessage()]); + continue; + } + + $jobId = json_decode($response->getContent(), true)['job_id']; + + $client->setStatus(ClientStatus::OFF); + $this->entityManager->persist($client); + $this->entityManager->flush(); + + $this->createService->__invoke($client, CommandTypes::SHUTDOWN, TraceStatus::SUCCESS, $jobId, []); } - $data = [ - 'nfn' => 'Apagar', - 'ids' => '0' - ]; - - try { - $response = $this->httpClient->request('POST', 'https://'.$client->getIp().':8000/ogAdmClient/Apagar', [ - 'verify_peer' => false, - 'verify_host' => false, - 'headers' => [ - 'Content-Type' => 'application/json', - ], - 'json' => $data, - ]); - $this->logger->info('Powering off client', ['client' => $client->getId()]); - - } catch (TransportExceptionInterface $e) { - $this->logger->error('Error powering off client', ['client' => $client->getId(), 'error' => $e->getMessage()]); - return new JsonResponse( - data: ['error' => $e->getMessage()], - status: Response::HTTP_INTERNAL_SERVER_ERROR - ); - } - - $jobId = json_decode($response->getContent(), true)['job_id']; - - $client->setStatus(ClientStatus::OFF); - $this->entityManager->persist($client); - $this->entityManager->flush(); - - $this->createService->__invoke($client, CommandTypes::SHUTDOWN, TraceStatus::SUCCESS, $jobId, []); - return new JsonResponse(data: $client, status: Response::HTTP_OK); } } diff --git a/src/Controller/OgAgent/RebootAction.php b/src/Controller/OgAgent/RebootAction.php index 323f782..72d9a43 100644 --- a/src/Controller/OgAgent/RebootAction.php +++ b/src/Controller/OgAgent/RebootAction.php @@ -4,6 +4,7 @@ declare(strict_types=1); namespace App\Controller\OgAgent; +use App\Dto\Input\MultipleClientsInput; use App\Entity\Client; use App\Entity\Command; use App\Entity\Image; @@ -37,44 +38,49 @@ class RebootAction extends AbstractController { } - public function __invoke(Client $client): JsonResponse + public function __invoke(MultipleClientsInput $input): JsonResponse { - if (!$client->getIp()) { - throw new ValidatorException('IP is required'); + foreach ($input->clients as $clientEntity) { + $client = $clientEntity->getEntity(); + + + if (!$client->getIp()) { + throw new ValidatorException('IP is required'); + } + + $data = [ + 'nfn' => 'Reiniciar', + 'ids' => '0' + ]; + + try { + $response = $this->httpClient->request('POST', 'https://' . $client->getIp() . ':8000/ogAdmClient/Reiniciar', [ + 'verify_peer' => false, + 'verify_host' => false, + 'headers' => [ + 'Content-Type' => 'application/json', + ], + 'json' => $data, + ]); + $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 + ); + } + + $jobId = json_decode($response->getContent(), true)['job_id']; + + $client->setStatus(ClientStatus::INITIALIZING); + $this->entityManager->persist($client); + $this->entityManager->flush(); + + $this->createService->__invoke($client, CommandTypes::REBOOT, TraceStatus::SUCCESS, $jobId, []); } - $data = [ - 'nfn' => 'Reiniciar', - 'ids' => '0' - ]; - - try { - $response = $this->httpClient->request('POST', 'https://'.$client->getIp().':8000/ogAdmClient/Reiniciar', [ - 'verify_peer' => false, - 'verify_host' => false, - 'headers' => [ - 'Content-Type' => 'application/json', - ], - 'json' => $data, - ]); - $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 - ); - } - - $jobId = json_decode($response->getContent(), true)['job_id']; - - $client->setStatus(ClientStatus::INITIALIZING); - $this->entityManager->persist($client); - $this->entityManager->flush(); - - $this->createService->__invoke($client, CommandTypes::REBOOT, TraceStatus::SUCCESS, $jobId, []); - return new JsonResponse(data: $client, status: Response::HTTP_OK); } } diff --git a/src/Controller/OgAgent/Webhook/ClientsController.php b/src/Controller/OgAgent/Webhook/ClientsController.php index e88e536..e628f7a 100644 --- a/src/Controller/OgAgent/Webhook/ClientsController.php +++ b/src/Controller/OgAgent/Webhook/ClientsController.php @@ -53,7 +53,7 @@ class ClientsController extends AbstractController public function index(Request $request): JsonResponse { $data = $request->toArray(); - $requiredFields = ['nfn', 'ids', 'res', 'der', 'job_id']; + $requiredFields = ['res', 'der', 'job_id']; foreach ($requiredFields as $field) { if (!isset($data[$field])) { diff --git a/src/Controller/OgBoot/PxeBootFile/PostAction.php b/src/Controller/OgBoot/PxeBootFile/PostAction.php index f869b76..7448a6d 100644 --- a/src/Controller/OgBoot/PxeBootFile/PostAction.php +++ b/src/Controller/OgBoot/PxeBootFile/PostAction.php @@ -30,11 +30,11 @@ class PostAction extends AbstractOgBootController { $ogRepoIp = $this->ogBootApiUrl; - if ($client->getRepository()) { - $ogRepoIp = $client->getRepository()->getIp(); - } else if ($client->getOrganizationalUnit()->getNetworkSettings()->getRepository()) { - $ogRepoIp = $client->getOrganizationalUnit()->getNetworkSettings()->getRepository()->getIp(); - } + $ogRepoIp = $client->getRepository()?->getIp() + ?? $client->getOrganizationalUnit()?->getNetworkSettings()?->getRepository()?->getIp(); + + $ogLive = $client->getOgLive() + ?? $client->getOrganizationalUnit()?->getNetworkSettings()?->getOgLive()->getFilename(); $params = [ 'json' => [ @@ -54,7 +54,7 @@ class PostAction extends AbstractOgBootController 'oglog' => $this->ogLogIp, 'ogshare' => $client->getOrganizationalUnit()->getNetworkSettings()?->getOgShare() ? $client->getOrganizationalUnit()->getNetworkSettings()?->getOgShare(): $this->ogBootApiUrl, - 'oglivedir' => $client->getOgLive()->getFilename(), + 'oglivedir' => $ogLive, 'ogprof' => 'false', 'hardprofile' => $client->getHardwareProfile() ? $client->getHardwareProfile()->getDescription() : 'default', 'ogntp' => $client->getOrganizationalUnit()->getNetworkSettings()?->getNtp(), diff --git a/src/Controller/OgRepository/Image/DeployImageAction.php b/src/Controller/OgRepository/Image/DeployImageAction.php index 4a50fd5..404dcd5 100644 --- a/src/Controller/OgRepository/Image/DeployImageAction.php +++ b/src/Controller/OgRepository/Image/DeployImageAction.php @@ -4,6 +4,7 @@ namespace App\Controller\OgRepository\Image; use App\Controller\OgRepository\AbstractOgRepositoryController; use App\Dto\Input\DeployImageInput; +use App\Entity\Client; use App\Entity\Command; use App\Entity\Image; use App\Model\CommandTypes; @@ -28,10 +29,8 @@ class DeployImageAction extends AbstractOgRepositoryController * @throws ClientExceptionInterface * @throws TransportExceptionInterface */ - public function __invoke(DeployImageInput $input, Image $data, HttpClientInterface $httpClient): JsonResponse + public function __invoke(DeployImageInput $input, Image $data, Client $client, HttpClientInterface $httpClient): JsonResponse { - $client = $input->client; - $params = [ 'json' => [ 'ID_img' => $data->getImageFullsum(), diff --git a/src/Dto/Input/DeployImageInput.php b/src/Dto/Input/DeployImageInput.php index 86012cc..fb51bac 100644 --- a/src/Dto/Input/DeployImageInput.php +++ b/src/Dto/Input/DeployImageInput.php @@ -6,11 +6,13 @@ use ApiPlatform\Metadata\ApiProperty; use App\Dto\Output\ClientOutput; use App\Dto\Output\ImageOutput; use App\Dto\Output\PartitionOutput; +use App\Validator\Constraints\ClientsHaveSamePartitionCount; use App\Validator\Constraints\OrganizationalUnitMulticastMode; use App\Validator\Constraints\OrganizationalUnitMulticastPort; use App\Validator\Constraints\OrganizationalUnitP2PMode; use Symfony\Component\Serializer\Annotation\Groups; +#[ClientsHaveSamePartitionCount] class DeployImageInput { #[Groups(['image:write'])] @@ -21,19 +23,24 @@ class DeployImageInput #[ApiProperty(description: 'The type of the image deployment', example: "")] public ?string $method = null; + /** + * @var ClientOutput[] + */ #[Groups(['image:write'])] #[ApiProperty(description: 'The client to deploy the image')] - public ?ClientOutput $client = null; + public ?array $clients = []; #[Groups(['image:write'])] - #[ApiProperty(description: 'The partition to deploy the image')] - public ?PartitionOutput $partition = null; + public ?int $diskNumber = null; + + #[Groups(['image:write'])] + public ?int $partitionNumber = null; #[OrganizationalUnitP2PMode] #[Groups(['image:write'])] public ?string $p2pMode = null; - #[Groups(['organizational-unit:write'])] + #[Groups(['image:write'])] public ?int $p2pTime = null; #[Groups(['image:write'])] diff --git a/src/Dto/Input/MultipleClientsInput.php b/src/Dto/Input/MultipleClientsInput.php new file mode 100644 index 0000000..c3dffde --- /dev/null +++ b/src/Dto/Input/MultipleClientsInput.php @@ -0,0 +1,16 @@ +operativeSystem = new OperativeSystemOutput($partition->getOperativeSystem()); } - if ($partition->getClient()) { - $this->client = new ClientOutput($partition->getClient()); - } $this->memoryUsage = $partition->getMemoryUsage(); if ($partition->getImage()) { @@ -114,7 +106,6 @@ final class PartitionInput if ($this->operativeSystem) { $partition->setOperativeSystem($this->operativeSystem->getEntity()); } - $partition->setClient($this->client->getEntity()); $partition->setMemoryUsage($this->memoryUsage * 100); if ($this->image) { diff --git a/src/Dto/Input/PartitionPostInput.php b/src/Dto/Input/PartitionPostInput.php index 4b52486..947d894 100644 --- a/src/Dto/Input/PartitionPostInput.php +++ b/src/Dto/Input/PartitionPostInput.php @@ -12,5 +12,11 @@ final class PartitionPostInput */ #[Groups(['partition:write'])] public array $partitions = []; + + /** + * @var ClientOutput[] + */ + #[Groups(['partition:write'])] + public array $clients = []; } diff --git a/src/Dto/Output/ClientOutput.php b/src/Dto/Output/ClientOutput.php index 6f275fd..f625812 100644 --- a/src/Dto/Output/ClientOutput.php +++ b/src/Dto/Output/ClientOutput.php @@ -103,10 +103,19 @@ final class ClientOutput extends AbstractOutput $this->menu = $client->getMenu() ? new MenuOutput($client->getMenu()) : null; $this->position = $client->getPosition(); $this->template = $client->getTemplate() ? new PxeTemplateOutput($client->getTemplate()) : null; - $this->repository = $client->getRepository() ? new ImageRepositoryOutput($client->getRepository()) : null; + + $repository = $client->getRepository() + ?? $client->getOrganizationalUnit()?->getNetworkSettings()?->getRepository(); + + $this->repository = $repository ? new ImageRepositoryOutput($repository) : null; + + $ogLive = $client->getOgLive() + ?? $client->getOrganizationalUnit()?->getNetworkSettings()?->getOgLive(); + + $this->ogLive = $ogLive ? new OgLiveOutput($ogLive) : null; + $this->hardwareProfile = $client->getHardwareProfile() ? new HardwareProfileOutput($client->getHardwareProfile()) : null; $this->subnet = $client->getSubnet()?->getIpAddress(); - $this->ogLive = $client->getOgLive() ? new OgLiveOutput($client->getOgLive()) : null; $this->status = $client->getStatus(); $this->createdAt = $client->getCreatedAt(); $this->createdBy = $client->getCreatedBy(); diff --git a/src/Validator/Constraints/ClientsHaveSamePartitionCount.php b/src/Validator/Constraints/ClientsHaveSamePartitionCount.php new file mode 100644 index 0000000..9ea7093 --- /dev/null +++ b/src/Validator/Constraints/ClientsHaveSamePartitionCount.php @@ -0,0 +1,23 @@ +message = 'All clients must have the same number of partitions.'; + } + + public function getTargets(): string + { + return self::CLASS_CONSTRAINT; + } +} \ No newline at end of file diff --git a/src/Validator/Constraints/ClientsHaveSamePartitionCountValidator.php b/src/Validator/Constraints/ClientsHaveSamePartitionCountValidator.php new file mode 100644 index 0000000..896dc3e --- /dev/null +++ b/src/Validator/Constraints/ClientsHaveSamePartitionCountValidator.php @@ -0,0 +1,39 @@ +clients) && is_array($value->clients)) { + $partitionCounts = []; + foreach ($value->clients as $client) { + $partitionCount = $client->getEntity()->getPartitions()->count(); + $partitionCounts[(string) $client->getEntity()->getIp()] = $partitionCount; + } + + if (count(array_unique($partitionCounts)) > 1) { + $errorDetails = []; + foreach ($partitionCounts as $clientIp => $partitionCount) { + $errorDetails[] = "Cliente $clientIp tiene $partitionCount particiones."; + } + + $detailedMessage = implode(" ", $errorDetails); + + $this->context->buildViolation($constraint->message . ' Detalles: ' . $detailedMessage) + ->addViolation(); + } + } + } +} \ No newline at end of file