ogRepo new endpoints. Export/Import image
testing/ogcore-api/pipeline/head This commit looks good Details

pull/20/head
Manuel Aranda Rosales 2025-01-31 13:27:03 +01:00
parent e421a38079
commit 3c7fa26e32
10 changed files with 156 additions and 29 deletions

View File

@ -34,7 +34,7 @@ resources:
class: ApiPlatform\Metadata\Post
method: POST
input: App\Dto\Input\WoLInput
uriTemplate: /image-repositories/{uuid}/wol
uriTemplate: /image-repositories/wol
controller: App\Controller\OgRepository\WoLAction
get_collection_images_ogrepository:

View File

@ -6,6 +6,7 @@ namespace App\Controller\OgRepository;
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;
@ -24,6 +25,7 @@ abstract class AbstractOgRepositoryController extends AbstractController
protected readonly EntityManagerInterface $entityManager,
protected readonly HttpClientInterface $httpClient,
protected readonly CreateService $createService,
protected readonly LoggerInterface $logger,
)
{
}

View File

@ -6,6 +6,9 @@ use App\Controller\OgRepository\AbstractOgRepositoryController;
use App\Dto\Input\ExportImportImageRepositoryInput;
use App\Entity\Image;
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;
@ -44,9 +47,18 @@ class ExportAction extends AbstractOgRepositoryController
]
];
$this->logger->info('Exporting image', ['image' => $image->getName(), 'repository' => $repository->getIp()]);
$content = $this->createRequest('PUT', 'http://'.$image->getRepository()->getIp().':8006/ogrepository/v1/repo/images', $params);
$image->setRepository($repository);
$inputData = [
'imageName' => $image->getName(),
'imageUuid' => $image->getUuid(),
];
$this->createService->__invoke($image->getClient(), CommandTypes::EXPORT_IMAGE, TraceStatus::IN_PROGRESS, $content['job_id'], $inputData);
$image->setStatus(ImageStatus::TRANSFERING);
$this->entityManager->persist($image);
$this->entityManager->flush();
}

View File

@ -6,6 +6,9 @@ use App\Controller\OgRepository\AbstractOgRepositoryController;
use App\Dto\Input\ExportImportImageRepositoryInput;
use App\Entity\Image;
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;
@ -46,7 +49,14 @@ class ImportAction extends AbstractOgRepositoryController
$content = $this->createRequest('POST', 'http://'.$image->getRepository()->getIp().':8006/ogrepository/v1/repo/images', $params);
$image->setRepository($repository);
$inputData = [
'imageName' => $image->getName(),
'imageUuid' => $image->getUuid(),
];
$this->createService->__invoke($image->getClient(), CommandTypes::IMPORT_IMAGE, TraceStatus::IN_PROGRESS, $content['job_id'], $inputData);
$image->setStatus(ImageStatus::TRANSFERING);
$this->entityManager->persist($image);
$this->entityManager->flush();
}

View File

