refs #1975. Integration ogGit. Create table and init API
testing/ogcore-api/pipeline/head There was a failure building this commit Details

pull/30/head
Manuel Aranda Rosales 2025-05-08 17:02:27 +02:00
parent 6df1057b20
commit 43f81a833e
19 changed files with 678 additions and 6 deletions

View File

@ -0,0 +1,41 @@
resources:
App\Entity\GitImageRepository:
processor: App\State\Processor\GitImageRepositoryProcessor
input: App\Dto\Input\GitImageRepositoryInput
output: App\Dto\Output\GitImageRepositoryOutput
normalizationContext:
groups: ['default', 'git-image-repository:read']
denormalizationContext:
groups: ['git-image-repository:write']
operations:
ApiPlatform\Metadata\GetCollection:
provider: App\State\Provider\GitImageRepositoryProvider
filters:
- 'api_platform.filter.image_image_repository.order'
- 'api_platform.filter.image_image_repository.search'
ApiPlatform\Metadata\Get:
provider: App\State\Provider\GitImageRepositoryProvider
ApiPlatform\Metadata\Put:
provider: App\State\Provider\GitImageRepositoryProvider
ApiPlatform\Metadata\Patch:
provider: App\State\Provider\GitImageRepositoryProvider
ApiPlatform\Metadata\Post: ~
ApiPlatform\Metadata\Delete: ~
get_image_ogrepository:
shortName: OgRepository Server
description: Get image in OgRepository
class: ApiPlatform\Metadata\Get
method: GET
input: false
uriTemplate: /image-image-repositories/server/{uuid}/get
controller: App\Controller\OgRepository\Image\GetAction
properties:
App\Entity\GitImageRepository:
id:
identifier: false
uuid:
identifier: true

View File

@ -30,7 +30,7 @@ resources:
method: POST
input: false
uriTemplate: /image-repositories/server/{uuid}/sync
controller: App\Controller\OgRepository\SyncAction
controller: App\Controller\OgRepository\Image\SyncAction
wol_client:
class: ApiPlatform\Metadata\Post
@ -46,7 +46,7 @@ resources:
method: POST
input: false
uriTemplate: /image-repositories/server/{uuid}/get-collection
controller: App\Controller\OgRepository\GetCollectionAction
controller: App\Controller\OgRepository\Image\GetCollectionAction
images_ogrepository_status:
shortName: OgRepository Server
@ -75,6 +75,23 @@ resources:
uriTemplate: /image-repositories/{uuid}/convert-image
controller: App\Controller\OgRepository\Image\ConvertAction
get_collection_images_oggit:
shortName: OgRepository Server
description: Get collection of image in OgRepository
class: ApiPlatform\Metadata\Post
method: POST
input: false
uriTemplate: /image-repositories/server/git/{uuid}/get-collection
controller: App\Controller\OgRepository\Git\GetCollectionAction
git_image_ogrepository_sync:
shortName: OgRepository Server
class: ApiPlatform\Metadata\Post
method: POST
input: false
uriTemplate: /image-repositories/server/git/{uuid}/sync
controller: App\Controller\OgRepository\Git\SyncAction
properties:
App\Entity\ImageRepository:
id:

View File

@ -0,0 +1,33 @@
<?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 Version20250430135412 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('CREATE TABLE git_image_repository (id INT AUTO_INCREMENT NOT NULL, image_id INT NOT NULL, uuid CHAR(36) NOT NULL COMMENT \'(DC2Type:uuid)\', migration_id VARCHAR(255) DEFAULT NULL, created_at DATETIME NOT NULL, updated_at DATETIME NOT NULL, created_by VARCHAR(255) DEFAULT NULL, updated_by VARCHAR(255) DEFAULT NULL, status VARCHAR(255) NOT NULL, branch VARCHAR(255) NOT NULL, created TINYINT(1) NOT NULL, UNIQUE INDEX UNIQ_E6944D5ED17F50A6 (uuid), INDEX IDX_E6944D5E3DA5256D (image_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB');
$this->addSql('ALTER TABLE git_image_repository ADD CONSTRAINT FK_E6944D5E3DA5256D FOREIGN KEY (image_id) REFERENCES image (id)');
}
public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE git_image_repository DROP FOREIGN KEY FK_E6944D5E3DA5256D');
$this->addSql('DROP TABLE git_image_repository');
}
}

