refs #1472. Changes in images and imageRepo
testing/ogcore-api/pipeline/head This commit looks good Details

hotfix-timeout
Manuel Aranda Rosales 2025-02-12 17:14:39 +01:00
parent 28914fd7de
commit 7ff5c87884
42 changed files with 947 additions and 369 deletions

View File

@ -27,67 +27,6 @@ resources:
ApiPlatform\Metadata\Post: ~
ApiPlatform\Metadata\Delete: ~
get_image_ogrepository:
shortName: OgRepository Server
description: Get image in OgRepository
class: ApiPlatform\Metadata\Get
method: GET
input: false
uriTemplate: /images/server/{uuid}/get
controller: App\Controller\OgRepository\Image\GetAction
create_aux_files_image_ogrepository:
shortName: OgRepository Server
class: ApiPlatform\Metadata\Post
method: POST
input: false
uriTemplate: /images/server/{uuid}/create-aux-files
controller: App\Controller\OgRepository\Image\CreateAuxFilesAction
deploy_image_ogrepository:
shortName: OgRepository Server
class: ApiPlatform\Metadata\Post
method: POST
input: App\Dto\Input\DeployImageInput
uriTemplate: /images/{uuid}/deploy-image
controller: App\Controller\DeployImageAction
trash_delete_image_ogrepository:
shortName: OgRepository Server
description: Delete Image in OgRepository
class: ApiPlatform\Metadata\Post
method: POST
input: false
uriTemplate: /images/server/{uuid}/delete-trash
controller: App\Controller\OgRepository\Image\DeleteTrashAction
permanent_delete_image_ogrepository:
shortName: OgRepository Server
description: Delete Image in OgRepository
class: ApiPlatform\Metadata\Post
method: POST
input: false
uriTemplate: /images/server/{uuid}/delete-permanent
controller: App\Controller\OgRepository\Image\DeletePermanentAction
recover_image_ogrepository:
shortName: OgRepository Server
description: Recover Image in OgRepository
class: ApiPlatform\Metadata\Post
method: POST
input: false
uriTemplate: /images/server/{uuid}/recover
controller: App\Controller\OgRepository\Image\RecoverAction
transfer_image_ogrepository:
shortName: OgRepository Server
description: Export Image in OgRepository
class: ApiPlatform\Metadata\Post
method: POST
input: App\Dto\Input\ExportImportImageRepositoryInput
uriTemplate: /images/{uuid}/transfer-image
controller: App\Controller\OgRepository\Image\TransferAction
properties:
App\Entity\Image:
id:

View File

@ -0,0 +1,92 @@
resources:
App\Entity\ImageImageRepository:
processor: App\State\Processor\ImageImageRepositoryProcessor
input: App\Dto\Input\ImageImageRepositoryInput
output: App\Dto\Output\ImageImageRepositoryOutput
normalizationContext:
groups: ['default', 'image-image-repository:read']
denormalizationContext:
groups: ['image-image-repository:write']
operations:
ApiPlatform\Metadata\GetCollection:
provider: App\State\Provider\ImageImageRepositoryProvider
filters:
- 'api_platform.filter.image_image_repository.order'
- 'api_platform.filter.image_image_repository.search'
ApiPlatform\Metadata\Get:
provider: App\State\Provider\ImageImageRepositoryProvider
ApiPlatform\Metadata\Put:
provider: App\State\Provider\ImageImageRepositoryProvider
ApiPlatform\Metadata\Patch:
provider: App\State\Provider\ImageImageRepositoryProvider
ApiPlatform\Metadata\Post: ~
ApiPlatform\Metadata\Delete: ~
get_image_ogrepository:
shortName: OgRepository Server
description: Get image in OgRepository
class: ApiPlatform\Metadata\Get
method: GET
input: false
uriTemplate: /image-image-repositories/server/{uuid}/get
controller: App\Controller\OgRepository\Image\GetAction
create_aux_files_image_ogrepository:
shortName: OgRepository Server
class: ApiPlatform\Metadata\Post
method: POST
input: false
uriTemplate: /image-image-repositories/server/{uuid}/create-aux-files
controller: App\Controller\OgRepository\Image\CreateAuxFilesAction
deploy_image_ogrepository:
shortName: OgRepository Server
class: ApiPlatform\Metadata\Post
method: POST
input: App\Dto\Input\DeployImageInput
uriTemplate: /image-image-repositories/{uuid}/deploy-image
controller: App\Controller\DeployImageAction
trash_delete_image_ogrepository:
shortName: OgRepository Server
description: Delete Image in OgRepository
class: ApiPlatform\Metadata\Post
method: POST
input: false
uriTemplate: /image-image-repositories/server/{uuid}/delete-trash
controller: App\Controller\OgRepository\Image\DeleteTrashAction
permanent_delete_image_ogrepository:
shortName: OgRepository Server
description: Delete Image in OgRepository
class: ApiPlatform\Metadata\Post
method: POST
input: false
uriTemplate: /image-image-repositories/server/{uuid}/delete-permanent
controller: App\Controller\OgRepository\Image\DeletePermanentAction
recover_image_ogrepository:
shortName: OgRepository Server
description: Recover Image in OgRepository
class: ApiPlatform\Metadata\Post
method: POST
input: false
uriTemplate: /image-image-repositories/server/{uuid}/recover
controller: App\Controller\OgRepository\Image\RecoverAction
transfer_image_ogrepository:
shortName: OgRepository Server
description: Export Image in OgRepository
class: ApiPlatform\Metadata\Post
method: POST
input: App\Dto\Input\ExportImportImageRepositoryInput
uriTemplate: /image-image-repositories/{uuid}/transfer-image
controller: App\Controller\OgRepository\Image\TransferAction
properties:
App\Entity\ImageImageRepository:
id:
identifier: false
uuid:
identifier: true

View File

@ -151,3 +151,8 @@ services:
bind:
$collectionProvider: '@api_platform.doctrine.orm.state.collection_provider'
$itemProvider: '@api_platform.doctrine.orm.state.item_provider'
App\State\Provider\ImageImageRepositoryProvider:
bind:
$collectionProvider: '@api_platform.doctrine.orm.state.collection_provider'
$itemProvider: '@api_platform.doctrine.orm.state.item_provider'

View File

@ -191,7 +191,19 @@ services:
api_platform.filter.repository.search:
parent: 'api_platform.doctrine.orm.search_filter'
arguments: [ { 'id': 'exact', 'name': 'partial'} ]
arguments: [ { 'id': 'exact', 'name': 'partial', 'ip': 'partial', 'status': 'exact'} ]
tags: [ 'api_platform.filter' ]
api_platform.filter.image_image_repository.order:
parent: 'api_platform.doctrine.orm.order_filter'
arguments:
$properties: { 'id': ~, 'name': ~ }
$orderParameterName: 'order'
tags: [ 'api_platform.filter' ]
api_platform.filter.image_image_repository.search:
parent: 'api_platform.doctrine.orm.search_filter'
arguments: [ { 'id': 'exact', 'name': 'partial', 'ip': 'partial', 'status': 'exact', 'repository.id': 'exact'} ]
tags: [ 'api_platform.filter' ]
repository.not_equal_filter:

View File

@ -0,0 +1,35 @@
<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20250211073126 extends AbstractMigration
{
public function getDescription(): string
{
return '';
}
public function up(Schema $schema): void
{
// this up() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE image_image_repository DROP FOREIGN KEY FK_B785133714C736FC');
$this->addSql('ALTER TABLE image_image_repository DROP FOREIGN KEY FK_B78513373DA5256D');
$this->addSql('DROP TABLE image_image_repository');
}
public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('CREATE TABLE image_image_repository (image_id INT NOT NULL, image_repository_id INT NOT NULL, INDEX IDX_B78513373DA5256D (image_id), INDEX IDX_B785133714C736FC (image_repository_id), PRIMARY KEY(image_id, image_repository_id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB COMMENT = \'\' ');
$this->addSql('ALTER TABLE image_image_repository ADD CONSTRAINT FK_B785133714C736FC FOREIGN KEY (image_repository_id) REFERENCES image_repository (id) ON DELETE CASCADE');
$this->addSql('ALTER TABLE image_image_repository ADD CONSTRAINT FK_B78513373DA5256D FOREIGN KEY (image_id) REFERENCES image (id) ON DELETE CASCADE');
}
}

