diff --git a/config/api_platform/Image.yaml b/config/api_platform/Image.yaml index 37ab891..3bb12ef 100644 --- a/config/api_platform/Image.yaml +++ b/config/api_platform/Image.yaml @@ -13,6 +13,7 @@ resources: filters: - 'api_platform.filter.image.order' - 'api_platform.filter.image.search' + - 'api_platform.filter.image.boolean' ApiPlatform\Metadata\Get: provider: App\State\Provider\ImageProvider ApiPlatform\Metadata\Put: diff --git a/config/services/api_platform.yaml b/config/services/api_platform.yaml index b5f7b49..04feaea 100644 --- a/config/services/api_platform.yaml +++ b/config/services/api_platform.yaml @@ -64,6 +64,11 @@ services: arguments: [ { 'id': 'exact', 'name': 'partial', } ] tags: [ 'api_platform.filter' ] + api_platform.filter.image.boolean: + parent: 'api_platform.doctrine.orm.boolean_filter' + arguments: [ { 'created': ~ } ] + tags: [ 'api_platform.filter' ] + api_platform.filter.og_live.order: parent: 'api_platform.doctrine.orm.order_filter' arguments: @@ -211,7 +216,7 @@ services: api_platform.filter.trace.search: parent: 'api_platform.doctrine.orm.search_filter' - arguments: [ { 'id': 'exact', 'command.id': 'exact', 'client.id': 'exact' } ] + arguments: [ { 'id': 'exact', 'command.id': 'exact', 'client.id': 'exact', status: 'exact' } ] tags: [ 'api_platform.filter' ] api_platform.filter.trace.order: diff --git a/migrations/Version20241105070853.php b/migrations/Version20241105070853.php new file mode 100644 index 0000000..3249af5 --- /dev/null +++ b/migrations/Version20241105070853.php @@ -0,0 +1,43 @@ +addSql('ALTER TABLE client ADD CONSTRAINT FK_C744045550C9D4F7 FOREIGN KEY (repository_id) REFERENCES image_repository (id)'); + $this->addSql('ALTER TABLE image DROP FOREIGN KEY FK_C53D045FFB84408A'); + $this->addSql('DROP INDEX IDX_C53D045FFB84408A ON image'); + $this->addSql('ALTER TABLE image ADD partition_info VARCHAR(255) DEFAULT NULL, CHANGE organizational_unit_id parent_id INT DEFAULT NULL'); + $this->addSql('ALTER TABLE image ADD CONSTRAINT FK_C53D045F727ACA70 FOREIGN KEY (parent_id) REFERENCES image (id)'); + $this->addSql('CREATE INDEX IDX_C53D045F727ACA70 ON image (parent_id)'); + $this->addSql('ALTER TABLE network_settings ADD CONSTRAINT FK_48869B5450C9D4F7 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 network_settings DROP FOREIGN KEY FK_48869B5450C9D4F7'); + $this->addSql('ALTER TABLE image DROP FOREIGN KEY FK_C53D045F727ACA70'); + $this->addSql('DROP INDEX IDX_C53D045F727ACA70 ON image'); + $this->addSql('ALTER TABLE image DROP partition_info, CHANGE parent_id organizational_unit_id INT DEFAULT NULL'); + $this->addSql('ALTER TABLE image ADD CONSTRAINT FK_C53D045FFB84408A FOREIGN KEY (organizational_unit_id) REFERENCES organizational_unit (id)'); + $this->addSql('CREATE INDEX IDX_C53D045FFB84408A ON image (organizational_unit_id)'); + $this->addSql('ALTER TABLE client DROP FOREIGN KEY FK_C744045550C9D4F7'); + } +} diff --git a/migrations/Version20241105085054.php b/migrations/Version20241105085054.php new file mode 100644 index 0000000..bfd061c --- /dev/null +++ b/migrations/Version20241105085054.php @@ -0,0 +1,35 @@ +addSql('ALTER TABLE image ADD client_id INT DEFAULT NULL'); + $this->addSql('ALTER TABLE image ADD CONSTRAINT FK_C53D045F19EB6921 FOREIGN KEY (client_id) REFERENCES client (id)'); + $this->addSql('CREATE INDEX IDX_C53D045F19EB6921 ON image (client_id)'); + } + + public function down(Schema $schema): void + { + // this down() migration is auto-generated, please modify it to your needs + $this->addSql('ALTER TABLE image DROP FOREIGN KEY FK_C53D045F19EB6921'); + $this->addSql('DROP INDEX IDX_C53D045F19EB6921 ON image'); + $this->addSql('ALTER TABLE image DROP client_id'); + } +} diff --git a/migrations/Version20241106133332.php b/migrations/Version20241106133332.php new file mode 100644 index 0000000..745afee --- /dev/null +++ b/migrations/Version20241106133332.php @@ -0,0 +1,31 @@ +addSql('ALTER TABLE trace ADD job_id 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 trace DROP job_id'); + } +} diff --git a/migrations/Version20241107074832.php b/migrations/Version20241107074832.php new file mode 100644 index 0000000..8481fc2 --- /dev/null +++ b/migrations/Version20241107074832.php @@ -0,0 +1,31 @@ +addSql('ALTER TABLE image ADD created TINYINT(1) 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 DROP created'); + } +} diff --git a/src/Controller/OgAgent/CreateImageActionController.php b/src/Controller/OgAgent/CreateImageActionController.php new file mode 100644 index 0000000..4f58327 --- /dev/null +++ b/src/Controller/OgAgent/CreateImageActionController.php @@ -0,0 +1,90 @@ +getClient()->getIp()) { + throw new ValidatorException('IP is required'); + } + + $partitionInfo = json_decode($image->getPartitionInfo(), true); + + $data = [ + 'dsk' => (string) $partitionInfo['numDisk'], + 'par' => (string) $partitionInfo['numPartition'], + 'cpt' => "83", + 'idi' => $image->getUuid(), + 'nci' => $image->getName(), + 'ipr' => $image->getRepository()->getIp(), + 'nfn' => 'CrearImagen', + 'ids' => '0' + ]; + + try { + $response = $this->httpClient->request('POST', 'https://localhost:4444/CloningEngine/CrearImagen', [ + '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']; + + $command = $this->entityManager->getRepository(Command::class)->findOneBy(['name' => 'Crear Imagen']); + + $client = $image->getClient(); + $client->setStatus(ClientStatus::BUSY); + $this->entityManager->persist($client); + + $trace = new Trace(); + $trace->setClient($image->getClient()); + $trace->setCommand($command ?? null); + $trace->setStatus('pending'); + $trace->setJobId($jobId); + $trace->setExecutedAt(new \DateTime()); + + $this->entityManager->persist($trace); + $this->entityManager->flush(); + + return new JsonResponse(status: Response::HTTP_OK); + } +} diff --git a/src/Controller/OgAgent/StatusAction.php b/src/Controller/OgAgent/StatusAction.php index d0ff631..9478b47 100644 --- a/src/Controller/OgAgent/StatusAction.php +++ b/src/Controller/OgAgent/StatusAction.php @@ -3,7 +3,9 @@ namespace App\Controller\OgAgent; use App\Entity\Client; +use App\Entity\OperativeSystem; use App\Entity\Partition; +use App\Model\ClientStatus; use App\Model\OgLiveStatus; use Doctrine\ORM\EntityManagerInterface; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; @@ -40,20 +42,20 @@ class StatusAction extends AbstractController } try { - $response = $this->httpClient->request('POST', 'https://' . $client->getIp() . ':8000/ogAdmClient/status', [ - 'verify_peer' => false, // Desactivar verificación del certificado - 'verify_host' => false, // Desactivar verificación del nombre del host - 'timeout' => 10, // Tiempo máximo de espera + $response = $this->httpClient->request('POST', 'https://localhost:4444/ogAdmClient/status', [ + 'verify_peer' => false, + 'verify_host' => false, + 'timeout' => 10, 'headers' => [ - 'Content-Type' => 'application/json', // Cabecera de tipo de contenido + 'Content-Type' => 'application/json', ], - 'json' => [], // Cuerpo de la solicitud como JSON + 'json' => [], ]); $statusCode = $response->getStatusCode(); - $client->setStatus($statusCode === Response::HTTP_OK ? 'active' : 'off'); + $client->setStatus($statusCode === Response::HTTP_OK ? ClientStatus::OG_LIVE : ClientStatus::OFF); } catch (TransportExceptionInterface $e) { - $client->setStatus('off'); + $client->setStatus(ClientStatus::OFF); return new JsonResponse( data: ['error' => $e->getMessage()], @@ -72,6 +74,18 @@ class StatusAction extends AbstractController $partitionEntity = new Partition(); } + if (isset($cfg['soi']) && $cfg['soi'] !== '') { + $operativeSystem = $this->entityManager->getRepository(OperativeSystem::class) + ->findOneBy(['name' => $cfg['soi']]); + + if (!$operativeSystem) { + $operativeSystem = new OperativeSystem(); + $operativeSystem->setName($cfg['soi']); + $this->entityManager->persist($operativeSystem); + } + $partitionEntity->setOperativeSystem($operativeSystem); + } + $partitionEntity->setClient($client); $partitionEntity->setDiskNumber($cfg['disk']); $partitionEntity->setPartitionNumber($cfg['par']); diff --git a/src/Controller/OgAgent/OgAdmClientController.php b/src/Controller/OgAgent/Webhook/AgentController.php similarity index 98% rename from src/Controller/OgAgent/OgAdmClientController.php rename to src/Controller/OgAgent/Webhook/AgentController.php index 4ec47f4..0d459ed 100644 --- a/src/Controller/OgAgent/OgAdmClientController.php +++ b/src/Controller/OgAgent/Webhook/AgentController.php @@ -2,12 +2,11 @@ declare(strict_types=1); -namespace App\Controller\OgAgent; +namespace App\Controller\OgAgent\Webhook; use App\Entity\Client; use App\Entity\OrganizationalUnit; use App\Entity\Partition; -use App\Model\OrganizationalUnitTypes; use Doctrine\ORM\EntityManagerInterface; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\JsonResponse; @@ -17,7 +16,7 @@ use Symfony\Component\HttpKernel\Attribute\AsController; use Symfony\Component\Routing\Attribute\Route; #[AsController] -class OgAdmClientController extends AbstractController +class AgentController extends AbstractController { public function __construct( protected readonly EntityManagerInterface $entityManager diff --git a/src/Controller/OgAgent/Webhook/ClientsController.php b/src/Controller/OgAgent/Webhook/ClientsController.php new file mode 100644 index 0000000..a5bb67a --- /dev/null +++ b/src/Controller/OgAgent/Webhook/ClientsController.php @@ -0,0 +1,67 @@ +toArray(); + $requiredFields = ['nfn', 'idi', 'dsk', 'par', 'cpt', 'ipr', 'inv_sft', 'ids', 'res', 'der', 'job_id']; + + foreach ($requiredFields as $field) { + if (!isset($data[$field])) { + return new JsonResponse(['message' => "Missing parameter: $field"], Response::HTTP_BAD_REQUEST); + } + } + + 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']]); + + if ($data['res'] === 1) { + $trace->setStatus(TraceStatus::SUCCESS); + $trace->setFinishedAt(new \DateTime()); + + $image->setCreated(true); + + } else { + $trace->setStatus(TraceStatus::FAILED); + $trace->setFinishedAt(new \DateTime()); + $trace->setOutput($data['der']); + + $image->setCreated(false); + } + $this->entityManager->persist($image); + + $client = $trace->getClient(); + $client->setStatus(ClientStatus::OG_LIVE); + + $this->entityManager->persist($trace); + $this->entityManager->flush(); + + } + + return new JsonResponse([], Response::HTTP_OK); + } +} \ No newline at end of file diff --git a/src/Controller/OgAgent/Webhook/GetStatusAction.php b/src/Controller/OgAgent/Webhook/GetStatusAction.php deleted file mode 100644 index fc256f8..0000000 --- a/src/Controller/OgAgent/Webhook/GetStatusAction.php +++ /dev/null @@ -1,44 +0,0 @@ -getContent(), true); - - if (!is_array($data)) { - return new JsonResponse(['error' => 'Invalid JSON data'], Response::HTTP_BAD_REQUEST); - } - - - - return new JsonResponse(data: $data, status: Response::HTTP_OK); - } -} \ No newline at end of file diff --git a/src/Controller/OgAgent/OgAgentController.php b/src/Controller/OgAgent/Webhook/OgAgentController.php similarity index 89% rename from src/Controller/OgAgent/OgAgentController.php rename to src/Controller/OgAgent/Webhook/OgAgentController.php index 9fc6edd..082ca13 100644 --- a/src/Controller/OgAgent/OgAgentController.php +++ b/src/Controller/OgAgent/Webhook/OgAgentController.php @@ -2,18 +2,26 @@ declare(strict_types=1); -namespace App\Controller\OgAgent; +namespace App\Controller\OgAgent\Webhook; +use App\Entity\Client; +use Doctrine\ORM\EntityManagerInterface; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; +use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Attribute\AsController; use Symfony\Component\Routing\Annotation\Route; -use Symfony\Component\HttpFoundation\JsonResponse; #[AsController] class OgAgentController extends AbstractController { + public function __construct( + protected readonly EntityManagerInterface $entityManager + ) + { + } + #[Route('/opengnsys/rest/ogagent/started', methods: ['POST'])] public function agentStarted(Request $request): JsonResponse { @@ -26,7 +34,7 @@ class OgAgentController extends AbstractController } } - // Procesar los datos recibidos si es necesario + $client = $this->entityManager->getRepository(Client::class)->findOneBy(['mac' => $data['mac']]); return new JsonResponse([], Response::HTTP_OK); } diff --git a/src/Dto/Input/ClientInput.php b/src/Dto/Input/ClientInput.php index 8e78aa0..c7e22e6 100644 --- a/src/Dto/Input/ClientInput.php +++ b/src/Dto/Input/ClientInput.php @@ -4,12 +4,14 @@ namespace App\Dto\Input; use ApiPlatform\Metadata\ApiProperty; use App\Dto\Output\HardwareProfileOutput; +use App\Dto\Output\ImageRepositoryOutput; use App\Dto\Output\MenuOutput; use App\Dto\Output\OgLiveOutput; use App\Dto\Output\OrganizationalUnitOutput; use App\Dto\Output\PxeTemplateOutput; use App\Entity\Client; -use App\Entity\OgRepository; +use App\Entity\ImageRepository; +use App\Model\ClientStatus; use Symfony\Component\Serializer\Annotation\Groups; use Symfony\Component\Validator\Constraints as Assert; @@ -64,7 +66,7 @@ final class ClientInput description: 'El estado del cliente', example: 'active' )] - public ?string $status = 'off'; + public ?string $status = ClientStatus::OFF; #[Assert\NotNull(message: 'validators.organizational_unit.not_null')] #[Groups(['client:write', 'client:patch'])] @@ -107,7 +109,7 @@ final class ClientInput #[ApiProperty( description: 'descriptions.client.validation' )] - public ?OgRepository $repository = null; + public ?ImageRepositoryOutput $repository = null; #[Groups(['client:write'])] #[ApiProperty( @@ -147,6 +149,10 @@ final class ClientInput if ($client->getHardwareProfile()) { $this->hardwareProfile = new HardwareProfileOutput($client->getHardwareProfile()); } + + if ($client->getRepository()) { + $this->repository = $client->getRepository(); + } } public function createOrUpdateEntity(?Client $client = null): Client @@ -165,6 +171,7 @@ final class ClientInput $client->setMenu($this->menu?->getEntity()); $client->setOgLive($this->ogLive?->getEntity()); $client->setHardwareProfile($this->hardwareProfile?->getEntity()); + $client->setRepository($this->repository?->getEntity()); $client->setTemplate($this->template?->getEntity()); $client->setPosition($this->position); $client->setStatus($this->status); diff --git a/src/Dto/Input/ImageInput.php b/src/Dto/Input/ImageInput.php index b994e9e..4f2ccae 100644 --- a/src/Dto/Input/ImageInput.php +++ b/src/Dto/Input/ImageInput.php @@ -6,9 +6,11 @@ use ApiPlatform\Metadata\ApiProperty; use App\Dto\Output\ClientOutput; use App\Dto\Output\ImageRepositoryOutput; use App\Dto\Output\OrganizationalUnitOutput; +use App\Dto\Output\PartitionOutput; use App\Dto\Output\SoftwareProfileOutput; use App\Entity\Image; use App\Entity\OrganizationalUnit; +use App\Entity\Partition; use Symfony\Component\Serializer\Annotation\Groups; use Symfony\Component\Validator\Constraints as Assert; @@ -32,20 +34,8 @@ final class ImageInput public ?string $type = null; #[Groups(['image:write'])] - #[ApiProperty(description: 'The path of the image', example: "/path/to/image")] - public ?string $path = null; - - #[Groups(['image:write'])] - #[ApiProperty(description: 'The revision of the image', example: "1.0")] - public ?string $revision = null; - - #[Groups(['image:write'])] - #[ApiProperty(description: 'The info of the image', example: "Image 1 info")] - public ?string $info = null; - - #[Groups(['image:write'])] - #[ApiProperty(description: 'The size of the image', example: 1024)] - public ?int $size = null; + #[ApiProperty(description: 'The type of the image', example: "Server")] + public ?string $source = 'input'; #[Groups(['image:write'])] #[ApiProperty(description: 'The software profile of the image')] @@ -56,6 +46,19 @@ final class ImageInput public ?ImageRepositoryOutput $imageRepository = null; #[Groups(['image:write'])] + #[ApiProperty(description: 'The client of the image')] + public ?ClientOutput $client = null; + + #[Groups(['image:write'])] + #[ApiProperty(description: 'The client of the image')] + public ?PartitionOutput $partition = null; + + #[Groups(['image:write'])] + #[ApiProperty(description: 'The parent of the image')] + public ?self $parent = null; + + #[Groups(['image:write'])] + #[ApiProperty(description: 'The remote pc of the image')] public ?bool $remotePc = false; public function __construct(?Image $image = null) @@ -68,10 +71,6 @@ final class ImageInput $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->remotePc = $image->isRemotePc(); if ($image->getSoftwareProfile()) { @@ -81,6 +80,14 @@ final class ImageInput if ($image->getRepository()) { $this->imageRepository = new ImageRepositoryOutput($image->getRepository()); } + + if ($image->getClient()) { + $this->client = new ClientOutput($image->getClient()); + } + + if ($image->getParent()) { + $this->parent = new self($image->getParent()); + } } public function createOrUpdateEntity(?Image $image = null): Image @@ -93,13 +100,37 @@ final class ImageInput $image->setDescription($this->description); $image->setComments($this->comments); $image->setType($this->type); - $image->setPath($this->path); - $image->setRevision($this->revision); - $image->setInfo($this->info); - $image->setSize($this->size); - $image->setSoftwareProfile($this->softwareProfile->getEntity()); - $image->setRepository($this->imageRepository->getEntity()); + + if ($this->softwareProfile) { + $image->setSoftwareProfile($this->softwareProfile->getEntity()); + } + + $image->setRepository($this->imageRepository ? $this->imageRepository->getEntity() + : $this->client->getEntity()->getRepository()); + + if ($this->client) { + $image->setClient($this->client->getEntity()); + } + + if ($this->parent) { + $image->setParent($this->parent->getEntity()); + } + $image->setRemotePc($this->remotePc); + $image->setCreated(false); + + $partitionInfo = []; + + if ($this->partition) { + /** @var Partition $partition */ + $partition = $this->partition->getEntity(); + $partitionInfo["numDisk"] = $partition->getDiskNumber(); + $partitionInfo["numPartition"] = $partition->getPartitionNumber(); + $partitionInfo["partitionCode"] = $partition->getPartitionCode(); + $partitionInfo["filesystem"] = $partition->getFilesystem(); + $partitionInfo["osName"] = $partition->getOperativeSystem()?->getName(); + $image->setPartitionInfo(json_encode($partitionInfo)); + } return $image; } diff --git a/src/Dto/Output/ClientOutput.php b/src/Dto/Output/ClientOutput.php index 3d9399c..d751f6d 100644 --- a/src/Dto/Output/ClientOutput.php +++ b/src/Dto/Output/ClientOutput.php @@ -48,6 +48,10 @@ final class ClientOutput extends AbstractOutput #[ApiProperty(readableLink: true )] public ?HardwareProfileOutput $hardwareProfile = null; + #[Groups(['client:read'])] + #[ApiProperty(readableLink: true )] + public ?ImageRepositoryOutput $repository = null; + #[Groups(['client:read', 'organizational-unit:read'])] #[ApiProperty(readableLink: true )] public ?PxeTemplateOutput $template = null; @@ -99,6 +103,7 @@ 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; $this->hardwareProfile = $client->getHardwareProfile() ? new HardwareProfileOutput($client->getHardwareProfile()) : null; $this->subnet = $client->getSubnet()?->getIpAddress(); $this->ogLive = $client->getOgLive() ? new OgLiveOutput($client->getOgLive()) : null; diff --git a/src/Dto/Output/ImageOutput.php b/src/Dto/Output/ImageOutput.php index 6569676..1f6dbfa 100644 --- a/src/Dto/Output/ImageOutput.php +++ b/src/Dto/Output/ImageOutput.php @@ -36,12 +36,18 @@ final class ImageOutput extends AbstractOutput #[Groups(['image:read'])] public ?bool $remotePc = null; + #[Groups(['image:read'])] + public ?bool $created = null; + #[Groups(['image:read'])] public ?SoftwareProfileOutput $softwareProfile = null; #[Groups(['image:read'])] public ?ImageRepositoryOutput $imageRepository = null; + #[Groups(['image:read'])] + public ?array $partitionInfo = null; + #[Groups(['image:read'])] public \DateTime $createdAt; @@ -62,7 +68,9 @@ final class ImageOutput extends AbstractOutput $this->size = $image->getSize(); $this->softwareProfile = $image->getSoftwareProfile() ? new SoftwareProfileOutput($image->getSoftwareProfile()) : null; $this->imageRepository = $image->getRepository() ? new ImageRepositoryOutput($image->getRepository()) : null; + $this->partitionInfo = json_decode($image->getPartitionInfo(), true); $this->remotePc = $image->isRemotePc(); + $this->created = $image->isCreated(); $this->createdAt = $image->getCreatedAt(); $this->createdBy = $image->getCreatedBy(); } diff --git a/src/Dto/Output/ImageRepositoryOutput.php b/src/Dto/Output/ImageRepositoryOutput.php index a940da1..5a7faa4 100644 --- a/src/Dto/Output/ImageRepositoryOutput.php +++ b/src/Dto/Output/ImageRepositoryOutput.php @@ -9,7 +9,7 @@ use Symfony\Component\Serializer\Annotation\Groups; #[Get(shortName: 'ImageRepository')] class ImageRepositoryOutput extends AbstractOutput { - #[Groups(['repository:read', 'image:read'])] + #[Groups(['repository:read', 'image:read', 'client:read'])] public ?string $name = ''; #[Groups(['repository:read'])] diff --git a/src/Dto/Output/OperativeSystemOutput.php b/src/Dto/Output/OperativeSystemOutput.php index bac0169..fac3ef1 100644 --- a/src/Dto/Output/OperativeSystemOutput.php +++ b/src/Dto/Output/OperativeSystemOutput.php @@ -9,7 +9,7 @@ use Symfony\Component\Serializer\Annotation\Groups; #[Get(shortName: 'OperativeSystem')] final class OperativeSystemOutput extends AbstractOutput { - #[Groups(['operative-system:read', 'partition:read', 'software-profile:read'])] + #[Groups(['operative-system:read', 'partition:read', 'software-profile:read', 'client:read'])] public string $name; #[Groups(['operative-system:read'])] diff --git a/src/Dto/Output/TraceOutput.php b/src/Dto/Output/TraceOutput.php index 265a9b2..465da71 100644 --- a/src/Dto/Output/TraceOutput.php +++ b/src/Dto/Output/TraceOutput.php @@ -19,6 +19,9 @@ final class TraceOutput extends AbstractOutput #[Groups(['trace:read'])] public string $status; + #[Groups(['trace:read'])] + public ?string $jobId = null; + #[Groups(['trace:read'])] public ?\DateTimeInterface $executedAt = null; @@ -41,6 +44,7 @@ final class TraceOutput extends AbstractOutput $this->command = new CommandOutput($trace->getCommand()); $this->client = new ClientOutput($trace->getClient()); $this->status = $trace->getStatus(); + $this->jobId = $trace->getJobId(); $this->executedAt = $trace->getExecutedAt(); $this->output = $trace->getOutput(); $this->finishedAt = $trace->getFinishedAt(); diff --git a/src/Entity/Client.php b/src/Entity/Client.php index 37546ed..0095ac7 100644 --- a/src/Entity/Client.php +++ b/src/Entity/Client.php @@ -61,7 +61,7 @@ class Client extends AbstractEntity private ?PxeTemplate $template = null; #[ORM\ManyToOne(inversedBy: 'clients')] - private ?OgRepository $repository = null; + private ?ImageRepository $repository = null; #[ORM\ManyToOne(inversedBy: 'clients')] #[ORM\JoinColumn( onDelete: 'SET NULL')] @@ -260,12 +260,12 @@ class Client extends AbstractEntity } - public function getRepository(): ?OgRepository + public function getRepository(): ?ImageRepository { return $this->repository; } - public function setRepository(?OgRepository $repository): static + public function setRepository(?ImageRepository $repository): static { $this->repository = $repository; diff --git a/src/Entity/Image.php b/src/Entity/Image.php index 5951f38..9f86cac 100644 --- a/src/Entity/Image.php +++ b/src/Entity/Image.php @@ -37,12 +37,6 @@ class Image extends AbstractEntity #[ORM\JoinColumn(nullable: true)] private ?SoftwareProfile $softwareProfile = null; - /** - * @var Collection - */ - #[ORM\OneToMany(mappedBy: 'image', targetEntity: Partition::class)] - private Collection $partitions; - #[ORM\Column] private ?bool $remotePc = null; @@ -50,6 +44,18 @@ class Image extends AbstractEntity #[ORM\JoinColumn(nullable: false)] private ?\App\Entity\ImageRepository $repository = null; + #[ORM\Column(length: 255, nullable: true)] + private ?string $partitionInfo = null; + + #[ORM\ManyToOne(targetEntity: self::class)] + private ?self $parent = null; + + #[ORM\ManyToOne] + private ?Client $client = null; + + #[ORM\Column(nullable: true)] + private ?bool $created = null; + public function __construct() { parent::__construct(); @@ -152,36 +158,6 @@ class Image extends AbstractEntity return $this; } - /** - * @return Collection - */ - public function getPartitions(): Collection - { - return $this->partitions; - } - - public function addPartition(Partition $partition): static - { - if (!$this->partitions->contains($partition)) { - $this->partitions->add($partition); - $partition->setImage($this); - } - - return $this; - } - - public function removePartition(Partition $partition): static - { - if ($this->partitions->removeElement($partition)) { - // set the owning side to null (unless already changed) - if ($partition->getImage() === $this) { - $partition->setImage(null); - } - } - - return $this; - } - public function isRemotePc(): ?bool { return $this->remotePc; @@ -205,4 +181,52 @@ class Image extends AbstractEntity return $this; } + + public function getPartitionInfo(): ?string + { + return $this->partitionInfo; + } + + public function setPartitionInfo(?string $partitionInfo): static + { + $this->partitionInfo = $partitionInfo; + + return $this; + } + + public function getParent(): ?self + { + return $this->parent; + } + + public function setParent(?self $parent): static + { + $this->parent = $parent; + + return $this; + } + + public function getClient(): ?Client + { + return $this->client; + } + + public function setClient(?Client $client): static + { + $this->client = $client; + + return $this; + } + + public function isCreated(): ?bool + { + return $this->created; + } + + public function setCreated(?bool $created): static + { + $this->created = $created; + + return $this; + } } diff --git a/src/Entity/NetworkSettings.php b/src/Entity/NetworkSettings.php index bbd2080..7e5a9ac 100644 --- a/src/Entity/NetworkSettings.php +++ b/src/Entity/NetworkSettings.php @@ -67,7 +67,7 @@ class NetworkSettings extends AbstractEntity private ?bool $validation = null; #[ORM\ManyToOne] - private ?OgRepository $repository = null; + private ?ImageRepository $repository = null; #[ORM\ManyToOne] private ?OgLive $ogLive = null; @@ -298,12 +298,12 @@ class NetworkSettings extends AbstractEntity return $this; } - public function getRepository(): ?OgRepository + public function getRepository(): ?ImageRepository { return $this->repository; } - public function setRepository(?OgRepository $repository): static + public function setRepository(?ImageRepository $repository): static { $this->repository = $repository; diff --git a/src/Entity/OgRepository.php b/src/Entity/OgRepository.php deleted file mode 100644 index 9aaaa74..0000000 --- a/src/Entity/OgRepository.php +++ /dev/null @@ -1,86 +0,0 @@ - - */ - #[ORM\OneToMany(mappedBy: 'repository', targetEntity: Client::class)] - private Collection $clients; - - public function __construct() - { - parent::__construct(); - $this->clients = new ArrayCollection(); - } - - public function getIpAddress(): ?string - { - return $this->ipAddress; - } - - public function setIpAddress(string $ipAddress): static - { - $this->ipAddress = $ipAddress; - - return $this; - } - - public function getDescription(): ?string - { - return $this->description; - } - - public function setDescription(?string $description): static - { - $this->description = $description; - - return $this; - } - - /** - * @return Collection - */ - public function getClients(): Collection - { - return $this->clients; - } - - public function addClient(Client $client): static - { - if (!$this->clients->contains($client)) { - $this->clients->add($client); - $client->setRepository($this); - } - - return $this; - } - - public function removeClient(Client $client): static - { - if ($this->clients->removeElement($client)) { - // set the owning side to null (unless already changed) - if ($client->getRepository() === $this) { - $client->setRepository(null); - } - } - - return $this; - } -} diff --git a/src/Entity/Trace.php b/src/Entity/Trace.php index 1f2f318..275c9ef 100644 --- a/src/Entity/Trace.php +++ b/src/Entity/Trace.php @@ -29,6 +29,9 @@ class Trace extends AbstractEntity #[ORM\Column(type: Types::DATETIME_MUTABLE, nullable: true)] private ?\DateTimeInterface $finishedAt = null; + #[ORM\Column(length: 255, nullable: true)] + private ?string $jobId = null; + public function getClient(): ?Client { return $this->client; @@ -100,4 +103,16 @@ class Trace extends AbstractEntity return $this; } + + public function getJobId(): ?string + { + return $this->jobId; + } + + public function setJobId(?string $jobId): static + { + $this->jobId = $jobId; + + return $this; + } } diff --git a/src/Factory/ImageFactory.php b/src/Factory/ImageFactory.php index d0a59fb..692c49d 100644 --- a/src/Factory/ImageFactory.php +++ b/src/Factory/ImageFactory.php @@ -35,8 +35,6 @@ final class ImageFactory extends ModelFactory return [ 'createdAt' => self::faker()->dateTime(), 'name' => self::faker()->text(255), - 'path' => self::faker()->text(255), - 'size' => self::faker()->randomNumber(), 'softwareProfile' => SoftwareProfileFactory::new(), 'repository' => ImageRepositoryFactory::new(), 'updatedAt' => self::faker()->dateTime(), diff --git a/src/Model/ClientStatus.php b/src/Model/ClientStatus.php new file mode 100644 index 0000000..0ef5b22 --- /dev/null +++ b/src/Model/ClientStatus.php @@ -0,0 +1,50 @@ + 'Apagado', + self::INITIALIZING => 'Inicializando', + self::OG_LIVE => 'OG Live', + self::BUSY => 'Ocupado', + self::LINUX => 'Linux', + self::LINUX_SESSION => 'Sesión Linux', + self::MACOS => 'MacOS', + self::WINDOWS => 'Windows', + self::WINDOWS_SESSION => 'Sesión Windows', + ]; + public static function getClientStatuses(): array + { + return self::CLIENT_STATUSES; + } + + public static function getClientStatus(string $clientStatus): ?string + { + return self::CLIENT_STATUSES[$clientStatus] ?? null; + } + + public static function getClientStatusKeys(): array + { + return array_keys(self::CLIENT_STATUSES); + } +} \ No newline at end of file diff --git a/src/Model/TraceStatus.php b/src/Model/TraceStatus.php index fc790b2..d055a3f 100644 --- a/src/Model/TraceStatus.php +++ b/src/Model/TraceStatus.php @@ -6,13 +6,13 @@ final class TraceStatus { public const string PENDING = 'pending'; public const string IN_PROGRESS = 'in-progress'; - public const string COMPLETED = 'completed'; + public const string SUCCESS = 'success'; public const string FAILED = 'failed'; private const array STATUS = [ self::PENDING => 'Pendiente', self::IN_PROGRESS => 'En progreso', - self::COMPLETED => 'Completado', + self::SUCCESS => 'Finalizado con éxito', self::FAILED => 'Fallido', ]; diff --git a/src/Repository/OgRepositoryRepository.php b/src/Repository/OgRepositoryRepository.php deleted file mode 100644 index 0db2b01..0000000 --- a/src/Repository/OgRepositoryRepository.php +++ /dev/null @@ -1,18 +0,0 @@ - - */ -class OgRepositoryRepository extends AbstractRepository -{ - public function __construct(ManagerRegistry $registry) - { - parent::__construct($registry, self::class); - } -} diff --git a/src/State/Processor/ImageProcessor.php b/src/State/Processor/ImageProcessor.php index 833225d..89ef94e 100644 --- a/src/State/Processor/ImageProcessor.php +++ b/src/State/Processor/ImageProcessor.php @@ -9,6 +9,7 @@ use ApiPlatform\Metadata\Post; use ApiPlatform\Metadata\Put; use ApiPlatform\State\ProcessorInterface; use ApiPlatform\Validator\ValidatorInterface; +use App\Controller\OgAgent\CreateImageActionController; use App\Dto\Input\ImageInput; use App\Dto\Output\ImageOutput; use App\Repository\ImageRepository; @@ -17,7 +18,8 @@ readonly class ImageProcessor implements ProcessorInterface { public function __construct( private ImageRepository $imageRepository, - private ValidatorInterface $validator + private ValidatorInterface $validator, + private CreateImageActionController $createImageActionController ) { } @@ -52,6 +54,11 @@ readonly class ImageProcessor implements ProcessorInterface } $image = $data->createOrUpdateEntity($entity); + + if ($data->source !== 'input') { + $response = $this->createImageActionController->__invoke($image); + } + $this->validator->validate($image); $this->imageRepository->save($image); diff --git a/tests/Functional/ImageTest.php b/tests/Functional/ImageTest.php index 6f0e399..f682a18 100644 --- a/tests/Functional/ImageTest.php +++ b/tests/Functional/ImageTest.php @@ -105,14 +105,12 @@ class ImageTest extends AbstractTest $this->createClientWithCredentials()->request('PUT', $iri, ['json' => [ 'name' => self::IMAGE_UPDATE, - 'size' => 123 ]]); $this->assertResponseIsSuccessful(); $this->assertJsonContains([ '@id' => $iri, 'name' => self::IMAGE_UPDATE, - 'size' => 123 ]); }