View File

@ -0,0 +1,35 @@
<?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 Version20250430140218 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 git_image_repository ADD image_repository_id INT DEFAULT NULL');
$this->addSql('ALTER TABLE git_image_repository ADD CONSTRAINT FK_E6944D5E14C736FC FOREIGN KEY (image_repository_id) REFERENCES image_repository (id)');
$this->addSql('CREATE INDEX IDX_E6944D5E14C736FC ON git_image_repository (image_repository_id)');
}
public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE git_image_repository DROP FOREIGN KEY FK_E6944D5E14C736FC');
$this->addSql('DROP INDEX IDX_E6944D5E14C736FC ON git_image_repository');
$this->addSql('ALTER TABLE git_image_repository DROP image_repository_id');
}
}

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 Version20250430140326 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 git_image_repository 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 git_image_repository DROP name');
}
}

View File

@ -0,0 +1,33 @@
<?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 Version20250508134732 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 `partition` DROP FOREIGN KEY FK_9EB910E43DA5256D');
$this->addSql('ALTER TABLE `partition` ADD CONSTRAINT FK_9EB910E43DA5256D FOREIGN KEY (image_id) REFERENCES image_image_repository (id)');
}
public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE `partition` DROP FOREIGN KEY FK_9EB910E43DA5256D');
$this->addSql('ALTER TABLE `partition` ADD CONSTRAINT FK_9EB910E43DA5256D FOREIGN KEY (image_id) REFERENCES image (id)');
}
}

View File

@ -0,0 +1,31 @@
<?php
namespace App\Controller\OgRepository\Git;
use App\Controller\OgRepository\AbstractOgRepositoryController;
use App\Entity\ImageRepository;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Attribute\AsController;
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 GetCollectionAction extends AbstractOgRepositoryController
{
/**
* @throws TransportExceptionInterface
* @throws ServerExceptionInterface
* @throws RedirectionExceptionInterface
* @throws ClientExceptionInterface
*/
public function __invoke(ImageRepository $data): JsonResponse
{
$content = $this->createRequest('GET', 'http://'.$data->getIp().':8006/ogrepository/v1/git/repositories');
return new JsonResponse(data: $content, status: Response::HTTP_OK);
}
}

View File

@ -0,0 +1,73 @@
<?php
namespace App\Controller\OgRepository\Git;
use App\Controller\OgRepository\AbstractOgRepositoryController;
use App\Entity\GitImageRepository;
use App\Entity\Image;
use App\Entity\ImageImageRepository;
use App\Entity\ImageRepository;
use App\Model\ImageStatus;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
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 SyncAction extends AbstractOgRepositoryController
{
/**
* @throws TransportExceptionInterface
* @throws ServerExceptionInterface
* @throws RedirectionExceptionInterface
* @throws ClientExceptionInterface
*/
public function __invoke(ImageRepository $input): JsonResponse
{
$content = $this->createRequest('GET', 'http://' . $input->getIp() . ':8006/ogrepository/v1/git/repositories');
if (!isset($content['repositories'])) {
return new JsonResponse(data: 'No repositories found', status: Response::HTTP_NOT_FOUND);
}
$repository = $this->entityManager->getRepository(GitImageRepository::class);
$existingRepositories = $repository->findBy(['imageRepository' => $input]);
foreach ($content['repositories'] as $repositoryData) {
$gitImageRepositoryEntity = $repository->findOneBy([
'imageRepository' => $input,
'name' => $repositoryData
]);
$imageEntity = $this->entityManager->getRepository(Image::class)->findOneBy(['name' => $repositoryData]);
if (!$imageEntity) {
$imageEntity = new Image();
$imageEntity->setName($repositoryData);
$imageEntity->setRemotePc(false);
$imageEntity->setIsGlobal(false);
$this->entityManager->persist($imageEntity);
}
if (!$gitImageRepositoryEntity) {
$gitImageRepositoryEntity = new GitImageRepository();
$gitImageRepositoryEntity->setName($repositoryData);
$gitImageRepositoryEntity->setStatus(ImageStatus::SUCCESS);
$gitImageRepositoryEntity->setImageRepository($input);
$gitImageRepositoryEntity->setImage($imageEntity);
$gitImageRepositoryEntity->setBranch('main');
$gitImageRepositoryEntity->setCreated(true);
$gitImageRepositoryEntity->setCreatedAt(new \DateTime());
$this->entityManager->persist($gitImageRepositoryEntity);
}
}
$this->entityManager->flush();
return new JsonResponse(data: $content, status: Response::HTTP_OK);
}
}