@ -7,6 +7,7 @@ use App\Entity\Trace;
use App\Model\ImageStatus;
use App\Model\TraceStatus;
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 ResponseController extends AbstractController
{
public function __construct(
protected readonly EntityManagerInterface $entityManager
protected readonly EntityManagerInterface $entityManager,
protected readonly LoggerInterface $logger,
)
{
}
@ -28,6 +30,27 @@ class ResponseController extends AbstractController
{
$data = json_decode($request->getContent(), true);
if (!isset($data['job_id'])) {
return new JsonResponse(['message' => 'Invalid request'], Response::HTTP_BAD_REQUEST);
}
$action = $data['job_id'];
if (str_starts_with($action, "CreateAuxiliarFiles_")) {
$this->handleCreateAuxFiles($action, $data);
} elseif (str_starts_with($action, "ExportImage_")) {
$this->handleExportImage($action, $data);
} elseif (str_starts_with($action, "ImportImage_")) {
$this->handleImportImage($action, $data);
} else {
return new JsonResponse(['message' => 'Invalid action'], Response::HTTP_BAD_REQUEST);
}
return new JsonResponse($data, Response::HTTP_OK);
}
private function handleCreateAuxFiles(string $action, array $data): void
{
$trace = $this->entityManager->getRepository(Trace::class)->findOneBy(['jobId' => $data['job_id']]);
$imageUuid = $trace->getInput()['imageUuid'];
@ -40,7 +63,8 @@ class ResponseController extends AbstractController
$this->entityManager->persist($trace);
$this->entityManager->flush();
return new JsonResponse(['message' => 'Image not found'], Response::HTTP_NOT_FOUND);
new JsonResponse(['message' => 'Image not found'], Response::HTTP_NOT_FOUND);
return;
}
$image->setImageFullsum($data['image_id']);
@ -52,8 +76,69 @@ class ResponseController extends AbstractController
$this->entityManager->persist($trace);
$this->entityManager->flush();
}
return new JsonResponse($data, Response::HTTP_OK);
private function handleExportImage(string $action, array $data): void
{
$trace = $this->entityManager->getRepository(Trace::class)->findOneBy(['jobId' => $data['job_id']]);
$imageUuid = $trace->getInput()['imageUuid'];
$image = $this->entityManager->getRepository(Image::class)->findOneBy(['uuid' => $imageUuid]);
if ($image === null) {
$trace->setStatus(TraceStatus::FAILED);
$trace->setFinishedAt(new \DateTime());
$trace->setOutput('Image not found');
$this->entityManager->persist($trace);
$this->entityManager->flush();
new JsonResponse(['message' => 'Image not found'], Response::HTTP_NOT_FOUND);
return;
}
$this->logger->info('Image exported', ['image' => $image->getName()]);
$image->setStatus(ImageStatus::SUCCESS);
$this->entityManager->persist($image);
$trace->setStatus(TraceStatus::SUCCESS);
$trace->setFinishedAt(new \DateTime());
$this->entityManager->persist($trace);
$this->entityManager->flush();
}
private function handleImportImage(string $action, array $data): void
{
$trace = $this->entityManager->getRepository(Trace::class)->findOneBy(['jobId' => $data['job_id']]);
$imageUuid = $trace->getInput()['imageUuid'];
$image = $this->entityManager->getRepository(Image::class)->findOneBy(['uuid' => $imageUuid]);
if ($image === null) {
$trace->setStatus(TraceStatus::FAILED);
$trace->setFinishedAt(new \DateTime());
$trace->setOutput('Image not found');
$this->entityManager->persist($trace);
$this->entityManager->flush();
new JsonResponse(['message' => 'Image not found'], Response::HTTP_NOT_FOUND);
return;
}
$this->logger->info('Image imported', ['image' => $image->getName()]);
$image->setStatus(ImageStatus::SUCCESS);
$this->entityManager->persist($image);
$trace->setStatus(TraceStatus::SUCCESS);
$trace->setFinishedAt(new \DateTime());
$this->entityManager->persist($trace);
$this->entityManager->flush();
}
}

View File

