refs #2735. Error handler ogRepo
testing/ogcore-api/pipeline/head This commit looks good Details

pull/49/head
Manuel Aranda Rosales 2025-09-03 06:51:54 +02:00
parent b5cd1b49ff
commit 20b9ffdfa1
2 changed files with 211 additions and 58 deletions

View File

@ -34,10 +34,26 @@ class BackupImageAction extends AbstractOgRepositoryController
$image = $imageImageRepository->getImage();
$repository = $imageImageRepository->getRepository();
$this->validateImageName($image);
$this->logger->info('Create backup image', ['image' => $image->getName()]);
$content = $this->createBackupRequest($input, $imageImageRepository, $repository);
$this->handleBackupResponse($content);
$this->processBackupSuccess($input, $image, $repository, $imageImageRepository, $content);
return new JsonResponse(data: $content, status: Response::HTTP_OK);
}
private function validateImageName(Image $image): void
{
if (!$image->getName()) {
throw new BadRequestHttpException('Name is required');
}
}
private function createBackupRequest(BackupImageInput $input, ImageImageRepository $imageImageRepository, ImageRepository $repository): array
{
$params = [
'json' => [
'ID_img' => $imageImageRepository->getImageFullsum(),
@ -48,16 +64,85 @@ class BackupImageAction extends AbstractOgRepositoryController
]
];
$this->logger->info('Create backup image', ['image' => $image->getName()]);
return $this->createRequest('PUT', 'http://'.$repository->getIp().':8006/ogrepository/v1/repo/images', $params);
}
$repository = $imageImageRepository->getRepository();
$content = $this->createRequest('PUT', 'http://'.$repository->getIp().':8006/ogrepository/v1/repo/images', $params);
if (isset($content['error']) && $content['code'] === Response::HTTP_INTERNAL_SERVER_ERROR ) {
throw new BadRequestHttpException('Error backing up image: ' . $content['error'] . ' - ' . $content['details']);
private function handleBackupResponse(array $content): void
{
if (!isset($content['error'])) {
return;
}
$errorMessage = $this->extractErrorMessage($content);
$errorCode = $content['code'] ?? Response::HTTP_BAD_REQUEST;
$this->throwAppropriateException($errorCode, $errorMessage);
}
private function extractErrorMessage(array $content): string
{
$errorMessage = $content['error'];
$errorDetails = $content['details'] ?? null;
if (!$errorDetails) {
return $errorMessage;
}
$extractedMessage = $this->extractMessageFromDetails($errorDetails);
return $extractedMessage ?: $errorMessage;
}
private function extractMessageFromDetails($errorDetails): ?string
{
if (is_array($errorDetails)) {
return $errorDetails['details'] ?? $errorDetails['message'] ?? $errorDetails['error'] ?? null;
}
if (is_string($errorDetails)) {
$parsed = $this->parseJsonString($errorDetails);
if ($parsed !== null) {
return $parsed['details'] ?? $parsed['message'] ?? $parsed['error'] ?? null;
}
return !empty($errorDetails) ? $errorDetails : null;
}
return null;
}
private function parseJsonString(string $jsonString): ?array
{
$cleanJson = trim($jsonString, " \t\n\r\0\x0B");
$decoded = json_decode($cleanJson, true);
return (json_last_error() === JSON_ERROR_NONE && is_array($decoded)) ? $decoded : null;
}
private function throwAppropriateException(int $errorCode, string $errorMessage): void
{
if ($errorCode === Response::HTTP_INTERNAL_SERVER_ERROR) {
throw new BadRequestHttpException('Error backing up image: ' . $errorMessage);
}
if ($errorCode >= 400 && $errorCode < 500) {
throw new BadRequestHttpException($errorMessage);
}
if ($errorCode >= 500) {
throw new BadRequestHttpException('Error backing up image: ' . $errorMessage);
}
throw new BadRequestHttpException($errorMessage);
}
private function processBackupSuccess(
BackupImageInput $input,
Image $image,
ImageRepository $repository,
ImageImageRepository $imageImageRepository,
array $content
): void {
$inputData = [
'imageName' => $image->getName(),
'repositoryUuid' => $repository->getUuid(),
@ -67,13 +152,16 @@ class BackupImageAction extends AbstractOgRepositoryController
'remote_path' => $input->remotePath
];
$this->createService->__invoke($image->getClient(), CommandTypes::BACKUP_IMAGE, TraceStatus::IN_PROGRESS, $content['job_id'], $inputData);
$this->createService->__invoke(
$image->getClient(),
CommandTypes::BACKUP_IMAGE,
TraceStatus::IN_PROGRESS,
$content['job_id'],
$inputData
);
$imageImageRepository->setStatus(ImageStatus::BACKUP);
$this->entityManager->persist($imageImageRepository);
$this->entityManager->flush();
return new JsonResponse(data: $content, status: Response::HTTP_OK);
}
}