View File

@ -48,6 +48,10 @@ class ConvertImageToVirtualAction extends AbstractOgRepositoryController
$content = $this->createRequest('PUT', 'http://'.$repository->getIp().':8006/ogrepository/v1/images/virtual', $params);
if (isset($content['error']) && $content['code'] === Response::HTTP_INTERNAL_SERVER_ERROR ) {
throw new ValidatorException('Error converting image');
}
$inputData = [
'imageName' => $image->getName(),
'repositoryUuid' => $repository->getUuid(),

View File

@ -1,7 +1,8 @@
<?php
namespace App\Controller\OgRepository;
namespace App\Controller\OgRepository\Image;
use App\Controller\OgRepository\AbstractOgRepositoryController;
use App\Entity\ImageRepository;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
@ -10,7 +11,6 @@ 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;
#[AsController]
class GetCollectionAction extends AbstractOgRepositoryController

View File

@ -1,7 +1,8 @@
<?php
namespace App\Controller\OgRepository;
namespace App\Controller\OgRepository\Image;
use App\Controller\OgRepository\AbstractOgRepositoryController;
use App\Entity\Image;
use App\Entity\ImageImageRepository;
use App\Entity\ImageRepository;

View File

@ -89,9 +89,12 @@ class ResponseController extends AbstractOgRepositoryController
return $this->jsonResponseError('Action failed', Response::HTTP_BAD_REQUEST, $trace);
}
$latestImageRepo = $this->entityManager->getRepository(ImageImageRepository::class)->findLatestVersionByImageAndRepository($image, $repository);
$newImageRepo = new ImageImageRepository();
$newImageRepo->setName($image->getName().'_v'.($originImageImageRepository->getVersion() + 1));
$newImageRepo->setName($image->getName().'_v'.($latestImageRepo ? $latestImageRepo->getVersion() + 1 : 1));
$newImageRepo->setImage($image);
$newImageRepo->setVersion($latestImageRepo ? $latestImageRepo->getVersion() + 1 : 1);
$newImageRepo->setRepository($repository);
$newImageRepo->setStatus(ImageStatus::SUCCESS);

View File

@ -0,0 +1,33 @@
<?php
namespace App\Dto\Input;
use App\Entity\GitImageRepository;
use App\Entity\ImageImageRepository;
use Symfony\Component\Serializer\Annotation\Groups;
final class GitImageRepositoryInput
{
#[Groups(['git-image-repository:write'])]
public ?string $name = '';
public function __construct(?GitImageRepository $gitImageRepository = null)
{
if (!$gitImageRepository) {
return;
}
$this->name = $gitImageRepository->getName();
}
public function createOrUpdateEntity(?GitImageRepository $gitImageRepository = null): GitImageRepository
{
if (!$gitImageRepository) {
$gitImageRepository = new GitImageRepository();
}
$gitImageRepository->setName($this->name);
return $gitImageRepository;
}
}

View File

@ -0,0 +1,54 @@
<?php
namespace App\Dto\Output;
use ApiPlatform\Metadata\Get;
use App\Entity\GitImageRepository;
use App\Entity\ImageImageRepository;
use Symfony\Component\Serializer\Annotation\Groups;
#[Get(shortName: 'GitImageRepository')]
final class GitImageRepositoryOutput extends AbstractOutput
{
#[Groups(['git-image-repository:read', 'image:read'])]
public ?ImageOutput $image = null;
#[Groups(['git-image-repository:read', 'image:read'])]
public ?ImageRepositoryOutput $imageRepository = null;
#[Groups(['git-image-repository:read', 'image:read'])]
public string $status = '';
#[Groups(['git-image-repository:read', 'image:read'])]
public string $name = '';
#[Groups(['git-image-repository:read', 'image:read'])]
public string $branch = '';
#[Groups(['git-image-repository:read', 'image:read'])]
public \DateTime $createdAt;
#[Groups(['git-image-repository:read', 'image:read'])]
public ?string $createdBy = null;
public function __construct(GitImageRepository $gitImageRepository, array $context = [])
{
parent::__construct($gitImageRepository);
if (isset($context['groups']) && in_array('git-image-repository:read', $context['groups'])) {
if ($gitImageRepository->getImage()) {
$this->image = new ImageOutput($gitImageRepository->getImage());
}
}
if ($gitImageRepository->getImageRepository()) {
$this->imageRepository = new ImageRepositoryOutput($gitImageRepository->getImageRepository());
}
$this->name = $gitImageRepository->getName();
$this->status = $gitImageRepository->getStatus();
$this->branch = $gitImageRepository->getBranch();
$this->createdAt = $gitImageRepository->getCreatedAt();
$this->createdBy = $gitImageRepository->getCreatedBy();
}
}

