Some improvements. Added new filters
testing/ogcore-api/pipeline/head There was a failure building this commit Details

hotfix-timeout
Manuel Aranda Rosales 2025-02-17 09:13:48 +01:00
parent 4fd3a78c0a
commit ca3e547b56
18 changed files with 227 additions and 14 deletions

View File

@ -0,0 +1,31 @@
<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20250214114518 extends AbstractMigration
{
public function getDescription(): string
{
return '';
}
public function up(Schema $schema): void
{
// this up() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE og_live ADD date DATETIME NOT NULL, ADD name VARCHAR(255) NOT NULL');
}
public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE og_live DROP date, DROP name');
}
}

View File

@ -0,0 +1,31 @@
<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20250214120305 extends AbstractMigration
{
public function getDescription(): string
{
return '';
}
public function up(Schema $schema): void
{
// this up() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE trace CHANGE client_id client_id INT DEFAULT NULL');
}
public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE trace CHANGE client_id client_id INT NOT NULL');
}
}

View File

@ -0,0 +1,31 @@
<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20250214121437 extends AbstractMigration
{
public function getDescription(): string
{
return '';
}
public function up(Schema $schema): void
{
// this up() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE og_live CHANGE date date DATETIME DEFAULT NULL');
}
public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE og_live CHANGE date date DATETIME NOT NULL');
}
}

View File

@ -6,6 +6,8 @@ namespace App\Controller\OgBoot;
use App\Controller\OgBoot\PxeBootFile\PostAction;
use App\Service\Trace\CreateService;
use App\Service\Utils\ExtractOgLiveFilenameDateService;
use App\Service\Utils\SymflipyOgLiveFilenameService;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\DependencyInjection\Attribute\Autowire;
@ -24,14 +26,16 @@ abstract class AbstractOgBootController extends AbstractController
{
public function __construct(
#[Autowire(env: 'OG_BOOT_API_URL')]
protected string $ogBootApiUrl,
protected string $ogBootApiUrl,
#[Autowire(env: 'OG_CORE_IP')]
protected string $ogCoreIP,
protected string $ogCoreIP,
#[Autowire(env: 'OG_LOG_IP')]
protected string $ogLogIp,
protected readonly EntityManagerInterface $entityManager,
protected readonly HttpClientInterface $httpClient,
protected readonly CreateService $createService,
protected string $ogLogIp,
protected readonly EntityManagerInterface $entityManager,
protected readonly HttpClientInterface $httpClient,
protected readonly CreateService $createService,
protected readonly SymflipyOgLiveFilenameService $symflipyOgLiveFilenameService,
protected readonly ExtractOgLiveFilenameDateService $extractOgLiveFilenameDateService,
)
{
}

View File

@ -25,6 +25,24 @@ class GetIsosAction extends AbstractOgBootController
{
$content = $this->createRequest('GET', 'http://'.$this->ogBootApiUrl.'/ogboot/v1/oglives/isos');
return new JsonResponse(data: $content, status: Response::HTTP_OK);
if (!isset($content['message']) || !is_array($content['message'])) {
return new JsonResponse(data: ['error' => 'Invalid response'], status: Response::HTTP_BAD_REQUEST);
}
$isos = array_map(function ($iso) {
$filename = $this->symflipyOgLiveFilenameService->__invoke($iso['filename']);
return [
'id' => $iso['id'],
'filename' => $filename,
'url' => $iso['url'],
'installed' => $iso['installed'],
'compatible' => $iso['compatible'],
];
}, $content['message']);
usort($isos, fn($a, $b) => $b['id'] <=> $a['id']);
return new JsonResponse(data: ['success' => 'ISOs retrieved successfully', 'message' => $isos], status: Response::HTTP_OK);
}
}
}

View File

@ -4,7 +4,9 @@ namespace App\Controller\OgBoot\OgLive;
use App\Controller\OgBoot\AbstractOgBootController;
use App\Entity\OgLive;
use App\Model\CommandTypes;
use App\Model\OgLiveStatus;
use App\Model\TraceStatus;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
@ -38,8 +40,17 @@ class InstallAction extends AbstractOgBootController
]
];
$inputData= [
'downloadUrl' => $data->getDownloadUrl(),
'uuid' => 'InstallOgLive_'.$data->getUuid()
];
$content = $this->createRequest('POST', 'http://'.$this->ogBootApiUrl.'/ogboot/v1/oglives/install', $params);
$this->createService->__invoke(null, CommandTypes::INSTALL_OGLIVE, TraceStatus::IN_PROGRESS, 'InstallOgLive_'.$data->getUuid(), $inputData);
$data->setName($this->symflipyOgLiveFilenameService->__invoke($data->getFilename()));
$data->setDate(new \DateTime());
$data->setStatus(OgLiveStatus::PENDING);
$this->entityManager->persist($data);
$this->entityManager->flush();

View File

