commit
63721ab428
|
@ -34,3 +34,7 @@ debian/*.log
|
|||
debian/.debhelper/
|
||||
debian/files
|
||||
|
||||
### Certificates
|
||||
certs/
|
||||
|
||||
|
||||
|
|
13
CHANGELOG.md
13
CHANGELOG.md
|
@ -1,8 +1,19 @@
|
|||
# Changelog
|
||||
## [0.17.3] - 2025-08-04
|
||||
## [0.18.1] - 2025-08-06
|
||||
### Improved
|
||||
- Se ha añadido el filtro "jobId" a la entidad Trace.
|
||||
|
||||
---
|
||||
## [0.18.0] -2025-08-06
|
||||
### Added
|
||||
- Se ha añadido una inetragracin con el agente, que hace que podamos comprobar el tamaño de las particiones, y si son correctas.
|
||||
|
||||
### Improved
|
||||
- Se ha actualizado la funcionalidad para actualizar imagenes de ogGIt
|
||||
- Se ha mejorado y actualizado la funcionalidad de creacion de tareas, actualizando el script que se ejecuta cada minuto.
|
||||
- Se ha eliminado el ".py" del menu browser.
|
||||
- Mejora en el formato de las fechas (datetime) en la ejecucion de algunos scripts.
|
||||
|
||||
---
|
||||
## [0.17.2] - 2025-08-04
|
||||
### Improved
|
||||
|
|
|
@ -92,6 +92,13 @@ resources:
|
|||
uriTemplate: /clients/server/power-off
|
||||
controller: App\Controller\OgAgent\PowerOffAction
|
||||
|
||||
check_partition_sizes:
|
||||
class: ApiPlatform\Metadata\Post
|
||||
method: POST
|
||||
input: App\Dto\Input\CheckPartitionSizesInput
|
||||
uriTemplate: /clients/{uuid}/check-partition-sizes
|
||||
controller: App\Controller\OgAgent\CheckPartitionSizesAction
|
||||
|
||||
|
||||
properties:
|
||||
App\Entity\Client:
|
||||
|
|
|
@ -93,7 +93,7 @@ resources:
|
|||
description: 'ID del ImageRepository'
|
||||
|
||||
git_deploy_image:
|
||||
shortName: Git Repository
|
||||
shortName: Deploy Git Image
|
||||
description: Deploy Git image
|
||||
class: ApiPlatform\Metadata\Post
|
||||
method: POST
|
||||
|
@ -101,6 +101,25 @@ resources:
|
|||
uriTemplate: /git-repositories/deploy-image
|
||||
controller: App\Controller\DeployGitImageAction
|
||||
|
||||
|
||||
git_update_image:
|
||||
shortName: Update Git Image
|
||||
description: Update Git image
|
||||
class: ApiPlatform\Metadata\Post
|
||||
method: POST
|
||||
input: App\Dto\Input\UpdateGitImageInput
|
||||
uriTemplate: /git-repositories/update-image
|
||||
controller: App\Controller\UpdateGitImageAction
|
||||
|
||||
get_git_data:
|
||||
shortName: Get Git Data
|
||||
description: Get Git data
|
||||
class: ApiPlatform\Metadata\Post
|
||||
method: POST
|
||||
input: App\Dto\Input\GetGitDataInput
|
||||
uriTemplate: /git-repositories/get-git-data
|
||||
controller: App\Controller\OgAgent\GetGitDataAction
|
||||
|
||||
properties:
|
||||
App\Entity\GitRepository:
|
||||
id:
|
||||
|
|
|
@ -102,6 +102,25 @@ resources:
|
|||
uriTemplate: /image-repositories/server/git/{uuid}/branches
|
||||
controller: App\Controller\OgRepository\Git\GetBranchesAction
|
||||
|
||||
git_repository_create_tag:
|
||||
shortName: OgRepository Server
|
||||
description: Create a tag in a Git repository
|
||||
class: ApiPlatform\Metadata\Post
|
||||
method: POST
|
||||
input: App\Dto\Input\CreateTagInput
|
||||
uriTemplate: /image-repositories/server/git/{uuid}/create-tag
|
||||
controller: App\Controller\OgRepository\Git\CreateTagAction
|
||||
|
||||
git_repository_create_branch:
|
||||
shortName: OgRepository Server
|
||||
description: Create a branch in a Git repository
|
||||
class: ApiPlatform\Metadata\Post
|
||||
method: POST
|
||||
input: App\Dto\Input\CreateBranchInput
|
||||
uriTemplate: /image-repositories/server/git/{uuid}/create-branch
|
||||
controller: App\Controller\OgRepository\Git\CreateBranchAction
|
||||
|
||||
|
||||
properties:
|
||||
App\Entity\ImageRepository:
|
||||
id:
|
||||
|
|
|
@ -47,7 +47,7 @@ when@prod:
|
|||
syslog:
|
||||
type: syslog
|
||||
ident: "ogcore"
|
||||
level: error
|
||||
level: info
|
||||
formatter: App\Formatter\CustomLineFormatter
|
||||
channels: ["!event"]
|
||||
deprecation:
|
||||
|
|
|
@ -33,7 +33,7 @@ class CheckClientAvailability extends Command
|
|||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$io = new SymfonyStyle($input, $output);
|
||||
$threshold = (new \DateTime())->modify(' - '.self::THRESHOLD_MINUTES . ' minutes');
|
||||
$threshold = (new \DateTimeImmutable('UTC'))->modify(' - '.self::THRESHOLD_MINUTES . ' minutes');
|
||||
$startQueryTime = microtime(true);
|
||||
|
||||
$validStatuses = [ClientStatus::OG_LIVE, ClientStatus::WINDOWS, ClientStatus::LINUX, ClientStatus::MACOS, ClientStatus::INITIALIZING, ClientStatus::LINUX_SESSION, ClientStatus::WINDOWS_SESSION];
|
||||
|
|
|
@ -4,7 +4,21 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Command;
|
||||
|
||||
use App\Controller\OgAgent\CreateImageAction;
|
||||
use App\Controller\OgAgent\DeployImageAction;
|
||||
use App\Controller\OgAgent\PartitionAssistantAction;
|
||||
use App\Controller\OgAgent\RunScriptAction;
|
||||
use App\Dto\Input\CommandExecuteInput;
|
||||
use App\Dto\Input\DeployImageInput;
|
||||
use App\Dto\Input\PartitionInput;
|
||||
use App\Dto\Input\PartitionPostInput;
|
||||
use App\Dto\Output\ClientOutput;
|
||||
use App\Entity\Client;
|
||||
use App\Entity\Image;
|
||||
use App\Entity\ImageImageRepository;
|
||||
use App\Entity\Partition;
|
||||
use App\Entity\Trace;
|
||||
use App\Model\CommandTypes;
|
||||
use App\Model\TraceStatus;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
|
@ -17,7 +31,11 @@ use Symfony\Component\Console\Style\SymfonyStyle;
|
|||
class ExecutePendingTracesCommand extends Command
|
||||
{
|
||||
public function __construct(
|
||||
private readonly EntityManagerInterface $entityManager
|
||||
private readonly EntityManagerInterface $entityManager,
|
||||
private readonly CreateImageAction $createImageAction,
|
||||
private readonly DeployImageAction $deployImageAction,
|
||||
private readonly PartitionAssistantAction $partitionAssistantAction,
|
||||
private readonly RunScriptAction $runScriptAction
|
||||
) {
|
||||
parent::__construct();
|
||||
}
|
||||
|
@ -28,22 +46,271 @@ class ExecutePendingTracesCommand extends Command
|
|||
$startTime = microtime(true);
|
||||
|
||||
$traces = $this->entityManager->getRepository(Trace::class)
|
||||
->findBy(['status' => TraceStatus::PENDING]);
|
||||
->createQueryBuilder('t')
|
||||
->select('t')
|
||||
->where('t.status = :status')
|
||||
->setParameter('status', TraceStatus::PENDING)
|
||||
->andWhere('t.id IN (
|
||||
SELECT MIN(t2.id)
|
||||
FROM App\Entity\Trace t2
|
||||
WHERE t2.status = :status
|
||||
GROUP BY t2.client
|
||||
)')
|
||||
->orderBy('t.id', 'ASC')
|
||||
->getQuery()
|
||||
->getResult();
|
||||
|
||||
$count = count($traces);
|
||||
$io->info("Found $count pending traces");
|
||||
$io->info("Found $count pending trace(s) - processing the latest one");
|
||||
|
||||
$processedCount = 0;
|
||||
$errorCount = 0;
|
||||
|
||||
foreach ($traces as $trace) {
|
||||
$trace->setStatus(TraceStatus::IN_PROGRESS);
|
||||
$this->entityManager->persist($trace);
|
||||
try {
|
||||
$io->info("Processing trace {$trace->getUuid()} with command: {$trace->getCommand()}");
|
||||
|
||||
$result = $this->executeTrace($trace);
|
||||
|
||||
if ($result) {
|
||||
$processedCount++;
|
||||
$io->success("Successfully processed trace {$trace->getUuid()}");
|
||||
} else {
|
||||
$errorCount++;
|
||||
$io->error("Failed to process trace {$trace->getUuid()}");
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
$errorCount++;
|
||||
$io->error("Error processing trace {$trace->getUuid()}: " . $e->getMessage());
|
||||
|
||||
$trace->setStatus(TraceStatus::FAILED);
|
||||
$trace->setOutput($e->getMessage());
|
||||
$trace->setFinishedAt(new \DateTime());
|
||||
$this->entityManager->persist($trace);
|
||||
}
|
||||
}
|
||||
|
||||
$this->entityManager->flush();
|
||||
|
||||
$executionTime = microtime(true) - $startTime;
|
||||
$io->success("Updated $count traces to IN_PROGRESS status");
|
||||
$io->success("Processed $processedCount traces successfully, $errorCount failed");
|
||||
$io->note("Execution time: " . round($executionTime, 3) . "s");
|
||||
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
|
||||
private function executeTrace(Trace $trace): bool
|
||||
{
|
||||
$command = $trace->getCommand();
|
||||
$input = $trace->getInput() ?? [];
|
||||
$client = $trace->getClient();
|
||||
|
||||
if (!$client) {
|
||||
throw new \Exception("No client associated with trace");
|
||||
}
|
||||
|
||||
$trace->setExecutedAt(new \DateTime());
|
||||
$this->entityManager->persist($trace);
|
||||
$this->entityManager->flush();
|
||||
|
||||
try {
|
||||
switch ($command) {
|
||||
case CommandTypes::CREATE_IMAGE:
|
||||
return $this->executeCreateImage($trace, $input);
|
||||
|
||||
case CommandTypes::DEPLOY_IMAGE:
|
||||
return $this->executeDeployImage($trace, $input);
|
||||
|
||||
case CommandTypes::PARTITION_AND_FORMAT:
|
||||
return $this->executePartitionAssistant($trace, $input);
|
||||
|
||||
case CommandTypes::RUN_SCRIPT:
|
||||
return $this->executeRunScript($trace, $input);
|
||||
|
||||
default:
|
||||
throw new \Exception("Unsupported command type: $command");
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
$trace->setStatus(TraceStatus::FAILED);
|
||||
$trace->setOutput($e->getMessage());
|
||||
$trace->setFinishedAt(new \DateTime());
|
||||
$this->entityManager->persist($trace);
|
||||
$this->entityManager->flush();
|
||||
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
private function executeCreateImage(Trace $trace, array $input): bool
|
||||
{
|
||||
$client = $trace->getClient();
|
||||
|
||||
if (!isset($input['image'])) {
|
||||
throw new \Exception("Image UUID not found in trace input");
|
||||
}
|
||||
|
||||
$image = $this->entityManager->getRepository(Image::class)
|
||||
->findOneBy(['uuid' => $input['image']]);
|
||||
|
||||
if (!$image) {
|
||||
throw new \Exception("Image not found with UUID: {$input['image']}");
|
||||
}
|
||||
|
||||
$partition = null;
|
||||
if (isset($input['diskNumber']) && isset($input['partitionNumber'])) {
|
||||
$partition = $this->entityManager->getRepository(Partition::class)
|
||||
->findOneBy([
|
||||
'client' => $client,
|
||||
'diskNumber' => $input['diskNumber'],
|
||||
'partitionNumber' => $input['partitionNumber']
|
||||
]);
|
||||
|
||||
if (!$partition) {
|
||||
throw new \Exception("Partition not found for client {$client->getUuid()} with disk {$input['diskNumber']} and partition {$input['partitionNumber']}");
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
$response = $this->createImageAction->__invoke(
|
||||
queue: false,
|
||||
image: $image,
|
||||
partition: $partition,
|
||||
client: $client,
|
||||
gitRepositoryName: $input['gitRepositoryName'] ?? null,
|
||||
existingTrace: $trace
|
||||
);
|
||||
|
||||
if ($response->getStatusCode() === 200) {
|
||||
$trace->setStatus(TraceStatus::SUCCESS);
|
||||
$trace->setFinishedAt(new \DateTime());
|
||||
$this->entityManager->persist($trace);
|
||||
$this->entityManager->flush();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
} catch (\Exception $e) {
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private function executeDeployImage(Trace $trace, array $input): bool
|
||||
{
|
||||
$client = $trace->getClient();
|
||||
|
||||
if (!isset($input['imageImageRepository'])) {
|
||||
throw new \Exception("ImageImageRepository UUID not found in trace input");
|
||||
}
|
||||
|
||||
$imageImageRepository = $this->entityManager->getRepository(ImageImageRepository::class)
|
||||
->findOneBy(['uuid' => $input['imageImageRepository']]);
|
||||
|
||||
if (!$imageImageRepository) {
|
||||
throw new \Exception("ImageImageRepository not found with UUID: {$input['imageImageRepository']}");
|
||||
}
|
||||
|
||||
$deployInput = new DeployImageInput();
|
||||
$deployInput->method = $input['method'] ?? 'unicast';
|
||||
$deployInput->type = $input['type'] ?? 'monolithic';
|
||||
$deployInput->diskNumber = $input['diskNumber'] ?? 1;
|
||||
$deployInput->partitionNumber = $input['partitionNumber'] ?? 1;
|
||||
$deployInput->mcastMode = $input['mcastMode'] ?? 'duplex';
|
||||
$deployInput->mcastSpeed = $input['mcastSpeed'] ?? 100;
|
||||
$deployInput->mcastPort = $input['mcastPort'] ?? 8000;
|
||||
$deployInput->mcastIp = $input['mcastIp'] ?? '224.0.0.1';
|
||||
$deployInput->maxClients = $input['maxClients'] ?? 10;
|
||||
$deployInput->maxTime = $input['maxTime'] ?? 3600;
|
||||
$deployInput->p2pMode = $input['p2pMode'] ?? 'seed';
|
||||
$deployInput->p2pTime = $input['p2pTime'] ?? 300;
|
||||
|
||||
$jobId = $this->deployImageAction->__invoke(
|
||||
imageImageRepository: $imageImageRepository,
|
||||
input: $deployInput,
|
||||
client: $client
|
||||
);
|
||||
|
||||
$trace->setJobId($jobId);
|
||||
$this->entityManager->persist($trace);
|
||||
$this->entityManager->flush();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private function executePartitionAssistant(Trace $trace, array $input): bool
|
||||
{
|
||||
$client = $trace->getClient();
|
||||
|
||||
$partitionInput = new PartitionPostInput();
|
||||
$partitionInput->clients = [new ClientOutput($client)];
|
||||
|
||||
$partitions = [];
|
||||
$diskNumber = 1;
|
||||
|
||||
foreach ($input as $item) {
|
||||
if (isset($item['dis'])) {
|
||||
$diskNumber = (int)$item['dis'];
|
||||
} elseif (isset($item['par'])) {
|
||||
$partitionInputObj = new PartitionInput();
|
||||
$partitionInputObj->diskNumber = $diskNumber;
|
||||
$partitionInputObj->partitionNumber = (int)$item['par'];
|
||||
$partitionInputObj->partitionCode = $item['cpt'] ?? 'LINUX';
|
||||
$partitionInputObj->size = (float)($item['tam'] / 1024);
|
||||
$partitionInputObj->filesystem = $item['sfi'] ?? 'EXT4';
|
||||
$partitionInputObj->format = ($item['ope'] ?? '0') === '1';
|
||||
$partitions[] = $partitionInputObj;
|
||||
}
|
||||
}
|
||||
|
||||
$partitionInput->partitions = $partitions;
|
||||
$partitionInput->queue = false;
|
||||
|
||||
try {
|
||||
$response = $this->partitionAssistantAction->__invoke($partitionInput, $trace);
|
||||
|
||||
if ($response->getStatusCode() === 200) {
|
||||
$trace->setStatus(TraceStatus::SUCCESS);
|
||||
$trace->setFinishedAt(new \DateTime());
|
||||
$this->entityManager->persist($trace);
|
||||
$this->entityManager->flush();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
} catch (\Exception $e) {
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private function executeRunScript(Trace $trace, array $input): bool
|
||||
{
|
||||
$client = $trace->getClient();
|
||||
|
||||
if (!isset($input['script'])) {
|
||||
throw new \Exception("Script not found in trace input");
|
||||
}
|
||||
|
||||
$commandExecuteInput = new CommandExecuteInput();
|
||||
$commandExecuteInput->clients = [new ClientOutput($client)];
|
||||
$commandExecuteInput->script = $input['script'];
|
||||
$commandExecuteInput->queue = false;
|
||||
|
||||
try {
|
||||
$response = $this->runScriptAction->__invoke($commandExecuteInput, $trace);
|
||||
|
||||
if ($response->getStatusCode() === 200) {
|
||||
$trace->setStatus(TraceStatus::SUCCESS);
|
||||
$trace->setFinishedAt(new \DateTime());
|
||||
$this->entityManager->persist($trace);
|
||||
$this->entityManager->flush();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
} catch (\Exception $e) {
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,13 +4,23 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Command;
|
||||
|
||||
use App\Controller\OgAgent\CreateImageAction;
|
||||
use App\Controller\OgAgent\DeployImageAction;
|
||||
use App\Controller\OgAgent\PartitionAssistantAction;
|
||||
use App\Controller\OgAgent\RunScriptAction;
|
||||
use App\Dto\Input\CommandExecuteInput;
|
||||
use App\Dto\Input\DeployImageInput;
|
||||
use App\Dto\Input\PartitionInput;
|
||||
use App\Dto\Input\PartitionPostInput;
|
||||
use App\Dto\Output\ClientOutput;
|
||||
use App\Entity\CommandTask;
|
||||
use App\Entity\Image;
|
||||
use App\Entity\ImageImageRepository;
|
||||
use App\Entity\Partition;
|
||||
use App\Entity\Trace;
|
||||
use App\Model\ClientStatus;
|
||||
use App\Model\CommandTypes;
|
||||
use App\Model\TraceStatus;
|
||||
use App\Repository\CommandTaskRepository;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
|
@ -27,6 +37,8 @@ class RunScheduledCommandTasksCommand extends Command
|
|||
private readonly EntityManagerInterface $entityManager,
|
||||
private readonly RunScriptAction $runScriptAction,
|
||||
private readonly DeployImageAction $deployImageAction,
|
||||
private readonly CreateImageAction $createImageAction,
|
||||
private readonly PartitionAssistantAction $partitionAssistantAction,
|
||||
)
|
||||
{
|
||||
parent::__construct();
|
||||
|
@ -38,47 +50,39 @@ class RunScheduledCommandTasksCommand extends Command
|
|||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$now = new \DateTimeImmutable('now +2 hours');
|
||||
$now->setTimezone(new \DateTimeZone('Europe/Madrid'));
|
||||
$nowMinute = $now->format('Y-m-d H:i');
|
||||
$now = new \DateTimeImmutable('now');
|
||||
|
||||
$tasks = $this->commandTaskRepository->findAll();
|
||||
|
||||
foreach ($tasks as $task) {
|
||||
/** @var CommandTask $task */
|
||||
$nextExecution = $task->getNextExecution();
|
||||
|
||||
if (!$nextExecution) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$taskMinute = $nextExecution->format('Y-m-d H:i');
|
||||
$difference = $now->getTimestamp() - $nextExecution->getTimestamp();
|
||||
|
||||
if ($taskMinute === $nowMinute) {
|
||||
$output->writeln("Now: " . $now->format('Y-m-d H:i:s T'));
|
||||
$output->writeln("NextExecution: " . $nextExecution->format('Y-m-d H:i:s T'));
|
||||
$output->writeln("Diferencia: $difference segundos para la tarea {$task->getName()}");
|
||||
|
||||
if (abs($difference) < 30) {
|
||||
$output->writeln("Ejecutando tarea: " . $task->getName());
|
||||
|
||||
$scripts = $task->getCommandTaskScripts()->toArray();
|
||||
usort($scripts, fn($a, $b) => $a->getExecutionOrder() <=> $b->getExecutionOrder());
|
||||
|
||||
foreach ($scripts as $script) {
|
||||
$output->writeln(" - Ejecutando script de tipo {$script->getType()} con orden {$script->getExecutionOrder()}");
|
||||
$output->writeln(" - Creando traza para script de tipo {$script->getType()} con orden {$script->getExecutionOrder()}");
|
||||
|
||||
if ($script->getType() === 'run-script') {
|
||||
$input = new CommandExecuteInput();
|
||||
|
||||
foreach ($task->getOrganizationalUnit()?->getClients() as $client) {
|
||||
if ($client->getStatus() !== ClientStatus::OG_LIVE) {
|
||||
continue;
|
||||
}
|
||||
$input->clients[] = new ClientOutput($client);
|
||||
}
|
||||
$input->script = $script->getContent();
|
||||
|
||||
$this->runScriptAction->__invoke($input);
|
||||
}
|
||||
$this->createTraceForScript($script, $task, $output);
|
||||
}
|
||||
|
||||
$task->setLastExecution(new \DateTime());
|
||||
$task->setLastExecution(new \DateTimeImmutable('now'));
|
||||
$task->setNextExecution($task->calculateNextExecutionDate());
|
||||
|
||||
$this->entityManager->persist($task);
|
||||
}
|
||||
}
|
||||
|
@ -86,4 +90,134 @@ class RunScheduledCommandTasksCommand extends Command
|
|||
$this->entityManager->flush();
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
|
||||
private function createTraceForScript($script, CommandTask $task, OutputInterface $output): void
|
||||
{
|
||||
$scriptParameters = $script->getParameters();
|
||||
|
||||
if ($task->getScope() !== 'clients') {
|
||||
$clients = $task->getOrganizationalUnit()?->getClients();
|
||||
} else {
|
||||
$clients = $task->getClients();
|
||||
}
|
||||
|
||||
foreach ($clients as $client) {
|
||||
$trace = new Trace();
|
||||
$trace->setClient($client);
|
||||
$trace->setStatus(TraceStatus::PENDING);
|
||||
$trace->setExecutedAt(new \DateTime());
|
||||
|
||||
switch ($script->getType()) {
|
||||
case 'run-script':
|
||||
$trace->setCommand(CommandTypes::RUN_SCRIPT);
|
||||
$trace->setInput([
|
||||
'script' => $script->getContent()
|
||||
]);
|
||||
break;
|
||||
|
||||
case 'deploy-image':
|
||||
$trace->setCommand(CommandTypes::DEPLOY_IMAGE);
|
||||
$trace->setInput([
|
||||
'imageImageRepository' => $scriptParameters['imageImageRepositoryUuid'],
|
||||
'method' => $scriptParameters['method'] ?? 'unicast',
|
||||
'type' => $scriptParameters['type'] ?? 'monolithic',
|
||||
'diskNumber' => $scriptParameters['diskNumber'] ?? 1,
|
||||
'partitionNumber' => $scriptParameters['partitionNumber'] ?? 1,
|
||||
'mcastMode' => $scriptParameters['mcastMode'] ?? 'duplex',
|
||||
'mcastSpeed' => $scriptParameters['mcastSpeed'] ?? 100,
|
||||
'mcastPort' => $scriptParameters['mcastPort'] ?? 8000,
|
||||
'mcastIp' => $scriptParameters['mcastIp'] ?? '224.0.0.1',
|
||||
'maxClients' => $scriptParameters['maxClients'] ?? 10,
|
||||
'maxTime' => $scriptParameters['maxTime'] ?? 3600,
|
||||
'p2pMode' => $scriptParameters['p2pMode'] ?? 'seed',
|
||||
'p2pTime' => $scriptParameters['p2pTime'] ?? 300
|
||||
]);
|
||||
break;
|
||||
|
||||
case 'create-image':
|
||||
$trace->setCommand(CommandTypes::CREATE_IMAGE);
|
||||
$trace->setInput([
|
||||
'image' => $scriptParameters['imageUuid'],
|
||||
'diskNumber' => $scriptParameters['diskNumber'] ?? null,
|
||||
'partitionNumber' => $scriptParameters['partitionNumber'] ?? null,
|
||||
'gitRepositoryName' => $scriptParameters['gitRepositoryName'] ?? null
|
||||
]);
|
||||
break;
|
||||
|
||||
case 'partition-assistant':
|
||||
$trace->setCommand(CommandTypes::PARTITION_AND_FORMAT);
|
||||
$trace->setInput($scriptParameters);
|
||||
break;
|
||||
|
||||
default:
|
||||
$output->writeln(" - Tipo de script no soportado: {$script->getType()}");
|
||||
continue 2; // Salta al siguiente cliente
|
||||
}
|
||||
|
||||
$this->entityManager->persist($trace);
|
||||
$output->writeln(" - Traza creada para cliente {$client->getUuid()} con comando {$trace->getCommand()}");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private function executePartitionAssistant($script, CommandTask $task, OutputInterface $output): void
|
||||
{
|
||||
$scriptParameters = $script->getParameters();
|
||||
|
||||
$output->writeln(" - Debug: Parameters = " . ($scriptParameters ? json_encode($scriptParameters) : 'null'));
|
||||
|
||||
if (!$scriptParameters) {
|
||||
$output->writeln(" - Error: Parámetros del script vacíos o nulos");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!is_array($scriptParameters)) {
|
||||
$output->writeln(" - Error: Los parámetros deben ser un array");
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($task->getOrganizationalUnit()?->getClients() as $client) {
|
||||
$partitionInput = new PartitionPostInput();
|
||||
$partitionInput->clients = [new ClientOutput($client)];
|
||||
|
||||
$partitions = [];
|
||||
|
||||
foreach ($scriptParameters as $partitionData) {
|
||||
if (isset($partitionData['removed']) && $partitionData['removed']) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!isset($partitionData['size']) || $partitionData['size'] <= 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$partitionInputObj = new PartitionInput();
|
||||
$partitionInputObj->diskNumber = $partitionData['diskNumber'] ?? 1;
|
||||
$partitionInputObj->partitionNumber = $partitionData['partitionNumber'] ?? 1;
|
||||
$partitionInputObj->partitionCode = $partitionData['partitionCode'] ?? 'LINUX';
|
||||
$partitionInputObj->size = (float)($partitionData['size'] / 1024);
|
||||
$partitionInputObj->filesystem = $partitionData['filesystem'] ?? 'EXT4';
|
||||
$partitionInputObj->format = $partitionData['format'] ?? false;
|
||||
$partitionInputObj->memoryUsage = $partitionData['memoryUsage'] ?? 0;
|
||||
|
||||
$partitions[] = $partitionInputObj;
|
||||
}
|
||||
|
||||
if (empty($partitions)) {
|
||||
$output->writeln(" - Warning: No hay particiones válidas para procesar");
|
||||
continue;
|
||||
}
|
||||
|
||||
$partitionInput->partitions = $partitions;
|
||||
$partitionInput->queue = false;
|
||||
|
||||
try {
|
||||
$response = $this->partitionAssistantAction->__invoke($partitionInput, null);
|
||||
|
||||
$output->writeln(" - Partition assistant iniciado para cliente {$client->getUuid()}");
|
||||
} catch (\Exception $e) {
|
||||
$output->writeln(" - Error en partition assistant para cliente {$client->getUuid()}: " . $e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,118 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Controller\OgAgent;
|
||||
|
||||
use App\Dto\Input\CheckPartitionSizesInput;
|
||||
use App\Entity\Client;
|
||||
use App\Entity\Command;
|
||||
use App\Entity\Image;
|
||||
use App\Entity\Partition;
|
||||
use App\Entity\Trace;
|
||||
use App\Model\ClientStatus;
|
||||
use App\Model\CommandTypes;
|
||||
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\HttpKernel\Exception\BadRequestHttpException;
|
||||
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 CheckPartitionSizesAction extends AbstractOgAgentController
|
||||
{
|
||||
/**
|
||||
* @throws TransportExceptionInterface
|
||||
* @throws ServerExceptionInterface
|
||||
* @throws RedirectionExceptionInterface
|
||||
* @throws ClientExceptionInterface
|
||||
*/
|
||||
public function __invoke(CheckPartitionSizesInput $input, Client $client): JsonResponse
|
||||
{
|
||||
$partitions = $input->partitions;
|
||||
|
||||
if (empty($partitions)) {
|
||||
throw new BadRequestHttpException('Partitions is required');
|
||||
}
|
||||
|
||||
$this->logger->info('Input received', [
|
||||
'partitions_count' => count($partitions),
|
||||
'input_type' => gettype($input),
|
||||
'partitions_type' => gettype($partitions)
|
||||
]);
|
||||
|
||||
$disks = [];
|
||||
foreach ($partitions as $index => $partition) {
|
||||
$diskNumber = $partition->diskNumber;
|
||||
|
||||
$partitionEntity = $this->entityManager->getRepository(Partition::class)->findOneBy([
|
||||
'client' => $client,
|
||||
'partitionNumber' => $partition->partitionNumber,
|
||||
'diskNumber' => $partition->diskNumber,
|
||||
]);
|
||||
|
||||
if ($partitionEntity) {
|
||||
$partitionEntity->setClient($client);
|
||||
$this->entityManager->persist($partitionEntity);
|
||||
}
|
||||
|
||||
if (!isset($disks[$diskNumber])) {
|
||||
$disks[$diskNumber] = [
|
||||
'diskData' => [],
|
||||
'partitionData' => []
|
||||
];
|
||||
}
|
||||
|
||||
$disks[$diskNumber]['diskData'] = [
|
||||
'dis' => (string) $diskNumber,
|
||||
'tch' => (string) ($partition->size * 1024),
|
||||
];
|
||||
|
||||
$disks[$diskNumber]['partitionData'][] = [
|
||||
'par' => (string) $partition->partitionNumber,
|
||||
'cpt' => $partition->partitionCode,
|
||||
'sfi' => $partition->filesystem,
|
||||
'tam' => (string) (integer) ($partition->size * 1024),
|
||||
'ope' => $partition->format ? "1" : "0",
|
||||
];
|
||||
}
|
||||
|
||||
foreach ($disks as $diskNumber => $diskInfo) {
|
||||
$data = [];
|
||||
if (!empty($diskInfo['diskData'])) {
|
||||
$data[] = $diskInfo['diskData'];
|
||||
}
|
||||
$data = array_merge($data, $diskInfo['partitionData']);
|
||||
|
||||
$result = [
|
||||
"nfn" => "Configurar",
|
||||
"dsk" => (string) $diskNumber,
|
||||
"cfg" => $data,
|
||||
"check-sizes" => "true",
|
||||
"ids" => "0"
|
||||
];
|
||||
|
||||
$response = $this->createRequest(
|
||||
method: 'POST',
|
||||
url: 'https://'.$client->getIp().':8000/opengnsys/Configurar',
|
||||
params: [
|
||||
'json' => $result,
|
||||
],
|
||||
token: $client->getToken(),
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
return new JsonResponse(data: $response, status: Response::HTTP_OK);
|
||||
}
|
||||
}
|
|
@ -42,7 +42,7 @@ class CreateImageAction extends AbstractOgAgentController
|
|||
* @throws RedirectionExceptionInterface
|
||||
* @throws ClientExceptionInterface
|
||||
*/
|
||||
public function __invoke(bool $queue, Image $image, ?Partition $partition = null, ?Client $client = null, ?string $gitRepositoryName = null): JsonResponse
|
||||
public function __invoke(bool $queue, Image $image, ?Partition $partition = null, ?Client $client = null, ?string $gitRepositoryName = null, ?Trace $existingTrace = null): JsonResponse
|
||||
{
|
||||
$client = $client ?? $image->getClient();
|
||||
|
||||
|
@ -77,13 +77,11 @@ class CreateImageAction extends AbstractOgAgentController
|
|||
|
||||
$this->entityManager->persist($imageImageRepository);
|
||||
|
||||
return $this->createMonolithicImage($imageImageRepository, $partitionInfo, $image, $repository, $client, $queue);
|
||||
return $this->createMonolithicImage($imageImageRepository, $partitionInfo, $image, $repository, $client, $queue, $existingTrace);
|
||||
} else {
|
||||
$repository = $image->getClient()->getRepository();
|
||||
|
||||
// Para imágenes Git, no necesitamos crear entidades en la base de datos
|
||||
// ya que los repositorios Git son datos externos
|
||||
return $this->createGitImage($image, $partitionInfo, $repository, $queue, $gitRepositoryName);
|
||||
return $this->createGitImage($image, $partitionInfo, $repository, $queue, $gitRepositoryName, $existingTrace);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -99,7 +97,8 @@ class CreateImageAction extends AbstractOgAgentController
|
|||
Image $image,
|
||||
ImageRepository $repository,
|
||||
?Client $client = null,
|
||||
bool $queue = false
|
||||
bool $queue = false,
|
||||
?Trace $existingTrace = null
|
||||
): JsonResponse
|
||||
{
|
||||
if (!isset($partitionInfo['numDisk'], $partitionInfo['numPartition'], $partitionInfo['partitionCode'], $partitionInfo['filesystem'])) {
|
||||
|
@ -159,6 +158,8 @@ class CreateImageAction extends AbstractOgAgentController
|
|||
'image' => $image->getUuid(),
|
||||
'partitionCode' => $partitionInfo['partitionCode'],
|
||||
'partitionType' => $partitionInfo['filesystem'],
|
||||
'partitionNumber' => $partitionInfo['numPartition'],
|
||||
'diskNumber' => $partitionInfo['numDisk'],
|
||||
'repository' => $repository->getIp(),
|
||||
'name' => $image->getName().'_v'.$imageImageRepository->getVersion(),
|
||||
];
|
||||
|
@ -190,17 +191,27 @@ class CreateImageAction extends AbstractOgAgentController
|
|||
'image' => $image->getUuid(),
|
||||
'partitionCode' => $partitionInfo['partitionCode'],
|
||||
'partitionType' => $partitionInfo['filesystem'],
|
||||
'partitionNumber' => $partitionInfo['numPartition'],
|
||||
'diskNumber' => $partitionInfo['numDisk'],
|
||||
'repository' => $repository->getIp(),
|
||||
'name' => $image->getName().'_v'.$imageImageRepository->getVersion(),
|
||||
];
|
||||
|
||||
$this->createService->__invoke(
|
||||
$image->getClient(),
|
||||
CommandTypes::CREATE_IMAGE,
|
||||
TraceStatus::IN_PROGRESS,
|
||||
$jobId,
|
||||
$inputData
|
||||
);
|
||||
if ($existingTrace) {
|
||||
$existingTrace->setStatus(TraceStatus::IN_PROGRESS);
|
||||
$existingTrace->setJobId($jobId);
|
||||
$existingTrace->setInput($inputData);
|
||||
$this->entityManager->persist($existingTrace);
|
||||
$this->entityManager->flush();
|
||||
} else {
|
||||
$this->createService->__invoke(
|
||||
$image->getClient(),
|
||||
CommandTypes::CREATE_IMAGE,
|
||||
TraceStatus::IN_PROGRESS,
|
||||
$jobId,
|
||||
$inputData
|
||||
);
|
||||
}
|
||||
|
||||
return new JsonResponse(data: ['/clients/' . $client->getUuid() => $jobId], status: Response::HTTP_OK);
|
||||
} catch (Exception $e) {
|
||||
|
@ -228,7 +239,8 @@ class CreateImageAction extends AbstractOgAgentController
|
|||
array $partitionInfo,
|
||||
ImageRepository $repository,
|
||||
bool $queue = false,
|
||||
?string $gitRepositoryName = null
|
||||
?string $gitRepositoryName = null,
|
||||
?Trace $existingTrace = null
|
||||
): JsonResponse
|
||||
{
|
||||
if (!isset($partitionInfo['numDisk'], $partitionInfo['numPartition'], $partitionInfo['partitionCode'], $partitionInfo['filesystem'])) {
|
||||
|
@ -285,6 +297,8 @@ class CreateImageAction extends AbstractOgAgentController
|
|||
'image' => $image->getUuid(),
|
||||
'partitionCode' => $partitionInfo['partitionCode'],
|
||||
'partitionType' => $partitionInfo['filesystem'],
|
||||
'partitionNumber' => $partitionInfo['numPartition'],
|
||||
'diskNumber' => $partitionInfo['numDisk'],
|
||||
'repository' => $repository->getIp(),
|
||||
'name' => $image->getName(),
|
||||
];
|
||||
|
@ -315,17 +329,27 @@ class CreateImageAction extends AbstractOgAgentController
|
|||
'image' => $image->getUuid(),
|
||||
'partitionCode' => $partitionInfo['partitionCode'],
|
||||
'partitionType' => $partitionInfo['filesystem'],
|
||||
'partitionNumber' => $partitionInfo['numPartition'],
|
||||
'diskNumber' => $partitionInfo['numDisk'],
|
||||
'repository' => $repository->getIp(),
|
||||
'name' => $image->getName(),
|
||||
];
|
||||
|
||||
$this->createService->__invoke(
|
||||
$image->getClient(),
|
||||
CommandTypes::CREATE_IMAGE_GIT,
|
||||
TraceStatus::IN_PROGRESS,
|
||||
$jobId,
|
||||
$inputData
|
||||
);
|
||||
if ($existingTrace) {
|
||||
$existingTrace->setStatus(TraceStatus::IN_PROGRESS);
|
||||
$existingTrace->setJobId($jobId);
|
||||
$existingTrace->setInput($inputData);
|
||||
$this->entityManager->persist($existingTrace);
|
||||
$this->entityManager->flush();
|
||||
} else {
|
||||
$this->createService->__invoke(
|
||||
$image->getClient(),
|
||||
CommandTypes::CREATE_IMAGE_GIT,
|
||||
TraceStatus::IN_PROGRESS,
|
||||
$jobId,
|
||||
$inputData
|
||||
);
|
||||
}
|
||||
|
||||
return new JsonResponse(data: ['/clients/' . $client->getUuid() => $jobId], status: Response::HTTP_OK);
|
||||
} catch (Exception $e) {
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Controller\OgAgent;
|
||||
|
||||
use App\Dto\Input\GetGitDataInput;
|
||||
use App\Entity\Client;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
class GetGitDataAction extends AbstractOgAgentController
|
||||
{
|
||||
public function __invoke(GetGitDataInput $input): JsonResponse
|
||||
{
|
||||
$data = [
|
||||
'nfn' => 'GetGitData',
|
||||
'dsk' => (string) $input->partition->getEntity()->getDiskNumber(),
|
||||
'par' => (string) $input->partition->getEntity()->getPartitionNumber(),
|
||||
];
|
||||
|
||||
|
||||
$response = $this->createRequest(
|
||||
method: 'POST',
|
||||
url: 'https://'.$input->client->getEntity()->getIp().':8000/opengnsys/GetGitData',
|
||||
params: [
|
||||
'json' => $data,
|
||||
],
|
||||
token: $input->client->getEntity()->getToken(),
|
||||
);
|
||||
|
||||
$parsedResponse = [
|
||||
'branch' => $response['branch'] ?? null,
|
||||
'repo' => $response['repo'] ?? null,
|
||||
];
|
||||
|
||||
return new JsonResponse(data: $parsedResponse, status: Response::HTTP_OK);
|
||||
}
|
||||
}
|
|
@ -37,7 +37,7 @@ class PartitionAssistantAction extends AbstractOgAgentController
|
|||
* @throws RedirectionExceptionInterface
|
||||
* @throws ClientExceptionInterface
|
||||
*/
|
||||
public function __invoke(PartitionPostInput $input): JsonResponse
|
||||
public function __invoke(PartitionPostInput $input, ?Trace $existingTrace = null): JsonResponse
|
||||
{
|
||||
$partitions = $input->partitions;
|
||||
|
||||
|
@ -127,7 +127,15 @@ class PartitionAssistantAction extends AbstractOgAgentController
|
|||
$this->entityManager->persist($client);
|
||||
$this->entityManager->flush();
|
||||
|
||||
$this->createService->__invoke($client, CommandTypes::PARTITION_AND_FORMAT, TraceStatus::IN_PROGRESS, $jobId, $data);
|
||||
if ($existingTrace) {
|
||||
$existingTrace->setStatus(TraceStatus::IN_PROGRESS);
|
||||
$existingTrace->setJobId($jobId);
|
||||
$existingTrace->setInput($data);
|
||||
$this->entityManager->persist($existingTrace);
|
||||
$this->entityManager->flush();
|
||||
} else {
|
||||
$this->createService->__invoke($client, CommandTypes::PARTITION_AND_FORMAT, TraceStatus::IN_PROGRESS, $jobId, $data);
|
||||
}
|
||||
|
||||
$clientJobs['/clients/' . $client->getUuid()] = $jobId;
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ namespace App\Controller\OgAgent;
|
|||
use App\Dto\Input\CommandExecuteInput;
|
||||
use App\Dto\Input\MultipleClientsInput;
|
||||
use App\Entity\Client;
|
||||
use App\Entity\Trace;
|
||||
use App\Model\ClientStatus;
|
||||
use App\Model\CommandTypes;
|
||||
use App\Model\TraceStatus;
|
||||
|
@ -30,7 +31,7 @@ class RunScriptAction extends AbstractOgAgentController
|
|||
* @throws RedirectionExceptionInterface
|
||||
* @throws ClientExceptionInterface
|
||||
*/
|
||||
public function __invoke(CommandExecuteInput $input): JsonResponse
|
||||
public function __invoke(CommandExecuteInput $input, ?Trace $existingTrace = null): JsonResponse
|
||||
{
|
||||
$clientJobs = [];
|
||||
|
||||
|
@ -43,51 +44,111 @@ class RunScriptAction extends AbstractOgAgentController
|
|||
throw new BadRequestHttpException('IP is required');
|
||||
}
|
||||
|
||||
$data = [
|
||||
'nfn' => 'EjecutarScript',
|
||||
'scp' => base64_encode($input->script),
|
||||
'ids' => '0'
|
||||
];
|
||||
$data = $this->buildRequestData($client, $input->script);
|
||||
$response = $this->executeScript($client, $data);
|
||||
|
||||
$response = $this->createRequest(
|
||||
method: 'POST',
|
||||
url: 'https://'.$client->getIp().':8000/opengnsys/EjecutarScript',
|
||||
params: [
|
||||
'json' => $data,
|
||||
],
|
||||
token: $client->getToken(),
|
||||
);
|
||||
|
||||
if (isset($response['error']) && $response['code'] === Response::HTTP_INTERNAL_SERVER_ERROR) {
|
||||
$this->logger->error('Error running script', ['client' => $client->getId(), 'error' => $response['error']]);
|
||||
|
||||
if ($input->queue) {
|
||||
$inputData = [
|
||||
'script' => $input->script,
|
||||
];
|
||||
$this->createService->__invoke($client, CommandTypes::RUN_SCRIPT, TraceStatus::PENDING, null, $inputData);
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($this->isErrorResponse($response)) {
|
||||
$this->handleError($client, $input, $response);
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->logger->info('Powering off client', ['client' => $client->getId()]);
|
||||
|
||||
$jobId = $response['job_id'];
|
||||
|
||||
$clientJobs[(string) '/clients/' . $client->getUuid()] = $jobId;
|
||||
|
||||
$this->entityManager->persist($client);
|
||||
$this->entityManager->flush();
|
||||
|
||||
$inputData = [
|
||||
'script' => $input->script,
|
||||
];
|
||||
|
||||
$this->createService->__invoke($client, CommandTypes::RUN_SCRIPT, TraceStatus::IN_PROGRESS, $jobId, $inputData);
|
||||
$this->handleSuccess($client, $input, $response, $existingTrace);
|
||||
}
|
||||
|
||||
return new JsonResponse(data: $clientJobs, status: Response::HTTP_OK);
|
||||
}
|
||||
|
||||
private function buildRequestData(Client $client, string $script): array
|
||||
{
|
||||
$scriptBase64 = base64_encode($script);
|
||||
|
||||
if ($this->isLinuxOrWindows($client)) {
|
||||
return [
|
||||
'script' => $scriptBase64,
|
||||
'client' => 'false'
|
||||
];
|
||||
}
|
||||
|
||||
if ($this->isLinuxOrWindowsSession($client)) {
|
||||
return [
|
||||
'script' => $scriptBase64,
|
||||
'client' => 'true'
|
||||
];
|
||||
}
|
||||
|
||||
return [
|
||||
'nfn' => 'EjecutarScript',
|
||||
'scp' => $scriptBase64,
|
||||
'ids' => '0'
|
||||
];
|
||||
}
|
||||
|
||||
private function isLinuxOrWindows(Client $client): bool
|
||||
{
|
||||
return $client->getStatus() === ClientStatus::LINUX || $client->getStatus() === ClientStatus::WINDOWS;
|
||||
}
|
||||
|
||||
private function isLinuxOrWindowsSession(Client $client): bool
|
||||
{
|
||||
return $client->getStatus() === ClientStatus::LINUX_SESSION || $client->getStatus() === ClientStatus::WINDOWS_SESSION;
|
||||
}
|
||||
|
||||
private function executeScript(Client $client, array $data): array
|
||||
{
|
||||
return $this->createRequest(
|
||||
method: 'POST',
|
||||
url: 'https://'.$client->getIp().':8000/opengnsys/EjecutarScript',
|
||||
params: [
|
||||
'json' => $data,
|
||||
],
|
||||
token: $client->getToken(),
|
||||
);
|
||||
}
|
||||
|
||||
private function isErrorResponse(array $response): bool
|
||||
{
|
||||
return isset($response['error']) && $response['code'] === Response::HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
|
||||
private function handleError(Client $client, CommandExecuteInput $input, array $response): void
|
||||
{
|
||||
$this->logger->error('Error running script', [
|
||||
'client' => $client->getId(),
|
||||
'error' => $response['error']
|
||||
]);
|
||||
|
||||
if ($input->queue) {
|
||||
$inputData = ['script' => $input->script];
|
||||
$this->createService->__invoke($client, CommandTypes::RUN_SCRIPT, TraceStatus::PENDING, null, $inputData);
|
||||
}
|
||||
}
|
||||
|
||||
private function handleSuccess(Client $client, CommandExecuteInput $input, array $response, ?Trace $existingTrace): void
|
||||
{
|
||||
$this->logger->info('Running script on client', ['client' => $client->getId()]);
|
||||
|
||||
$jobId = $response['job_id'];
|
||||
$inputData = ['script' => $input->script];
|
||||
|
||||
$this->entityManager->persist($client);
|
||||
$this->entityManager->flush();
|
||||
|
||||
if ($existingTrace) {
|
||||
$this->updateExistingTrace($existingTrace, $jobId, $inputData);
|
||||
} else {
|
||||
$this->createService->__invoke($client, CommandTypes::RUN_SCRIPT, TraceStatus::IN_PROGRESS, $jobId, $inputData);
|
||||
}
|
||||
}
|
||||
|
||||
private function updateExistingTrace(Trace $trace, string $jobId, array $inputData): void
|
||||
{
|
||||
$trace->setStatus(TraceStatus::IN_PROGRESS);
|
||||
$trace->setJobId($jobId);
|
||||
$trace->setInput($inputData);
|
||||
$this->entityManager->persist($trace);
|
||||
$this->entityManager->flush();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Controller\OgAgent;
|
||||
|
||||
use App\Dto\Input\UpdateGitImageInput;
|
||||
use App\Entity\Client;
|
||||
use App\Model\ClientStatus;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
|
||||
use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface;
|
||||
use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface;
|
||||
use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface;
|
||||
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
|
||||
|
||||
class UpdateGitImageAction extends AbstractOgAgentController
|
||||
{
|
||||
/**
|
||||
* @throws RedirectionExceptionInterface
|
||||
* @throws ClientExceptionInterface
|
||||
* @throws TransportExceptionInterface
|
||||
* @throws ServerExceptionInterface
|
||||
*/
|
||||
public function __invoke(UpdateGitImageInput $input, Client $client)
|
||||
{
|
||||
if (!$client->getIp()) {
|
||||
throw new BadRequestHttpException('IP is required');
|
||||
}
|
||||
|
||||
if (!$input->gitRepository) {
|
||||
throw new BadRequestHttpException('Git repository name is required for Git image update');
|
||||
}
|
||||
|
||||
$partition = $input->partition->getEntity();
|
||||
$repository = $client->getRepository();
|
||||
|
||||
$data = [
|
||||
'dsk' => (string) $partition->getDiskNumber(),
|
||||
'par' => (string) $partition->getPartitionNumber(),
|
||||
'nci' => $input->gitRepository,
|
||||
'ipr' => $repository->getIp(),
|
||||
'msg' => 'updating git image',
|
||||
'nfn' => 'ModificarImagenGit',
|
||||
'ids' => '0'
|
||||
];
|
||||
|
||||
$url = 'https://'.$client->getIp().':8000/opengnsys/ModificarImagenGit';
|
||||
|
||||
$response = $this->createRequest(
|
||||
method: 'POST',
|
||||
url: $url,
|
||||
params: [
|
||||
'json' => $data,
|
||||
],
|
||||
token: $client->getToken(),
|
||||
);
|
||||
|
||||
$this->logger->info('Updating Git image', [
|
||||
'repository' => $input->gitRepository,
|
||||
'client' => $client->getIp(),
|
||||
'disk' => $partition->getDiskNumber(),
|
||||
'partition' => $partition->getPartitionNumber()
|
||||
]);
|
||||
|
||||
if (isset($response['error']) && $response['code'] === Response::HTTP_INTERNAL_SERVER_ERROR) {
|
||||
throw new BadRequestHttpException('Error updating Git image');
|
||||
}
|
||||
|
||||
$jobId = $response['job_id'];
|
||||
|
||||
$client->setStatus(ClientStatus::BUSY);
|
||||
$this->entityManager->persist($client);
|
||||
$this->entityManager->flush();
|
||||
|
||||
return $jobId;
|
||||
}
|
||||
}
|
|
@ -57,6 +57,8 @@ class AgentSessionController extends AbstractController
|
|||
return new JsonResponse(['message' => 'Invalid status'], Response::HTTP_BAD_REQUEST);
|
||||
}
|
||||
|
||||
$client->setToken($data['secret'] ?? null);
|
||||
|
||||
$this->entityManager->persist($client);
|
||||
$this->entityManager->flush();
|
||||
|
||||
|
|
|
@ -39,6 +39,7 @@ class StatusController extends AbstractController
|
|||
{
|
||||
const string CREATE_IMAGE = 'RESPUESTA_CrearImagen';
|
||||
const string CREATE_IMAGE_GIT = 'RESPUESTA_CrearImagenGit';
|
||||
const string UPDATE_IMAGE_GIT = 'RESPUESTA_ActualizarImagenGit';
|
||||
const string RESTORE_IMAGE = 'RESPUESTA_RestaurarImagen';
|
||||
const string RESTORE_IMAGE_GIT = 'RESPUESTA_RestaurarImagenGit';
|
||||
const string CONFIGURE_IMAGE = 'RESPUESTA_Configurar';
|
||||
|
@ -115,6 +116,30 @@ class StatusController extends AbstractController
|
|||
$this->logger->info('Git image creation completed.', ['job_id' => $data['job_id'], 'success' => $data['res'] === 1]);
|
||||
}
|
||||
|
||||
if (isset($data['nfn']) && $data['nfn'] === self::UPDATE_IMAGE_GIT) {
|
||||
$trace = $this->entityManager->getRepository(Trace::class)->findOneBy(['jobId' => $data['job_id']]);
|
||||
|
||||
if (!$trace) {
|
||||
$this->logger->error('Trace not found', $data);
|
||||
return new JsonResponse(['message' => 'Trace not found'], Response::HTTP_NOT_FOUND);
|
||||
}
|
||||
|
||||
if ($data['res'] === 1) {
|
||||
$trace->setStatus(TraceStatus::SUCCESS);
|
||||
$trace->setFinishedAt(new \DateTime());
|
||||
} else {
|
||||
$trace->setStatus(TraceStatus::FAILED);
|
||||
$trace->setFinishedAt(new \DateTime());
|
||||
$trace->setOutput($data['der']);
|
||||
}
|
||||
|
||||
$client = $trace->getClient();
|
||||
$client->setStatus(ClientStatus::OG_LIVE);
|
||||
$this->entityManager->persist($client);
|
||||
$this->entityManager->persist($trace);
|
||||
$this->entityManager->flush();
|
||||
$this->logger->info('Git image update completed.', ['job_id' => $data['job_id'], 'success' => $data['res'] === 1]);
|
||||
}
|
||||
|
||||
if (isset($data['nfn']) && $data['nfn'] === self::CREATE_IMAGE) {
|
||||
$trace = $this->entityManager->getRepository(Trace::class)->findOneBy(['jobId' => $data['job_id']]);
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
|
||||
namespace App\Controller\OgRepository\Git;
|
||||
|
||||
use App\Controller\OgRepository\AbstractOgRepositoryController;
|
||||
use App\Dto\Input\CreateBranchInput;
|
||||
use App\Entity\ImageRepository;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\HttpKernel\Attribute\AsController;
|
||||
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
|
||||
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;
|
||||
|
||||
#[AsController]
|
||||
class CreateBranchAction extends AbstractOgRepositoryController
|
||||
{
|
||||
public function __invoke(ImageRepository $repository, CreateBranchInput $input): JsonResponse
|
||||
{
|
||||
$content = $this->createRequest('POST', 'http://'.$repository->getIp().':8006/ogrepository/v1/git/repositories/'.$input->repository.'/branches', [
|
||||
'json' => [
|
||||
'name' => $input->name,
|
||||
'commit' => $input->commit,
|
||||
]
|
||||
]);
|
||||
|
||||
if (isset($content['error']) && $content['code'] === Response::HTTP_INTERNAL_SERVER_ERROR) {
|
||||
throw new BadRequestHttpException('Error creating branch');
|
||||
}
|
||||
|
||||
return new JsonResponse(data: [], status: Response::HTTP_OK);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
<?php
|
||||
|
||||
namespace App\Controller\OgRepository\Git;
|
||||
|
||||
use App\Controller\OgRepository\AbstractOgRepositoryController;
|
||||
use App\Dto\Input\CreateTagInput;
|
||||
use App\Entity\ImageRepository;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\HttpKernel\Attribute\AsController;
|
||||
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
|
||||
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;
|
||||
|
||||
#[AsController]
|
||||
class CreateTagAction extends AbstractOgRepositoryController
|
||||
{
|
||||
public function __invoke(ImageRepository $repository, CreateTagInput $input): JsonResponse
|
||||
{
|
||||
$content = $this->createRequest('POST', 'http://'.$repository->getIp().':8006/ogrepository/v1/git/repositories/'.$input->repository.'/tags', [
|
||||
'json' => [
|
||||
'commit' => $input->commit,
|
||||
'message' => $input->message,
|
||||
'name' => $input->name
|
||||
]
|
||||
]);
|
||||
|
||||
if (isset($content['error']) && $content['code'] === Response::HTTP_INTERNAL_SERVER_ERROR) {
|
||||
throw new BadRequestHttpException('Error creating tag');
|
||||
}
|
||||
|
||||
return new JsonResponse(data: [], status: Response::HTTP_OK);
|
||||
}
|
||||
}
|
|
@ -58,11 +58,11 @@ class ImportAction extends AbstractOgRepositoryController
|
|||
}
|
||||
|
||||
$imageImageRepositoryEntity = new ImageImageRepository();
|
||||
$imageImageRepositoryEntity->setName($imageEntity->getName().'_v'.$imageImageRepositoryEntity->getVersion() + 1);
|
||||
$imageImageRepositoryEntity->setName($imageEntity->getName());
|
||||
$imageImageRepositoryEntity->setStatus(ImageStatus::AUX_FILES_PENDING);
|
||||
$imageImageRepositoryEntity->setImage($imageEntity);
|
||||
$imageImageRepositoryEntity->setRepository($repository);
|
||||
$imageImageRepositoryEntity->setVersion(1);
|
||||
$imageImageRepositoryEntity->setVersion($this->extractVersionFromImageName($image));
|
||||
|
||||
$this->entityManager->persist($imageImageRepositoryEntity);
|
||||
$this->entityManager->flush();
|
||||
|
@ -90,4 +90,26 @@ class ImportAction extends AbstractOgRepositoryController
|
|||
|
||||
return new JsonResponse(data: [], status: Response::HTTP_OK);
|
||||
}
|
||||
|
||||
|
||||
private function extractVersionFromImageName(string $imageName): int
|
||||
{
|
||||
// Buscar patrones como "_v2", "_v3", etc.
|
||||
if (preg_match('/_v(\d+)$/', $imageName, $matches)) {
|
||||
return (int) $matches[1];
|
||||
}
|
||||
|
||||
// Buscar patrones como "-v2", "-v3", etc.
|
||||
if (preg_match('/-v(\d+)$/', $imageName, $matches)) {
|
||||
return (int) $matches[1];
|
||||
}
|
||||
|
||||
// Buscar patrones como "v2", "v3" al final del nombre
|
||||
if (preg_match('/v(\d+)$/', $imageName, $matches)) {
|
||||
return (int) $matches[1];
|
||||
}
|
||||
|
||||
// Si no se encuentra ningún patrón de versión, devolver 1 por defecto
|
||||
return 1;
|
||||
}
|
||||
}
|
|
@ -96,6 +96,7 @@ class ResponseController extends AbstractOgRepositoryController
|
|||
$newImageRepo->setImage($image);
|
||||
$newImageRepo->setVersion($originImageImageRepository->getVersion());
|
||||
$newImageRepo->setRepository($repository);
|
||||
$newImageRepo->setPartitionInfo($originImageImageRepository->getPartitionInfo());
|
||||
$newImageRepo->setStatus(ImageStatus::SUCCESS);
|
||||
|
||||
if ($trace->getInput()['imageImageRepositoryUuid'] ?? false) {
|
||||
|
|
|
@ -0,0 +1,89 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Controller;
|
||||
|
||||
use ApiPlatform\Validator\ValidatorInterface;
|
||||
use App\Dto\Input\UpdateGitImageInput;
|
||||
use App\Entity\Client;
|
||||
use App\Model\CommandTypes;
|
||||
use App\Model\DeployMethodTypes;
|
||||
use App\Model\TraceStatus;
|
||||
use App\Service\Trace\CreateService;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Routing\Attribute\Route;
|
||||
use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface;
|
||||
use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface;
|
||||
use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface;
|
||||
|
||||
class UpdateGitImageAction extends AbstractController
|
||||
{
|
||||
public function __construct(
|
||||
protected readonly EntityManagerInterface $entityManager,
|
||||
protected readonly CreateService $createService,
|
||||
protected readonly ValidatorInterface $validator,
|
||||
public readonly \App\Controller\OgAgent\UpdateGitImageAction $updateGitImageOgAgentAction,
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws RedirectionExceptionInterface
|
||||
* @throws ClientExceptionInterface
|
||||
* @throws ServerExceptionInterface
|
||||
*/
|
||||
public function __invoke(UpdateGitImageInput $input): JsonResponse
|
||||
{
|
||||
$this->validator->validate($input);
|
||||
|
||||
if (!$input->client) {
|
||||
throw new \InvalidArgumentException('Client is required');
|
||||
}
|
||||
|
||||
if (!$input->partition) {
|
||||
throw new \InvalidArgumentException('Partition is required');
|
||||
}
|
||||
|
||||
$this->handleGitUpdate($input);
|
||||
|
||||
return new JsonResponse(data: [], status: Response::HTTP_OK);
|
||||
}
|
||||
|
||||
private function handleGitUpdate(UpdateGitImageInput $input): void
|
||||
{
|
||||
$client = $input->client->getEntity();
|
||||
$partition = $input->partition->getEntity();
|
||||
|
||||
$inputData = $this->createInputData($input, $client, $partition);
|
||||
$this->processUpdate($client, $input, $inputData, DeployMethodTypes::GIT);
|
||||
}
|
||||
|
||||
private function processUpdate(Client $client, UpdateGitImageInput $input, array $inputData, string $updateType): void
|
||||
{
|
||||
$agentJobId = $this->updateGitImageOgAgentAction->__invoke($input, $client);
|
||||
|
||||
if (!$agentJobId) {
|
||||
if ($input->queue) {
|
||||
$this->createService->__invoke($client, CommandTypes::UPDATE_IMAGE_GIT, TraceStatus::PENDING, null, $inputData);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
$this->createService->__invoke($client, CommandTypes::UPDATE_IMAGE_GIT, TraceStatus::IN_PROGRESS, $agentJobId, $inputData);
|
||||
}
|
||||
|
||||
private function createInputData(UpdateGitImageInput $input, Client $client, $partition): array
|
||||
{
|
||||
return [
|
||||
'method' => 'ModificarImagenGit',
|
||||
'type' => 'git',
|
||||
'client' => $client->getUuid(),
|
||||
'diskNumber' => $partition->getDiskNumber(),
|
||||
'partitionNumber' => $partition->getPartitionNumber(),
|
||||
'repositoryName' => $input->gitRepository,
|
||||
];
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
<?php
|
||||
|
||||
namespace App\Dto\Input;
|
||||
|
||||
use App\Dto\Output\ClientOutput;
|
||||
use Symfony\Component\Serializer\Annotation\Groups;
|
||||
|
||||
final class CheckPartitionSizesInput
|
||||
{
|
||||
/**
|
||||
* @var PartitionInput[]
|
||||
*/
|
||||
#[Groups(['client:write'])]
|
||||
public array $partitions = [];
|
||||
|
||||
}
|
||||
|
|
@ -69,8 +69,9 @@ final class CommandTaskInput
|
|||
$this->clients[] = new ClientOutput($client);
|
||||
}
|
||||
}
|
||||
|
||||
$this->organizationalUnit = new OrganizationalUnitOutput($commandTask->getOrganizationalUnit());
|
||||
if ($commandTask->getOrganizationalUnit()) {
|
||||
$this->organizationalUnit = new OrganizationalUnitOutput($commandTask->getOrganizationalUnit());
|
||||
}
|
||||
$this->notes = $commandTask->getNotes();
|
||||
$this->scope = $commandTask->getScope();
|
||||
$this->content = $commandTask->getParameters();
|
||||
|
@ -87,12 +88,15 @@ final class CommandTaskInput
|
|||
|
||||
$commandTask->setName($this->name);
|
||||
|
||||
$clientsToAdd = [];
|
||||
foreach ($this->clients as $client) {
|
||||
$clientsToAdd[] = $client->getEntity();
|
||||
}
|
||||
}
|
||||
|
||||
$commandTask->setOrganizationalUnit($this->organizationalUnit->getEntity());
|
||||
$commandTask->setClients( $clientsToAdd ?? [] );
|
||||
if ($this->organizationalUnit) {
|
||||
$commandTask->setOrganizationalUnit($this->organizationalUnit->getEntity());
|
||||
}
|
||||
$commandTask->setClients( $clientsToAdd );
|
||||
$commandTask->setNotes($this->notes);
|
||||
$commandTask->setParameters($this->content);
|
||||
$commandTask->setScope($this->scope);
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
<?php
|
||||
|
||||
namespace App\Dto\Input;
|
||||
|
||||
use Symfony\Component\Serializer\Annotation\Groups;
|
||||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
|
||||
class CreateBranchInput
|
||||
{
|
||||
#[Assert\NotNull]
|
||||
#[Groups(['repository:write'])]
|
||||
public ?string $repository = null;
|
||||
|
||||
#[Assert\NotNull]
|
||||
#[Groups(['repository:write'])]
|
||||
public ?string $commit = null;
|
||||
|
||||
#[Assert\NotNull]
|
||||
#[Groups(['repository:write'])]
|
||||
public ?string $name = null;
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
<?php
|
||||
|
||||
namespace App\Dto\Input;
|
||||
|
||||
use Symfony\Component\Serializer\Annotation\Groups;
|
||||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
|
||||
class CreateTagInput
|
||||
{
|
||||
#[Assert\NotNull]
|
||||
#[Groups(['repository:write'])]
|
||||
public ?string $repository = null;
|
||||
|
||||
#[Assert\NotNull]
|
||||
#[Groups(['repository:write'])]
|
||||
public ?string $commit = null;
|
||||
|
||||
#[Assert\NotNull]
|
||||
#[Groups(['repository:write'])]
|
||||
public ?string $message = null;
|
||||
|
||||
#[Assert\NotNull]
|
||||
#[Groups(['repository:write'])]
|
||||
public ?string $name = null;
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
<?php
|
||||
|
||||
namespace App\Dto\Input;
|
||||
|
||||
use App\Dto\Output\ClientOutput;
|
||||
use App\Dto\Output\PartitionOutput;
|
||||
use Symfony\Component\Serializer\Annotation\Groups;
|
||||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
|
||||
class GetGitDataInput
|
||||
{
|
||||
#[Assert\NotNull]
|
||||
#[Groups(['git-repository:write'])]
|
||||
public ?PartitionOutput $partition = null;
|
||||
|
||||
#[Assert\NotNull]
|
||||
#[Groups(['git-repository:write'])]
|
||||
public ?ClientOutput $client = null;
|
||||
|
||||
}
|
|
@ -25,10 +25,6 @@ final class ImageInput
|
|||
#[ApiProperty(description: 'The name of the image', example: "Image 1")]
|
||||
public ?string $name = null;
|
||||
|
||||
#[Groups(['image:write'])]
|
||||
#[ApiProperty(description: 'The type of the image', example: "Server")]
|
||||
public ?string $source = 'input';
|
||||
|
||||
#[Groups(['image:write'])]
|
||||
#[ApiProperty(description: 'The type of the image', example: "Server")]
|
||||
public ?string $type = '';
|
||||
|
|
|
@ -16,53 +16,53 @@ use Symfony\Component\Validator\Constraints as Assert;
|
|||
|
||||
final class PartitionInput
|
||||
{
|
||||
#[Groups(['partition:write'])]
|
||||
#[Groups(['partition:write', 'client:write'])]
|
||||
public ?UuidInterface $uuid = null;
|
||||
|
||||
#[Groups(['partition:write'])]
|
||||
public ?bool $removed = null;
|
||||
|
||||
#[Groups(['partition:write'])]
|
||||
#[Groups(['partition:write', 'client:write'])]
|
||||
public ?bool $format = null;
|
||||
|
||||
#[Groups(['partition:write'])]
|
||||
#[Groups(['partition:write', 'client:write'])]
|
||||
#[ApiProperty(description: 'The disk number of the partition', example: 1)]
|
||||
public ?int $diskNumber = null;
|
||||
|
||||
#[Groups(['partition:write'])]
|
||||
#[Groups(['partition:write', 'client:write'])]
|
||||
#[ApiProperty(description: 'The number of the partition', example: 1)]
|
||||
public ?int $partitionNumber = null;
|
||||
|
||||
#[Groups(['partition:write'])]
|
||||
#[Groups(['partition:write', 'client:write'])]
|
||||
#[ApiProperty(description: 'The code of the partition', example: "code")]
|
||||
public ?string $partitionCode = null;
|
||||
|
||||
#[Assert\NotNull()]
|
||||
#[Groups(['partition:write'])]
|
||||
#[Groups(['partition:write', 'client:write'])]
|
||||
#[ApiProperty(description: 'The size of the partition', example: 100)]
|
||||
public ?float $size = null;
|
||||
|
||||
#[Groups(['partition:write'])]
|
||||
#[Groups(['partition:write', 'client:write'])]
|
||||
#[ApiProperty(description: 'The cache content of the partition', example: "cache content")]
|
||||
public ?string $cacheContent = null;
|
||||
|
||||
#[Groups(['partition:write'])]
|
||||
#[Groups(['partition:write', 'client:write'])]
|
||||
#[ApiProperty(description: 'The type of the partition', example: "LINUX")]
|
||||
public ?string $type = null;
|
||||
|
||||
#[Groups(['partition:write'])]
|
||||
#[Groups(['partition:write', 'client:write'])]
|
||||
#[ApiProperty(description: 'The filesystem of the partition', example: "EXT4")]
|
||||
public ?string $filesystem = null;
|
||||
|
||||
#[Groups(['partition:write'])]
|
||||
#[Groups(['partition:write', 'client:write'])]
|
||||
#[ApiProperty(description: 'The operative system name of the partition', example: "Ubuntu")]
|
||||
public ?OperativeSystemOutput $operativeSystem = null;
|
||||
|
||||
#[Groups(['partition:write'])]
|
||||
#[Groups(['partition:write', 'client:write'])]
|
||||
#[ApiProperty(description: 'The memory usage of the partition', example: 100)]
|
||||
public ?int $memoryUsage = null;
|
||||
|
||||
#[Groups(['partition:write'])]
|
||||
#[Groups(['partition:write', 'client:write'])]
|
||||
#[ApiProperty(description: 'The image of the partition')]
|
||||
public ?ImageOutput $image = null;
|
||||
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Dto\Input;
|
||||
|
||||
use ApiPlatform\Metadata\ApiProperty;
|
||||
use App\Dto\Output\ClientOutput;
|
||||
use App\Dto\Output\PartitionOutput;
|
||||
use Symfony\Component\Serializer\Annotation\Groups;
|
||||
|
||||
class UpdateGitImageInput
|
||||
{
|
||||
#[Groups(['git-repository:write'])]
|
||||
#[ApiProperty(description: 'The client of the image')]
|
||||
public ?ClientOutput $client = null;
|
||||
|
||||
#[Groups(['git-repository:write'])]
|
||||
#[ApiProperty(description: 'The client of the image')]
|
||||
public ?PartitionOutput $partition = null;
|
||||
|
||||
#[Groups(['git-repository:write'])]
|
||||
#[ApiProperty(description: 'The name of the Git repository to use for this image', example: "mi-repositorio")]
|
||||
public ?string $gitRepository = null;
|
||||
|
||||
#[Groups(['git-repository:write'])]
|
||||
#[ApiProperty(description: 'The name of the Git branch to use for this image', example: "main")]
|
||||
public ?string $originalBranch = null;
|
||||
|
||||
#[Groups(['git-repository:write'])]
|
||||
#[ApiProperty(description: 'The name of the Git branch to use for this image', example: "main")]
|
||||
public ?string $destinationBranch = null;
|
||||
|
||||
#[Groups(['git-repository:write'])]
|
||||
#[ApiProperty(description: 'Whether to queue the update', example: false)]
|
||||
public bool $queue = false;
|
||||
}
|
|
@ -50,7 +50,9 @@ final class CommandTaskOutput extends AbstractOutput
|
|||
fn(Client $client) => new ClientOutput($client)
|
||||
)->toArray();
|
||||
|
||||
$this->organizationalUnit = new OrganizationalUnitOutput($commandTask->getOrganizationalUnit());
|
||||
if ($commandTask->getOrganizationalUnit()) {
|
||||
$this->organizationalUnit = new OrganizationalUnitOutput($commandTask->getOrganizationalUnit());
|
||||
}
|
||||
$this->notes = $commandTask->getNotes();
|
||||
$this->scope = $commandTask->getScope();
|
||||
$this->lastExecution = $commandTask->getLastExecution();
|
||||
|
|
|
@ -73,6 +73,7 @@ class Client extends AbstractEntity
|
|||
#[ORM\ManyToOne(inversedBy: 'clients')]
|
||||
#[ORM\JoinColumn( onDelete: 'SET NULL')]
|
||||
private ?Subnet $subnet = null;
|
||||
|
||||
#[ORM\ManyToOne(inversedBy: 'clients')]
|
||||
#[ORM\JoinColumn( onDelete: 'SET NULL')]
|
||||
private ?OgLive $ogLive = null;
|
||||
|
|
|
@ -8,6 +8,7 @@ final class CommandTypes
|
|||
public const string RESTORE_IMAGE = 'restore-image';
|
||||
public const string CREATE_IMAGE = 'create-image';
|
||||
public const string CREATE_IMAGE_GIT = 'create-image-git';
|
||||
public const string UPDATE_IMAGE_GIT = 'update-image-git';
|
||||
public const string CONVERT_IMAGE = 'convert-image';
|
||||
public const string CREATE_IMAGE_AUX_FILE = 'create-image-aux-file';
|
||||
public const string BACKUP_IMAGE = 'backup-image';
|
||||
|
@ -34,6 +35,7 @@ final class CommandTypes
|
|||
self::RESTORE_IMAGE => 'Update Cache',
|
||||
self::CREATE_IMAGE => 'Create Image',
|
||||
self::CREATE_IMAGE_GIT => 'Create Image Git',
|
||||
self::UPDATE_IMAGE_GIT => 'Update Image Git',
|
||||
self::CONVERT_IMAGE => 'Convert Image',
|
||||
self::CONVERT_IMAGE_TO_VIRTUAL => 'Convert Image to Virtual',
|
||||
self::CREATE_IMAGE_AUX_FILE => 'Create Image Aux File',
|
||||
|
|
|
@ -74,12 +74,12 @@ readonly class ImageProcessor implements ProcessorInterface
|
|||
$response = $this->createImageActionController->__invoke($data->queue, $data->selectedImage->getEntity(), $data->partition->getEntity(), $data->client->getEntity(), $data->gitRepository);
|
||||
} else {
|
||||
$image = $data->createOrUpdateEntity($entity);
|
||||
$this->validator->validate($image);
|
||||
|
||||
if ($this->kernel->getEnvironment() !== 'test') {
|
||||
$response = $this->createImageActionController->__invoke($data->queue, $image, null, null, $data->gitRepository);
|
||||
}
|
||||
|
||||
$this->validator->validate($image);
|
||||
|
||||
$this->imageRepository->save($image);
|
||||
}
|
||||
|
||||
|
|
|
@ -495,7 +495,7 @@
|
|||
<td class="partition-os">{{ partition.operativeSystem ? partition.operativeSystem.name : '-' }}</td>
|
||||
<td>
|
||||
{% if partition.operativeSystem %}
|
||||
<a href="command+output:/opt/opengnsys/scripts/bootOs.py {{ partition.diskNumber }} {{ partition.partitionNumber }}"
|
||||
<a href="command+output:/opt/opengnsys/scripts/bootOs {{ partition.diskNumber }} {{ partition.partitionNumber }}"
|
||||
class="partition-boot-btn"
|
||||
role="button">
|
||||
<i class="fas fa-play"></i>
|
||||
|
|
Loading…
Reference in New Issue