View File

@ -0,0 +1,89 @@
<?php
namespace App\Entity;
use App\Repository\GitImageRepositoryRepository;
use Doctrine\ORM\Mapping as ORM;
#[ORM\Entity(repositoryClass: GitImageRepositoryRepository::class)]
class GitImageRepository extends AbstractEntity
{
use NameableTrait;
#[ORM\ManyToOne(inversedBy: 'gitImageRepositories')]
#[ORM\JoinColumn(nullable: false)]
private ?Image $image = null;
#[ORM\ManyToOne(inversedBy: 'gitImageRepositories')]
private ?ImageRepository $imageRepository = null;
#[ORM\Column(length: 255)]
private ?string $status = null;
#[ORM\Column(length: 255)]
private ?string $branch = null;
#[ORM\Column]
private ?bool $created = null;
public function getImage(): ?Image
{
return $this->image;
}
public function setImage(?Image $image): static
{
$this->image = $image;
return $this;
}
public function getStatus(): ?string
{
return $this->status;
}
public function setStatus(string $status): static
{
$this->status = $status;
return $this;
}
public function getBranch(): ?string
{
return $this->branch;
}
public function setBranch(string $branch): static
{
$this->branch = $branch;
return $this;
}
public function isCreated(): ?bool
{
return $this->created;
}
public function setCreated(bool $created): static
{
$this->created = $created;
return $this;
}
public function getImageRepository(): ?ImageRepository
{
return $this->imageRepository;
}
public function setImageRepository(?ImageRepository $imageRepository): static
{
$this->imageRepository = $imageRepository;
return $this;
}
}

View File

@ -32,10 +32,17 @@ class ImageRepository extends AbstractEntity
#[ORM\Column(length: 255, nullable: true)]
private ?string $sshPort = null;
/**
* @var Collection<int, GitImageRepository>
*/
#[ORM\OneToMany(mappedBy: 'imageRepository', targetEntity: GitImageRepository::class)]
private Collection $gitImageRepositories;
public function __construct()
{
parent::__construct();
$this->imageImageRepositories = new ArrayCollection();
$this->gitImageRepositories = new ArrayCollection();
}
public function getIp(): ?string
@ -115,4 +122,34 @@ class ImageRepository extends AbstractEntity
return $this;
}
/**
* @return Collection<int, GitImageRepository>
*/
public function getGitImageRepositories(): Collection
{
return $this->gitImageRepositories;
}
public function addGitImageRepository(GitImageRepository $gitImageRepository): static
{
if (!$this->gitImageRepositories->contains($gitImageRepository)) {
$this->gitImageRepositories->add($gitImageRepository);
$gitImageRepository->setImageRepository($this);
}
return $this;
}
public function removeGitImageRepository(GitImageRepository $gitImageRepository): static
{
if ($this->gitImageRepositories->removeElement($gitImageRepository)) {
// set the owning side to null (unless already changed)
if ($gitImageRepository->getImageRepository() === $this) {
$gitImageRepository->setImageRepository(null);
}
}
return $this;
}
}

View File

@ -0,0 +1,18 @@
<?php
namespace App\Repository;
use App\Entity\GitImageRepository;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
/**
* @extends ServiceEntityRepository<GitImageRepository>
*/
class GitImageRepositoryRepository extends AbstractRepository
{
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, GitImageRepository::class);
}
}

View File