View File

@ -0,0 +1,35 @@
<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20250211073801 extends AbstractMigration
{
public function getDescription(): string
{
return '';
}
public function up(Schema $schema): void
{
// this up() migration is auto-generated, please modify it to your needs
$this->addSql('CREATE TABLE image_image_repository (id INT AUTO_INCREMENT NOT NULL, image_id INT DEFAULT NULL, repository_id INT NOT NULL, uuid CHAR(36) NOT NULL COMMENT \'(DC2Type:uuid)\', migration_id VARCHAR(255) DEFAULT NULL, created_at DATETIME NOT NULL, updated_at DATETIME NOT NULL, created_by VARCHAR(255) DEFAULT NULL, updated_by VARCHAR(255) DEFAULT NULL, status VARCHAR(255) NOT NULL, UNIQUE INDEX UNIQ_B7851337D17F50A6 (uuid), INDEX IDX_B78513373DA5256D (image_id), INDEX IDX_B785133750C9D4F7 (repository_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB');
$this->addSql('ALTER TABLE image_image_repository ADD CONSTRAINT FK_B78513373DA5256D FOREIGN KEY (image_id) REFERENCES image (id)');
$this->addSql('ALTER TABLE image_image_repository ADD CONSTRAINT FK_B785133750C9D4F7 FOREIGN KEY (repository_id) REFERENCES image_repository (id)');
}
public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE image_image_repository DROP FOREIGN KEY FK_B78513373DA5256D');
$this->addSql('ALTER TABLE image_image_repository DROP FOREIGN KEY FK_B785133750C9D4F7');
$this->addSql('DROP TABLE image_image_repository');
}
}

View File

@ -0,0 +1,33 @@
<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20250211081319 extends AbstractMigration
{
public function getDescription(): string
{
return '';
}
public function up(Schema $schema): void
{
// this up() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE image_image_repository DROP FOREIGN KEY FK_B785133750C9D4F7');
$this->addSql('ALTER TABLE image_image_repository ADD CONSTRAINT FK_B785133750C9D4F7 FOREIGN KEY (repository_id) REFERENCES image_image_repository (id)');
}
public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE image_image_repository DROP FOREIGN KEY FK_B785133750C9D4F7');
$this->addSql('ALTER TABLE image_image_repository ADD CONSTRAINT FK_B785133750C9D4F7 FOREIGN KEY (repository_id) REFERENCES image_repository (id)');
}
}

View File

@ -0,0 +1,33 @@
<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20250211081406 extends AbstractMigration
{
public function getDescription(): string
{
return '';
}
public function up(Schema $schema): void
{
// this up() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE image_image_repository DROP FOREIGN KEY FK_B785133750C9D4F7');
$this->addSql('ALTER TABLE image_image_repository ADD CONSTRAINT FK_B785133750C9D4F7 FOREIGN KEY (repository_id) REFERENCES image_repository (id)');
}
public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE image_image_repository DROP FOREIGN KEY FK_B785133750C9D4F7');
$this->addSql('ALTER TABLE image_image_repository ADD CONSTRAINT FK_B785133750C9D4F7 FOREIGN KEY (repository_id) REFERENCES image_image_repository (id)');
}
}

View File

@ -0,0 +1,31 @@
<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20250211103630 extends AbstractMigration
{
public function getDescription(): string
{
return '';
}
public function up(Schema $schema): void
{
// this up() migration is auto-generated, please modify it to your needs
$this->addSql('CREATE UNIQUE INDEX UNIQ_IDENTIFIER_IMAGE_REPOSITORY ON image_image_repository (image_id, repository_id)');
}
public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('DROP INDEX UNIQ_IDENTIFIER_IMAGE_REPOSITORY ON image_image_repository');
}
}

View File

@ -0,0 +1,31 @@
<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20250211105319 extends AbstractMigration
{
public function getDescription(): string
{
return '';
}
public function up(Schema $schema): void
{
// this up() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE image_image_repository CHANGE image_id image_id INT NOT NULL');
}
public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE image_image_repository CHANGE image_id image_id INT DEFAULT NULL');
}
}

View File

@ -0,0 +1,31 @@
<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20250211162339 extends AbstractMigration
{
public function getDescription(): string
{
return '';
}
public function up(Schema $schema): void
{
// this up() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE image DROP path, DROP type, DROP revision, DROP info, DROP size, DROP status');
}
public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE image ADD path VARCHAR(255) DEFAULT NULL, ADD type VARCHAR(255) DEFAULT NULL, ADD revision VARCHAR(255) DEFAULT NULL, ADD info VARCHAR(255) DEFAULT NULL, ADD size INT DEFAULT NULL, ADD status VARCHAR(255) NOT NULL');
}
}

View File

@ -0,0 +1,33 @@
<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20250211164155 extends AbstractMigration
{
public function getDescription(): string
{
return '';
}
public function up(Schema $schema): void
{
// this up() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE image DROP created, DROP image_fullsum');
$this->addSql('ALTER TABLE image_image_repository ADD created TINYINT(1) DEFAULT NULL, ADD image_fullsum 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 image_image_repository DROP created, DROP image_fullsum');
$this->addSql('ALTER TABLE image ADD created TINYINT(1) DEFAULT NULL, ADD image_fullsum VARCHAR(255) DEFAULT NULL');
}
}

View File