@ -56,9 +56,12 @@ class SyncAction extends AbstractOgBootController
* @param OgLive|null $ogLiveEntity
* @param mixed $ogLive
* @return void
* @throws \Exception
*/
private function extracted(OgLive $ogLiveEntity, mixed $ogLive): void
{
$ogLiveEntity->setName($this->symflipyOgLiveFilenameService->__invoke(str_replace(self::OG_BOOT_DIRECTORY, '', $ogLive['directory'])));
$ogLiveEntity->setDate(new \DateTime($this->extractOgLiveFilenameDateService->__invoke(str_replace(self::OG_BOOT_DIRECTORY, '', $ogLive['directory']))));
$ogLiveEntity->setInstalled(true);
$ogLiveEntity->setArchitecture($ogLive['architecture']);
$ogLiveEntity->setDistribution($ogLive['distribution']);

View File

@ -4,7 +4,10 @@ namespace App\Controller\OgBoot\OgLive\Webhook;
use App\Controller\OgBoot\AbstractOgBootController;
use App\Entity\OgLive;
use App\Entity\Trace;
use App\Model\OgLiveStatus;
use App\Service\Utils\ExtractOgLiveFilenameDateService;
use App\Service\Utils\SymflipyOgLiveFilenameService;
use Doctrine\ORM\EntityManagerInterface;
use Psr\Log\LoggerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
@ -28,12 +31,17 @@ class InstallOgLiveResponseAction extends AbstractController
const string OG_BOOT_DIRECTORY = '/opt/opengnsys/ogboot/tftpboot//';
public function __construct(
protected readonly EntityManagerInterface $entityManager,
protected readonly LoggerInterface $logger,
protected readonly EntityManagerInterface $entityManager,
protected readonly LoggerInterface $logger,
protected readonly SymflipyOgLiveFilenameService $symflipyOgLiveFilenameService,
protected readonly ExtractOgLiveFilenameDateService $extractOgLiveFilenameDateService,
)
{
}
/**
* @throws \Exception
*/
#[Route('/og-lives/install/webhook', name: 'install_webhook', methods: ['POST'])]
public function installWebhook(Request $request): JsonResponse
{
@ -54,11 +62,17 @@ class InstallOgLiveResponseAction extends AbstractController
$status = $data['status'];
$ogLive = $this->entityManager->getRepository(OgLive::class)->findOneBy(['uuid' => $ogCoreId]);
$trace = $this->entityManager->getRepository(Trace::class)->findOneBy(['jobId' => 'InstallOgLive_'.$ogCoreId]);
if (!$ogLive) {
return new JsonResponse(['error' => 'OgLive not found'], Response::HTTP_NOT_FOUND);
}
if ($trace) {
$trace->setStatus($status === self::OG_LIVE_INSTALL_SUCCESS ? 'success' : 'failure');
$this->entityManager->persist($trace);
}
if ($ogLive->getStatus() === OgLiveStatus::ACTIVE) {
return new JsonResponse(['error' => 'OgLive is already active'], Response::HTTP_BAD_REQUEST);
}
@ -69,9 +83,14 @@ class InstallOgLiveResponseAction extends AbstractController
return new JsonResponse(data: sprintf('OgLive %s updated successfully', $ogLive->getChecksum()), status: Response::HTTP_OK);
}
/**
* @throws \Exception
*/
private function updateOgLive (OgLive $ogLive, array $details, string $status): void
{
if ($status === self::OG_LIVE_INSTALL_SUCCESS) {
$ogLive->setName($this->symflipyOgLiveFilenameService->__invoke($details['filename']));
$ogLive->setDate(new \DateTime($this->extractOgLiveFilenameDateService->__invoke($details['filename'])));
$ogLive->setFilename(str_replace(self::OG_BOOT_DIRECTORY, '', $ogLive['directory']));
$ogLive->setInstalled(true);
$ogLive->setSynchronized(true);

View File

@ -37,6 +37,7 @@ final class OgLiveInput
$filename = substr($filename, 0, -4);
}
$ogLive->setName($filename);
$ogLive->setFilename($filename);
$ogLive->setDownloadUrl($this->downloadUrl);
$ogLive->setStatus(OgLiveStatus::INACTIVE);

View File

@ -10,6 +10,9 @@ use Symfony\Component\Serializer\Annotation\Groups;
#[Get(shortName: 'OgLive')]
final class OgLiveOutput extends AbstractOutput
{
#[Groups(['og-live:read', 'client:read', "organizational-unit:read"])]
public ?string $name = '';
#[Groups(['og-live:read'])]
public ?bool $synchronized = false;
@ -46,6 +49,9 @@ final class OgLiveOutput extends AbstractOutput
#[Groups(['og-live:read'])]
public \DateTime $createdAt;
#[Groups(['og-live:read', 'client:read', "organizational-unit:read"])]
public ?\DateTimeInterface $date;
#[Groups(['og-live:read'])]
public ?string $createdBy = null;
@ -53,6 +59,7 @@ final class OgLiveOutput extends AbstractOutput
{
parent::__construct($ogLive);
$this->name = $ogLive->getName();
$this->synchronized = $ogLive->isSynchronized();
$this->installed = $ogLive->isInstalled();
$this->isDefault = $ogLive->getIsDefault();
@ -64,6 +71,7 @@ final class OgLiveOutput extends AbstractOutput
$this->kernel = $ogLive->getKernel();
$this->architecture = $ogLive->getArchitecture();
$this->status = $ogLive->getStatus();
$this->date = $ogLive->getDate();
$this->createdAt = $ogLive->getCreatedAt();
$this->createdBy = $ogLive->getCreatedBy();
}

View File

@ -14,7 +14,7 @@ final class TraceOutput extends AbstractOutput
public ?string $command;
#[Groups(['trace:read'])]
public ClientOutput $client;
public ?ClientOutput $client = null;
#[Groups(['trace:read'])]
public string $status;
@ -45,7 +45,11 @@ final class TraceOutput extends AbstractOutput
parent::__construct($trace);
$this->command = $trace->getCommand();
$this->client = new ClientOutput($trace->getClient());
if ($trace->getClient() !== null) {
$this->client = new ClientOutput($trace->getClient());
}
$this->status = $trace->getStatus();
$this->jobId = $trace->getJobId();
$this->executedAt = $trace->getExecutedAt();

View File

@ -5,6 +5,7 @@ namespace App\Entity;
use App\Repository\OgLiveRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
@ -13,6 +14,7 @@ use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
#[UniqueEntity(fields: ['filename'], message: 'validators.og_live.filename.unique')]
class OgLive extends AbstractEntity
{
use NameableTrait;
use SynchronizedTrait;
#[ORM\Column(length: 255, nullable: true)]
@ -54,6 +56,9 @@ class OgLive extends AbstractEntity
#[ORM\Column(length: 255)]
private ?string $status = null;
#[ORM\Column(type: Types::DATETIME_MUTABLE, nullable: true)]
private ?\DateTimeInterface $date = null;
public function __construct()
{
parent::__construct();
@ -219,4 +224,16 @@ class OgLive extends AbstractEntity
return $this;
}
public function getDate(): ?\DateTimeInterface
{
return $this->date;
}
public function setDate(?\DateTimeInterface $date): static
{
$this->date = $date;
return $this;
}
}

View File

@ -10,7 +10,7 @@ use Doctrine\ORM\Mapping as ORM;
class Trace extends AbstractEntity
{
#[ORM\ManyToOne(inversedBy: 'traces')]
#[ORM\JoinColumn(nullable: false, onDelete: 'CASCADE')]
#[ORM\JoinColumn(nullable: true, onDelete: 'CASCADE')]
private ?Client $client = null;
#[ORM\Column(length: 255, nullable: true)]

View File

@ -33,6 +33,7 @@ final class OgLiveFactory extends ModelFactory
protected function getDefaults(): array
{
return [
'name' => self::faker()->text(255),
'createdAt' => self::faker()->dateTime(),
'filename' => self::faker()->text(255),
'status' => OgLiveStatus::ACTIVE,

View File

@ -18,6 +18,8 @@ final class CommandTypes
public const string LOGOUT = 'logout';
public const string PARTITION_AND_FORMAT = 'partition-and-format';
public const string INSTALL_OGLIVE = 'install-oglive';
private const array COMMAND_TYPES = [
self::DEPLOY_IMAGE => 'Deploy Image',
self::RESTORE_IMAGE => 'Update Cache',
@ -31,6 +33,8 @@ final class CommandTypes
self::LOGIN => 'Login',
self::LOGOUT => 'Logout',
self::PARTITION_AND_FORMAT => 'Partition and Format',
self::TRANSFER_IMAGE => 'Transfer Image',
self::INSTALL_OGLIVE => 'Instalar OgLive',
];
public static function getCommandTypes(): array

View File

@ -15,7 +15,7 @@ readonly class CreateService
{
}
public function __invoke(Client $client, ?string $command, string $status, ?string $jobId = '', ?array $input = []): Trace
public function __invoke(?Client $client = null, ?string $command, string $status, ?string $jobId = '', ?array $input = []): Trace
{
$trace = new Trace();
$trace->setClient($client);

View File

@ -0,0 +1,15 @@
<?php
namespace App\Service\Utils;
class ExtractOgLiveFilenameDateService
{
public function __invoke(string $filename): ?string
{
if (preg_match('/_(\d{8})$/', $filename, $matches)) {
return $matches[1];
}
return null;
}
}

View File

@ -0,0 +1,15 @@
<?php
namespace App\Service\Utils;
class SymflipyOgLiveFilenameService
{
public function __invoke(string $filename): string
{
if (preg_match('/^(.+)-r\d+\.[a-f0-9]+_(\d{8})(?:\.iso)?$/', $filename, $matches)) {
return "{$matches[1]}-{$matches[2]}";
}
return $filename;
}
}