View File

@ -19,6 +19,7 @@ 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\Component\HttpKernel\Exception\HttpException;
#[AsController]
class ImportAction extends AbstractOgRepositoryController
@ -30,20 +31,52 @@ class ImportAction extends AbstractOgRepositoryController
* @throws ClientExceptionInterface
*/
public function __invoke(ImportImageRepositoryInput $input, ImageRepository $repository): JsonResponse
{
$this->validateRepositoryStatus($repository);
$image = $input->name;
$imageEntity = $this->getOrCreateImageEntity($image);
$this->validateImageNotExistsInRepository($imageEntity, $repository);
$this->logger->info('Creating aux files', ['image' => $image]);
$content = $this->createTorrentSumRequest($repository, $image);
$this->handleTorrentSumResponse($content);
$imageImageRepositoryEntity = $this->createImageImageRepositoryEntity($imageEntity, $repository, $image);
$this->entityManager->persist($imageImageRepositoryEntity);
$this->entityManager->flush();
$this->createService->__invoke(
null,
CommandTypes::CREATE_IMAGE_AUX_FILE,
TraceStatus::IN_PROGRESS,
$content['job_id'],
[
'imageName' => $image,
'imageImageRepositoryUuid' => $imageImageRepositoryEntity->getUuid(),
]
);
return new JsonResponse(data: [], status: Response::HTTP_OK);
}
private function validateRepositoryStatus(ImageRepository $repository): void
{
$content = $this->createRequest('GET', 'http://'.$repository->getIp(). ':8006/ogrepository/v1/status');
if (isset($content['error']) && $content['code'] === Response::HTTP_INTERNAL_SERVER_ERROR) {
throw new BadRequestHttpException('An error occurred while fetching the status: ' . $content['details']);
}
}
$image = $input->name;
private function getOrCreateImageEntity(string $imageName): Image
{
$imageEntity = $this->entityManager->getRepository(Image::class)->findOneBy(['name' => $imageName]);
$imageEntity = $this->entityManager->getRepository(Image::class)->findOneBy(['name' => $image]);
if (!$imageEntity){
if (!$imageEntity) {
$imageEntity = new Image();
$imageEntity->setName($image);
$imageEntity->setName($imageName);
$imageEntity->setType('monolithic');
$imageEntity->setRemotePc(false);
$imageEntity->setIsGlobal(false);
@ -51,65 +84,97 @@ class ImportAction extends AbstractOgRepositoryController
$this->entityManager->persist($imageEntity);
}
$imageImageRepositoryEntity = $this->entityManager->getRepository(ImageImageRepository::class)->findOneBy(['image' => $imageEntity, 'repository' => $repository]);
return $imageEntity;
}
if ($imageImageRepositoryEntity){
private function validateImageNotExistsInRepository(Image $imageEntity, ImageRepository $repository): void
{
$imageImageRepositoryEntity = $this->entityManager->getRepository(ImageImageRepository::class)
->findOneBy(['image' => $imageEntity, 'repository' => $repository]);
if ($imageImageRepositoryEntity) {
throw new BadRequestHttpException('This image already exists in this repository');
}
}
$imageImageRepositoryEntity = new ImageImageRepository();
$imageImageRepositoryEntity->setName($imageEntity->getName());
$imageImageRepositoryEntity->setStatus(ImageStatus::AUX_FILES_PENDING);
$imageImageRepositoryEntity->setImage($imageEntity);
$imageImageRepositoryEntity->setRepository($repository);
$imageImageRepositoryEntity->setVersion($this->extractVersionFromImageName($image));
$this->entityManager->persist($imageImageRepositoryEntity);
$this->entityManager->flush();
$this->logger->info('Creating aux files', ['image' => $image]);
private function createTorrentSumRequest(ImageRepository $repository, string $image): array
{
$params = [
'json' => [
'image' => $image.'.img'
]
];
$content = $this->createRequest('POST', 'http://'.$repository->getIp().':8006/ogrepository/v1/images/torrentsum', $params);
if (isset($content['error']) && $content['code'] === Response::HTTP_INTERNAL_SERVER_ERROR ) {
throw new BadRequestHttpException('Error importing image' . ' - ' . $content['error'] . ' - ' . $content['details']);
}
$inputData = [
'imageName' => $image,
'imageImageRepositoryUuid' => $imageImageRepositoryEntity->getUuid(),
];
$this->createService->__invoke(null, CommandTypes::CREATE_IMAGE_AUX_FILE, TraceStatus::IN_PROGRESS, $content['job_id'], $inputData);
return new JsonResponse(data: [], status: Response::HTTP_OK);
return $this->createRequest('POST', 'http://'.$repository->getIp().':8006/ogrepository/v1/images/torrentsum', $params);
}
private function handleTorrentSumResponse(array $content): void
{
if (!isset($content['error'])) {
return;
}
$errorMessage = $this->extractErrorMessage($content);
$errorCode = $content['code'] ?? Response::HTTP_BAD_REQUEST;
$this->throwAppropriateException($errorCode, $errorMessage);
}
private function extractErrorMessage(array $content): string
{
$errorMessage = $content['error'];
$errorDetails = $content['details'] ?? null;
if (!$errorDetails) {
return $errorMessage;
}
if (is_array($errorDetails)) {
return $errorDetails['message'] ?? $errorDetails['error'] ?? $errorMessage;
}
if (is_string($errorDetails) && !empty($errorDetails)) {
return $errorDetails;
}
return $errorMessage;
}
private function throwAppropriateException(int $errorCode, string $errorMessage): void
{
if ($errorCode >= 400 && $errorCode < 500) {
throw new BadRequestHttpException($errorMessage);
}
if ($errorCode >= 500) {
throw new HttpException($errorCode, $errorMessage);
}
throw new BadRequestHttpException($errorMessage);
}
private function createImageImageRepositoryEntity(Image $imageEntity, ImageRepository $repository, string $imageName): ImageImageRepository
{
$imageImageRepositoryEntity = new ImageImageRepository();
$imageImageRepositoryEntity->setName($imageEntity->getName());
$imageImageRepositoryEntity->setStatus(ImageStatus::AUX_FILES_PENDING);
$imageImageRepositoryEntity->setImage($imageEntity);
$imageImageRepositoryEntity->setRepository($repository);
$imageImageRepositoryEntity->setVersion($this->extractVersionFromImageName($imageName));
return $imageImageRepositoryEntity;
}
private function extractVersionFromImageName(string $imageName): int
{
// Buscar patrones como "_v2", "_v3", etc.
if (preg_match('/_v(\d+)$/', $imageName, $matches)) {
return (int) $matches[1];
$patterns = ['/_v(\d+)$/', '/-v(\d+)$/', '/v(\d+)$/'];
foreach ($patterns as $pattern) {
if (preg_match($pattern, $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;
}
}