@ -36,31 +36,35 @@ class WoLAction extends AbstractOgRepositoryController
* @throws RedirectionExceptionInterface
* @throws ClientExceptionInterface
*/
public function __invoke(WoLInput $input, ImageRepository $repository): JsonResponse
public function __invoke(WoLInput $input): JsonResponse
{
/** @var Client $client */
$client = $input->client->getEntity();
foreach ($input->clients as $client) {
/** @var Client $client */
$client = $client->getEntity();
$repository = $client->getRepository();
if (!$repository->getIp()) {
throw new ValidatorException('IP is required');
}
if (!$repository->getIp()) {
throw new ValidatorException('IP is required');
$params = [
'json' => [
'broadcast_ip' => '255.255.255.255',
'mac' => $client->getMac()
]
];
$this->logger->info('Sending WoL to client', ['mac' => $client->getMac()]);
$content = $this->createRequest('POST', 'http://'.$repository->getIp(). ':8006/ogrepository/v1/wol', $params);
$client->setStatus(ClientStatus::INITIALIZING);
$this->entityManager->persist($client);
$this->entityManager->flush();
$this->createService->__invoke($client, CommandTypes::SHUTDOWN, TraceStatus::SUCCESS, '', []);
}
$params = [
'json' => [
'broadcast_ip' => '255.255.255.255',
'mac' => $client->getMac()
]
];
$content = $this->createRequest('POST', 'http://'.$repository->getIp(). ':8006/ogrepository/v1/wol', $params);
$client->setStatus(ClientStatus::INITIALIZING);
$this->entityManager->persist($client);
$this->entityManager->flush();
$this->createService->__invoke($client, CommandTypes::SHUTDOWN, TraceStatus::SUCCESS, '', []);
return new JsonResponse(data: $client, status: Response::HTTP_OK);
return new JsonResponse(data: [], status: Response::HTTP_OK);
}
}

View File

@ -38,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 status of the image', example: "PENDING")]
public ?string $status = ImageStatus::PENDING;
#[Groups(['image:write'])]
#[ApiProperty(description: 'The software profile of the image')]
public ?SoftwareProfileOutput $softwareProfile = null;
@ -73,6 +77,7 @@ final class ImageInput
$this->comments = $image->getComments();
$this->type = $image->getType();
$this->remotePc = $image->isRemotePc();
$this->status = $image->getStatus();
if ($image->getSoftwareProfile()) {
$this->softwareProfile = new SoftwareProfileOutput($image->getSoftwareProfile());
@ -95,13 +100,13 @@ final class ImageInput
{
if (!$image) {
$image = new Image();
$image->setStatus(ImageStatus::PENDING);
}
$image->setName($this->name);
$image->setDescription($this->description);
$image->setComments($this->comments);
$image->setType($this->type);
$image->setStatus(ImageStatus::PENDING);
if ($this->softwareProfile) {
$image->setSoftwareProfile($this->softwareProfile->getEntity());

View File

@ -8,7 +8,10 @@ use Symfony\Component\Serializer\Annotation\Groups;
class WoLInput
{
/**
* @var ClientOutput[]|null
*/
#[Groups(['repository:write'])]
#[ApiProperty(description: 'The client to wol')]
public ?ClientOutput $client = null;
public ?array $clients = null;
}

View File

@ -8,6 +8,8 @@ final class CommandTypes
public const string RESTORE_IMAGE = 'restore-image';
public const string CREATE_IMAGE = 'create-image';
public const string CREATE_IMAGE_AUX_FILE = 'create-image-aux-file';
public const string IMPORT_IMAGE = 'import-image';
public const string EXPORT_IMAGE = 'export-image';
public const string POWER_ON = 'power-on';
public const string REBOOT = 'reboot';
public const string SHUTDOWN = 'shutdown';
@ -20,6 +22,8 @@ final class CommandTypes
self::RESTORE_IMAGE => 'Update Cache',
self::CREATE_IMAGE => 'Create Image',
self::CREATE_IMAGE_AUX_FILE => 'Crear fichero auxiliar en repositorio',
self::IMPORT_IMAGE => 'Importar imagen',
self::EXPORT_IMAGE => 'Exportar imagen',
self::POWER_ON => 'Encender',
self::REBOOT => 'Reiniciar',
self::SHUTDOWN => 'Apagar',

View File

@ -10,6 +10,7 @@ final class ImageStatus
public const string SUCCESS = 'success';
public const string TRASH = 'trash';
public const string FAILED = 'failed';
public const string TRANSFERING = 'transfering';
private const array STATUS = [
self::PENDING => 'Pendiente',
@ -18,6 +19,7 @@ final class ImageStatus
self::TRASH => 'Papelera',
self::SUCCESS => 'Completado',
self::FAILED => 'Fallido',
self::TRANSFERING => 'Transferiendo',
];
public static function getStatus(): array