commit
351f952cba
15
CHANGELOG.md
15
CHANGELOG.md
|
@ -1,4 +1,19 @@
|
|||
# Changelog
|
||||
## [0.11.0] - 2025-04-11
|
||||
### Added
|
||||
- Se ha añadido funcionalidad para renombrar imagenes en ogRepository. Nuevo sistema de versionado.
|
||||
- Se ha añadido la integracion con el ogAgent para poder ejecutar scripts.
|
||||
- Se ha añadido el poder añadir descripcion a una imagen.
|
||||
- Se han añadido 2 nuevos campos en la gestion de los repositorios: usuario y puerto ssh.
|
||||
- Se ha añadido funcionalidad para poder gestionar el estado de un equipo de manera automatica. En caso de no haber conexion con el cliente, la web sera notificada en un tiempo maximo de 5 min.
|
||||
|
||||
### Improved
|
||||
- Se han modificado los logs para que puedan "salir" por syslog ademas de por fichero.
|
||||
|
||||
### Fixed
|
||||
- Se ha corregido el bug que hacia que cuando habia demasiados clientes, no se mostraran en pantalla debido a un error de memoria.
|
||||
---
|
||||
|
||||
## [0.10.1] - 2025-03-25
|
||||
### Improved
|
||||
- Se ha modificado el script de creación de usuarios, añadiendole la opcion del tipo de visionalizacion por defecto de la vista "grupos".
|
||||
|
|
|
@ -50,6 +50,13 @@ resources:
|
|||
uriTemplate: /clients/server/{uuid}/get-pxe
|
||||
controller: App\Controller\OgBoot\PxeBootFile\GetAction
|
||||
|
||||
login_client:
|
||||
class: ApiPlatform\Metadata\Post
|
||||
method: POST
|
||||
input: App\Dto\Input\MultipleClientsInput
|
||||
uriTemplate: /clients/server/login-client
|
||||
controller: App\Controller\OgAgent\LoginAction
|
||||
|
||||
reboot_client:
|
||||
class: ApiPlatform\Metadata\Post
|
||||
method: POST
|
||||
|
|
|
@ -7,6 +7,8 @@ resources:
|
|||
groups: ['default', 'command:read']
|
||||
denormalizationContext:
|
||||
groups: ['command:write']
|
||||
order:
|
||||
id: 'DESC'
|
||||
operations:
|
||||
ApiPlatform\Metadata\GetCollection:
|
||||
provider: App\State\Provider\CommandProvider
|
||||
|
@ -28,9 +30,8 @@ resources:
|
|||
class: ApiPlatform\Metadata\Post
|
||||
method: POST
|
||||
input: App\Dto\Input\CommandExecuteInput
|
||||
uriTemplate: /commands/{uuid}/execute
|
||||
controller: App\Controller\CommandExecuteAction
|
||||
|
||||
uriTemplate: /commands/run-script
|
||||
controller: App\Controller\OgAgent\RunScriptAction
|
||||
properties:
|
||||
App\Entity\Command:
|
||||
id:
|
||||
|
|
|
@ -64,6 +64,14 @@ resources:
|
|||
uriTemplate: /image-image-repositories/{uuid}/convert-image-to-virtual
|
||||
controller: App\Controller\OgRepository\Image\ConvertImageToVirtualAction
|
||||
|
||||
rename_image_ogrepository:
|
||||
shortName: OgRepository Server
|
||||
class: ApiPlatform\Metadata\Post
|
||||
method: POST
|
||||
input: App\Dto\Input\RenameImageInput
|
||||
uriTemplate: /image-image-repositories/{uuid}/rename-image
|
||||
controller: App\Controller\OgRepository\Image\RenameAction
|
||||
|
||||
trash_delete_image_ogrepository:
|
||||
shortName: OgRepository Server
|
||||
description: Delete Image in OgRepository
|
||||
|
|
|
@ -15,6 +15,12 @@ when@dev:
|
|||
type: console
|
||||
process_psr_3_messages: false
|
||||
channels: ["!event", "!doctrine", "!console"]
|
||||
syslog:
|
||||
type: syslog
|
||||
ident: "ogcore"
|
||||
level: info
|
||||
formatter: App\Formatter\CustomLineFormatter
|
||||
channels: ["!event"]
|
||||
|
||||
when@test:
|
||||
monolog:
|
||||
|
@ -42,6 +48,12 @@ when@prod:
|
|||
type: console
|
||||
process_psr_3_messages: false
|
||||
channels: ["!event", "!doctrine"]
|
||||
syslog:
|
||||
type: syslog
|
||||
ident: "ogcore"
|
||||
level: info
|
||||
formatter: App\Formatter\CustomLineFormatter
|
||||
channels: ["!event"]
|
||||
deprecation:
|
||||
type: stream
|
||||
channels: [deprecation]
|
||||
|
|
|
@ -42,7 +42,7 @@ services:
|
|||
|
||||
api_platform.filter.command.boolean:
|
||||
parent: 'api_platform.doctrine.orm.boolean_filter'
|
||||
arguments: [ { 'enabled': ~ } ]
|
||||
arguments: [ { 'enabled': ~, 'readOnly': ~ } ]
|
||||
tags: [ 'api_platform.filter' ]
|
||||
|
||||
api_platform.filter.hardware.order:
|
||||
|
|
|
@ -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 Version20250325075647 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 client ADD firmware_type VARCHAR(255) DEFAULT NULL');
|
||||
}
|
||||
|
||||
public function down(Schema $schema): void
|
||||
{
|
||||
// this down() migration is auto-generated, please modify it to your needs
|
||||
$this->addSql('ALTER TABLE client DROP firmware_type');
|
||||
}
|
||||
}
|
|
@ -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 Version20250326061450 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 command ADD parameters 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 command DROP parameters');
|
||||
}
|
||||
}
|
|
@ -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 Version20250331144522 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 ADD datasize 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 datasize');
|
||||
}
|
||||
}
|
|
@ -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 Version20250402060324 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 ADD version INT 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 version');
|
||||
}
|
||||
}
|
|
@ -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 Version20250402081107 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('DROP INDEX UNIQ_IDENTIFIER_IMAGE_REPOSITORY ON image_image_repository');
|
||||
}
|
||||
|
||||
public function down(Schema $schema): void
|
||||
{
|
||||
// this down() 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)');
|
||||
}
|
||||
}
|
|
@ -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 Version20250402094550 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 ADD version INT 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 version');
|
||||
}
|
||||
}
|
|
@ -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 Version20250407063100 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 ADD description 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 description');
|
||||
}
|
||||
}
|
|
@ -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 Version20250407154425 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 INDEX IDX_STATUS ON client (status)');
|
||||
$this->addSql('CREATE INDEX IDX_UPDATED_AT ON client (updated_at)');
|
||||
}
|
||||
|
||||
public function down(Schema $schema): void
|
||||
{
|
||||
// this down() migration is auto-generated, please modify it to your needs
|
||||
$this->addSql('DROP INDEX IDX_STATUS ON client');
|
||||
$this->addSql('DROP INDEX IDX_UPDATED_AT ON client');
|
||||
}
|
||||
}
|
|
@ -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 Version20250407154620 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 INDEX IDX_STATUS_UPDATED_AT ON client (status, updated_at)');
|
||||
}
|
||||
|
||||
public function down(Schema $schema): void
|
||||
{
|
||||
// this down() migration is auto-generated, please modify it to your needs
|
||||
$this->addSql('DROP INDEX IDX_STATUS_UPDATED_AT ON client');
|
||||
}
|
||||
}
|
|
@ -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 Version20250408140101 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_repository ADD user VARCHAR(255) DEFAULT NULL, ADD ssh_port 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_repository DROP user, DROP ssh_port');
|
||||
}
|
||||
}
|
|
@ -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 Version20250409093554 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 ADD name VARCHAR(255) 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 DROP name');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,98 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Command;
|
||||
|
||||
use App\Entity\Client;
|
||||
use App\Entity\Trace;
|
||||
use App\Model\ClientStatus;
|
||||
use App\Model\TraceStatus;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
use Symfony\Component\Mercure\HubInterface;
|
||||
use Symfony\Component\Mercure\Update;
|
||||
|
||||
#[AsCommand(name: 'opengnsys:check-client-availability', description: 'Check client availability')]
|
||||
class CheckClientAvailability extends Command
|
||||
{
|
||||
const int THRESHOLD_MINUTES = 3;
|
||||
|
||||
public function __construct(
|
||||
private readonly HubInterface $hub,
|
||||
private readonly EntityManagerInterface $entityManager
|
||||
)
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$io = new SymfonyStyle($input, $output);
|
||||
$threshold = (new \DateTime())->modify(' - '.self::THRESHOLD_MINUTES . ' minutes');
|
||||
|
||||
$startQueryTime = microtime(true);
|
||||
|
||||
$query = $this->entityManager->createQuery(
|
||||
'UPDATE App\Entity\Client c
|
||||
SET c.status = :status
|
||||
WHERE c.status = :currentStatus AND c.updatedAt < :threshold'
|
||||
);
|
||||
$query->setParameter('status', ClientStatus::DISCONNECTED);
|
||||
$query->setParameter('currentStatus', ClientStatus::OG_LIVE);
|
||||
$query->setParameter('threshold', $threshold);
|
||||
$updatedCount = $query->execute();
|
||||
|
||||
$queryTime = microtime(true) - $startQueryTime;
|
||||
|
||||
$startMercureTime = microtime(true);
|
||||
|
||||
$clients = $this->entityManager->createQueryBuilder()
|
||||
->select('c')
|
||||
->from(Client::class, 'c')
|
||||
->where('c.status = :status')
|
||||
->andWhere('c.updatedAt < :threshold')
|
||||
->setParameter('status', ClientStatus::DISCONNECTED)
|
||||
->setParameter('threshold', $threshold)
|
||||
->getQuery()
|
||||
->getResult();
|
||||
|
||||
$this->dispatchMercureEvent($clients);
|
||||
|
||||
$mercureTime = microtime(true) - $startMercureTime;
|
||||
|
||||
$io->success("Updated $updatedCount clients to DISCONNECTED status.");
|
||||
$io->note("Query time: " . round($queryTime, 3) . "s");
|
||||
$io->note("Mercure dispatch time: " . round($mercureTime, 3) . "s");
|
||||
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
|
||||
private function dispatchMercureEvent(array $clients, int $chunkSize = 10000): void
|
||||
{
|
||||
$chunks = array_chunk($clients, $chunkSize);
|
||||
|
||||
foreach ($chunks as $chunk) {
|
||||
$data = [];
|
||||
|
||||
foreach ($chunk as $client) {
|
||||
$data[] = [
|
||||
'@id' => '/clients/' . $client->getUuid(),
|
||||
'status' => $client->getStatus(),
|
||||
];
|
||||
}
|
||||
|
||||
$update = new Update(
|
||||
'clients',
|
||||
json_encode($data)
|
||||
);
|
||||
|
||||
$this->hub->publish($update);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,44 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Command;
|
||||
|
||||
use App\Entity\Client;
|
||||
use App\Entity\Trace;
|
||||
use App\Model\ClientStatus;
|
||||
use App\Model\TraceStatus;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
use Symfony\Component\Mercure\HubInterface;
|
||||
use Symfony\Component\Mercure\Update;
|
||||
|
||||
#[AsCommand(name: 'opengnsys:test', description: 'Hello PhpStorm')]
|
||||
class TestCommand extends Command
|
||||
{
|
||||
public function __construct(
|
||||
private readonly HubInterface $hub,
|
||||
private readonly EntityManagerInterface $entityManager
|
||||
)
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$io = new SymfonyStyle($input, $output);
|
||||
$trace = $this->entityManager->getRepository(Trace::class)->find(7236);
|
||||
|
||||
$trace->setStatus(TraceStatus::SUCCESS);
|
||||
$trace->setProgress(1000);
|
||||
|
||||
$this->entityManager->persist($trace);
|
||||
$this->entityManager->flush();
|
||||
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
}
|
|
@ -87,7 +87,7 @@ class DeployImageAction extends AbstractController
|
|||
];
|
||||
|
||||
try {
|
||||
$this->deployImageOgRepositoryAction->__invoke($input, $image, $client->getEntity(), $this->httpClient);
|
||||
$this->deployImageOgRepositoryAction->__invoke($input, $image, $client->getEntity());
|
||||
} catch (\Exception $e) {
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ use App\Entity\Client;
|
|||
use App\Entity\Command;
|
||||
use App\Entity\Image;
|
||||
use App\Entity\ImageImageRepository;
|
||||
use App\Entity\ImageRepository;
|
||||
use App\Entity\Trace;
|
||||
use App\Model\ClientStatus;
|
||||
use App\Model\CommandTypes;
|
||||
|
@ -56,10 +57,14 @@ class CreateImageAction extends AbstractController
|
|||
|
||||
$repository = $image->getClient()->getRepository();
|
||||
|
||||
$latestImageRepo = $this->entityManager->getRepository(ImageImageRepository::class)->findLatestVersionByImageAndRepository($image, $repository);
|
||||
|
||||
$imageImageRepository = new ImageImageRepository();
|
||||
$imageImageRepository->setName($image->getName().'_v'.($latestImageRepo ? $latestImageRepo->getVersion() + 1 : 1));
|
||||
$imageImageRepository->setImage($image);
|
||||
$imageImageRepository->setRepository($repository);
|
||||
$imageImageRepository->setStatus(ImageStatus::IN_PROGRESS);
|
||||
$imageImageRepository->setVersion($latestImageRepo ? $latestImageRepo->getVersion() + 1 : 1);
|
||||
|
||||
$this->entityManager->persist($imageImageRepository);
|
||||
|
||||
|
@ -68,7 +73,7 @@ class CreateImageAction extends AbstractController
|
|||
'par' => (string) $partitionInfo['numPartition'],
|
||||
'cpt' => null,
|
||||
'idi' => $imageImageRepository->getUuid(),
|
||||
'nci' => $image->getName(),
|
||||
'nci' => $image->getName().'_v'.$imageImageRepository->getVersion(),
|
||||
'ipr' => $repository->getIp(),
|
||||
'nfn' => 'CrearImagen',
|
||||
'ids' => '0'
|
||||
|
@ -90,7 +95,7 @@ class CreateImageAction extends AbstractController
|
|||
|
||||
try {
|
||||
$this->logger->info('Creating image', ['image' => $image->getId()]);
|
||||
$response = $this->httpClient->request('POST', 'https://'.$image->getClient()->getIp().':8000/CloningEngine/CrearImagen', [
|
||||
$response = $this->httpClient->request('POST', 'https://'.$image->getClient()->getIp().':8000/opengnsys/CrearImagen', [
|
||||
'verify_peer' => false,
|
||||
'verify_host' => false,
|
||||
'headers' => [
|
||||
|
|
|
@ -92,7 +92,7 @@ class DeployImageAction extends AbstractController
|
|||
];
|
||||
|
||||
try {
|
||||
$response = $this->httpClient->request('POST', 'https://'.$client->getIp().':8000/CloningEngine/RestaurarImagen', [
|
||||
$response = $this->httpClient->request('POST', 'https://'.$client->getIp().':8000/opengnsys/RestaurarImagen', [
|
||||
'verify_peer' => false,
|
||||
'verify_host' => false,
|
||||
'headers' => [
|
||||
|
|
|
@ -0,0 +1,93 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Controller\OgAgent;
|
||||
|
||||
use App\Dto\Input\MultipleClientsInput;
|
||||
use App\Entity\Client;
|
||||
use App\Entity\Command;
|
||||
use App\Entity\Image;
|
||||
use App\Entity\Trace;
|
||||
use App\Model\ClientStatus;
|
||||
use App\Model\CommandTypes;
|
||||
use App\Model\ImageStatus;
|
||||
use App\Model\TraceStatus;
|
||||
use App\Service\Trace\CreateService;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Routing\Attribute\Route;
|
||||
use Symfony\Component\Validator\Exception\ValidatorException;
|
||||
use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface;
|
||||
use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface;
|
||||
use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface;
|
||||
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
|
||||
use Symfony\Contracts\HttpClient\HttpClientInterface;
|
||||
|
||||
class LoginAction extends AbstractController
|
||||
{
|
||||
public function __construct(
|
||||
protected readonly EntityManagerInterface $entityManager,
|
||||
protected readonly HttpClientInterface $httpClient,
|
||||
protected readonly CreateService $createService,
|
||||
protected readonly LoggerInterface $logger,
|
||||
)
|
||||
{
|
||||
}
|
||||
|
||||
public function __invoke(MultipleClientsInput $input): JsonResponse
|
||||
{
|
||||
foreach ($input->clients as $clientEntity) {
|
||||
/** @var Client $client */
|
||||
$client = $clientEntity->getEntity();
|
||||
|
||||
|
||||
if (!$client->getIp()) {
|
||||
throw new ValidatorException('IP is required');
|
||||
}
|
||||
|
||||
if ($client->getStatus() !== ClientStatus::OG_LIVE) {
|
||||
throw new ValidatorException('Client is not in OG_LIVE status');
|
||||
}
|
||||
|
||||
$data = [
|
||||
'nfn' => 'IniciarSesion',
|
||||
'dsk' => '1',
|
||||
'par' => '1',
|
||||
'ids' => '0'
|
||||
];
|
||||
|
||||
try {
|
||||
$response = $this->httpClient->request('POST', 'https://' . $client->getIp() . ':8000/ogAdmClient/IniciarSesion', [
|
||||
'verify_peer' => false,
|
||||
'verify_host' => false,
|
||||
'headers' => [
|
||||
'Content-Type' => 'application/json',
|
||||
],
|
||||
'json' => $data,
|
||||
]);
|
||||
$this->logger->info('Login client', ['client' => $client->getId()]);
|
||||
|
||||
} catch (TransportExceptionInterface $e) {
|
||||
$this->logger->error('Login rebooting client', ['client' => $client->getId(), 'error' => $e->getMessage()]);
|
||||
return new JsonResponse(
|
||||
data: ['error' => $e->getMessage()],
|
||||
status: Response::HTTP_INTERNAL_SERVER_ERROR
|
||||
);
|
||||
}
|
||||
|
||||
$jobId = json_decode($response->getContent(), true)['job_id'];
|
||||
|
||||
$client->setStatus(ClientStatus::INITIALIZING);
|
||||
$this->entityManager->persist($client);
|
||||
$this->entityManager->flush();
|
||||
|
||||
$this->createService->__invoke($client, CommandTypes::REBOOT, TraceStatus::SUCCESS, $jobId, []);
|
||||
}
|
||||
|
||||
return new JsonResponse(data: [], status: Response::HTTP_OK);
|
||||
}
|
||||
}
|
|
@ -48,6 +48,7 @@ class PartitionAssistantAction extends AbstractController
|
|||
}
|
||||
|
||||
foreach ($input->clients as $clientInput) {
|
||||
/** @var Client $client */
|
||||
$client = $clientInput->getEntity();
|
||||
|
||||
$disks = [];
|
||||
|
@ -72,13 +73,10 @@ class PartitionAssistantAction extends AbstractController
|
|||
];
|
||||
}
|
||||
|
||||
if ($partition->filesystem === 'CACHE') {
|
||||
$disks[$diskNumber]['diskData'] = [
|
||||
'dis' => (string) $diskNumber,
|
||||
'che' => "0",
|
||||
'tch' => (string) ($partition->size * 1024),
|
||||
];
|
||||
}
|
||||
$disks[$diskNumber]['diskData'] = [
|
||||
'dis' => (string) $diskNumber,
|
||||
'tch' => (string) ($partition->size * 1024),
|
||||
];
|
||||
|
||||
$disks[$diskNumber]['partitionData'][] = [
|
||||
'par' => (string) $partition->partitionNumber,
|
||||
|
@ -104,7 +102,7 @@ class PartitionAssistantAction extends AbstractController
|
|||
];
|
||||
|
||||
try {
|
||||
$response = $this->httpClient->request('POST', 'https://' . $client->getIp() . ':8000/CloningEngine/Configurar', [
|
||||
$response = $this->httpClient->request('POST', 'https://' . $client->getIp() . ':8000/opengnsys/Configurar', [
|
||||
'verify_peer' => false,
|
||||
'verify_host' => false,
|
||||
'headers' => [
|
||||
|
@ -130,5 +128,4 @@ class PartitionAssistantAction extends AbstractController
|
|||
|
||||
return new JsonResponse(data: [], status: Response::HTTP_OK);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -53,13 +53,15 @@ class PowerOffAction extends AbstractController
|
|||
continue;
|
||||
}
|
||||
|
||||
$endpoint = $client->getStatus() === ClientStatus::OG_LIVE ? 'opengnsys/Apagar' : 'opengnsys/poweroff';
|
||||
|
||||
$data = [
|
||||
'nfn' => 'Apagar',
|
||||
'ids' => '0'
|
||||
];
|
||||
|
||||
try {
|
||||
$response = $this->httpClient->request('POST', 'https://'.$client->getIp().':8000/ogAdmClient/Apagar', [
|
||||
$response = $this->httpClient->request('POST', 'https://' . $client->getIp() . ':8000/'.$endpoint, [
|
||||
'verify_peer' => false,
|
||||
'verify_host' => false,
|
||||
'headers' => [
|
||||
|
|
|
@ -41,6 +41,7 @@ class RebootAction extends AbstractController
|
|||
public function __invoke(MultipleClientsInput $input): JsonResponse
|
||||
{
|
||||
foreach ($input->clients as $clientEntity) {
|
||||
/** @var Client $client */
|
||||
$client = $clientEntity->getEntity();
|
||||
|
||||
|
||||
|
@ -48,13 +49,15 @@ class RebootAction extends AbstractController
|
|||
throw new ValidatorException('IP is required');
|
||||
}
|
||||
|
||||
$endpoint = $client->getStatus() === ClientStatus::OG_LIVE ? 'opengnsys/Reiniciar' : '/opengnsys/reboot';
|
||||
|
||||
$data = [
|
||||
'nfn' => 'Reiniciar',
|
||||
'ids' => '0'
|
||||
];
|
||||
|
||||
try {
|
||||
$response = $this->httpClient->request('POST', 'https://' . $client->getIp() . ':8000/ogAdmClient/Reiniciar', [
|
||||
$response = $this->httpClient->request('POST', 'https://' . $client->getIp() . ':8000/'.$endpoint, [
|
||||
'verify_peer' => false,
|
||||
'verify_host' => false,
|
||||
'headers' => [
|
||||
|
@ -62,6 +65,7 @@ class RebootAction extends AbstractController
|
|||
],
|
||||
'json' => $data,
|
||||
]);
|
||||
|
||||
$this->logger->info('Rebooting client', ['client' => $client->getId()]);
|
||||
|
||||
} catch (TransportExceptionInterface $e) {
|
||||
|
|
|
@ -0,0 +1,81 @@
|
|||
<?php
|
||||
|
||||
namespace App\Controller\OgAgent;
|
||||
|
||||
use App\Dto\Input\CommandExecuteInput;
|
||||
use App\Dto\Input\MultipleClientsInput;
|
||||
use App\Entity\Client;
|
||||
use App\Model\ClientStatus;
|
||||
use App\Model\CommandTypes;
|
||||
use App\Model\TraceStatus;
|
||||
use App\Service\Trace\CreateService;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Validator\Exception\ValidatorException;
|
||||
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
|
||||
use Symfony\Contracts\HttpClient\HttpClientInterface;
|
||||
|
||||
class RunScriptAction extends AbstractController
|
||||
{
|
||||
public function __construct(
|
||||
protected readonly EntityManagerInterface $entityManager,
|
||||
protected readonly HttpClientInterface $httpClient,
|
||||
protected readonly CreateService $createService,
|
||||
protected readonly LoggerInterface $logger,
|
||||
)
|
||||
{
|
||||
}
|
||||
|
||||
public function __invoke(CommandExecuteInput $input): JsonResponse
|
||||
{
|
||||
/** @var Client $clientEntity */
|
||||
foreach ($input->clients as $clientEntity) {
|
||||
$client = $clientEntity->getEntity();
|
||||
|
||||
if (!$client->getIp()) {
|
||||
throw new ValidatorException('IP is required');
|
||||
}
|
||||
|
||||
$data = [
|
||||
'nfn' => 'EjecutarScript',
|
||||
'scp' => base64_encode($input->script),
|
||||
'ids' => '0'
|
||||
];
|
||||
|
||||
try {
|
||||
$response = $this->httpClient->request('POST', 'https://' . $client->getIp() . ':8000/opengnsys/EjecutarScript', [
|
||||
'verify_peer' => false,
|
||||
'verify_host' => false,
|
||||
'headers' => [
|
||||
'Content-Type' => 'application/json',
|
||||
],
|
||||
'json' => $data,
|
||||
]);
|
||||
$this->logger->info('Rebooting client', ['client' => $client->getId()]);
|
||||
|
||||
} catch (TransportExceptionInterface $e) {
|
||||
$this->logger->error('Error rebooting client', ['client' => $client->getId(), 'error' => $e->getMessage()]);
|
||||
return new JsonResponse(
|
||||
data: ['error' => $e->getMessage()],
|
||||
status: Response::HTTP_INTERNAL_SERVER_ERROR
|
||||
);
|
||||
}
|
||||
|
||||
$jobId = json_decode($response->getContent(), true)['job_id'];
|
||||
|
||||
$this->entityManager->persist($client);
|
||||
$this->entityManager->flush();
|
||||
|
||||
$inputData = [
|
||||
'script' => $input->script,
|
||||
];
|
||||
|
||||
$this->createService->__invoke($client, CommandTypes::RUN_SCRIPT, TraceStatus::SUCCESS, $jobId, $inputData);
|
||||
}
|
||||
|
||||
return new JsonResponse(data: [], status: Response::HTTP_OK);
|
||||
}
|
||||
}
|
|
@ -70,15 +70,19 @@ class StatusAction extends AbstractController
|
|||
{
|
||||
$this->logger->info('Checking client status', ['client' => $client->getId()]);
|
||||
|
||||
$params = [
|
||||
'full-config' => false,
|
||||
];
|
||||
|
||||
try {
|
||||
$response = $this->httpClient->request('POST', 'https://' . $client->getIp() . ':8000/ogAdmClient/status', [
|
||||
$response = $this->httpClient->request('POST', 'https://' . $client->getIp() . ':8000/opengnsys/status', [
|
||||
'verify_peer' => false,
|
||||
'verify_host' => false,
|
||||
'timeout' => 30,
|
||||
'timeout' => 10,
|
||||
'headers' => [
|
||||
'Content-Type' => 'application/json',
|
||||
],
|
||||
'json' => [],
|
||||
'json' => $params,
|
||||
]);
|
||||
$statusCode = $response->getStatusCode();
|
||||
$client->setStatus($statusCode === Response::HTTP_OK ? ClientStatus::OG_LIVE : ClientStatus::OFF);
|
||||
|
|
|
@ -7,6 +7,7 @@ namespace App\Controller\OgAgent\Webhook;
|
|||
use App\Entity\Client;
|
||||
use App\Model\ClientStatus;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
@ -18,7 +19,8 @@ use Symfony\Component\Routing\Annotation\Route;
|
|||
class AgentSessionController extends AbstractController
|
||||
{
|
||||
public function __construct(
|
||||
protected readonly EntityManagerInterface $entityManager
|
||||
protected readonly EntityManagerInterface $entityManager,
|
||||
protected readonly LoggerInterface $logger
|
||||
)
|
||||
{
|
||||
}
|
||||
|
@ -58,6 +60,14 @@ class AgentSessionController extends AbstractController
|
|||
$this->entityManager->persist($client);
|
||||
$this->entityManager->flush();
|
||||
|
||||
$this->logger->info('Client started', [
|
||||
'mac' => $data['mac'],
|
||||
'ip' => $data['ip'],
|
||||
'ostype' => $data['ostype'],
|
||||
'osversion' => $data['osversion'],
|
||||
'agent_version' => $data['agent_version'],
|
||||
]);
|
||||
|
||||
return new JsonResponse([], Response::HTTP_OK);
|
||||
}
|
||||
|
||||
|
@ -82,6 +92,13 @@ class AgentSessionController extends AbstractController
|
|||
$this->entityManager->persist($client);
|
||||
$this->entityManager->flush();
|
||||
|
||||
$this->logger->info('Client stopped', [
|
||||
'mac' => $data['mac'],
|
||||
'ip' => $data['ip'],
|
||||
'ostype' => $data['ostype'],
|
||||
'osversion' => $data['osversion'],
|
||||
]);
|
||||
|
||||
return new JsonResponse([], Response::HTTP_OK);
|
||||
}
|
||||
|
||||
|
@ -117,6 +134,18 @@ class AgentSessionController extends AbstractController
|
|||
return new JsonResponse(['message' => 'Invalid status'], Response::HTTP_BAD_REQUEST);
|
||||
}
|
||||
|
||||
$this->entityManager->persist($client);
|
||||
$this->entityManager->flush();
|
||||
|
||||
$this->logger->info('Client logged in', [
|
||||
'ip' => $data['ip'],
|
||||
'user' => $data['user'],
|
||||
'language' => $data['language'],
|
||||
'session' => $data['session'],
|
||||
'ostype' => $data['ostype'],
|
||||
'osversion' => $data['osversion'],
|
||||
]);
|
||||
|
||||
return new JsonResponse([], Response::HTTP_OK);
|
||||
}
|
||||
|
||||
|
@ -152,6 +181,15 @@ class AgentSessionController extends AbstractController
|
|||
return new JsonResponse(['message' => 'Invalid status'], Response::HTTP_BAD_REQUEST);
|
||||
}
|
||||
|
||||
$this->entityManager->persist($client);
|
||||
$this->entityManager->flush();
|
||||
|
||||
$this->logger->info('Client logged out', [
|
||||
'ip' => $data['ip'],
|
||||
'user' => $data['user'],
|
||||
'ostype' => $data['ostype'],
|
||||
]);
|
||||
|
||||
return new JsonResponse([], Response::HTTP_OK);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
namespace App\Controller\OgAgent\Webhook;
|
||||
|
||||
use App\Controller\OgRepository\Image\CreateAuxFilesAction;
|
||||
use App\Entity\Client;
|
||||
use App\Entity\Image;
|
||||
use App\Entity\ImageImageRepository;
|
||||
use App\Entity\OperativeSystem;
|
||||
|
@ -32,7 +33,7 @@ use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
|
|||
use Symfony\Contracts\HttpClient\HttpClientInterface;
|
||||
|
||||
#[AsController]
|
||||
class ClientsController extends AbstractController
|
||||
class StatusController extends AbstractController
|
||||
{
|
||||
const string CREATE_IMAGE = 'RESPUESTA_CrearImagen';
|
||||
const string RESTORE_IMAGE = 'RESPUESTA_RestaurarImagen';
|
||||
|
@ -59,20 +60,28 @@ class ClientsController extends AbstractController
|
|||
public function index(Request $request): JsonResponse
|
||||
{
|
||||
$data = $request->toArray();
|
||||
$requiredFields = ['job_id'];
|
||||
|
||||
foreach ($requiredFields as $field) {
|
||||
if (!isset($data[$field])) {
|
||||
return new JsonResponse(['message' => "Missing parameter: $field"], Response::HTTP_BAD_REQUEST);
|
||||
}
|
||||
}
|
||||
|
||||
$this->logger->info('Webhook data received', $data);
|
||||
|
||||
// Esta parte del codigo nos indica si el cliente se encuentra activo
|
||||
if (isset($data['iph']) && isset($data['timestamp'])) {
|
||||
$client = $this->entityManager->getRepository(Client::class)->findOneBy(['ip' => $data['iph']]);
|
||||
if (!$client) {
|
||||
$this->logger->error('Client not found', $data);
|
||||
return new JsonResponse(['message' => 'Client not found'], Response::HTTP_NOT_FOUND);
|
||||
}
|
||||
|
||||
$updateAt = (new \DateTime())->setTimestamp((int)$data['timestamp']);
|
||||
|
||||
$client->setUpdatedAt($updateAt);
|
||||
$this->entityManager->persist($client);
|
||||
$this->entityManager->flush();
|
||||
}
|
||||
|
||||
if (isset($data['progress'])){
|
||||
$trace = $this->entityManager->getRepository(Trace::class)->findOneBy(['jobId' => $data['job_id']]);
|
||||
if ($trace){
|
||||
$trace->setProgress($data['progress'] * 1000);
|
||||
$trace->setProgress($data['progress'] * 100);
|
||||
$this->entityManager->persist($trace);
|
||||
$this->entityManager->flush();
|
||||
}
|
|
@ -40,7 +40,7 @@ class PostAction extends AbstractOgBootController
|
|||
'json' => [
|
||||
'template_name' => $pxeTemplate->getName(),
|
||||
'mac' => strtolower($client->getMac()),
|
||||
'lang' => 'es_ES.UTF_8',
|
||||
'lang' => 'es_ES.UTF-8',
|
||||
'ip' => $client->getIp(),
|
||||
'server_ip' => $this->ogBootApiUrl,
|
||||
'router' => $client->getOrganizationalUnit()->getNetworkSettings()->getRouter(),
|
||||
|
|
|
@ -32,6 +32,7 @@ class BackupImageAction extends AbstractOgRepositoryController
|
|||
public function __invoke(BackupImageInput $input, ImageImageRepository $imageImageRepository): JsonResponse
|
||||
{
|
||||
$image = $imageImageRepository->getImage();
|
||||
$repository = $imageImageRepository->getRepository();
|
||||
|
||||
if (!$image->getName()) {
|
||||
throw new ValidatorException('Name is required');
|
||||
|
@ -41,8 +42,9 @@ class BackupImageAction extends AbstractOgRepositoryController
|
|||
'json' => [
|
||||
'ID_img' => $imageImageRepository->getImageFullsum(),
|
||||
'repo_ip' => $input->repoIp,
|
||||
'ssh_port' => $repository->getSshPort() ?? '22',
|
||||
'remote_path' => $input->remotePath,
|
||||
'user' => 'opengnsys'
|
||||
'user' => $repository->getUser() ?? 'opengnsys',
|
||||
]
|
||||
];
|
||||
|
||||
|
|
|
@ -53,12 +53,13 @@ class ConvertAction extends AbstractOgRepositoryController
|
|||
}
|
||||
|
||||
$imageImageRepositoryEntity = new ImageImageRepository();
|
||||
$imageImageRepositoryEntity->setName($imageEntity->getName().'_v'.$imageImageRepositoryEntity->getVersion() + 1);
|
||||
$imageImageRepositoryEntity->setStatus(ImageStatus::PENDING);
|
||||
$imageImageRepositoryEntity->setImage($imageEntity);
|
||||
$imageImageRepositoryEntity->setRepository($repository);
|
||||
$imageImageRepositoryEntity->setVersion(1);
|
||||
|
||||
$this->entityManager->persist($imageImageRepositoryEntity);
|
||||
$this->entityManager->flush();
|
||||
|
||||
$this->logger->info('Converting image', ['image' => $image]);
|
||||
|
||||
|
@ -74,6 +75,7 @@ class ConvertAction extends AbstractOgRepositoryController
|
|||
if (isset($content['error']) && $content['code'] === Response::HTTP_INTERNAL_SERVER_ERROR ) {
|
||||
throw new ValidatorException('Error converting image');
|
||||
}
|
||||
$this->entityManager->flush();
|
||||
|
||||
$inputData = [
|
||||
'imageName' => $image,
|
||||
|
|
|
@ -39,18 +39,18 @@ class CreateAuxFilesAction extends AbstractOgRepositoryController
|
|||
|
||||
$params = [
|
||||
'json' => [
|
||||
'image' => $image->getName().'.img'
|
||||
'image' => $data->getName().'.img'
|
||||
]
|
||||
];
|
||||
|
||||
$this->logger->info('Creating aux files', ['image' => $image->getName()]);
|
||||
$this->logger->info('Creating aux files', ['image' => $data->getName()]);
|
||||
|
||||
$repository = $data->getRepository();
|
||||
|
||||
$content = $this->createRequest('POST', 'http://'.$repository->getIp().':8006/ogrepository/v1/images/torrentsum', $params);
|
||||
|
||||
$inputData = [
|
||||
'imageName' => $image->getName(),
|
||||
'imageName' => $data->getName(),
|
||||
'imageImageRepositoryUuid' => $data->getUuid(),
|
||||
];
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ namespace App\Controller\OgRepository\Image;
|
|||
use App\Controller\OgRepository\AbstractOgRepositoryController;
|
||||
use App\Entity\Image;
|
||||
use App\Entity\ImageImageRepository;
|
||||
use App\Entity\ImageRepository;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\HttpKernel\Attribute\AsController;
|
||||
|
@ -30,6 +31,7 @@ class DeletePermanentAction extends AbstractOgRepositoryController
|
|||
throw new ValidatorException('Fullsum is required');
|
||||
}
|
||||
|
||||
/** @var ImageRepository $image */
|
||||
$image = $data->getImage();
|
||||
|
||||
$this->logger->info('Deleting image', ['image' => $image->getName()]);
|
||||
|
@ -43,6 +45,13 @@ class DeletePermanentAction extends AbstractOgRepositoryController
|
|||
$this->entityManager->remove($data);
|
||||
$this->entityManager->flush();
|
||||
|
||||
$imageImageCollection = $image->getImageImageRepositories();
|
||||
|
||||
if ($imageImageCollection->isEmpty()) {
|
||||
$this->entityManager->remove($image);
|
||||
$this->entityManager->flush();
|
||||
}
|
||||
|
||||
return new JsonResponse(data: $content, status: Response::HTTP_OK);
|
||||
}
|
||||
}
|
|
@ -45,6 +45,13 @@ class DeleteTrashAction extends AbstractOgRepositoryController
|
|||
$this->entityManager->persist($image);
|
||||
$this->entityManager->flush();
|
||||
|
||||
$imageImageCollection = $image->getImageImageRepositories();
|
||||
|
||||
if ($imageImageCollection->isEmpty()) {
|
||||
$this->entityManager->remove($image);
|
||||
$this->entityManager->flush();
|
||||
}
|
||||
|
||||
return new JsonResponse(data: $content, status: Response::HTTP_OK);
|
||||
}
|
||||
}
|
|
@ -30,7 +30,7 @@ class DeployImageAction extends AbstractOgRepositoryController
|
|||
* @throws ClientExceptionInterface
|
||||
* @throws TransportExceptionInterface
|
||||
*/
|
||||
public function __invoke(DeployImageInput $input, ImageImageRepository $data, Client $client, HttpClientInterface $httpClient): JsonResponse
|
||||
public function __invoke(DeployImageInput $input, ImageImageRepository $data, Client $client): JsonResponse
|
||||
{
|
||||
$params = [
|
||||
'json' => [
|
||||
|
@ -45,9 +45,9 @@ class DeployImageAction extends AbstractOgRepositoryController
|
|||
];
|
||||
|
||||
$type = match ($input->method) {
|
||||
'udpcast', 'udpcast_direct' => DeployMethodTypes::MULTICAST_UDPCAST,
|
||||
'udpcast', 'udpcast-direct' => DeployMethodTypes::MULTICAST_UDPCAST,
|
||||
'p2p' => DeployMethodTypes::TORRENT,
|
||||
default => DeployMethodTypes::MULTICAST_UFTP,
|
||||
default => null,
|
||||
};
|
||||
|
||||
$repository = $client->getRepository();
|
||||
|
|
|
@ -51,9 +51,11 @@ class ImportAction extends AbstractOgRepositoryController
|
|||
}
|
||||
|
||||
$imageImageRepositoryEntity = new ImageImageRepository();
|
||||
$imageImageRepositoryEntity->setName($imageEntity->getName().'_v'.$imageImageRepositoryEntity->getVersion() + 1);
|
||||
$imageImageRepositoryEntity->setStatus(ImageStatus::AUX_FILES_PENDING);
|
||||
$imageImageRepositoryEntity->setImage($imageEntity);
|
||||
$imageImageRepositoryEntity->setRepository($repository);
|
||||
$imageImageRepositoryEntity->setVersion(1);
|
||||
|
||||
$this->entityManager->persist($imageImageRepositoryEntity);
|
||||
$this->entityManager->flush();
|
||||
|
@ -74,7 +76,7 @@ class ImportAction extends AbstractOgRepositoryController
|
|||
|
||||
$inputData = [
|
||||
'imageName' => $image,
|
||||
'imageUuid' => $imageImageRepositoryEntity->getUuid(),
|
||||
'imageImageRepositoryUuid' => $imageImageRepositoryEntity->getUuid(),
|
||||
];
|
||||
|
||||
$this->createService->__invoke(null, CommandTypes::CREATE_IMAGE_AUX_FILE, TraceStatus::IN_PROGRESS, $content['job_id'], $inputData);
|
||||
|
|
|
@ -0,0 +1,125 @@
|
|||
<?php
|
||||
|
||||
namespace App\Controller\OgRepository\Image;
|
||||
|
||||
use App\Controller\OgRepository\AbstractOgRepositoryController;
|
||||
use App\Dto\Input\DeployImageInput;
|
||||
use App\Dto\Input\RenameImageInput;
|
||||
use App\Entity\Image;
|
||||
use App\Entity\ImageImageRepository;
|
||||
use App\Entity\ImageRepository;
|
||||
use App\Model\CommandTypes;
|
||||
use App\Model\ImageStatus;
|
||||
use App\Model\TraceStatus;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\HttpKernel\Attribute\AsController;
|
||||
use Symfony\Component\Validator\Exception\ValidatorException;
|
||||
use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface;
|
||||
use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface;
|
||||
use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface;
|
||||
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
|
||||
use Symfony\Contracts\HttpClient\HttpClientInterface;
|
||||
|
||||
#[AsController]
|
||||
class RenameAction extends AbstractOgRepositoryController
|
||||
{
|
||||
/**
|
||||
* @throws TransportExceptionInterface
|
||||
* @throws ServerExceptionInterface
|
||||
* @throws RedirectionExceptionInterface
|
||||
* @throws ClientExceptionInterface
|
||||
*/
|
||||
public function __invoke(RenameImageInput $input, ImageImageRepository $imageImageRepository): JsonResponse
|
||||
{
|
||||
$image = $imageImageRepository->getImage();
|
||||
|
||||
if ($image->isGlobal()) {
|
||||
$repositories = $image->getImageImageRepositories();
|
||||
|
||||
if ($repositories->count() === 0) {
|
||||
return $this->jsonError('Image is not in any repository');
|
||||
}
|
||||
|
||||
if (!$this->isAvailableInAllRepositories($repositories)) {
|
||||
$this->logger->info('Image is not available in all repositories', ['image' => $image->getName()]);
|
||||
return $this->jsonError('Image is not available in all repositories');
|
||||
}
|
||||
|
||||
$repoWithImage = $this->entityManager
|
||||
->getRepository(ImageImageRepository::class)
|
||||
->findBy(['image' => $image, 'repository' => $imageImageRepository->getRepository()]);
|
||||
} else {
|
||||
$repoWithImage = [$imageImageRepository];
|
||||
}
|
||||
|
||||
$hasError = false;
|
||||
|
||||
foreach ($repoWithImage as $repository) {
|
||||
$content = $this->renameImageInRepository($repository, $input->newName);
|
||||
|
||||
if (isset($content['error']) && $content['code'] === Response::HTTP_INTERNAL_SERVER_ERROR) {
|
||||
$hasError = true;
|
||||
}
|
||||
|
||||
$repository->setName($input->newName);
|
||||
$this->entityManager->persist($repository);
|
||||
}
|
||||
|
||||
$this->entityManager->flush();
|
||||
|
||||
if ($hasError) {
|
||||
return new JsonResponse(['error' => 'Error renaming image'], Response::HTTP_INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
|
||||
return new JsonResponse([], Response::HTTP_OK);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws RedirectionExceptionInterface
|
||||
* @throws ClientExceptionInterface
|
||||
* @throws ServerExceptionInterface
|
||||
*/
|
||||
private function isAvailableInAllRepositories($repositories): bool
|
||||
{
|
||||
foreach ($repositories as $repository) {
|
||||
try {
|
||||
$this->createRequest('GET', 'http://' . $repository->getRepository()->getIp() . ':8006/ogrepository/v1/status');
|
||||
} catch (TransportExceptionInterface $e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws TransportExceptionInterface
|
||||
* @throws ServerExceptionInterface
|
||||
* @throws RedirectionExceptionInterface
|
||||
* @throws ClientExceptionInterface
|
||||
*/
|
||||
private function renameImageInRepository(ImageImageRepository $repository, string $newName): array
|
||||
{
|
||||
$params = [
|
||||
'json' => [
|
||||
'ID_img' => $repository->getImageFullsum(),
|
||||
'image_new_name' => $newName,
|
||||
]
|
||||
];
|
||||
|
||||
return $this->createRequest(
|
||||
'PUT',
|
||||
'http://' . $repository->getRepository()->getIp() . ':8006/ogrepository/v1/images/rename',
|
||||
$params
|
||||
);
|
||||
}
|
||||
|
||||
private function jsonError(string $message): JsonResponse
|
||||
{
|
||||
return new JsonResponse(
|
||||
['error' => $message, 'code' => Response::HTTP_INTERNAL_SERVER_ERROR],
|
||||
Response::HTTP_BAD_REQUEST
|
||||
);
|
||||
}
|
||||
|
||||
}
|
|
@ -47,7 +47,8 @@ class TransferAction extends AbstractOgRepositoryController
|
|||
'json' => [
|
||||
'image' => $image->getName().'.img',
|
||||
'repo_ip' => $imageImageRepository->getRepository()->getIp(),
|
||||
'user' => 'opengnsys',
|
||||
'user' => $repository->getUser(),
|
||||
'ssh_port' => $repository->getSshPort()
|
||||
]
|
||||
];
|
||||
|
||||
|
|
|
@ -48,7 +48,8 @@ class TransferGlobalAction extends AbstractOgRepositoryController
|
|||
'json' => [
|
||||
'image' => $image->getName().'.img',
|
||||
'repo_ip' => $imageImageRepository->getRepository()->getIp(),
|
||||
'user' => 'opengnsys',
|
||||
'user' => $repository->getUser(),
|
||||
'ssh_port' => $repository->getSshPort()
|
||||
]
|
||||
];
|
||||
|
||||
|
|
|
@ -56,13 +56,16 @@ class SyncAction extends AbstractOgRepositoryController
|
|||
|
||||
if (!$imageImageRepositoryEntity) {
|
||||
$imageImageRepositoryEntity = new ImageImageRepository();
|
||||
$imageImageRepositoryEntity->setImageFullsum($image['fullsum']);
|
||||
$imageImageRepositoryEntity->setStatus(ImageStatus::SUCCESS);
|
||||
$imageImageRepositoryEntity->setImage($imageEntity);
|
||||
$imageImageRepositoryEntity->setRepository($input);
|
||||
|
||||
$this->entityManager->persist($imageImageRepositoryEntity);
|
||||
}
|
||||
|
||||
$imageImageRepositoryEntity->setImageFullsum($image['fullsum']);
|
||||
$imageImageRepositoryEntity->setDatasize($image['datasize']);
|
||||
$imageImageRepositoryEntity->setStatus(ImageStatus::SUCCESS);
|
||||
$imageImageRepositoryEntity->setImage($imageEntity);
|
||||
$imageImageRepositoryEntity->setRepository($input);
|
||||
|
||||
$this->entityManager->persist($imageImageRepositoryEntity);
|
||||
|
||||
}
|
||||
|
||||
foreach ($existingImages as $existingImage) {
|
||||
|
|
|
@ -51,10 +51,17 @@ class ResponseController extends AbstractOgRepositoryController
|
|||
$imageImageRepository = $this->getImageImageRepository($trace);
|
||||
if (!$imageImageRepository) return $this->jsonResponseError('Image not found', Response::HTTP_NOT_FOUND, $trace);
|
||||
|
||||
$imageImageRepository->setStatus(ImageStatus::SUCCESS);
|
||||
$this->entityManager->persist($imageImageRepository);
|
||||
|
||||
if (isset($data['success']) && $data['success'] !== true) {
|
||||
$this->updateTraceStatus($trace, TraceStatus::FAILED, $data['output'] ?? 'Action failed');
|
||||
return new JsonResponse(['message' => 'Success'], Response::HTTP_OK);
|
||||
}
|
||||
|
||||
if ($setFullsum) {
|
||||
$imageImageRepository->setImageFullsum($data['image_id']);
|
||||
}
|
||||
$imageImageRepository->setStatus(ImageStatus::SUCCESS);
|
||||
|
||||
$this->entityManager->persist($imageImageRepository);
|
||||
$this->updateTraceStatus($trace, TraceStatus::SUCCESS);
|
||||
|
@ -83,6 +90,7 @@ class ResponseController extends AbstractOgRepositoryController
|
|||
}
|
||||
|
||||
$newImageRepo = new ImageImageRepository();
|
||||
$newImageRepo->setName($image->getName().'_v'.($originImageImageRepository->getVersion() + 1));
|
||||
$newImageRepo->setImage($image);
|
||||
$newImageRepo->setRepository($repository);
|
||||
$newImageRepo->setStatus(ImageStatus::SUCCESS);
|
||||
|
|
|
@ -14,4 +14,9 @@ final class CommandExecuteInput
|
|||
#[Assert\NotNull]
|
||||
#[Groups(['command:write'])]
|
||||
public array $clients = [];
|
||||
|
||||
|
||||
#[Assert\NotNull]
|
||||
#[Groups(['command:write'])]
|
||||
public string $script = '';
|
||||
}
|
|
@ -40,6 +40,13 @@ final class CommandInput
|
|||
)]
|
||||
public ?bool $enabled = true;
|
||||
|
||||
#[Groups(['command:write'])]
|
||||
#[ApiProperty(
|
||||
description: 'Tiene parámetros?',
|
||||
example: 'true',
|
||||
)]
|
||||
public ?bool $parameters = true;
|
||||
|
||||
#[Groups(['command:write'])]
|
||||
#[ApiProperty(
|
||||
description: 'Los comentarios del comando',
|
||||
|
@ -57,6 +64,7 @@ final class CommandInput
|
|||
$this->script = $command->getScript();
|
||||
$this->enabled = $command->isEnabled();
|
||||
$this->readOnly = $command->isReadOnly();
|
||||
$this->parameters = $command->isParameters();
|
||||
$this->comments = $command->getComments();
|
||||
}
|
||||
|
||||
|
@ -70,6 +78,7 @@ final class CommandInput
|
|||
$command->setScript($this->script);
|
||||
$command->setEnabled($this->enabled);
|
||||
$command->setReadOnly($this->readOnly);
|
||||
$command->setParameters($this->parameters);
|
||||
$command->setComments($this->comments);
|
||||
|
||||
return $command;
|
||||
|
|
|
@ -12,13 +12,8 @@ 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 ?string $description = '';
|
||||
|
||||
public function __construct(?ImageImageRepository $imageImageRepository = null)
|
||||
{
|
||||
|
@ -26,8 +21,7 @@ final class ImageImageRepositoryInput
|
|||
return;
|
||||
}
|
||||
|
||||
$this->imageRepository = new ImageRepositoryOutput($imageImageRepository->getRepository());
|
||||
$this->status = $imageImageRepository->getStatus();
|
||||
$this->description = $imageImageRepository->getDescription();
|
||||
}
|
||||
|
||||
public function createOrUpdateEntity(?ImageImageRepository $imageImageRepository = null): ImageImageRepository
|
||||
|
@ -36,8 +30,7 @@ final class ImageImageRepositoryInput
|
|||
$imageImageRepository = new ImageImageRepository();
|
||||
}
|
||||
|
||||
$imageImageRepository->setRepository($this->imageRepository);
|
||||
$imageImageRepository->setStatus($this->status);
|
||||
$imageImageRepository->setDescription($this->description);
|
||||
|
||||
return $imageImageRepository;
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ namespace App\Dto\Input;
|
|||
use ApiPlatform\Metadata\ApiProperty;
|
||||
use App\Dto\Output\ClientOutput;
|
||||
use App\Dto\Output\ImageImageRepositoryOutput;
|
||||
use App\Dto\Output\ImageOutput;
|
||||
use App\Dto\Output\ImageRepositoryOutput;
|
||||
use App\Dto\Output\OrganizationalUnitOutput;
|
||||
use App\Dto\Output\PartitionOutput;
|
||||
|
@ -37,6 +38,10 @@ final class ImageInput
|
|||
#[ApiProperty(description: 'The type of the image', example: "Server")]
|
||||
public ?string $source = 'input';
|
||||
|
||||
#[Groups(['image:write'])]
|
||||
#[ApiProperty(description: 'The optional selected image')]
|
||||
public ?ImageOutput $selectedImage = null;
|
||||
|
||||
#[Groups(['image:write'])]
|
||||
#[ApiProperty(description: 'The software profile of the image')]
|
||||
public ?SoftwareProfileOutput $softwareProfile = null;
|
||||
|
@ -60,6 +65,10 @@ final class ImageInput
|
|||
#[ApiProperty(description: 'The parent of the image')]
|
||||
public ?self $parent = null;
|
||||
|
||||
#[Groups(['image:write'])]
|
||||
#[ApiProperty(description: 'The parent of the image')]
|
||||
public ?int $version = null;
|
||||
|
||||
#[Groups(['image:write'])]
|
||||
#[ApiProperty(description: 'The remote pc of the image')]
|
||||
public ?bool $remotePc = false;
|
||||
|
@ -79,6 +88,7 @@ final class ImageInput
|
|||
$this->comments = $image->getComments();
|
||||
$this->remotePc = $image->isRemotePc();
|
||||
$this->isGlobal = $image->isGlobal();
|
||||
$this->version = $image->getVersion();
|
||||
|
||||
if ($image->getSoftwareProfile()) {
|
||||
$this->softwareProfile = new SoftwareProfileOutput($image->getSoftwareProfile());
|
||||
|
|
|
@ -27,11 +27,19 @@ final class ImageRepositoryInput
|
|||
#[ApiProperty(description: 'The IP of the repository', example: "")]
|
||||
public ?string $ip = null;
|
||||
|
||||
|
||||
#[Groups(['repository:write'])]
|
||||
#[ApiProperty(description: 'The comments of the repository', example: "Repository 1 comments")]
|
||||
public ?string $comments = null;
|
||||
|
||||
#[Assert\NotBlank]
|
||||
#[Groups(['repository:write'])]
|
||||
#[ApiProperty(description: 'The user of the repository', example: "Repository user")]
|
||||
public ?string $user = 'opengnsys';
|
||||
|
||||
#[Groups(['repository:write'])]
|
||||
#[ApiProperty(description: 'The sshPort of the repository', example: "Repository ssh port")]
|
||||
public ?string $sshPort = '22';
|
||||
|
||||
|
||||
public function __construct(?ImageRepository $repository = null)
|
||||
{
|
||||
|
@ -42,6 +50,8 @@ final class ImageRepositoryInput
|
|||
$this->name = $repository->getName();
|
||||
$this->ip = $repository->getIp();
|
||||
$this->comments = $repository->getComments();
|
||||
$this->user = $repository->getUser();
|
||||
$this->sshPort = $repository->getSshPort();
|
||||
}
|
||||
|
||||
public function createOrUpdateEntity(?ImageRepository $repository = null): ImageRepository
|
||||
|
@ -53,6 +63,8 @@ final class ImageRepositoryInput
|
|||
$repository->setName($this->name);
|
||||
$repository->setIp($this->ip);
|
||||
$repository->setComments($this->comments);
|
||||
$repository->setUser($this->user);
|
||||
$repository->setSshPort($this->sshPort);
|
||||
|
||||
return $repository;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
<?php
|
||||
|
||||
namespace App\Dto\Input;
|
||||
|
||||
use Symfony\Component\Serializer\Annotation\Groups;
|
||||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
|
||||
final class RenameImageInput
|
||||
{
|
||||
#[Assert\NotNull]
|
||||
#[Groups(['image-image-repository:write'])]
|
||||
public ?string $newName = '';
|
||||
}
|
|
@ -25,6 +25,9 @@ final class ClientOutput extends AbstractOutput
|
|||
#[Groups(['client:read', 'organizational-unit:read', 'pxe-template:read', 'trace:read', 'subnet:read'])]
|
||||
public ?string $mac = '';
|
||||
|
||||
#[Groups(['client:read'])]
|
||||
public ?string $firmwareType = '';
|
||||
|
||||
#[Groups(['client:read', 'organizational-unit:read', 'trace:read'])]
|
||||
public ?string $serialNumber = '';
|
||||
|
||||
|
@ -91,6 +94,7 @@ final class ClientOutput extends AbstractOutput
|
|||
$this->ip = $client->getIp();
|
||||
$this->netiface = $client->getNetiface();
|
||||
$this->netDriver = $client->getNetDriver();
|
||||
$this->firmwareType = $client->getFirmwareType();
|
||||
|
||||
if ($client->getOrganizationalUnit()) {
|
||||
$this->organizationalUnit = new OrganizationalUnitOutput($client->getOrganizationalUnit());
|
||||
|
|
|
@ -21,6 +21,9 @@ final class CommandOutput extends AbstractOutput
|
|||
#[Groups(['command:read'])]
|
||||
public ?bool $enabled = true;
|
||||
|
||||
#[Groups(['command:read'])]
|
||||
public ?bool $parameters = true;
|
||||
|
||||
#[Groups(['command:read'])]
|
||||
public ?string $comments = '';
|
||||
|
||||
|
@ -37,6 +40,7 @@ final class CommandOutput extends AbstractOutput
|
|||
$this->name = $command->getName();
|
||||
$this->script = $command->getScript();
|
||||
$this->readOnly = $command->isReadOnly();
|
||||
$this->parameters = $command->isParameters();
|
||||
$this->enabled = $command->isEnabled();
|
||||
$this->comments = $command->getComments();
|
||||
$this->createdAt = $command->getCreatedAt();
|
||||
|
|
|
@ -18,9 +18,21 @@ class ImageImageRepositoryOutput extends AbstractOutput
|
|||
#[Groups(['image-image-repository:read', 'image:read'])]
|
||||
public string $status;
|
||||
|
||||
#[Groups(['image-image-repository:read', 'image:read'])]
|
||||
public string $name;
|
||||
|
||||
#[Groups(['image-image-repository:read', 'image:read'])]
|
||||
public ?string $imageFullsum = null;
|
||||
|
||||
#[Groups(['image-image-repository:read', 'image:read'])]
|
||||
public ?string $datasize = null;
|
||||
|
||||
#[Groups(['image-image-repository:read', 'image:read'])]
|
||||
public ?string $description = null;
|
||||
|
||||
#[Groups(['image:read', 'image-image-repository:read'])]
|
||||
public ?int $version = null;
|
||||
|
||||
#[Groups(['image-image-repository:read', 'image:read'])]
|
||||
public \DateTime $createdAt;
|
||||
|
||||
|
@ -41,8 +53,12 @@ class ImageImageRepositoryOutput extends AbstractOutput
|
|||
$this->imageRepository = new ImageRepositoryOutput($imageImageRepository->getRepository());
|
||||
}
|
||||
|
||||
$this->name = $imageImageRepository->getName();
|
||||
$this->version = $imageImageRepository->getVersion();
|
||||
$this->status = $imageImageRepository->getStatus();
|
||||
$this->imageFullsum = $imageImageRepository->getImageFullsum();
|
||||
$this->datasize = $imageImageRepository->getDatasize();
|
||||
$this->description = $imageImageRepository->getDescription();
|
||||
$this->createdAt = $imageImageRepository->getCreatedAt();
|
||||
$this->createdBy = $imageImageRepository->getCreatedBy();
|
||||
}
|
||||
|
|
|
@ -39,6 +39,9 @@ final class ImageOutput extends AbstractOutput
|
|||
#[Groups(['image:read'])]
|
||||
public ?array $partitionInfo = null;
|
||||
|
||||
#[Groups(['image:read', 'image-image-repository:read'])]
|
||||
public ?int $version = null;
|
||||
|
||||
#[Groups(['image:read'])]
|
||||
public \DateTime $createdAt;
|
||||
|
||||
|
@ -58,6 +61,7 @@ final class ImageOutput extends AbstractOutput
|
|||
fn(ImageImageRepository $image) => new ImageImageRepositoryOutput($image)
|
||||
)->toArray();
|
||||
|
||||
$this->version = $image->getVersion();
|
||||
$this->partitionInfo = json_decode($image->getPartitionInfo(), true);
|
||||
$this->remotePc = $image->isRemotePc();
|
||||
$this->isGlobal = $image->isGlobal();
|
||||
|
|
|
@ -18,6 +18,12 @@ class ImageRepositoryOutput extends AbstractOutput
|
|||
#[Groups(['repository:read'])]
|
||||
public ?string $comments = '';
|
||||
|
||||
#[Groups(['repository:read'])]
|
||||
public ?string $sshPort = '';
|
||||
|
||||
#[Groups(['repository:read'])]
|
||||
public ?string $user = '';
|
||||
|
||||
#[Groups(['repository:read'])]
|
||||
public \DateTime $createdAt;
|
||||
|
||||
|
@ -31,6 +37,8 @@ class ImageRepositoryOutput extends AbstractOutput
|
|||
$this->name = $imageRepository->getName();
|
||||
$this->ip = $imageRepository->getIp();
|
||||
$this->comments = $imageRepository->getComments();
|
||||
$this->sshPort = $imageRepository->getSshPort();
|
||||
$this->user = $imageRepository->getUser();
|
||||
$this->createdAt = $imageRepository->getCreatedAt();
|
||||
$this->createdBy = $imageRepository->getCreatedBy();
|
||||
}
|
||||
|
|
|
@ -48,9 +48,6 @@ final class OrganizationalUnitOutput extends AbstractOutput
|
|||
#[Groups(['organizational-unit:read'])]
|
||||
public array $children = [];
|
||||
|
||||
#[Groups(['organizational-unit:read'])]
|
||||
public array $clients = [];
|
||||
|
||||
#[Groups(['organizational-unit:read', "client:read"])]
|
||||
#[ApiProperty(readableLink: true)]
|
||||
public ?RemoteCalendarOutput $remoteCalendar = null;
|
||||
|
@ -96,12 +93,6 @@ final class OrganizationalUnitOutput extends AbstractOutput
|
|||
)->toArray();
|
||||
}
|
||||
|
||||
if (isset($context['groups']) && in_array('organizational-unit:read', $context['groups'])) {
|
||||
$this->clients = $organizationalUnit->getClients()->map(
|
||||
fn(Client $client) => new ClientOutput($client)
|
||||
)->toArray();
|
||||
}
|
||||
|
||||
$this->excludeParentChanges = $organizationalUnit->isExcludeParentChanges();
|
||||
$this->path = $organizationalUnit->getPath();
|
||||
$this->createdAt = $organizationalUnit->getCreatedAt();
|
||||
|
|
|
@ -33,9 +33,6 @@ final class SubnetOutput extends AbstractOutput
|
|||
#[Groups(['subnet:read'])]
|
||||
public ?string $dns = null;
|
||||
|
||||
#[Groups(['subnet:read'])]
|
||||
public array $clients;
|
||||
|
||||
#[Groups(['subnet:read'])]
|
||||
public ?bool $synchronized = false;
|
||||
|
||||
|
@ -61,11 +58,6 @@ final class SubnetOutput extends AbstractOutput
|
|||
$this->bootFileName = $subnet->getBootFileName();
|
||||
$this->synchronized = $subnet->isSynchronized();
|
||||
$this->serverId = $subnet->getServerId();
|
||||
|
||||
$this->clients = $subnet->getClients()->map(
|
||||
fn(Client $client) => new ClientOutput($client)
|
||||
)->toArray();
|
||||
|
||||
$this->createdAt = $subnet->getCreatedAt();
|
||||
$this->createdBy = $subnet->getCreatedBy();
|
||||
}
|
||||
|
|
|
@ -59,7 +59,7 @@ final class TraceOutput extends AbstractOutput
|
|||
$this->output = $trace->getOutput();
|
||||
$this->input = $trace->getInput();
|
||||
$this->finishedAt = $trace->getFinishedAt();
|
||||
$this->progress = $trace->getProgress() / 100;
|
||||
$this->progress = $trace->getProgress();
|
||||
$this->createdAt = $trace->getCreatedAt();
|
||||
$this->createdBy = $trace->getCreatedBy();
|
||||
}
|
||||
|
|
|
@ -14,6 +14,9 @@ use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
|
|||
#[ORM\UniqueConstraint(name: 'UNIQ_IDENTIFIER_MAC', fields: ['mac'])]
|
||||
#[UniqueEntity(fields: ['ip'], message: 'This IP address is already in use.')]
|
||||
#[UniqueEntity(fields: ['mac'], message: 'This MAC address is already in use.')]
|
||||
#[ORM\Index(fields: ['status'], name: 'IDX_STATUS')]
|
||||
#[ORM\Index(fields: ['updatedAt'], name: 'IDX_UPDATED_AT')]
|
||||
#[ORM\Index(fields: ['status', 'updatedAt'], name: 'IDX_STATUS_UPDATED_AT')]
|
||||
class Client extends AbstractEntity
|
||||
{
|
||||
use NameableTrait;
|
||||
|
@ -82,6 +85,9 @@ class Client extends AbstractEntity
|
|||
#[ORM\Column(nullable: true)]
|
||||
private ?bool $pxeSync = null;
|
||||
|
||||
#[ORM\Column(length: 255, nullable: true)]
|
||||
private ?string $firmwareType = null;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
|
@ -335,4 +341,16 @@ class Client extends AbstractEntity
|
|||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getFirmwareType(): ?string
|
||||
{
|
||||
return $this->firmwareType;
|
||||
}
|
||||
|
||||
public function setFirmwareType(?string $firmwareType): static
|
||||
{
|
||||
$this->firmwareType = $firmwareType;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,6 +35,9 @@ class Command extends AbstractEntity
|
|||
#[ORM\ManyToMany(targetEntity: CommandTask::class, mappedBy: 'commands')]
|
||||
private Collection $commandTasks;
|
||||
|
||||
#[ORM\Column(nullable: true)]
|
||||
private ?bool $parameters = null;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
|
@ -131,4 +134,16 @@ class Command extends AbstractEntity
|
|||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function isParameters(): ?bool
|
||||
{
|
||||
return $this->parameters;
|
||||
}
|
||||
|
||||
public function setParameters(?bool $parameters): static
|
||||
{
|
||||
$this->parameters = $parameters;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -46,6 +46,9 @@ class Image extends AbstractEntity
|
|||
#[ORM\OneToMany(mappedBy: 'image', targetEntity: ImageImageRepository::class, cascade: ['persist'], orphanRemoval: true)]
|
||||
private Collection $imageImageRepositories;
|
||||
|
||||
#[ORM\Column(nullable: true)]
|
||||
private ?int $version = null;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
|
@ -191,4 +194,16 @@ class Image extends AbstractEntity
|
|||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getVersion(): ?int
|
||||
{
|
||||
return $this->version;
|
||||
}
|
||||
|
||||
public function setVersion(?int $version): static
|
||||
{
|
||||
$this->version = $version;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,8 +7,6 @@ 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')]
|
||||
|
@ -28,6 +26,18 @@ class ImageImageRepository extends AbstractEntity
|
|||
#[ORM\Column(length: 255, nullable: true)]
|
||||
private ?string $imageFullsum = null;
|
||||
|
||||
#[ORM\Column(length: 255, nullable: true)]
|
||||
private ?string $datasize = null;
|
||||
|
||||
#[ORM\Column(nullable: true)]
|
||||
private ?int $version = null;
|
||||
|
||||
#[ORM\Column(length: 255, nullable: true)]
|
||||
private ?string $description = null;
|
||||
|
||||
#[ORM\Column(length: 255)]
|
||||
private ?string $name = null;
|
||||
|
||||
public function getImage(): ?Image
|
||||
{
|
||||
return $this->image;
|
||||
|
@ -87,4 +97,52 @@ class ImageImageRepository extends AbstractEntity
|
|||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getDatasize(): ?string
|
||||
{
|
||||
return $this->datasize;
|
||||
}
|
||||
|
||||
public function setDatasize(?string $datasize): static
|
||||
{
|
||||
$this->datasize = $datasize;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getVersion(): ?int
|
||||
{
|
||||
return $this->version;
|
||||
}
|
||||
|
||||
public function setVersion(?int $version): static
|
||||
{
|
||||
$this->version = $version;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getDescription(): ?string
|
||||
{
|
||||
return $this->description;
|
||||
}
|
||||
|
||||
public function setDescription(?string $description): static
|
||||
{
|
||||
$this->description = $description;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getName(): ?string
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
public function setName(string $name): static
|
||||
{
|
||||
$this->name = $name;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,6 +10,8 @@ use Doctrine\ORM\Mapping as ORM;
|
|||
#[ORM\Entity(repositoryClass: ImageRepositoryRepository::class)]
|
||||
class ImageRepository extends AbstractEntity
|
||||
{
|
||||
const string DEFAULT_USER = 'opengnsys';
|
||||
|
||||
use NameableTrait;
|
||||
|
||||
#[ORM\Column(length: 255)]
|
||||
|
@ -24,6 +26,12 @@ class ImageRepository extends AbstractEntity
|
|||
#[ORM\OneToMany(mappedBy: 'repository', targetEntity: ImageImageRepository::class)]
|
||||
private Collection $imageImageRepositories;
|
||||
|
||||
#[ORM\Column(length: 255, nullable: true)]
|
||||
private ?string $user = self::DEFAULT_USER;
|
||||
|
||||
#[ORM\Column(length: 255, nullable: true)]
|
||||
private ?string $sshPort = null;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
|
@ -83,4 +91,28 @@ class ImageRepository extends AbstractEntity
|
|||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getUser(): ?string
|
||||
{
|
||||
return $this->user;
|
||||
}
|
||||
|
||||
public function setUser(?string $user): static
|
||||
{
|
||||
$this->user = $user;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getSshPort(): ?string
|
||||
{
|
||||
return $this->sshPort;
|
||||
}
|
||||
|
||||
public function setSshPort(?string $sshPort): static
|
||||
{
|
||||
$this->sshPort = $sshPort;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,6 +25,14 @@ class ClientStatusNotifier
|
|||
|
||||
public function postUpdate(Client $client, PostUpdateEventArgs $event): void
|
||||
{
|
||||
$em = $event->getObjectManager();
|
||||
$uow = $em->getUnitOfWork();
|
||||
$changeSet = $uow->getEntityChangeSet($client);
|
||||
|
||||
if (!array_key_exists('status', $changeSet)) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
$this->notifyClientStatusChange($client);
|
||||
} catch (\Exception $e) {
|
||||
|
@ -38,9 +46,14 @@ class ClientStatusNotifier
|
|||
|
||||
private function notifyClientStatusChange(Client $client): void
|
||||
{
|
||||
$data[] = [
|
||||
'@id' => '/clients/' . $client->getUuid(),
|
||||
'status' => $client->getStatus(),
|
||||
];
|
||||
|
||||
$update = new Update(
|
||||
'clients',
|
||||
json_encode(['@id' => '/clients/'.$client->getUuid(), 'status' => $client->getStatus()])
|
||||
json_encode($data)
|
||||
);
|
||||
$this->hub->publish($update);
|
||||
|
||||
|
|
|
@ -42,7 +42,7 @@ class TraceStatusProgressNotifier
|
|||
{
|
||||
$update = new Update(
|
||||
'traces',
|
||||
json_encode(['@id' => '/traces/' . $trace->getUuid(), 'status' => $trace->getStatus(), 'progress' => $trace->getProgress() / 100])
|
||||
json_encode(['@id' => '/traces/' . $trace->getUuid(), 'status' => $trace->getStatus(), 'progress' => $trace->getProgress()])
|
||||
);
|
||||
$this->hub->publish($update);
|
||||
|
||||
|
|
|
@ -58,9 +58,14 @@ class MercureSubscriber implements EventSubscriberInterface
|
|||
/** @var Client $client */
|
||||
$client = $clientOutput->getEntity();
|
||||
|
||||
$data[] = [
|
||||
'@id' => '/clients/' . $client->getUuid(),
|
||||
'status' => $client->getStatus(),
|
||||
];
|
||||
|
||||
$update = new Update(
|
||||
'clients',
|
||||
json_encode(['@id' => '/clients/'.$client->getUuid(), 'status' => $client->getStatus()])
|
||||
json_encode($data)
|
||||
);
|
||||
$this->hub->publish($update);
|
||||
|
||||
|
|
|
@ -5,18 +5,25 @@ namespace App\EventSubscriber;
|
|||
use ApiPlatform\Symfony\EventListener\EventPriorities;
|
||||
use App\Controller\OgBoot\PxeBootFile\PostAction;
|
||||
use App\Dto\Output\OrganizationalUnitOutput;
|
||||
use App\Entity\Client;
|
||||
use App\Entity\NetworkSettings;
|
||||
use App\Entity\OrganizationalUnit;
|
||||
use App\Model\OrganizationalUnitTypes;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpKernel\Event\ViewEvent;
|
||||
use Symfony\Component\HttpKernel\KernelEvents;
|
||||
use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface;
|
||||
use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface;
|
||||
use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface;
|
||||
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
|
||||
|
||||
final readonly class OrganizationalUnitSubscriber implements EventSubscriberInterface
|
||||
{
|
||||
public function __construct(
|
||||
private EntityManagerInterface $entityManager,
|
||||
private readonly PostAction $postAction,
|
||||
)
|
||||
{
|
||||
|
||||
|
@ -29,6 +36,12 @@ final readonly class OrganizationalUnitSubscriber implements EventSubscriberInte
|
|||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws TransportExceptionInterface
|
||||
* @throws ServerExceptionInterface
|
||||
* @throws RedirectionExceptionInterface
|
||||
* @throws ClientExceptionInterface
|
||||
*/
|
||||
public function updateNetworkSettings(ViewEvent $event): void
|
||||
{
|
||||
$organizationalUnitOutput = $event->getControllerResult();
|
||||
|
@ -50,7 +63,9 @@ final readonly class OrganizationalUnitSubscriber implements EventSubscriberInte
|
|||
|
||||
$this->updateChildrenNetworkSettings($organizationalUnitEntity, $newNetworkSettings);
|
||||
|
||||
$this->entityManager->flush();
|
||||
if ($organizationalUnitEntity->getType() === OrganizationalUnitTypes::CLASSROOM) {
|
||||
//$this->syncOgBoot($organizationalUnitEntity);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -58,14 +73,21 @@ final readonly class OrganizationalUnitSubscriber implements EventSubscriberInte
|
|||
{
|
||||
/** @var OrganizationalUnit $childUnit */
|
||||
foreach ($parentUnit->getOrganizationalUnits() as $childUnit) {
|
||||
//var_dump($childUnit->getNetworkSettings()->getMcastPort());
|
||||
if ($childUnit->isExcludeParentChanges()) {
|
||||
$childUnit->setNetworkSettings(null);
|
||||
} else{
|
||||
$childUnit->setNetworkSettings($networkSettings);
|
||||
|
||||
foreach ($childUnit->getClients() as $client) {
|
||||
$client->setOgLive($networkSettings->getOgLive());
|
||||
$client->setMenu($networkSettings->getMenu());
|
||||
$client->setRepository($networkSettings->getRepository());
|
||||
$this->entityManager->persist($client);
|
||||
}
|
||||
|
||||
}
|
||||
$this->entityManager->persist($childUnit);
|
||||
$this->entityManager->flush();
|
||||
|
||||
$this->updateChildrenNetworkSettings($childUnit, $networkSettings);
|
||||
}
|
||||
|
@ -94,7 +116,32 @@ final readonly class OrganizationalUnitSubscriber implements EventSubscriberInte
|
|||
$newNetworkSettings->setMenu($organizationalUnitEntity->getNetworkSettings()->getMenu());
|
||||
$newNetworkSettings->setRepository($organizationalUnitEntity->getNetworkSettings()->getRepository());
|
||||
$newNetworkSettings->setOgLive($organizationalUnitEntity->getNetworkSettings()->getOgLive());
|
||||
$newNetworkSettings->setNetiface($organizationalUnitEntity->getNetworkSettings()->getNetiface());
|
||||
|
||||
return $newNetworkSettings;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws TransportExceptionInterface
|
||||
* @throws ServerExceptionInterface
|
||||
* @throws RedirectionExceptionInterface
|
||||
* @throws ClientExceptionInterface
|
||||
*/
|
||||
private function syncOgBoot(OrganizationalUnit $organizationalUnitEntity): void
|
||||
{
|
||||
$clients = $this->entityManager->getRepository(Client::class)->findClientsByOrganizationalUnitAndDescendants($organizationalUnitEntity->getId(), []);
|
||||
|
||||
if (empty($clients)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/** @var Client $client */
|
||||
foreach ($clients as $client) {
|
||||
if ($client->getTemplate() === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->postAction->__invoke($client, $client->getTemplate());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
<?php
|
||||
|
||||
namespace App\Factory;
|
||||
|
||||
use App\Entity\ImageImageRepository;
|
||||
use App\Repository\ImageImageRepositoryRepository;
|
||||
use Zenstruck\Foundry\ModelFactory;
|
||||
use Zenstruck\Foundry\Persistence\PersistentProxyObjectFactory;
|
||||
use Zenstruck\Foundry\Persistence\Proxy;
|
||||
use Zenstruck\Foundry\Persistence\ProxyRepositoryDecorator;
|
||||
|
||||
/**
|
||||
* @extends PersistentProxyObjectFactory<ImageImageRepository>
|
||||
*/
|
||||
final class ImageImageRepositoryFactory extends ModelFactory
|
||||
{
|
||||
/**
|
||||
* @see https://symfony.com/bundles/ZenstruckFoundryBundle/current/index.html#factories-as-services
|
||||
*
|
||||
* @todo inject services if required
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see https://symfony.com/bundles/ZenstruckFoundryBundle/current/index.html#model-factories
|
||||
*
|
||||
* @todo add your default values here
|
||||
*/
|
||||
protected function getDefaults(): array
|
||||
{
|
||||
return [
|
||||
'createdAt' => self::faker()->dateTime(),
|
||||
'image' => ImageFactory::new(),
|
||||
'name' => self::faker()->text(255),
|
||||
'repository' => ImageRepositoryFactory::new(),
|
||||
'status' => self::faker()->text(255),
|
||||
'updatedAt' => self::faker()->dateTime(),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @see https://symfony.com/bundles/ZenstruckFoundryBundle/current/index.html#initialization
|
||||
*/
|
||||
protected function initialize(): self
|
||||
{
|
||||
return $this
|
||||
// ->afterInstantiate(function(ImageImageRepository $imageImageRepository): void {})
|
||||
;
|
||||
}
|
||||
|
||||
protected static function getClass(): string
|
||||
{
|
||||
return ImageImageRepository::class;
|
||||
}
|
||||
}
|
|
@ -6,6 +6,7 @@ final class ClientStatus
|
|||
{
|
||||
public const string OFF = 'off';
|
||||
public const string INITIALIZING = 'initializing';
|
||||
public const string DISCONNECTED = 'disconnected';
|
||||
public const string TURNING_OFF = 'turning-off';
|
||||
public const string OG_LIVE = 'og-live';
|
||||
public const string BUSY = 'busy';
|
||||
|
@ -20,6 +21,7 @@ final class ClientStatus
|
|||
self::OFF => 'Apagado',
|
||||
self::TURNING_OFF => 'Apagando',
|
||||
self::INITIALIZING => 'Inicializando',
|
||||
self::DISCONNECTED => 'Conexión perdida',
|
||||
self::OG_LIVE => 'OG Live',
|
||||
self::BUSY => 'Ocupado',
|
||||
self::LINUX => 'Linux',
|
||||
|
|
|
@ -12,6 +12,7 @@ final class CommandTypes
|
|||
public const string BACKUP_IMAGE = 'backup-image';
|
||||
public const string IMPORT_IMAGE = 'import-image';
|
||||
public const string EXPORT_IMAGE = 'export-image';
|
||||
public const string RENAME_IMAGE = 'rename-image';
|
||||
public const string CONVERT_IMAGE_TO_VIRTUAL = 'convert-image-to-virtual';
|
||||
public const string TRANSFER_IMAGE = 'transfer-image';
|
||||
public const string POWER_ON = 'power-on';
|
||||
|
@ -21,6 +22,7 @@ final class CommandTypes
|
|||
public const string LOGOUT = 'logout';
|
||||
public const string PARTITION_AND_FORMAT = 'partition-and-format';
|
||||
public const string INSTALL_OGLIVE = 'install-oglive';
|
||||
public const string RUN_SCRIPT = 'run-script';
|
||||
|
||||
private const array COMMAND_TYPES = [
|
||||
self::DEPLOY_IMAGE => 'Deploy Image',
|
||||
|
@ -32,6 +34,7 @@ final class CommandTypes
|
|||
self::BACKUP_IMAGE => 'Backup Image',
|
||||
self::IMPORT_IMAGE => 'Import image',
|
||||
self::EXPORT_IMAGE => 'Export image',
|
||||
self::RENAME_IMAGE => 'Rename Image',
|
||||
self::POWER_ON => 'Encender',
|
||||
self::REBOOT => 'Reiniciar',
|
||||
self::SHUTDOWN => 'Apagar',
|
||||
|
@ -40,6 +43,7 @@ final class CommandTypes
|
|||
self::PARTITION_AND_FORMAT => 'Partition and Format',
|
||||
self::TRANSFER_IMAGE => 'Transfer Image',
|
||||
self::INSTALL_OGLIVE => 'Instalar OgLive',
|
||||
self::RUN_SCRIPT => 'Run Script',
|
||||
];
|
||||
|
||||
public static function getCommandTypes(): array
|
||||
|
|
|
@ -2,7 +2,9 @@
|
|||
|
||||
namespace App\Repository;
|
||||
|
||||
use App\Entity\Image;
|
||||
use App\Entity\ImageImageRepository;
|
||||
use App\Entity\ImageRepository as Repository;
|
||||
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
|
||||
use Doctrine\Persistence\ManagerRegistry;
|
||||
|
||||
|
@ -15,4 +17,27 @@ class ImageImageRepositoryRepository extends AbstractRepository
|
|||
{
|
||||
parent::__construct($registry, ImageImageRepository::class);
|
||||
}
|
||||
|
||||
public function findLatestVersionByImageAndRepository(Image $image, Repository $repository): ?ImageImageRepository
|
||||
{
|
||||
return $this->createQueryBuilder('i')
|
||||
->andWhere('i.image = :imageId')
|
||||
->setParameter('imageId', $image->getId())
|
||||
->andWhere('i.repository = :repository')
|
||||
->setParameter('repository', $repository->getId())
|
||||
->orderBy('i.version', 'DESC')
|
||||
->setMaxResults(1)
|
||||
->getQuery()
|
||||
->getOneOrNullResult();
|
||||
}
|
||||
|
||||
public function findLatestVersion(): ?ImageImageRepository
|
||||
{
|
||||
return $this->createQueryBuilder('i')
|
||||
->orderBy('i.version', 'DESC')
|
||||
->setMaxResults(1)
|
||||
->getQuery()
|
||||
->getOneOrNullResult();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -26,11 +26,19 @@ class CreatePartitionService
|
|||
|
||||
$receivedPartitions = [];
|
||||
|
||||
foreach ($data['cfg'] as $cfg) {
|
||||
if (!isset($cfg['disk'], $cfg['par'], $cfg['tam'], $cfg['uso'], $cfg['fsi'])) {
|
||||
continue;
|
||||
}
|
||||
$filteredCfg = array_filter($data['cfg'], function ($cfg) {
|
||||
return isset($cfg['disk'], $cfg['par'], $cfg['tam'], $cfg['uso'], $cfg['fsi']);
|
||||
});
|
||||
|
||||
foreach ($data['cfg'] as $cfg) {
|
||||
if (!empty($cfg['fwt'])) {
|
||||
$clientEntity->setFirmwareType($cfg['fwt']);
|
||||
$this->entityManager->persist($clientEntity);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($filteredCfg as $cfg) {
|
||||
$partitionEntity = $this->entityManager->getRepository(Partition::class)
|
||||
->findOneBy(['client' => $clientEntity, 'diskNumber' => $cfg['disk'], 'partitionNumber' => $cfg['par']]);
|
||||
|
||||
|
@ -38,6 +46,8 @@ class CreatePartitionService
|
|||
$partitionEntity = new Partition();
|
||||
}
|
||||
|
||||
$partitionEntity->setOperativeSystem(null);
|
||||
|
||||
if (isset($cfg['soi']) && $cfg['soi'] !== '') {
|
||||
$operativeSystem = $this->entityManager->getRepository(OperativeSystem::class)
|
||||
->findOneBy(['name' => $cfg['soi']]);
|
||||
|
|
|
@ -10,6 +10,7 @@ use ApiPlatform\Metadata\Put;
|
|||
use ApiPlatform\State\ProcessorInterface;
|
||||
use ApiPlatform\Validator\ValidatorInterface;
|
||||
use App\Controller\OgAgent\CreateImageAction;
|
||||
use App\Controller\OgRepository\Image\RenameAction;
|
||||
use App\Controller\OgRepository\Image\TransferAction;
|
||||
use App\Dto\Input\ImageInput;
|
||||
use App\Dto\Input\ImageRepositoryInput;
|
||||
|
@ -17,15 +18,16 @@ use App\Dto\Output\ImageOutput;
|
|||
use App\Entity\ImageImageRepository;
|
||||
use App\Repository\ImageRepository;
|
||||
use App\Repository\ImageRepositoryRepository as ImageRepositoryRepository;
|
||||
use Symfony\Component\HttpKernel\KernelInterface;
|
||||
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
|
||||
|
||||
readonly class ImageProcessor implements ProcessorInterface
|
||||
{
|
||||
public function __construct(
|
||||
private ImageRepositoryRepository $imageRepositoryRepository,
|
||||
private ImageRepository $imageRepository,
|
||||
private ValidatorInterface $validator,
|
||||
private CreateImageAction $createImageActionController,
|
||||
private KernelInterface $kernel,
|
||||
)
|
||||
{
|
||||
}
|
||||
|
@ -61,16 +63,24 @@ readonly class ImageProcessor implements ProcessorInterface
|
|||
$entity = $this->imageRepository->findOneByUuid($uriVariables['uuid']);
|
||||
}
|
||||
|
||||
$image = $data->createOrUpdateEntity($entity);
|
||||
$this->validator->validate($image);
|
||||
|
||||
if ($data->source !== 'input') {
|
||||
$response = $this->createImageActionController->__invoke($image);
|
||||
if ($data->selectedImage){
|
||||
//$content = $this->renameActionController->__invoke($data->selectedImage->getEntity());
|
||||
|
||||
$response = $this->createImageActionController->__invoke($data->selectedImage->getEntity());
|
||||
|
||||
} else {
|
||||
$image = $data->createOrUpdateEntity($entity);
|
||||
|
||||
if ($this->kernel->getEnvironment() !== 'test') {
|
||||
$response = $this->createImageActionController->__invoke($image);
|
||||
}
|
||||
|
||||
$this->validator->validate($image);
|
||||
$this->imageRepository->save($image);
|
||||
}
|
||||
|
||||
$this->imageRepository->save($image);
|
||||
|
||||
return new ImageOutput($image);
|
||||
return new ImageOutput($data->selectedImage?->getEntity() ?? $image);
|
||||
}
|
||||
|
||||
private function processDelete($data, Operation $operation, array $uriVariables = [], array $context = []): null
|
||||
|
|
|
@ -9,6 +9,7 @@ use ApiPlatform\Metadata\Patch;
|
|||
use ApiPlatform\Metadata\Put;
|
||||
use ApiPlatform\State\Pagination\TraversablePaginator;
|
||||
use ApiPlatform\State\ProviderInterface;
|
||||
use App\Dto\Input\ImageImageRepositoryInput;
|
||||
use App\Dto\Output\ImageImageRepositoryOutput;
|
||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
|
||||
|
@ -26,6 +27,9 @@ readonly class ImageImageRepositoryProvider implements ProviderInterface
|
|||
switch ($operation){
|
||||
case $operation instanceof GetCollection:
|
||||
return $this->provideCollection($operation, $uriVariables, $context);
|
||||
case $operation instanceof Patch:
|
||||
case $operation instanceof Put:
|
||||
return $this->provideInput($operation, $uriVariables, $context);
|
||||
case $operation instanceof Get:
|
||||
return $this->provideItem($operation, $uriVariables, $context);
|
||||
}
|
||||
|
@ -53,4 +57,15 @@ readonly class ImageImageRepositoryProvider implements ProviderInterface
|
|||
|
||||
return new ImageImageRepositoryOutput($item);
|
||||
}
|
||||
|
||||
public function provideInput(Operation $operation, array $uriVariables = [], array $context = []): object|array|null
|
||||
{
|
||||
if (isset($uriVariables['uuid'])) {
|
||||
$item = $this->itemProvider->provide($operation, $uriVariables, $context);
|
||||
|
||||
return $item !== null ? new ImageImageRepositoryInput($item) : null;
|
||||
}
|
||||
|
||||
return new ImageImageRepositoryInput();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ use App\Entity\OrganizationalUnit;
|
|||
use App\Entity\SoftwareProfile;
|
||||
use App\Factory\ClientFactory;
|
||||
use App\Factory\ImageFactory;
|
||||
use App\Factory\ImageImageRepositoryFactory;
|
||||
use App\Factory\ImageRepositoryFactory;
|
||||
use App\Factory\OrganizationalUnitFactory;
|
||||
use App\Factory\SoftwareProfileFactory;
|
||||
|
@ -70,12 +71,12 @@ class ImageTest extends AbstractTest
|
|||
SoftwareProfileFactory::createOne(['description' => self::SOFTWARE_PROFILE]);
|
||||
$swPIri = $this->findIriBy(SoftwareProfile::class, ['description' => self::SOFTWARE_PROFILE]);
|
||||
|
||||
$imageRepositories = ImageRepositoryFactory::createMany(5);
|
||||
$imageRepositories = ImageImageRepositoryFactory::createMany(5);
|
||||
|
||||
$this->createClientWithCredentials()->request('POST', '/images',['json' => [
|
||||
'name' => self::IMAGE_CREATE,
|
||||
'softwareProfile' => $swPIri,
|
||||
'imageRepositories' => array_map(fn($repo) => '/image-repositories/'. $repo->getUuid(), $imageRepositories)
|
||||
'imageImageRepositories' => array_map(fn($repo) => '/image-repositories/'. $repo->getUuid(), $imageRepositories)
|
||||
]]);
|
||||
|
||||
$this->assertResponseStatusCodeSame(201);
|
||||
|
@ -102,11 +103,11 @@ class ImageTest extends AbstractTest
|
|||
ImageFactory::createOne(['name' => self::IMAGE_CREATE]);
|
||||
$iri = $this->findIriBy(Image::class, ['name' => self::IMAGE_CREATE]);
|
||||
|
||||
$imageRepositories = ImageRepositoryFactory::createMany(5);
|
||||
$imageRepositories = ImageImageRepositoryFactory::createMany(5);
|
||||
|
||||
$this->createClientWithCredentials()->request('PUT', $iri, ['json' => [
|
||||
'name' => self::IMAGE_UPDATE,
|
||||
'imageRepositories' => array_map(fn($repo) => '/image-repositories/'. $repo->getUuid(), $imageRepositories)
|
||||
'imageImageRepositories' => array_map(fn($repo) => '/image-repositories/'. $repo->getUuid(), $imageRepositories)
|
||||
]]);
|
||||
|
||||
$this->assertResponseIsSuccessful();
|
||||
|
|
Loading…
Reference in New Issue