ogcore/src/Controller/OgAgent/CreateImageAction.php

352 lines
14 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Controller\OgAgent;
use App\Controller\OgRepository\Git\CreateRepositoryAction;
use App\Entity\Client;
use App\Entity\Command;
use App\Entity\GitRepository;
use App\Entity\Image;
use App\Entity\ImageImageRepository;
use App\Entity\ImageRepository;
use App\Entity\Partition;
use App\Entity\Trace;
use App\Model\ClientStatus;
use App\Model\CommandTypes;
use App\Model\ImageStatus;
use App\Model\PartitionTypes;
use App\Model\TraceStatus;
use App\Service\Trace\CreateService;
use Doctrine\ORM\EntityManagerInterface;
use Exception;
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 CreateImageAction extends AbstractOgAgentController
{
/**
* @throws TransportExceptionInterface
* @throws ServerExceptionInterface
* @throws RedirectionExceptionInterface
* @throws ClientExceptionInterface
*/
public function __invoke(bool $queue, Image $image, ?Partition $partition = null, ?Client $client = null, ?string $gitRepositoryName = null): JsonResponse
{
$client = $client ?? $image->getClient();
if (!$client->getIp()) {
throw new BadRequestHttpException('IP is required');
}
$partitionInfo = [];
if ($partition) {
$partitionInfo["numPartition"] = $partition->getPartitionNumber();
$partitionInfo["numDisk"] = $partition->getDiskNumber();
$partitionInfo["partitionCode"] = $partition->getPartitionCode();
$partitionInfo["filesystem"] = $partition->getFilesystem();
$partitionInfo["osName"] = $partition->getOperativeSystem()?->getName();
$image->setPartitionInfo(json_encode($partitionInfo));
} else {
$partitionInfo = json_decode($image->getPartitionInfo(), true);
}
if ($image->getType() === 'monolithic') {
$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);
$imageImageRepository->setPartitionInfo(json_encode($partitionInfo));
$this->entityManager->persist($imageImageRepository);
return $this->createMonolithicImage($imageImageRepository, $partitionInfo, $image, $repository, $client, $queue);
} 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);
}
}
/**
* @throws TransportExceptionInterface
* @throws ServerExceptionInterface
* @throws RedirectionExceptionInterface
* @throws ClientExceptionInterface
*/
public function createMonolithicImage(
ImageImageRepository $imageImageRepository,
array $partitionInfo,
Image $image,
ImageRepository $repository,
?Client $client = null,
bool $queue = false
): JsonResponse
{
if (!isset($partitionInfo['numDisk'], $partitionInfo['numPartition'], $partitionInfo['partitionCode'], $partitionInfo['filesystem'])) {
throw new BadRequestHttpException('Missing required partition information');
}
$client = $client ?? $image->getClient();
if (!$client->getIp() || !$client->getToken()) {
throw new BadRequestHttpException('Client IP or token is missing');
}
$data = [
'dsk' => (string) $partitionInfo['numDisk'],
'par' => (string) $partitionInfo['numPartition'],
'cpt' => null,
'idi' => $imageImageRepository->getUuid(),
'nci' => $image->getName().'_v'.$imageImageRepository->getVersion(),
'ipr' => $repository->getIp(),
'nfn' => 'CrearImagen',
'ids' => '0'
];
$partitionTypes = PartitionTypes::getPartitionTypes();
$partitionCode = $partitionInfo['partitionCode'];
$cptKey = array_search($partitionCode, array_column($partitionTypes, 'name'), true);
if ($cptKey !== false) {
$keys = array_keys($partitionTypes);
$partitionTypeCode = $keys[$cptKey];
$data['cpt'] = dechex($partitionTypeCode);
} else {
throw new BadRequestHttpException("Invalid partition code: {$partitionCode}");
}
$this->logger->info('Creating image', ['image' => $image->getId()]);
try {
$response = $this->createRequest(
method: 'POST',
url: 'https://'.$client->getIp().':8000/opengnsys/CrearImagen',
params: [
'json' => $data,
],
token: $client->getToken(),
);
$this->logger->info('Creating image', ['image' => $imageImageRepository->getName(), 'repository' => $repository->getIp()]);
if (isset($response['error']) && $response['code'] === Response::HTTP_INTERNAL_SERVER_ERROR) {
if ($queue) {
$inputData = [
'method' => 'CrearImagen',
'type' => 'monolithic',
'client' => $client->getUuid(),
'image' => $image->getUuid(),
'partitionCode' => $partitionInfo['partitionCode'],
'partitionType' => $partitionInfo['filesystem'],
'repository' => $repository->getIp(),
'name' => $image->getName().'_v'.$imageImageRepository->getVersion(),
];
$this->createService->__invoke($client, CommandTypes::CREATE_IMAGE, TraceStatus::PENDING, null, $inputData);
return new JsonResponse(data: [], status: Response::HTTP_OK);
}
throw new BadRequestHttpException('Error creating image: ' . ($response['message'] ?? 'Unknown error'));
}
if (!isset($response['job_id'])) {
throw new BadRequestHttpException('No job ID received from server');
}
$jobId = $response['job_id'];
try {
$client->setStatus(ClientStatus::BUSY);
$imageImageRepository->setStatus(ImageStatus::IN_PROGRESS);
$this->entityManager->persist($client);
$this->entityManager->persist($imageImageRepository);
$this->entityManager->flush();
$inputData = [
'method' => 'CrearImagen',
'type' => 'monolithic',
'client' => $client->getUuid(),
'image' => $image->getUuid(),
'partitionCode' => $partitionInfo['partitionCode'],
'partitionType' => $partitionInfo['filesystem'],
'repository' => $repository->getIp(),
'name' => $image->getName().'_v'.$imageImageRepository->getVersion(),
];
$this->createService->__invoke(
$image->getClient(),
CommandTypes::CREATE_IMAGE,
TraceStatus::IN_PROGRESS,
$jobId,
$inputData
);
return new JsonResponse(data: $image, status: Response::HTTP_OK);
} catch (Exception $e) {
$client->setStatus(ClientStatus::OG_LIVE);
$this->entityManager->persist($client);
$this->entityManager->flush();
throw $e;
}
} catch (Exception $e) {
$this->logger->error('Error in monolithic image creation process', [
'repository' => $repository->getId(),
'error' => $e->getMessage(),
'trace' => $e->getTraceAsString()
]);
return new JsonResponse(
data: ['error' => $e->getMessage()],
status: Response::HTTP_INTERNAL_SERVER_ERROR
);
}
}
public function createGitImage(
Image $image,
array $partitionInfo,
ImageRepository $repository,
bool $queue = false,
?string $gitRepositoryName = null
): JsonResponse
{
if (!isset($partitionInfo['numDisk'], $partitionInfo['numPartition'], $partitionInfo['partitionCode'], $partitionInfo['filesystem'])) {
throw new BadRequestHttpException('Missing required partition information');
}
$client = $image->getClient();
if (!$client->getIp() || !$client->getToken()) {
throw new BadRequestHttpException('Client IP or token is missing');
}
try {
$data = [
'dsk' => (string) $partitionInfo['numDisk'],
'par' => (string) $partitionInfo['numPartition'],
'cpt' => null,
'idi' => $gitRepositoryName ?: $image->getUuid(),
'nci' => $gitRepositoryName ?: $image->getName(),
'ipr' => $repository->getIp(),
'nfn' => 'CrearImagenGit',
'tag' => '',
'ids' => '0'
];
$partitionTypes = PartitionTypes::getPartitionTypes();
$partitionCode = $partitionInfo['partitionCode'];
$cptKey = array_search($partitionCode, array_column($partitionTypes, 'name'), true);
if ($cptKey !== false) {
$keys = array_keys($partitionTypes);
$partitionTypeCode = $keys[$cptKey];
$data['cpt'] = dechex($partitionTypeCode);
} else {
throw new BadRequestHttpException("Invalid partition code: {$partitionCode}");
}
//$this->sshKeyAction->__invoke($repository, $client);
$response = $this->createRequest(
method: 'POST',
url: 'https://'.$client->getIp().':8000/opengnsys/CrearImagenGit',
params: [
'json' => $data,
],
token: $client->getToken(),
);
if (isset($response['error']) && $response['code'] === Response::HTTP_INTERNAL_SERVER_ERROR) {
if ($queue) {
$inputData = [
'method' => 'CrearImagenGit',
'type' => 'git',
'client' => $client->getUuid(),
'image' => $image->getUuid(),
'partitionCode' => $partitionInfo['partitionCode'],
'partitionType' => $partitionInfo['filesystem'],
'repository' => $repository->getIp(),
'name' => $image->getName(),
];
$this->createService->__invoke($client, CommandTypes::CREATE_IMAGE_GIT, TraceStatus::PENDING, null, $inputData);
return new JsonResponse(data: [], status: Response::HTTP_OK);
}
throw new BadRequestHttpException('Error creating image: ' . ($response['message'] ?? 'Unknown error'));
}
if (!isset($response['job_id'])) {
throw new BadRequestHttpException('No job ID received from server');
}
$jobId = $response['job_id'];
try {
$client->setStatus(ClientStatus::BUSY);
$this->entityManager->persist($client);
$this->entityManager->flush();
$inputData = [
'method' => 'CrearImagenGit',
'type' => 'git',
'client' => $client->getUuid(),
'image' => $image->getUuid(),
'partitionCode' => $partitionInfo['partitionCode'],
'partitionType' => $partitionInfo['filesystem'],
'repository' => $repository->getIp(),
'name' => $image->getName(),
];
$this->createService->__invoke(
$image->getClient(),
CommandTypes::CREATE_IMAGE_GIT,
TraceStatus::IN_PROGRESS,
$jobId,
$inputData
);
return new JsonResponse(data: $image, status: Response::HTTP_OK);
} catch (Exception $e) {
$client->setStatus(ClientStatus::OG_LIVE);
$this->entityManager->persist($client);
$this->entityManager->flush();
throw $e;
}
} catch (Exception $e) {
$this->logger->error('Error in git image creation process', [
'repository' => $repository->getId(),
'error' => $e->getMessage(),
'trace' => $e->getTraceAsString()
]);
return new JsonResponse(
data: ['error' => $e->getMessage()],
status: Response::HTTP_INTERNAL_SERVER_ERROR
);
}
}
}