@ -0,0 +1,68 @@
<?php
namespace App\State\Processor;
use ApiPlatform\Metadata\Delete;
use ApiPlatform\Metadata\Operation;
use ApiPlatform\Metadata\Patch;
use ApiPlatform\Metadata\Post;
use ApiPlatform\Metadata\Put;
use ApiPlatform\State\ProcessorInterface;
use ApiPlatform\Validator\ValidatorInterface;
use App\Dto\Input\GitImageRepositoryInput;
use App\Dto\Output\GitImageRepositoryOutput;
use App\Repository\GitImageRepositoryRepository;
readonly class GitImageRepositoryProcessor implements ProcessorInterface
{
public function __construct(
private GitImageRepositoryRepository $imageRepository,
private ValidatorInterface $validator,
)
{
}
/**
* @throws \Exception
*/
public function process(mixed $data, Operation $operation, array $uriVariables = [], array $context = []): GitImageRepositoryOutput|null
{
switch ($operation){
case $operation instanceof Post:
case $operation instanceof Put:
case $operation instanceof Patch:
return $this->processCreateOrUpdate($data, $operation, $uriVariables, $context);
case $operation instanceof Delete:
return $this->processDelete($data, $operation, $uriVariables, $context);
}
}
/**
* @throws \Exception
*/
private function processCreateOrUpdate($data, Operation $operation, array $uriVariables = [], array $context = []): GitImageRepositoryOutput
{
if (!($data instanceof GitImageRepositoryInput)) {
throw new \Exception(sprintf('data is not instance of %s', GitImageRepositoryInput::class));
}
$entity = null;
if (isset($uriVariables['uuid'])) {
$entity = $this->imageRepository->findOneByUuid($uriVariables['uuid']);
}
$image = $data->createOrUpdateEntity($entity);
$this->validator->validate($image);
$this->imageRepository->save($image);
return new GitImageRepositoryOutput($image);
}
private function processDelete($data, Operation $operation, array $uriVariables = [], array $context = []): null
{
$user = $this->imageRepository->findOneByUuid($uriVariables['uuid']);
$this->imageRepository->delete($user);
return null;
}
}

View File

@ -0,0 +1,71 @@
<?php
namespace App\State\Provider;
use ApiPlatform\Metadata\Get;
use ApiPlatform\Metadata\GetCollection;
use ApiPlatform\Metadata\Operation;
use ApiPlatform\Metadata\Patch;
use ApiPlatform\Metadata\Put;
use ApiPlatform\State\Pagination\TraversablePaginator;
use ApiPlatform\State\ProviderInterface;
use App\Dto\Input\GitImageRepositoryInput;
use App\Dto\Output\GitImageRepositoryOutput;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
readonly class GitImageRepositoryProvider implements ProviderInterface
{
public function __construct(
private ProviderInterface $collectionProvider,
private ProviderInterface $itemProvider
)
{
}
public function provide(Operation $operation, array $uriVariables = [], array $context = []): object|array|null
{
switch ($operation){
case $operation instanceof GetCollection:
return $this->provideCollection($operation, $uriVariables, $context);
case $operation instanceof Patch:
case $operation instanceof Put:
return $this->provideInput($operation, $uriVariables, $context);
case $operation instanceof Get:
return $this->provideItem($operation, $uriVariables, $context);
}
}
private function provideCollection(Operation $operation, array $uriVariables = [], array $context = []): object
{
$paginator = $this->collectionProvider->provide($operation, $uriVariables, $context);
$items = new \ArrayObject();
foreach ($paginator->getIterator() as $item){
$items[] = new GitImageRepositoryOutput($item, $context);
}
return new TraversablePaginator($items, $paginator->getCurrentPage(), $paginator->getItemsPerPage(), $paginator->getTotalItems());
}
public function provideItem(Operation $operation, array $uriVariables = [], array $context = []): object|array|null
{
$item = $this->itemProvider->provide($operation, $uriVariables, $context);
if (!$item) {
throw new NotFoundHttpException('ImageImageRepository not found');
}
return new GitImageRepositoryOutput($item);
}
public function provideInput(Operation $operation, array $uriVariables = [], array $context = []): object|array|null
{
if (isset($uriVariables['uuid'])) {
$item = $this->itemProvider->provide($operation, $uriVariables, $context);
return $item !== null ? new GitImageRepositoryInput($item) : null;
}
return new GitImageRepositoryInput();
}
}