@ -8,6 +8,7 @@ use ApiPlatform\Validator\ValidatorInterface;
use App\Dto\Input\DeployImageInput;
use App\Entity\Command;
use App\Entity\Image;
use App\Entity\ImageImageRepository;
use App\Entity\OrganizationalUnit;
use App\Entity\Partition;
use App\Model\CommandTypes;
@ -42,7 +43,7 @@ class DeployImageAction extends AbstractController
* @throws ClientExceptionInterface
* @throws ServerExceptionInterface
*/
public function __invoke(DeployImageInput $input, Image $image): JsonResponse
public function __invoke(DeployImageInput $input, ImageImageRepository $image): JsonResponse
{
$this->validator->validate($input);
@ -68,7 +69,6 @@ class DeployImageAction extends AbstractController
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,

View File

@ -7,6 +7,7 @@ namespace App\Controller\OgAgent;
use App\Entity\Client;
use App\Entity\Command;
use App\Entity\Image;
use App\Entity\ImageImageRepository;
use App\Entity\Trace;
use App\Model\ClientStatus;
use App\Model\CommandTypes;
@ -55,11 +56,18 @@ class CreateImageAction extends AbstractController
$repository = $image->getClient()->getRepository();
$imageImageRepository = new ImageImageRepository();
$imageImageRepository->setImage($image);
$imageImageRepository->setRepository($repository);
$imageImageRepository->setStatus(ImageStatus::IN_PROGRESS);
$this->entityManager->persist($imageImageRepository);
$data = [
'dsk' => (string) $partitionInfo['numDisk'],
'par' => (string) $partitionInfo['numPartition'],
'cpt' => null,
'idi' => $image->getUuid(),
'idi' => $imageImageRepository->getUuid(),
'nci' => $image->getName(),
'ipr' => $repository->getIp(),
'nfn' => 'CrearImagen',
@ -102,9 +110,6 @@ class CreateImageAction extends AbstractController
$jobId = json_decode($response->getContent(), true)['job_id'];
$image->setStatus(ImageStatus::IN_PROGRESS);
$this->entityManager->persist($image);
$client = $image->getClient();
$client->setStatus(ClientStatus::BUSY);
$this->entityManager->persist($client);

View File

@ -8,6 +8,7 @@ use App\Dto\Input\DeployImageInput;
use App\Entity\Client;
use App\Entity\Command;
use App\Entity\Image;
use App\Entity\ImageImageRepository;
use App\Entity\Partition;
use App\Entity\Trace;
use App\Model\ClientStatus;
@ -38,8 +39,10 @@ class DeployImageAction extends AbstractController
{
}
public function __invoke(Image $image, DeployImageInput $input, Client $client, string $method)
public function __invoke(ImageImageRepository $imageImageRepository, DeployImageInput $input, Client $client, string $method)
{
$image = $imageImageRepository->getImage();
if (!$image->getClient()->getIp()) {
throw new ValidatorException('IP is required');
}
@ -69,7 +72,7 @@ class DeployImageAction extends AbstractController
default => throw new ValidatorException('Invalid method'),
};
$repository = $client->getRepository();
$repository = $imageImageRepository->getRepository();
$data = [
'dsk' => (string) $input->diskNumber,

View File

@ -4,6 +4,7 @@ namespace App\Controller\OgAgent\Webhook;
use App\Controller\OgRepository\Image\CreateAuxFilesAction;
use App\Entity\Image;
use App\Entity\ImageImageRepository;
use App\Entity\OperativeSystem;
use App\Entity\Partition;
use App\Entity\Software;
@ -65,9 +66,10 @@ class ClientsController extends AbstractController
if ($data['nfn'] === 'RESPUESTA_CrearImagen') {
$trace = $this->entityManager->getRepository(Trace::class)->findOneBy(['jobId' => $data['job_id']]);
$image = $this->entityManager->getRepository(Image::class)->findOneBy(['uuid' => $data['idi']]);
/** @var ImageImageRepository $imageImageRepository */
$imageImageRepository = $this->entityManager->getRepository(ImageImageRepository::class)->findOneBy(['uuid' => $data['idi']]);
if (!$image) {
if (!$imageImageRepository) {
$this->logger->error('Image not found', $data);
return new JsonResponse(['message' => 'Image not found'], Response::HTTP_NOT_FOUND);
}
@ -80,37 +82,41 @@ class ClientsController extends AbstractController
if ($data['res'] === 1) {
$trace->setStatus(TraceStatus::SUCCESS);
$trace->setFinishedAt(new \DateTime());
$image->setStatus(ImageStatus::AUX_FILES_PENDING);
$image->setCreated(true);
$this->logger->info('Start partition creation. ', ['image' => (string) $image->getUuid()]);
$imageImageRepository->setStatus(ImageStatus::AUX_FILES_PENDING);
$imageImageRepository->setCreated(true);
$this->entityManager->persist($imageImageRepository);
$this->logger->info('Start partition creation. ', ['image' => (string) $imageImageRepository->getUuid()]);
if (isset($data['cfg'])) {
$this->createPartitionService->__invoke($data, $image->getClient());
$this->createPartitionService->__invoke($data, $imageImageRepository->getImage()->getClient());
}
$this->logger->info('Starting software profile creation. ', ['image' => (string) $image->getUuid()]);
$this->createSoftwareProfile($data['inv_sft'], $image);
$this->logger->info('Start aux files ogrepo API ', ['image' => (string) $image->getUuid()]);
$this->logger->info('Starting software profile creation. ', ['image' => (string) $imageImageRepository->getUuid()]);
$this->createSoftwareProfile($data['inv_sft'], $imageImageRepository);
$this->logger->info('Start aux files ogrepo API ', ['image' => (string) $imageImageRepository->getUuid()]);
try {
$this->createAuxFilesAction->__invoke($image);
$this->createAuxFilesAction->__invoke($imageImageRepository);
} catch (\Exception $e) {
$this->logger->error('Error creating aux files', ['image' => (string) $image->getUuid(), 'error' => $e->getMessage()]);
$this->logger->error('Error creating aux files', ['image' => (string) $imageImageRepository->getUuid(), 'error' => $e->getMessage()]);
}
$this->logger->info('End aux files ogrepo API ', ['image' => (string) $image->getUuid()]);
$this->logger->info('End aux files ogrepo API ', ['image' => (string) $imageImageRepository->getUuid()]);
} else {
$trace->setStatus(TraceStatus::FAILED);
$trace->setFinishedAt(new \DateTime());
$trace->setOutput($data['der']);
$image->setCreated(false);
$image->setStatus(ImageStatus::FAILED);
$imageImageRepository->setCreated(false);
$imageImageRepository->setStatus(ImageStatus::FAILED);
$this->logger->error('Image updated failed', $data);
}
$this->entityManager->persist($image);
$this->entityManager->persist($imageImageRepository);
$client = $trace->getClient();
$client->setStatus(ClientStatus::OG_LIVE);
$this->entityManager->persist($client);
$this->entityManager->persist($trace);
$this->entityManager->flush();
$this->logger->info('Image updated. Success.', ['image' => (string) $image->getUuid()]);
$this->logger->info('Image updated. Success.', ['image' => (string) $imageImageRepository->getUuid()]);
}
if ($data['nfn'] === 'RESPUESTA_RestaurarImagen'|| $data['nfn'] === 'RESPUESTA_Configurar') {
@ -139,7 +145,7 @@ class ClientsController extends AbstractController
return new JsonResponse(data: 'Webhook finished', status: Response::HTTP_OK);
}
public function createSoftwareProfile(string $base64Data, Image $image): void
public function createSoftwareProfile(string $base64Data, ImageImageRepository $imageImageRepository): void
{
$decodedData = base64_decode($base64Data);
$this->logger->info('Software profile decoded', ['data' => '']);
@ -156,6 +162,8 @@ class ClientsController extends AbstractController
$this->entityManager->persist($softwareEntity);
}
$image = $imageImageRepository->getImage();
$softwareProfile = new SoftwareProfile();
$softwareProfile->setDescription('Perfil software: ' . $image->getClient()->getName());
$softwareProfile->setOrganizationalUnit($image->getClient()->getOrganizationalUnit());
@ -167,6 +175,7 @@ class ClientsController extends AbstractController
$image->setSoftwareProfile($softwareProfile);
$this->entityManager->persist($image);
$this->entityManager->persist($imageImageRepository);
$this->entityManager->persist($softwareProfile);
$this->entityManager->flush();
}

View File

@ -5,6 +5,7 @@ namespace App\Controller\OgRepository\Image;
use App\Controller\OgRepository\AbstractOgRepositoryController;
use App\Entity\Command;
use App\Entity\Image;
use App\Entity\ImageImageRepository;
use App\Model\CommandTypes;
use App\Model\ImageStatus;
use App\Model\TraceStatus;
@ -28,34 +29,36 @@ class CreateAuxFilesAction extends AbstractOgRepositoryController
* @throws RedirectionExceptionInterface
* @throws ClientExceptionInterface
*/
public function __invoke(Image $data): JsonResponse
public function __invoke(ImageImageRepository $data): JsonResponse
{
if (!$data->getName()) {
$image = $data->getImage();
if (!$image->getName()) {
throw new ValidatorException('Name is required');
}
$params = [
'json' => [
'image' => $data->getName().'.img'
'image' => $image->getName().'.img'
]
];
$this->logger->info('Creating aux files', ['image' => $data->getName()]);
$this->logger->info('Creating aux files', ['image' => $image->getName()]);
$repository = $data->getClient()->getRepository();
$repository = $image->getClient()->getRepository();
$content = $this->createRequest('POST', 'http://'.$repository->getIp().':8006/ogrepository/v1/images/torrentsum', $params);
$inputData = [
'imageName' => $data->getName(),
'imageName' => $image->getName(),
'imageUuid' => $data->getUuid(),
];
$this->createService->__invoke($data->getClient(), CommandTypes::CREATE_IMAGE_AUX_FILE, TraceStatus::IN_PROGRESS, $content['job_id'], $inputData);
$this->createService->__invoke($image->getClient(), CommandTypes::CREATE_IMAGE_AUX_FILE, TraceStatus::IN_PROGRESS, $content['job_id'], $inputData);
$this->logger->info('Aux files created successfully', ['image' => $data->getName()]);
$this->logger->info('Aux files created successfully', ['image' => $image->getName()]);
$data->setStatus(ImageStatus::IN_PROGRESS);
$data->setStatus(ImageStatus::AUX_FILES_PENDING);
$this->entityManager->persist($data);
$this->entityManager->flush();

View File

@ -4,6 +4,7 @@ namespace App\Controller\OgRepository\Image;
use App\Controller\OgRepository\AbstractOgRepositoryController;
use App\Entity\Image;
use App\Entity\ImageImageRepository;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Attribute\AsController;
@ -23,19 +24,21 @@ class DeletePermanentAction extends AbstractOgRepositoryController
* @throws RedirectionExceptionInterface
* @throws ClientExceptionInterface
*/
public function __invoke(Image $data, HttpClientInterface $httpClient): JsonResponse
public function __invoke(ImageImageRepository $data, HttpClientInterface $httpClient): JsonResponse
{
if (!$data->getImageFullsum()) {
throw new ValidatorException('Fullsum is required');
}
$this->logger->info('Deleting image', ['image' => $data->getName()]);
$image = $data->getImage();
$repository = $data->getClient()->getRepository();
$this->logger->info('Deleting image', ['image' => $image->getName()]);
$repository = $image->getClient()->getRepository();
$content = $this->createRequest( 'DELETE', 'http://'.$repository->getIp().':8006/ogrepository/v1/images/'.$data->getImageFullsum().'?method=permanent');
$this->logger->info('Image deleted', ['image' => $data->getName()]);
$this->logger->info('Image deleted', ['image' => $image->getName()]);
$this->entityManager->remove($data);
$this->entityManager->flush();

View File

@ -3,7 +3,10 @@
namespace App\Controller\OgRepository\Image;
use App\Controller\OgRepository\AbstractOgRepositoryController;
use App\Dto\Input\DeleteImageInput;
use App\Entity\Image;
use App\Entity\ImageImageRepository;
use App\Entity\ImageRepository;
use App\Model\ImageStatus;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
@ -13,7 +16,6 @@ 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;
#[AsController]
class DeleteTrashAction extends AbstractOgRepositoryController
@ -24,22 +26,25 @@ class DeleteTrashAction extends AbstractOgRepositoryController
* @throws RedirectionExceptionInterface
* @throws ClientExceptionInterface
*/
public function __invoke(Image $data, HttpClientInterface $httpClient): JsonResponse
public function __invoke(ImageImageRepository $imageImageRepository): JsonResponse
{
if (!$data->getImageFullsum()) {
$repository = $imageImageRepository->getRepository();
$image = $imageImageRepository->getImage();
if (!$imageImageRepository->getImageFullsum()) {
throw new ValidatorException('Fullsum is required');
}
$this->logger->info('Deleting image', ['image' => $data->getName()]);
$this->logger->info('Deleting image', ['image' => $image->getName()]);
$repository = $data->getClient()->getRepository();
$repository = $image->getClient()->getRepository();
$content = $this->createRequest('DELETE', 'http://'.$repository->getIp().':8006/ogrepository/v1/images/'.$data->getImageFullsum().'?method=trash');
$content = $this->createRequest('DELETE', 'http://'.$repository->getIp().':8006/ogrepository/v1/images/'.$imageImageRepository->getImageFullsum().'?method=trash');
$this->logger->info('Image deleted', ['image' => $data->getName()]);
$this->logger->info('Image deleted', ['image' => $image->getName()]);
$data->setStatus(ImageStatus::TRASH);
$this->entityManager->persist($data);
$imageImageRepository->setStatus(ImageStatus::TRASH);
$this->entityManager->persist($image);
$this->entityManager->flush();
return new JsonResponse(data: $content, status: Response::HTTP_OK);

View File

@ -7,6 +7,7 @@ use App\Dto\Input\DeployImageInput;
use App\Entity\Client;
use App\Entity\Command;
use App\Entity\Image;
use App\Entity\ImageImageRepository;
use App\Model\CommandTypes;
use App\Model\DeployImageTypes;
use App\Model\DeployMethodTypes;
@ -29,7 +30,7 @@ class DeployImageAction extends AbstractOgRepositoryController
* @throws ClientExceptionInterface
* @throws TransportExceptionInterface
*/
public function __invoke(DeployImageInput $input, Image $data, Client $client, HttpClientInterface $httpClient): JsonResponse
public function __invoke(DeployImageInput $input, ImageImageRepository $data, Client $client, HttpClientInterface $httpClient): JsonResponse
{
$params = [
'json' => [

View File

@ -4,6 +4,7 @@ namespace App\Controller\OgRepository\Image;
use App\Controller\OgRepository\AbstractOgRepositoryController;
use App\Entity\Image;
use App\Entity\ImageImageRepository;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Attribute\AsController;
@ -23,30 +24,13 @@ class GetAction extends AbstractOgRepositoryController
* @throws RedirectionExceptionInterface
* @throws ClientExceptionInterface
*/
public function __invoke(Image $data): JsonResponse
public function __invoke(ImageImageRepository $data): JsonResponse
{
if (!$data->getImageFullsum()) {
throw new ValidatorException('Fullsum is required');
}
$content = [];
foreach ($data->getRepositories() as $repository) {
try {
$response = $this->createRequest('GET', 'http://' . $repository->getIp() . ':8006/ogrepository/v1/images/' . $data->getImageFullsum());
$content[] = [
'repository' => $repository->getIp(),
'data' => $response
];
} catch (\Exception $e) {
$this->logger->error(sprintf('Error en repositorio %s: %s', $repository->getIp(), $e->getMessage()));
$content[] = [
'repository' => $repository->getIp(),
'error' => $e->getMessage(),
'details' => $e->getMessage()
];
}
}
$content = $this->createRequest('GET', 'http://'.$data->getRepository()->getIp().':8006/ogrepository/v1/images/'.$data->getImageFullsum());
return new JsonResponse(data: $content, status: Response::HTTP_OK);
}

View File

@ -5,6 +5,7 @@ namespace App\Controller\OgRepository\Image;
use App\Controller\OgRepository\AbstractOgRepositoryController;
use App\Dto\Input\DeployImageInput;
use App\Entity\Image;
use App\Entity\ImageImageRepository;
use App\Model\CommandTypes;
use App\Model\ImageStatus;
use App\Model\TraceStatus;
@ -27,25 +28,27 @@ class RecoverAction extends AbstractOgRepositoryController
* @throws RedirectionExceptionInterface
* @throws ClientExceptionInterface
*/
public function __invoke(Image $data, HttpClientInterface $httpClient): JsonResponse
public function __invoke(ImageImageRepository $data, HttpClientInterface $httpClient): JsonResponse
{
if (!$data->getImageFullsum()) {
throw new ValidatorException('Fullsum is required');
}
$image = $data->getImage();
$params = [
'json' => [
'ID_img' => $data->getImageFullsum()
]
];
$this->logger->info('Recovering image', ['image' => $data->getName()]);
$this->logger->info('Recovering image', ['image' => $image->getName()]);
$repository = $data->getClient()->getRepository();
$repository = $image->getClient()->getRepository();
$content = $this->createRequest('POST', 'http://'.$repository->getIp().':8006/ogrepository/v1/trash/images', $params);
$this->logger->info('Image recovered successfully', ['image' => $data->getName()]);
$this->logger->info('Image recovered successfully', ['image' => $image->getName()]);
$data->setStatus(ImageStatus::SUCCESS);
$this->entityManager->persist($data);

View File

@ -5,6 +5,7 @@ namespace App\Controller\OgRepository\Image;
use App\Controller\OgRepository\AbstractOgRepositoryController;
use App\Dto\Input\ExportImportImageRepositoryInput;
use App\Entity\Image;
use App\Entity\ImageImageRepository;
use App\Entity\ImageRepository;
use App\Model\CommandTypes;
use App\Model\ImageStatus;
@ -27,13 +28,14 @@ class TransferAction extends AbstractOgRepositoryController
* @throws RedirectionExceptionInterface
* @throws ClientExceptionInterface
*/
public function __invoke(ExportImportImageRepositoryInput $input, Image $image): JsonResponse
public function __invoke(ExportImportImageRepositoryInput $input, ImageImageRepository $imageImageRepository): JsonResponse
{
$repositories = $input->repositories;
foreach ($repositories as $repositoryEntity) {
/** @var ImageRepository $repository */
$repository = $repositoryEntity->getEntity();
$image = $imageImageRepository->getImage();
if (!$image->getImageFullsum()) {
throw new ValidatorException('Fullsum is required');
@ -63,7 +65,7 @@ class TransferAction extends AbstractOgRepositoryController
$this->createService->__invoke($image->getClient(), CommandTypes::TRANSFER_IMAGE, TraceStatus::IN_PROGRESS, $content['job_id'], $inputData);
$image->setStatus(ImageStatus::TRANSFERRING);
$imageImageRepository->setStatus(ImageStatus::TRANSFERRING);
$this->entityManager->persist($image);
$this->entityManager->flush();
}

View File

@ -21,7 +21,7 @@ class StatusAction extends AbstractOgRepositoryController
* @throws RedirectionExceptionInterface
* @throws ClientExceptionInterface
*/
public function __invoke(ImageRepository $data, HttpClientInterface $httpClient): JsonResponse
public function __invoke(ImageRepository $data): JsonResponse
{
$content = $this->createRequest('GET', 'http://'.$data->getIp(). ':8006/ogrepository/v1/status');

View File

@ -4,6 +4,7 @@ namespace App\Controller\OgRepository\Webhook;
use App\Controller\OgRepository\AbstractOgRepositoryController;
use App\Entity\Image;
use App\Entity\ImageImageRepository;
use App\Entity\ImageRepository;
use App\Entity\Trace;
use App\Model\CommandTypes;
@ -60,21 +61,21 @@ class ResponseController extends AbstractOgRepositoryController
$trace = $this->entityManager->getRepository(Trace::class)->findOneBy(['jobId' => $data['job_id']]);
$imageUuid = $trace->getInput()['imageUuid'];
$image = $this->entityManager->getRepository(Image::class)->findOneBy(['uuid' => $imageUuid]);
/* @var ImageImageRepository $imageImageRepository */
$imageImageRepository = $this->entityManager->getRepository(ImageImageRepository::class)->findOneBy(['uuid' => $imageUuid]);
if ($image === null) {
if ($imageImageRepository === null) {
$this->updateTraceStatus($trace, TraceStatus::FAILED, 'Image not found');
return;
}
$image->setImageFullsum($data['image_id']);
$image->setStatus(ImageStatus::SUCCESS);
$this->entityManager->persist($image);
$imageImageRepository->setImageFullsum($data['image_id']);
$imageImageRepository->setStatus(ImageStatus::SUCCESS);
$this->entityManager->persist($imageImageRepository);
$this->updateTraceStatus($trace, TraceStatus::SUCCESS);
}
/**
* @throws TransportExceptionInterface
* @throws ServerExceptionInterface

View File

@ -0,0 +1,13 @@
<?php
namespace App\Dto\Input;
use App\Dto\Output\ImageRepositoryOutput;
use Symfony\Component\Serializer\Annotation\Groups;
use Symfony\Component\Validator\Constraints as Assert;
class DeleteImageInput
{
#[Assert\NotNull]
#[Groups(['image:write'])]
public ImageRepositoryOutput $repository;
}

View File

@ -15,52 +15,51 @@ use Symfony\Component\Serializer\Annotation\Groups;
#[ClientsHaveSamePartitionCount]
class DeployImageInput
{
#[Groups(['image:write'])]
#[Groups(['image-image-repository:write'])]
#[ApiProperty(description: 'The type of the image deployment', example: "")]
public ?string $type = null;
#[Groups(['image:write'])]
#[Groups(['image-image-repository:write'])]
#[ApiProperty(description: 'The type of the image deployment', example: "")]
public ?string $method = null;
/**
* @var ClientOutput[]
*/
#[Groups(['image:write'])]
#[Groups(['image-image-repository:write'])]
#[ApiProperty(description: 'The client to deploy the image')]
public ?array $clients = [];
#[Groups(['image:write'])]
#[Groups(['image-image-repository:write'])]
public ?int $diskNumber = null;
#[Groups(['image:write'])]
#[Groups(['image-image-repository:write'])]
public ?int $partitionNumber = null;
#[OrganizationalUnitP2PMode]
#[Groups(['image:write'])]
#[Groups(['image-image-repository:write'])]
public ?string $p2pMode = null;
#[Groups(['image:write'])]
#[Groups(['image-image-repository:write'])]
public ?int $p2pTime = null;
#[Groups(['image:write'])]
#[Groups(['image-image-repository:write'])]
public ?string $mcastIp = null;
#[Groups(['image:write'])]
#[Groups(['image-image-repository:write'])]
public ?int $mcastSpeed = null;
#[OrganizationalUnitMulticastPort]
#[Groups(['image:write'])]
#[Groups(['image-image-repository:write'])]
public ?int $mcastPort = null;
#[OrganizationalUnitMulticastMode]
#[Groups(['image:write'])]
#[Groups(['image-image-repository:write'])]
public ?string $mcastMode = null;
#[Groups(['image:write'])]
#[Groups(['image-image-repository:write'])]
public ?int $maxClients = null;
#[Groups(['image:write'])]
#[Groups(['image-image-repository:write'])]
public ?int $maxTime = null;
}

View File

@ -0,0 +1,44 @@
<?php
namespace App\Dto\Input;
use ApiPlatform\Metadata\ApiProperty;
use App\Dto\Output\ImageOutput;
use App\Dto\Output\ImageRepositoryOutput;
use App\Entity\ImageImageRepository;
use App\Entity\PxeTemplate;
use Symfony\Component\Serializer\Annotation\Groups;
use Symfony\Component\Validator\Constraints as Assert;
final class ImageImageRepositoryInput
{
#[Assert\NotNull]
#[Groups(['image-image-repository:write'])]
public ?ImageRepositoryOutput $imageRepository = null;
#[Assert\NotNull]
#[Groups(['image-image-repository:write'])]
public ?string $status = '';
public function __construct(?ImageImageRepository $imageImageRepository = null)
{
if (!$imageImageRepository) {
return;
}
$this->imageRepository = new ImageRepositoryOutput($imageImageRepository->getRepository());
$this->status = $imageImageRepository->getStatus();
}
public function createOrUpdateEntity(?ImageImageRepository $imageImageRepository = null): ImageImageRepository
{
if (!$imageImageRepository) {
$imageImageRepository = new ImageImageRepository();
}
$imageImageRepository->setRepository($this->imageRepository);
$imageImageRepository->setStatus($this->status);
return $imageImageRepository;
}
}

View File

@ -4,12 +4,14 @@ namespace App\Dto\Input;
use ApiPlatform\Metadata\ApiProperty;
use App\Dto\Output\ClientOutput;
use App\Dto\Output\ImageImageRepositoryOutput;
use App\Dto\Output\ImageRepositoryOutput;
use App\Dto\Output\OrganizationalUnitOutput;
use App\Dto\Output\PartitionOutput;
use App\Dto\Output\RemoteCalendarRuleOutput;
use App\Dto\Output\SoftwareProfileOutput;
use App\Entity\Image;
use App\Entity\ImageImageRepository;
use App\Entity\OrganizationalUnit;
use App\Entity\Partition;
use App\Model\ImageStatus;
@ -31,18 +33,10 @@ final class ImageInput
#[ApiProperty(description: 'The comments of the image', example: "Image 1 comments")]
public ?string $comments = null;
#[Groups(['image:write'])]
#[ApiProperty(description: 'The type of the image', example: "Server")]
public ?string $type = null;
#[Groups(['image:write'])]
#[ApiProperty(description: 'The type of the image', example: "Server")]
public ?string $source = 'input';
#[Groups(['image:write'])]
#[ApiProperty(description: 'The status of the image', example: "PENDING")]
public ?string $status = ImageStatus::PENDING;
#[Groups(['image:write'])]
#[ApiProperty(description: 'The software profile of the image')]
public ?SoftwareProfileOutput $softwareProfile = null;
@ -74,7 +68,6 @@ final class ImageInput
#[ApiProperty(description: 'The global property of the image')]
public ?bool $isGlobal = false;
public function __construct(?Image $image = null)
{
if (!$image) {
@ -84,25 +77,21 @@ final class ImageInput
$this->name = $image->getName();
$this->description = $image->getDescription();
$this->comments = $image->getComments();
$this->type = $image->getType();
$this->remotePc = $image->isRemotePc();
$this->isGlobal = $image->isGlobal();
$this->status = $image->getStatus();
if ($image->getSoftwareProfile()) {
$this->softwareProfile = new SoftwareProfileOutput($image->getSoftwareProfile());
}
if ($image->getRepositories()) {
foreach ($image->getRepositories() as $repository) {
$this->imageRepositories[] = new ImageRepositoryOutput($repository);
}
}
if ($image->getClient()) {
$this->client = new ClientOutput($image->getClient());
}
if ($image->getImageImageRepositories()) {
$this->imageRepositories = array_map(fn($imageImageRepository) => new ImageImageRepositoryOutput($imageImageRepository), $image->getImageImageRepositories()->toArray());
}
if ($image->getParent()) {
$this->parent = new self($image->getParent());
}
@ -112,13 +101,11 @@ final class ImageInput
{
if (!$image) {
$image = new Image();
$image->setStatus(ImageStatus::PENDING);
}
$image->setName($this->name);
$image->setDescription($this->description);
$image->setComments($this->comments);
$image->setType($this->type);
if ($this->softwareProfile) {
$image->setSoftwareProfile($this->softwareProfile->getEntity());
@ -129,15 +116,17 @@ final class ImageInput
}
if ($this->imageRepositories) {
foreach ($this->imageRepositories as $repository) {
$repositoriesToAdd[] = $repository->getEntity();
foreach ($this->imageRepositories as $imageRepository) {
$aux = new ImageImageRepository();
$aux->setImage($image);
$aux->setRepository($imageRepository->getEntity());
$aux->setStatus('');
if (!$image->containsImageImageRepository($aux)) {
$image->addImageImageRepository($aux);
}
}
} else {
$repositoriesToAdd[] = $image->getClient()?->getRepository();
}
$image->setRepositories( $repositoriesToAdd ?? [] );
$image->setRemotePc($this->remotePc);
$image->setIsGlobal($this->isGlobal);
$image->setCreated(false);

View File

@ -0,0 +1,49 @@
<?php
namespace App\Dto\Output;
use ApiPlatform\Metadata\Get;
use App\Entity\ImageImageRepository;
use Symfony\Component\Serializer\Annotation\Groups;
#[Get(shortName: 'ImageImageRepository')]
class ImageImageRepositoryOutput extends AbstractOutput
{
#[Groups(['image-image-repository:read', 'image:read'])]
public ?ImageOutput $image = null;
#[Groups(['image-image-repository:read', 'image:read'])]
public ?ImageRepositoryOutput $imageRepository= null;
#[Groups(['image-image-repository:read', 'image:read'])]
public string $status;
#[Groups(['image-image-repository:read', 'image:read'])]
public ?string $imageFullsum = null;
#[Groups(['image-image-repository:read', 'image:read'])]
public \DateTime $createdAt;
#[Groups(['image-image-repository:read', 'image:read'])]
public ?string $createdBy = null;
public function __construct(ImageImageRepository $imageImageRepository, array $context = [])
{
parent::__construct($imageImageRepository);
if (isset($context['groups']) && in_array('image-image-repository:read', $context['groups'])) {
if ($imageImageRepository->getImage()) {
$this->image = new ImageOutput($imageImageRepository->getImage());
}
}
if ($imageImageRepository->getRepository()) {
$this->imageRepository = new ImageRepositoryOutput($imageImageRepository->getRepository());
}
$this->status = $imageImageRepository->getStatus();
$this->imageFullsum = $imageImageRepository->getImageFullsum();
$this->createdAt = $imageImageRepository->getCreatedAt();
$this->createdBy = $imageImageRepository->getCreatedBy();
}
}

View File

@ -4,6 +4,7 @@ namespace App\Dto\Output;
use ApiPlatform\Metadata\Get;
use App\Entity\Image;
use App\Entity\ImageImageRepository;
use App\Entity\ImageRepository;
use App\Entity\Software;
use Symfony\Component\Serializer\Annotation\Groups;
@ -11,7 +12,7 @@ use Symfony\Component\Serializer\Annotation\Groups;
#[Get(shortName: 'Image')]
final class ImageOutput extends AbstractOutput
{
#[Groups(['image:read'])]
#[Groups(['image:read', 'image-image-repository:read'])]
public ?string $name = '';
#[Groups(['image:read'])]
@ -20,30 +21,12 @@ final class ImageOutput extends AbstractOutput
#[Groups(['image:read'])]
public ?string $comments = '';
#[Groups(['image:read'])]
public ?string $type = null;
#[Groups(['image:read'])]
public ?string $path = '';
#[Groups(['image:read'])]
public ?string $revision = '';
#[Groups(['image:read'])]
public ?string $info = '';
#[Groups(['image:read'])]
public ?int $size = null;
#[Groups(['image:read'])]
public ?bool $remotePc = null;
#[Groups(['image:read'])]
public ?bool $isGlobal = null;
#[Groups(['image:read'])]
public ?bool $created = null;
#[Groups(['image:read'])]
public ?SoftwareProfileOutput $softwareProfile = null;
@ -56,12 +39,6 @@ final class ImageOutput extends AbstractOutput
#[Groups(['image:read'])]
public ?array $partitionInfo = null;
#[Groups(['image:read'])]
public ?string $imageFullsum = '';
#[Groups(['image:read'])]
public ?string $status = null;
#[Groups(['image:read'])]
public \DateTime $createdAt;
@ -75,24 +52,15 @@ final class ImageOutput extends AbstractOutput
$this->name = $image->getName();
$this->description = $image->getDescription();
$this->comments = $image->getComments();
$this->type = $image->getType();
$this->path = $image->getPath();
$this->revision = $image->getRevision();
$this->info = $image->getInfo();
$this->size = $image->getSize();
$this->imageFullsum = $image->getImageFullsum();
$this->status = $image->getStatus();
$this->softwareProfile = $image->getSoftwareProfile() ? new SoftwareProfileOutput($image->getSoftwareProfile()) : null;
$this->imageRepositories = $image->getRepositories()->map(
fn(ImageRepository $image) => new ImageRepositoryOutput($image)
$this->imageRepositories = $image->getImageImageRepositories()->map(
fn(ImageImageRepository $image) => new ImageImageRepositoryOutput($image)
)->toArray();
$this->partitionInfo = json_decode($image->getPartitionInfo(), true);
$this->remotePc = $image->isRemotePc();
$this->isGlobal = $image->isGlobal();
$this->created = $image->isCreated();
$this->createdAt = $image->getCreatedAt();
$this->createdBy = $image->getCreatedBy();
}

View File

@ -9,7 +9,7 @@ use Symfony\Component\Serializer\Annotation\Groups;
#[Get(shortName: 'ImageRepository')]
class ImageRepositoryOutput extends AbstractOutput
{
#[Groups(['repository:read', 'image:read', 'client:read', "organizational-unit:read"])]
#[Groups(['repository:read', 'image:read', 'client:read', "organizational-unit:read", "image-image-repository:read"])]
public ?string $name = '';
#[Groups(['repository:read'])]
@ -18,19 +18,23 @@ class ImageRepositoryOutput extends AbstractOutput
#[Groups(['repository:read'])]
public ?string $comments = '';
#[Groups(['repository:read'])]
public ?bool $status = true;
#[Groups(['repository:read'])]
public \DateTime $createdAt;
#[Groups(['repository:read'])]
public ?string $createdBy = null;
public function __construct(ImageRepository $imageRepository)
public function __construct(ImageRepository $imageRepository, bool $status = true)
{
parent::__construct($imageRepository);
$this->name = $imageRepository->getName();
$this->ip = $imageRepository->getIp();
$this->comments = $imageRepository->getComments();
$this->status = $status;
$this->createdAt = $imageRepository->getCreatedAt();
$this->createdBy = $imageRepository->getCreatedBy();
}

View File

@ -34,7 +34,7 @@ final class MenuOutput extends AbstractOutput
#[Groups(['menu:read'])]
public ?string $createdBy = null;
public function __construct(Menu $menu)
public function __construct(Menu $menu)
{
parent::__construct($menu);

View File

@ -21,21 +21,6 @@ class Image extends AbstractEntity
#[ORM\Column(length: 255, nullable: true)]
private ?string $comments = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $path = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $type = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $revision = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $info = null;
#[ORM\Column(length: 255, nullable: true)]
private ?int $size = null;
#[ORM\ManyToOne]
#[ORM\JoinColumn(nullable: true)]
private ?SoftwareProfile $softwareProfile = null;
@ -43,12 +28,6 @@ class Image extends AbstractEntity
#[ORM\Column]
private ?bool $remotePc = null;
/**
* @var Collection<int, ImageRepository>
*/
#[ORM\ManyToMany(targetEntity: \App\Entity\ImageRepository::class, inversedBy: 'images')]
private Collection $repositories;
#[ORM\Column(length: 255, nullable: true)]
private ?string $partitionInfo = null;
@ -58,24 +37,19 @@ class Image extends AbstractEntity
#[ORM\ManyToOne]
private ?Client $client = null;
#[ORM\Column(nullable: true)]
private ?bool $created = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $imageFullsum = null;
#[ORM\Column(length: 255)]
private ?string $status = null;
#[ORM\Column]
private ?bool $isGlobal = null;
/**
* @var Collection<int, ImageImageRepository>
*/
#[ORM\OneToMany(mappedBy: 'image', targetEntity: ImageImageRepository::class, cascade: ['persist'], orphanRemoval: true)]
private Collection $imageImageRepositories;
public function __construct()
{
parent::__construct();
$this->repositories = new ArrayCollection();
$this->imageImageRepositories = new ArrayCollection();
}
public function getDescription(): ?string
@ -102,66 +76,6 @@ class Image extends AbstractEntity
return $this;
}
public function getPath(): ?string
{
return $this->path;
}
public function setPath(?string $path): static
{
$this->path = $path;
return $this;
}
public function getType(): ?string
{
return $this->type;
}
public function setType(?string $type): static
{
$this->type = $type;
return $this;
}
public function getRevision(): ?string
{
return $this->revision;
}
public function setRevision(?string $revision): static
{
$this->revision = $revision;
return $this;
}
public function getInfo(): ?string
{
return $this->info;
}
public function setInfo(?string $info): static
{
$this->info = $info;
return $this;
}
public function getSize(): ?int
{
return $this->size;
}
public function setSize(?int $size): static
{
$this->size = $size;
return $this;
}
public function getSoftwareProfile(): ?SoftwareProfile
{
return $this->softwareProfile;
@ -186,39 +100,6 @@ class Image extends AbstractEntity
return $this;
}
public function getRepositories(): ?Collection
{
return $this->repositories;
}
public function setRepositories(array $repositories): static
{
$this->repositories->clear();
foreach ($repositories as $repository){
$this->addRepository($repository);
}
return $this;
}
public function addRepository(\App\Entity\ImageRepository $repository): static
{
if (!$this->repositories->contains($repository)) {
$this->repositories->add($repository);
//$repository->addImage($this);
}
return $this;
}
public function removeRepository(?\App\Entity\ImageRepository $repository): static
{
$this->repositories->removeElement($repository);
return $this;
}
public function getPartitionInfo(): ?string
{
return $this->partitionInfo;
@ -279,18 +160,6 @@ class Image extends AbstractEntity
return $this;
}
public function getStatus(): ?string
{
return $this->status;
}
public function setStatus(string $status): static
{
$this->status = $status;
return $this;
}
public function isGlobal(): ?bool
{
return $this->isGlobal;
@ -302,4 +171,48 @@ class Image extends AbstractEntity
return $this;
}
/**
* @return Collection<int, ImageImageRepository>
*/
public function getImageImageRepositories(): Collection
{
return $this->imageImageRepositories;
}
public function addImageImageRepository(ImageImageRepository $imageImageRepository): static
{
if (!$this->imageImageRepositories->contains($imageImageRepository)) {
$this->imageImageRepositories->add($imageImageRepository);
$imageImageRepository->setImage($this);
}
return $this;
}
public function removeImageImageRepository(ImageImageRepository $imageImageRepository): static
{
if ($this->imageImageRepositories->removeElement($imageImageRepository)) {
// set the owning side to null (unless already changed)
if ($imageImageRepository->getImage() === $this) {
$imageImageRepository->setImage(null);
}
}
return $this;
}
public function containsImageImageRepository(ImageImageRepository $imageImageRepository): bool
{
foreach ($this->imageImageRepositories as $existing) {
if (
$existing->getImage()->getId() === $imageImageRepository->getImage()->getId() &&
$existing->getRepository()->getId() === $imageImageRepository->getRepository()->getId()
) {
return true;
}
}
return false;
}
}

View File

@ -0,0 +1,90 @@
<?php
namespace App\Entity;
use App\Repository\ImageImageRepositoryRepository;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
#[ORM\Entity(repositoryClass: ImageImageRepositoryRepository::class)]
#[ORM\UniqueConstraint(name: 'UNIQ_IDENTIFIER_IMAGE_REPOSITORY', columns: ['image_id', 'repository_id'])]
#[UniqueEntity(fields: ['image', 'repository'], message: 'This image is already associated with this repository')]
class ImageImageRepository extends AbstractEntity
{
#[ORM\ManyToOne(targetEntity: Image::class, cascade: ['persist'], inversedBy: 'imageImageRepositories')]
#[ORM\JoinColumn(nullable: false)]
private ?Image $image = null;
#[ORM\ManyToOne(targetEntity: ImageRepository::class, cascade: ['persist'], inversedBy: 'imageImageRepositories')]
#[ORM\JoinColumn(nullable: false)]
private ?ImageRepository $repository = null;
#[ORM\Column(length: 255)]
private ?string $status = null;
#[ORM\Column(nullable: true)]
private ?bool $created = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $imageFullsum = null;
public function getImage(): ?Image
{
return $this->image;
}
public function setImage(?Image $image): static
{
$this->image = $image;
return $this;
}
public function getRepository(): ?ImageRepository
{
return $this->repository;
}
public function setRepository(?ImageRepository $repository): static
{
$this->repository = $repository;
return $this;
}
public function getStatus(): ?string
{
return $this->status;
}
public function setStatus(string $status): static
{
$this->status = $status;
return $this;
}
public function getCreated(): ?bool
{
return $this->created;
}
public function setCreated(?bool $created): static
{
$this->created = $created;
return $this;
}
public function getImageFullsum(): ?string
{
return $this->imageFullsum;
}
public function setImageFullsum(?string $imageFullsum): static
{
$this->imageFullsum = $imageFullsum;
return $this;
}
}

View File

@ -19,15 +19,15 @@ class ImageRepository extends AbstractEntity
private ?string $comments = null;
/**
* @var Collection<int, Image>
* @var Collection<int, ImageImageRepository>
*/
#[ORM\ManyToMany(targetEntity: Image::class, mappedBy: 'repositories')]
private Collection $images;
#[ORM\OneToMany(mappedBy: 'repository', targetEntity: ImageImageRepository::class)]
private Collection $imageImageRepositories;
public function __construct()
{
parent::__construct();
$this->images = new ArrayCollection();
$this->imageImageRepositories = new ArrayCollection();
}
public function getIp(): ?string
@ -55,10 +55,32 @@ class ImageRepository extends AbstractEntity
}
/**
* @return Collection<int, Image>
* @return Collection<int, ImageImageRepository>
*/
public function getImages(): Collection
public function getImageImageRepositories(): Collection
{
return $this->images;
return $this->imageImageRepositories;
}
public function addImageImageRepository(ImageImageRepository $imageImageRepository): static
{
if (!$this->imageImageRepositories->contains($imageImageRepository)) {
$this->imageImageRepositories->add($imageImageRepository);
$imageImageRepository->setRepository($this);
}
return $this;
}
public function removeImageImageRepository(ImageImageRepository $imageImageRepository): static
{
if ($this->imageImageRepositories->removeElement($imageImageRepository)) {
// set the owning side to null (unless already changed)
if ($imageImageRepository->getRepository() === $this) {
$imageImageRepository->setRepository(null);
}
}
return $this;
}
}

View File

@ -35,9 +35,7 @@ final class ImageFactory extends ModelFactory
return [
'createdAt' => self::faker()->dateTime(),
'name' => self::faker()->text(255),
'status' => self::faker()->randomElement(['IN_PROGRESS', 'FINISHED', 'ERROR']),
'softwareProfile' => SoftwareProfileFactory::new(),
'repositories' => ImageRepositoryFactory::createMany(5),
'updatedAt' => self::faker()->dateTime(),
'remotePc' => self::faker()->boolean(),
'isGlobal' => self::faker()->boolean(),

View File

@ -0,0 +1,18 @@
<?php
namespace App\Repository;
use App\Entity\ImageImageRepository;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
/**
* @extends ServiceEntityRepository<ImageImageRepositoryRepository>
*/
class ImageImageRepositoryRepository extends AbstractRepository
{
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, ImageImageRepository::class);
}
}

View File

@ -0,0 +1,68 @@
<?php
namespace App\State\Processor;
use ApiPlatform\Metadata\Delete;
use ApiPlatform\Metadata\Operation;
use ApiPlatform\Metadata\Patch;
use ApiPlatform\Metadata\Post;
use ApiPlatform\Metadata\Put;
use ApiPlatform\State\ProcessorInterface;
use ApiPlatform\Validator\ValidatorInterface;
use App\Dto\Input\ImageImageRepositoryInput;
use App\Dto\Output\ImageImageRepositoryOutput;
use App\Repository\ImageImageRepositoryRepository;
readonly class ImageImageRepositoryProcessor implements ProcessorInterface
{
public function __construct(
private ImageImageRepositoryRepository $imageRepository,
private ValidatorInterface $validator,
)
{
}
/**
* @throws \Exception
*/
public function process(mixed $data, Operation $operation, array $uriVariables = [], array $context = []): ImageImageRepositoryOutput|null
{
switch ($operation){
case $operation instanceof Post:
case $operation instanceof Put:
case $operation instanceof Patch:
return $this->processCreateOrUpdate($data, $operation, $uriVariables, $context);
case $operation instanceof Delete:
return $this->processDelete($data, $operation, $uriVariables, $context);
}
}
/**
* @throws \Exception
*/
private function processCreateOrUpdate($data, Operation $operation, array $uriVariables = [], array $context = []): ImageImageRepositoryOutput
{
if (!($data instanceof ImageImageRepositoryInput)) {
throw new \Exception(sprintf('data is not instance of %s', ImageImageRepositoryInput::class));
}
$entity = null;
if (isset($uriVariables['uuid'])) {
$entity = $this->imageRepository->findOneByUuid($uriVariables['uuid']);
}
$image = $data->createOrUpdateEntity($entity);
$this->validator->validate($image);
$this->imageRepository->save($image);
return new ImageImageRepositoryOutput($image);
}
private function processDelete($data, Operation $operation, array $uriVariables = [], array $context = []): null
{
$user = $this->imageRepository->findOneByUuid($uriVariables['uuid']);
$this->imageRepository->delete($user);
return null;
}
}

View File

@ -11,7 +11,9 @@ use ApiPlatform\State\ProcessorInterface;
use ApiPlatform\Validator\ValidatorInterface;
use App\Controller\OgAgent\CreateImageAction;
use App\Dto\Input\ImageInput;
use App\Dto\Input\ImageRepositoryInput;
use App\Dto\Output\ImageOutput;
use App\Entity\ImageImageRepository;
use App\Repository\ImageRepository;
readonly class ImageProcessor implements ProcessorInterface

View File

@ -0,0 +1,56 @@
<?php
namespace App\State\Provider;
use ApiPlatform\Metadata\Get;
use ApiPlatform\Metadata\GetCollection;
use ApiPlatform\Metadata\Operation;
use ApiPlatform\Metadata\Patch;
use ApiPlatform\Metadata\Put;
use ApiPlatform\State\Pagination\TraversablePaginator;
use ApiPlatform\State\ProviderInterface;
use App\Dto\Output\ImageImageRepositoryOutput;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
readonly class ImageImageRepositoryProvider implements ProviderInterface
{
public function __construct(
private ProviderInterface $collectionProvider,
private ProviderInterface $itemProvider
)
{
}
public function provide(Operation $operation, array $uriVariables = [], array $context = []): object|array|null
{
switch ($operation){
case $operation instanceof GetCollection:
return $this->provideCollection($operation, $uriVariables, $context);
case $operation instanceof Get:
return $this->provideItem($operation, $uriVariables, $context);
}
}
private function provideCollection(Operation $operation, array $uriVariables = [], array $context = []): object
{
$paginator = $this->collectionProvider->provide($operation, $uriVariables, $context);
$items = new \ArrayObject();
foreach ($paginator->getIterator() as $item){
$items[] = new ImageImageRepositoryOutput($item, $context);
}
return new TraversablePaginator($items, $paginator->getCurrentPage(), $paginator->getItemsPerPage(), $paginator->getTotalItems());
}
public function provideItem(Operation $operation, array $uriVariables = [], array $context = []): object|array|null
{
$item = $this->itemProvider->provide($operation, $uriVariables, $context);
if (!$item) {
throw new NotFoundHttpException('ImageImageRepository not found');
}
return new ImageImageRepositoryOutput($item);
}
}

View File

@ -9,17 +9,23 @@ use ApiPlatform\Metadata\Patch;
use ApiPlatform\Metadata\Put;
use ApiPlatform\State\Pagination\TraversablePaginator;
use ApiPlatform\State\ProviderInterface;
use App\Controller\OgRepository\StatusAction;
use App\Dto\Input\ImageInput;
use App\Dto\Input\ImageRepositoryInput;
use App\Dto\Output\ImageOutput;
use App\Dto\Output\ImageRepositoryOutput;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
readonly class ImageRepositoryProvider implements ProviderInterface
{
public function __construct(
private ProviderInterface $collectionProvider,
private ProviderInterface $itemProvider
private ProviderInterface $collectionProvider,
private ProviderInterface $itemProvider,
private StatusAction $statusAction
)
{
}
@ -37,13 +43,23 @@ readonly class ImageRepositoryProvider implements ProviderInterface
}
}
/**
* @throws TransportExceptionInterface
* @throws ServerExceptionInterface
* @throws RedirectionExceptionInterface
* @throws ClientExceptionInterface
*/
private function provideCollection(Operation $operation, array $uriVariables = [], array $context = []): object
{
$paginator = $this->collectionProvider->provide($operation, $uriVariables, $context);
$items = new \ArrayObject();
foreach ($paginator->getIterator() as $item){
$items[] = new ImageRepositoryOutput($item);
$statusResponse = $this->statusAction->__invoke($item);
$content = json_decode($statusResponse->getContent(), true);
$status = !isset($content['error']);
$items[] = new ImageRepositoryOutput($item, $status);
}
return new TraversablePaginator($items, $paginator->getCurrentPage(), $paginator->getItemsPerPage(), $paginator->getTotalItems());