diff --git a/config/api_platform/Client.yaml b/config/api_platform/Client.yaml index 33a92c3..6078953 100644 --- a/config/api_platform/Client.yaml +++ b/config/api_platform/Client.yaml @@ -49,6 +49,20 @@ resources: uriTemplate: /clients/server/{uuid}/get-pxe controller: App\Controller\OgBoot\PxeBootFile\GetAction + reboot_client: + class: ApiPlatform\Metadata\Post + method: POST + input: false + uriTemplate: /clients/server/{uuid}/reboot + controller: App\Controller\OgAgent\RebootAction + + power_off_client: + class: ApiPlatform\Metadata\Post + method: POST + input: false + uriTemplate: /clients/server/{uuid}/power-off + controller: App\Controller\OgAgent\PowerOffAction + properties: App\Entity\Client: diff --git a/config/api_platform/ImageRepository.yaml b/config/api_platform/ImageRepository.yaml index 7ff7d33..f8879bb 100644 --- a/config/api_platform/ImageRepository.yaml +++ b/config/api_platform/ImageRepository.yaml @@ -30,6 +30,13 @@ resources: uriTemplate: /image-repositories/server/sync controller: App\Controller\OgRepository\SyncAction + wol_client: + class: ApiPlatform\Metadata\Post + method: POST + input: App\Dto\Input\WoLInput + uriTemplate: /image-repositories/{uuid}/wol + controller: App\Controller\OgRepository\WoLAction + get_collection_images_ogrepository: shortName: OgRepository Server description: Get collection of image in OgRepository diff --git a/config/api_platform/Partition.yaml b/config/api_platform/Partition.yaml index 3103413..cb933cb 100644 --- a/config/api_platform/Partition.yaml +++ b/config/api_platform/Partition.yaml @@ -1,7 +1,7 @@ resources: App\Entity\Partition: processor: App\State\Processor\PartitionProcessor - input: App\Dto\Input\PartitionInput + input: App\Dto\Input\PartitionPostInput output: App\Dto\Output\PartitionOutput orderBy: partitionNumber: 'ASC' @@ -29,4 +29,4 @@ properties: id: identifier: false uuid: - identifier: true \ No newline at end of file + identifier: true diff --git a/config/services/api_platform.yaml b/config/services/api_platform.yaml index 844be53..cc3b13b 100644 --- a/config/services/api_platform.yaml +++ b/config/services/api_platform.yaml @@ -135,7 +135,7 @@ services: api_platform.filter.partition.order: parent: 'api_platform.doctrine.orm.order_filter' arguments: - $properties: { 'id': ~, 'usage': ~ } + $properties: { 'id': ~, 'usage': ~, 'partitionNumber': 'ASC' } $orderParameterName: 'order' tags: [ 'api_platform.filter' ] diff --git a/src/Controller/OgAgent/PartitionAssistantAction.php b/src/Controller/OgAgent/PartitionAssistantAction.php new file mode 100644 index 0000000..2ebf04f --- /dev/null +++ b/src/Controller/OgAgent/PartitionAssistantAction.php @@ -0,0 +1,120 @@ +partitions; + + if (empty($partitions)) { + throw new ValidatorException('Partitions is required'); + } + + /** @var Client $client */ + $client = $input->partitions[0]->client->getEntity(); + + $data = []; + $diskNumber = 0; + $cacheSize = 0; + $disks = []; + $cpt = ''; + + $data = []; + $diskData = []; + + foreach ($partitions as $partition) { + if ($partition->filesystem === 'CACHE') { + $cacheSize = $partition->size * 1024; + $disks[$partition->diskNumber] = $cacheSize; + } + + $diskNumber = $partition->diskNumber; + + $data[] = [ + 'par' => (string) $partition->partitionNumber, + 'cpt' => $partition->partitionCode, + 'sfi' => $partition->filesystem, + 'tam' => (string) ($partition->size * 1024), + 'ope' => $partition->format ? "1" : "0", + ]; + } + + foreach ($disks as $diskNumber => $size) { + $diskData[] = [ + 'dis' => (string) $diskNumber, + 'che' => "0", + 'tch' => (string) $size, + ]; + } + + $data = array_merge($diskData, $data); + + $result = [ + "nfn" => "Configurar", + "dsk" => "1", + "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, + ]); + + } catch (TransportExceptionInterface $e) { + return new JsonResponse( + data: ['error' => $e->getMessage()], + status: Response::HTTP_INTERNAL_SERVER_ERROR + ); + } + + $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); + } +} diff --git a/src/Controller/OgAgent/PowerOffAction.php b/src/Controller/OgAgent/PowerOffAction.php new file mode 100644 index 0000000..2ba5741 --- /dev/null +++ b/src/Controller/OgAgent/PowerOffAction.php @@ -0,0 +1,76 @@ +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, + ]); + + } catch (TransportExceptionInterface $e) { + 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 new file mode 100644 index 0000000..dcbc139 --- /dev/null +++ b/src/Controller/OgAgent/RebootAction.php @@ -0,0 +1,76 @@ +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, + ]); + + } catch (TransportExceptionInterface $e) { + 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/StatusAction.php b/src/Controller/OgAgent/StatusAction.php index 5ce9d66..13f9964 100644 --- a/src/Controller/OgAgent/StatusAction.php +++ b/src/Controller/OgAgent/StatusAction.php @@ -9,6 +9,7 @@ use App\Model\ClientStatus; use App\Model\OgLiveStatus; use App\Service\CreatePartitionService; use Doctrine\ORM\EntityManagerInterface; +use Psr\Log\LoggerInterface; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpClient\HttpClient; use Symfony\Component\HttpClient\Internal\ClientState; @@ -28,7 +29,8 @@ class StatusAction extends AbstractController public function __construct( protected readonly EntityManagerInterface $entityManager, protected readonly HttpClientInterface $httpClient, - protected readonly CreatePartitionService $createPartitionService + protected readonly CreatePartitionService $createPartitionService, + protected readonly LoggerInterface $logger, ) {} /** @@ -61,6 +63,8 @@ class StatusAction extends AbstractController public function getOgLiveStatus (Client $client): JsonResponse|int|string { + $this->logger->info('Checking client status', ['client' => $client->getId()]); + try { $response = $this->httpClient->request('POST', 'https://' . $client->getIp() . ':8000/ogAdmClient/status', [ 'verify_peer' => false, @@ -83,6 +87,7 @@ class StatusAction extends AbstractController $data = json_decode($response->getContent(), true); if (isset($data['cfg'])) { + $this->logger->info('Creating partitions', ['data' => $data['cfg']]); $this->createPartitionService->__invoke($data, $client); } diff --git a/src/Controller/OgAgent/Webhook/ClientsController.php b/src/Controller/OgAgent/Webhook/ClientsController.php index 1fe5dd1..aeca19e 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', 'idi', 'dsk', 'par', 'ids', 'res', 'der', 'job_id']; + $requiredFields = ['nfn', 'ids', 'res', 'der', 'job_id']; foreach ($requiredFields as $field) { if (!isset($data[$field])) { @@ -123,6 +123,7 @@ class ClientsController extends AbstractController $trace->setStatus(TraceStatus::SUCCESS); $trace->setFinishedAt(new \DateTime()); $image->setStatus(ImageStatus::PENDING); + $client->setStatus(ClientStatus::OG_LIVE); } else { $trace->setStatus(TraceStatus::FAILED); $trace->setFinishedAt(new \DateTime()); @@ -136,6 +137,29 @@ class ClientsController extends AbstractController $this->entityManager->flush(); } + if ($data['nfn'] === 'RESPUESTA_Configurar') { + $trace = $this->entityManager->getRepository(Trace::class)->findOneBy(['jobId' => $data['job_id']]); + + $client = $trace->getClient(); + + if ($data['res'] === 1) { + $trace->setStatus(TraceStatus::SUCCESS); + $trace->setFinishedAt(new \DateTime()); + $client->setStatus(ClientStatus::OG_LIVE); + if (isset($data['cfg'])) { + $this->createPartitionService->__invoke($data,$client); + } + } else { + $trace->setStatus(TraceStatus::FAILED); + $trace->setFinishedAt(new \DateTime()); + $trace->setOutput($data['der']); + } + + $this->entityManager->persist($client); + $this->entityManager->persist($trace); + $this->entityManager->flush(); + } + return new JsonResponse(data: 'Webhook finished', status: Response::HTTP_OK); } @@ -170,4 +194,4 @@ class ClientsController extends AbstractController $this->entityManager->persist($softwareProfile); $this->entityManager->flush(); } -} \ No newline at end of file +} diff --git a/src/Controller/OgBoot/PxeTemplate/SyncAction.php b/src/Controller/OgBoot/PxeTemplate/SyncAction.php index be8f980..2b256e1 100644 --- a/src/Controller/OgBoot/PxeTemplate/SyncAction.php +++ b/src/Controller/OgBoot/PxeTemplate/SyncAction.php @@ -41,6 +41,7 @@ class SyncAction extends AbstractOgBootController } $templateContent = $this->createRequest('GET', 'http://'.$this->ogBootApiUrl . '/ogboot/v1/pxe-templates/'.$templateEntity->getName()); + $templateEntity->setTemplateContent($templateContent['template_content']); $templateEntity->setSynchronized(true); @@ -50,4 +51,4 @@ class SyncAction extends AbstractOgBootController return new JsonResponse(data: $content, status: Response::HTTP_OK); } -} \ No newline at end of file +} diff --git a/src/Controller/OgRepository/WoLAction.php b/src/Controller/OgRepository/WoLAction.php new file mode 100644 index 0000000..e8abfa3 --- /dev/null +++ b/src/Controller/OgRepository/WoLAction.php @@ -0,0 +1,66 @@ +client->getEntity(); + + + if (!$repository->getIp()) { + throw new ValidatorException('IP is required'); + } + + $params = [ + 'json' => [ + 'broadcast_ip' => '255.255.255.255', + 'mac' => $client->getMac() + ] + ]; + + $content = $this->createRequest('POST', 'http://'.$repository->getIp(). ':8006/ogrepository/v1/wol', $params); + + $client->setStatus(ClientStatus::OFF); + $this->entityManager->persist($client); + $this->entityManager->flush(); + + $this->createService->__invoke($client, CommandTypes::SHUTDOWN, TraceStatus::SUCCESS, '', []); + + return new JsonResponse(data: $client, status: Response::HTTP_OK); + } +} diff --git a/src/Dto/Input/PartitionInput.php b/src/Dto/Input/PartitionInput.php index 635149f..a00c7ed 100644 --- a/src/Dto/Input/PartitionInput.php +++ b/src/Dto/Input/PartitionInput.php @@ -10,11 +10,21 @@ use App\Dto\Output\OrganizationalUnitOutput; use App\Entity\HardwareProfile; use App\Entity\Menu; use App\Entity\Partition; +use Ramsey\Uuid\UuidInterface; use Symfony\Component\Serializer\Annotation\Groups; use Symfony\Component\Validator\Constraints as Assert; final class PartitionInput { + #[Groups(['partition:write'])] + public ?UuidInterface $uuid = null; + + #[Groups(['partition:write'])] + public ?bool $removed = null; + + #[Groups(['partition:write'])] + public ?bool $format = null; + #[Groups(['partition:write'])] #[ApiProperty(description: 'The disk number of the partition', example: 1)] public ?int $diskNumber = null; @@ -37,7 +47,11 @@ final class PartitionInput public ?string $cacheContent = null; #[Groups(['partition:write'])] - #[ApiProperty(description: 'The filesystem of the partition', example: "filesystem")] + #[ApiProperty(description: 'The type of the partition', example: "LINUX")] + public ?string $type = null; + + #[Groups(['partition:write'])] + #[ApiProperty(description: 'The filesystem of the partition', example: "EXT4")] public ?string $filesystem = null; #[Groups(['partition:write'])] @@ -109,4 +123,4 @@ final class PartitionInput return $partition; } -} \ No newline at end of file +} diff --git a/src/Dto/Input/PartitionPostInput.php b/src/Dto/Input/PartitionPostInput.php new file mode 100644 index 0000000..4b52486 --- /dev/null +++ b/src/Dto/Input/PartitionPostInput.php @@ -0,0 +1,16 @@ + */ #[ORM\OneToMany(mappedBy: 'client', targetEntity: Partition::class)] + #[ORM\OrderBy(['partitionNumber' => 'ASC'])] private Collection $partitions; #[ORM\ManyToOne] diff --git a/src/Model/CommandTypes.php b/src/Model/CommandTypes.php index 4744681..fd2570e 100644 --- a/src/Model/CommandTypes.php +++ b/src/Model/CommandTypes.php @@ -13,6 +13,7 @@ final class CommandTypes public const string SHUTDOWN = 'shutdown'; public const string LOGIN = 'login'; public const string LOGOUT = 'logout'; + public const string PARTITION_AND_FORMAT = 'partition-and-format'; private const array COMMAND_TYPES = [ self::DEPLOY_IMAGE => 'Deploy Image', @@ -24,6 +25,7 @@ final class CommandTypes self::SHUTDOWN => 'Apagar', self::LOGIN => 'Login', self::LOGOUT => 'Logout', + self::PARTITION_AND_FORMAT => 'Partition and Format', ]; public static function getCommandTypes(): array @@ -35,4 +37,4 @@ final class CommandTypes { return self::COMMAND_TYPES[$type] ?? null; } -} \ No newline at end of file +} diff --git a/src/Model/PartitionTypes.php b/src/Model/PartitionTypes.php new file mode 100644 index 0000000..47601dd --- /dev/null +++ b/src/Model/PartitionTypes.php @@ -0,0 +1,94 @@ + ['name' => 'EMPTY', 'active' => false], + 1 => ['name' => 'FAT12', 'active' => true], + 5 => ['name' => 'EXTENDED', 'active' => false], + 6 => ['name' => 'FAT16', 'active' => true], + 7 => ['name' => 'NTFS', 'active' => true], + 11 => ['name' => 'FAT32', 'active' => true], + 17 => ['name' => 'HFAT12', 'active' => true], + 22 => ['name' => 'HFAT16', 'active' => true], + 23 => ['name' => 'HNTFS', 'active' => true], + 27 => ['name' => 'HFAT32', 'active' => true], + 130 => ['name' => 'LINUX-SWAP', 'active' => false], + 131 => ['name' => 'LINUX', 'active' => true], + 142 => ['name' => 'LINUX-LVM', 'active' => true], + 165 => ['name' => 'FREEBSD', 'active' => true], + 166 => ['name' => 'OPENBSD', 'active' => true], + 169 => ['name' => 'NETBSD', 'active' => true], + 175 => ['name' => 'HFS', 'active' => true], + 190 => ['name' => 'SOLARIS-BOOT', 'active' => true], + 191 => ['name' => 'SOLARIS', 'active' => true], + 202 => ['name' => 'CACHE', 'active' => false], + 218 => ['name' => 'DATA', 'active' => true], + 238 => ['name' => 'GPT', 'active' => false], + 239 => ['name' => 'EFI', 'active' => true], + 251 => ['name' => 'VMFS', 'active' => true], + 253 => ['name' => 'LINUX-RAID', 'active' => true], + 1792 => ['name' => 'WINDOWS', 'active' => true], + 3073 => ['name' => 'WIN-RESERV', 'active' => true], + 9984 => ['name' => 'WIN-RECOV', 'active' => true], + 32512 => ['name' => 'CHROMEOS-KRN', 'active' => true], + 32513 => ['name' => 'CHROMEOS', 'active' => true], + 32514 => ['name' => 'CHROMEOS-RESERV', 'active' => true], + 33280 => ['name' => 'LINUX-SWAP', 'active' => false], + 33536 => ['name' => 'LINUX', 'active' => true], + 33537 => ['name' => 'LINUX-RESERV', 'active' => true], + 33538 => ['name' => 'LINUX', 'active' => true], + 36352 => ['name' => 'LINUX-LVM', 'active' => true], + 42240 => ['name' => 'FREEBSD-DISK', 'active' => false], + 42241 => ['name' => 'FREEBSD-BOOT', 'active' => true], + 42242 => ['name' => 'FREEBSD-SWAP', 'active' => false], + 42243 => ['name' => 'FREEBSD', 'active' => true], + 42244 => ['name' => 'FREEBSD', 'active' => true], + 43265 => ['name' => 'NETBSD-SWAP', 'active' => false], + 43266 => ['name' => 'NETBSD', 'active' => true], + 43267 => ['name' => 'NETBSD', 'active' => true], + 43268 => ['name' => 'NETBSD', 'active' => true], + 43269 => ['name' => 'NETBSD', 'active' => true], + 43270 => ['name' => 'NETBSD-RAID', 'active' => true], + 43776 => ['name' => 'HFS-BOOT', 'active' => true], + 44800 => ['name' => 'HFS', 'active' => true], + 44801 => ['name' => 'HFS-RAID', 'active' => true], + 44802 => ['name' => 'HFS-RAID', 'active' => true], + 48640 => ['name' => 'SOLARIS-BOOT', 'active' => true], + 48896 => ['name' => 'SOLARIS', 'active' => true], + 48897 => ['name' => 'SOLARIS', 'active' => true], + 48898 => ['name' => 'SOLARIS-SWAP', 'active' => false], + 48899 => ['name' => 'SOLARIS-DISK', 'active' => true], + 48900 => ['name' => 'SOLARIS', 'active' => true], + 48901 => ['name' => 'SOLARIS', 'active' => true], + 51712 => ['name' => 'CACHE', 'active' => false], + 61184 => ['name' => 'EFI', 'active' => true], + 61185 => ['name' => 'MBR', 'active' => false], + 61186 => ['name' => 'BIOS-BOOT', 'active' => false], + 64256 => ['name' => 'VMFS', 'active' => true], + 64257 => ['name' => 'VMFS-RESERV', 'active' => true], + 64258 => ['name' => 'VMFS-KRN', 'active' => true], + 64768 => ['name' => 'LINUX-RAID', 'active' => true], + 65535 => ['name' => 'UNKNOWN', 'active' => true], + 65536 => ['name' => 'LVM-LV', 'active' => true], + 65552 => ['name' => 'ZFS-VOL', 'active' => true], + 39 => ['name' => 'HNTFS-WINRE', 'active' => true], + ]; + + public static function getPartitionTypes(): array + { + return self::PARTITION_TYPES; + } + + public static function getPartitionType(int $code): ?array + { + return self::PARTITION_TYPES[$code] ?? null; + } + + public static function getPartitionKeys(): array + { + return array_keys(self::PARTITION_TYPES); + } +} diff --git a/src/Repository/AbstractRepository.php b/src/Repository/AbstractRepository.php index 2eb3b12..8e5431c 100644 --- a/src/Repository/AbstractRepository.php +++ b/src/Repository/AbstractRepository.php @@ -32,4 +32,4 @@ abstract class AbstractRepository extends ServiceEntityRepository $this->getEntityManager()->flush(); } } -} \ No newline at end of file +} diff --git a/src/Repository/PartitionRepository.php b/src/Repository/PartitionRepository.php index e4964b3..39b6d46 100644 --- a/src/Repository/PartitionRepository.php +++ b/src/Repository/PartitionRepository.php @@ -3,11 +3,10 @@ namespace App\Repository; use App\Entity\Partition; -use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository; use Doctrine\Persistence\ManagerRegistry; /** - * @extends ServiceEntityRepository + * @extends AbstractRepository */ class PartitionRepository extends AbstractRepository { diff --git a/src/Service/CreatePartitionService.php b/src/Service/CreatePartitionService.php index f95ff01..77cd2b4 100644 --- a/src/Service/CreatePartitionService.php +++ b/src/Service/CreatePartitionService.php @@ -5,6 +5,7 @@ namespace App\Service; use App\Entity\Client; use App\Entity\OperativeSystem; use App\Entity\Partition; +use App\Model\PartitionTypes; use Doctrine\ORM\EntityManagerInterface; class CreatePartitionService @@ -17,6 +18,11 @@ class CreatePartitionService public function __invoke(array $data, Client $clientEntity): void { + $currentPartitions = $this->entityManager->getRepository(Partition::class) + ->findBy(['client' => $clientEntity]); + + $receivedPartitions = []; + foreach ($data['cfg'] as $cfg) { if (!isset($cfg['disk'], $cfg['par'], $cfg['tam'], $cfg['uso'], $cfg['fsi'])) { continue; @@ -45,9 +51,34 @@ class CreatePartitionService $partitionEntity->setDiskNumber($cfg['disk']); $partitionEntity->setPartitionNumber($cfg['par']); $partitionEntity->setSize($cfg['tam']); + + if (isset($cfg['cpt']) && $cfg['fsi'] !== '') { + $partitionEntity->setPartitionCode(PartitionTypes::getPartitionType(hexdec((integer)$cfg['cpt']))['name']); + } else { + $partitionEntity->setPartitionCode(PartitionTypes::getPartitionType(0)['name']); + } + $partitionEntity->setFilesystem($cfg['fsi']); $partitionEntity->setMemoryUsage(((int) $cfg['uso']) * 100); $this->entityManager->persist($partitionEntity); + + $receivedPartitions[] = ['disk' => $cfg['disk'], 'partition' => $cfg['par']]; + } + + foreach ($currentPartitions as $currentPartition) { + $exists = false; + + foreach ($receivedPartitions as $receivedPartition) { + if ($currentPartition->getDiskNumber() == $receivedPartition['disk'] && + $currentPartition->getPartitionNumber() == $receivedPartition['partition']) { + $exists = true; + break; + } + } + + if (!$exists) { + $this->entityManager->remove($currentPartition); + } } $this->entityManager->flush(); diff --git a/src/State/Processor/PartitionProcessor.php b/src/State/Processor/PartitionProcessor.php index f17affc..00e67a5 100644 --- a/src/State/Processor/PartitionProcessor.php +++ b/src/State/Processor/PartitionProcessor.php @@ -9,8 +9,10 @@ use ApiPlatform\Metadata\Post; use ApiPlatform\Metadata\Put; use ApiPlatform\State\ProcessorInterface; use ApiPlatform\Validator\ValidatorInterface; +use App\Controller\OgAgent\PartitionAssistantAction; use App\Dto\Input\MenuInput; use App\Dto\Input\PartitionInput; +use App\Dto\Input\PartitionPostInput; use App\Dto\Input\UserGroupInput; use App\Dto\Output\MenuOutput; use App\Dto\Output\PartitionOutput; @@ -18,12 +20,15 @@ use App\Dto\Output\UserGroupOutput; use App\Repository\MenuRepository; use App\Repository\PartitionRepository; use App\Repository\UserGroupRepository; +use Symfony\Component\HttpFoundation\JsonResponse; +use Symfony\Component\HttpFoundation\Response; readonly class PartitionProcessor implements ProcessorInterface { public function __construct( - private PartitionRepository $partitionRepository, - private ValidatorInterface $validator + private PartitionRepository $partitionRepository, + private ValidatorInterface $validator, + private PartitionAssistantAction $partitionAssistantAction ) { } @@ -31,7 +36,7 @@ readonly class PartitionProcessor implements ProcessorInterface /** * @throws \Exception */ - public function process(mixed $data, Operation $operation, array $uriVariables = [], array $context = []): PartitionOutput|null + public function process(mixed $data, Operation $operation, array $uriVariables = [], array $context = []): JsonResponse { switch ($operation){ case $operation instanceof Post: @@ -46,22 +51,32 @@ readonly class PartitionProcessor implements ProcessorInterface /** * @throws \Exception */ - private function processCreateOrUpdate($data, Operation $operation, array $uriVariables = [], array $context = []): PartitionOutput + private function processCreateOrUpdate($data, Operation $operation, array $uriVariables = [], array $context = []): JsonResponse { - if (!($data instanceof PartitionInput)) { - throw new \Exception(sprintf('data is not instance of %s', PartitionInput::class)); + if (!($data instanceof PartitionPostInput)) { + throw new \Exception(sprintf('data is not instance of %s', PartitionPostInput::class)); } - $entity = null; - if (isset($uriVariables['uuid'])) { - $entity = $this->partitionRepository->findOneByUuid($uriVariables['uuid']); + foreach ($data->partitions as $partition) { + $entity = null; + if (isset($partition->uuid)) { + $entity = $this->partitionRepository->findOneByUuid($partition->uuid); + + if ($partition->removed && $entity) { + $this->partitionRepository->delete($entity); + continue; + } + } + + $entity = $partition->createOrUpdateEntity($entity); + $this->validator->validate($entity); + + //$this->partitionRepository->save($entity); } - $partition = $data->createOrUpdateEntity($entity); - $this->validator->validate($partition); - $this->partitionRepository->save($partition); + $this->partitionAssistantAction->__invoke($data); - return new PartitionOutput($partition); + return new JsonResponse('OK', Response::HTTP_NO_CONTENT); } private function processDelete($data, Operation $operation, array $uriVariables = [], array $context = []): null diff --git a/tests/Functional/PartitionTest.php b/tests/Functional/PartitionTest.php index e587484..859bba0 100644 --- a/tests/Functional/PartitionTest.php +++ b/tests/Functional/PartitionTest.php @@ -54,72 +54,4 @@ class PartitionTest extends AbstractTest 'hydra:totalItems' => 10, ]); } - - /** - * @throws RedirectionExceptionInterface - * @throws DecodingExceptionInterface - * @throws ClientExceptionInterface - * @throws TransportExceptionInterface - * @throws ServerExceptionInterface - */ - public function testCreatePartition(): void - { - UserFactory::createOne(['username' => self::USER_ADMIN, 'roles'=> [UserGroupPermissions::ROLE_SUPER_ADMIN]]); - - $ou = OrganizationalUnitFactory::createOne(['type' => OrganizationalUnitTypes::ORGANIZATIONAL_UNIT]); - $hp = HardwareProfileFactory::createOne(['description' => self::HW_PROFILE]); - - ClientFactory::createOne(['name' => self::CLIENT_CREATE, 'serialNumber' => '123abc', 'organizationalUnit' => $ou, 'hardwareProfile' => $hp]); - $iri = $this->findIriBy(Client::class, ['name' => self::CLIENT_CREATE]); - - OperativeSystemFactory::createOne(['name' => 'Ubuntu']); - $osIri = $this->findIriBy(OperativeSystem::class, ['name' => 'Ubuntu']); - - ImageFactory::createOne(['name' => 'Image 1']); - $imageIri = $this->findIriBy(Image::class, ['name' => 'Image 1']); - - $this->createClientWithCredentials()->request('POST', '/partitions',['json' => [ - 'size' => 100, - 'operativeSystem' => $osIri, - 'image' => $imageIri, - 'client' => $iri, - 'memoryUsage' => 100 - ]]); - - $this->assertResponseStatusCodeSame(201); - $this->assertResponseHeaderSame('content-type', 'application/ld+json; charset=utf-8'); - $this->assertJsonContains([ - '@context' => '/contexts/PartitionOutput', - '@type' => 'Partition', - 'size' => 100, - 'memoryUsage' => 100 - ]); - } - - /** - * @throws RedirectionExceptionInterface - * @throws DecodingExceptionInterface - * @throws ClientExceptionInterface - * @throws TransportExceptionInterface - * @throws ServerExceptionInterface - */ - public function testUpdatePartition(): void - { - UserFactory::createOne(['username' => self::USER_ADMIN, 'roles'=> [UserGroupPermissions::ROLE_SUPER_ADMIN]]); - - PartitionFactory::createOne(['size' => 100, 'memoryUsage' => 100]); - $iri = $this->findIriBy(Partition::class, ['size' => 100, 'memoryUsage' => 100]); - - $this->createClientWithCredentials()->request('PUT', $iri, ['json' => [ - 'size' => 200, - 'memoryUsage' => 300 - ]]); - - $this->assertResponseIsSuccessful(); - $this->assertJsonContains([ - '@id' => $iri, - 'size' => 200, - 'memoryUsage' => 300 - ]); - } } \ No newline at end of file