Compare commits

...

34 Commits

Author SHA1 Message Date
Manuel Aranda Rosales 9089224522 refs #1523. Hierarchy networkSettings.
testing/ogcore-api/pipeline/tag This commit looks good Details
testing/ogcore-api/pipeline/head This commit looks good Details
2025-02-17 14:43:15 +01:00
Manuel Aranda Rosales 546546bb42 refs #1523. Hierarchy networkSettings
testing/ogcore-api/pipeline/head This commit looks good Details
2025-02-17 13:11:49 +01:00
Manuel Aranda Rosales ca3e547b56 Some improvements. Added new filters
testing/ogcore-api/pipeline/head There was a failure building this commit Details
2025-02-17 09:13:48 +01:00
Manuel Aranda Rosales 4fd3a78c0a refs #1523. Hierarchy networkSettings
testing/ogcore-api/pipeline/head There was a failure building this commit Details
2025-02-14 12:43:30 +01:00
Manuel Aranda Rosales ce61d3cfc2 refs #1516. Changed form and global import
testing/ogcore-api/pipeline/head This commit looks good Details
2025-02-14 12:41:28 +01:00
Manuel Aranda Rosales 083aa9db7e FIxed client/trace constraint onDelete
testing/ogcore-api/pipeline/head There was a failure building this commit Details
2025-02-14 09:38:54 +01:00
Manuel Aranda Rosales 64e721cd09 Fixed test
testing/ogcore-api/pipeline/head This commit looks good Details
2025-02-14 07:59:51 +01:00
Manuel Aranda Rosales 626dc276a8 Added loaded trace command
testing/ogcore-api/pipeline/head There was a failure building this commit Details
2025-02-14 07:46:01 +01:00
Manuel Aranda Rosales b98d6d2be8 Added loaded trace command
testing/ogcore-api/pipeline/head There was a failure building this commit Details
2025-02-14 07:42:29 +01:00
Manuel Aranda Rosales de165935e0 refs #1516. Changed form and global import
testing/ogcore-api/pipeline/head This commit looks good Details
2025-02-13 17:31:26 +01:00
Manuel Aranda Rosales 6772c9d191 refs #1516. Changed form and global import
testing/ogcore-api/pipeline/head This commit looks good Details
2025-02-13 16:48:53 +01:00
Manuel Aranda Rosales 60f6348eca refs #1516. Changed form and global import
testing/ogcore-api/pipeline/head This commit looks good Details
2025-02-13 16:47:10 +01:00
Manuel Aranda Rosales e9b982ffe4 refs #1516. Changed form and global import
testing/ogcore-api/pipeline/head This commit looks good Details
2025-02-13 16:39:56 +01:00
Manuel Aranda Rosales 947817daae refs #1516. Changed form and global import
testing/ogcore-api/pipeline/head This commit looks good Details
2025-02-13 16:22:56 +01:00
Manuel Aranda Rosales b2f5c3802a refs #1516. Changed form and global import
testing/ogcore-api/pipeline/head This commit looks good Details
2025-02-13 16:00:30 +01:00
Manuel Aranda Rosales b94e6e2cf2 refs #1516. Changed form and global import
testing/ogcore-api/pipeline/head This commit looks good Details
2025-02-13 15:57:42 +01:00
Manuel Aranda Rosales d61be99b84 refs #1516. Changed form and global import
testing/ogcore-api/pipeline/head This commit looks good Details
2025-02-13 15:42:18 +01:00
Manuel Aranda Rosales 7ede1a646a refs #1472. Changes in images and imageRepo
testing/ogcore-api/pipeline/head This commit looks good Details
2025-02-13 08:38:22 +01:00
Manuel Aranda Rosales 3ed65f0668 refs #1472. Changes in images and imageRepo
testing/ogcore-api/pipeline/head This commit looks good Details
2025-02-13 08:36:26 +01:00
Manuel Aranda Rosales a448fb071d refs #1472. Changes in images and imageRepo
testing/ogcore-api/pipeline/head This commit looks good Details
2025-02-13 07:59:38 +01:00
Manuel Aranda Rosales acf772f139 refs #1472. Changes in images and imageRepo
testing/ogcore-api/pipeline/head This commit looks good Details
2025-02-13 07:45:57 +01:00
Manuel Aranda Rosales c381b32d09 refs #1472. Changes in images and imageRepo
testing/ogcore-api/pipeline/head This commit looks good Details
2025-02-12 19:20:18 +01:00
Manuel Aranda Rosales ed614c4ac4 refs #1472. Changes in images and imageRepo
testing/ogcore-api/pipeline/head This commit looks good Details
2025-02-12 19:10:29 +01:00
Manuel Aranda Rosales dde936be67 refs #1472. Changes in images and imageRepo
testing/ogcore-api/pipeline/head This commit looks good Details
2025-02-12 19:03:42 +01:00
Manuel Aranda Rosales 7ff5c87884 refs #1472. Changes in images and imageRepo
testing/ogcore-api/pipeline/head This commit looks good Details
2025-02-12 17:14:39 +01:00
Manuel Aranda Rosales 28914fd7de refs #1472. Changes in images and imageRepo
testing/ogcore-api/pipeline/head This commit looks good Details
2025-02-10 13:59:37 +01:00
Manuel Aranda Rosales dc68c8eb43 Testing new ogRepo import data
testing/ogcore-api/pipeline/head This commit looks good Details
2025-02-10 10:30:54 +01:00
Manuel Aranda Rosales 31657113a8 Testing new ogRepo import data
testing/ogcore-api/pipeline/head This commit looks good Details
2025-02-10 10:16:02 +01:00
Manuel Aranda Rosales 3bde0333d7 Testing new ogRepo import data
testing/ogcore-api/pipeline/head This commit looks good Details
2025-02-10 10:06:18 +01:00
Manuel Aranda Rosales 81bb1c5268 refs #1480. Fixed test
testing/ogcore-api/pipeline/head This commit looks good Details
2025-02-10 08:15:20 +01:00
Manuel Aranda Rosales d5c75f6c45 refs #1473. Changes in ogRepo. Import
testing/ogcore-api/pipeline/head This commit looks good Details
2025-02-07 11:58:28 +01:00
Manuel Aranda Rosales 95b85ccca1 refs #1471. Changed relationship image-imageRepositories
testing/ogcore-api/pipeline/head This commit looks good Details
2025-02-06 18:27:50 +01:00
Manuel Aranda Rosales 10a89da948 Merge branch 'main' into develop 2025-02-06 14:50:40 +01:00
Manuel Aranda Rosales 935240809e Added CHANGELOG 2025-02-06 14:50:22 +01:00
91 changed files with 1958 additions and 503 deletions

View File

@ -0,0 +1,23 @@
# Changelog
## [0.7.3] - 2025-01-03
### 🔹 Added
- Adaptados cambios en los endpoints para multiseleccion de clientes.
- Se agregó la funcionalidad de importar/exportar. Integración con ogRepository.
- Se agregó la funcionalidad de borrar imágenes. Integración con ogRepository.
- Se agregó el modo "TORRENT" y "UDPCAST" en el despliegue de imágenes.
### 🛠️ Fixed
### ⚡ Changed
- Refactorización del webhook de ogRepository.
### 🛑 Removed
---
## Formato de cambios:
- **Added**: Secciones con nuevas características.
- **Fixed**: Corrección de errores y bugs.
- **Changed**: Modificaciones o mejoras en funcionalidades existentes.
- **Removed**: Funcionalidades o dependencias eliminadas.

View File

@ -7,6 +7,8 @@ resources:
groups: ['default', 'image:read']
denormalizationContext:
groups: ['image:write']
order:
id: 'DESC'
operations:
ApiPlatform\Metadata\GetCollection:
provider: App\State\Provider\ImageProvider
@ -14,6 +16,8 @@ resources:
- 'api_platform.filter.image.order'
- 'api_platform.filter.image.search'
- 'api_platform.filter.image.boolean'
- 'image.repository_filter'
ApiPlatform\Metadata\Get:
provider: App\State\Provider\ImageProvider
ApiPlatform\Metadata\Put:
@ -23,58 +27,6 @@ resources:
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: /images/server/{uuid}/get
controller: App\Controller\OgRepository\Image\GetAction
create_aux_files_image_ogrepository:
shortName: OgRepository Server
class: ApiPlatform\Metadata\Post
method: POST
input: false
uriTemplate: /images/server/{uuid}/create-aux-files
controller: App\Controller\OgRepository\Image\CreateAuxFilesAction
deploy_image_ogrepository:
shortName: OgRepository Server
class: ApiPlatform\Metadata\Post
method: POST
input: App\Dto\Input\DeployImageInput
uriTemplate: /images/{uuid}/deploy-image
controller: App\Controller\DeployImageAction
trash_delete_image_ogrepository:
shortName: OgRepository Server
description: Delete Image in OgRepository
class: ApiPlatform\Metadata\Post
method: POST
input: false
uriTemplate: /images/server/{uuid}/delete-trash
controller: App\Controller\OgRepository\Image\DeleteTrashAction
permanent_delete_image_ogrepository:
shortName: OgRepository Server
description: Delete Image in OgRepository
class: ApiPlatform\Metadata\Post
method: POST
input: false
uriTemplate: /images/server/{uuid}/delete-permanent
controller: App\Controller\OgRepository\Image\DeletePermanentAction
recover_image_ogrepository:
shortName: OgRepository Server
description: Recover Image in OgRepository
class: ApiPlatform\Metadata\Post
method: POST
input: false
uriTemplate: /images/server/{uuid}/recover
controller: App\Controller\OgRepository\Image\RecoverAction
properties:
App\Entity\Image:
id:

View File

@ -0,0 +1,92 @@
resources:
App\Entity\ImageImageRepository:
processor: App\State\Processor\ImageImageRepositoryProcessor
input: App\Dto\Input\ImageImageRepositoryInput
output: App\Dto\Output\ImageImageRepositoryOutput
normalizationContext:
groups: ['default', 'image-image-repository:read']
denormalizationContext:
groups: ['image-image-repository:write']
operations:
ApiPlatform\Metadata\GetCollection:
provider: App\State\Provider\ImageImageRepositoryProvider
filters:
- 'api_platform.filter.image_image_repository.order'
- 'api_platform.filter.image_image_repository.search'
ApiPlatform\Metadata\Get:
provider: App\State\Provider\ImageImageRepositoryProvider
ApiPlatform\Metadata\Put:
provider: App\State\Provider\ImageImageRepositoryProvider
ApiPlatform\Metadata\Patch:
provider: App\State\Provider\ImageImageRepositoryProvider
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
create_aux_files_image_ogrepository:
shortName: OgRepository Server
class: ApiPlatform\Metadata\Post
method: POST
input: false
uriTemplate: /image-image-repositories/server/{uuid}/create-aux-files
controller: App\Controller\OgRepository\Image\CreateAuxFilesAction
deploy_image_ogrepository:
shortName: OgRepository Server
class: ApiPlatform\Metadata\Post
method: POST
input: App\Dto\Input\DeployImageInput
uriTemplate: /image-image-repositories/{uuid}/deploy-image
controller: App\Controller\DeployImageAction
trash_delete_image_ogrepository:
shortName: OgRepository Server
description: Delete Image in OgRepository
class: ApiPlatform\Metadata\Post
method: POST
input: false
uriTemplate: /image-image-repositories/server/{uuid}/delete-trash
controller: App\Controller\OgRepository\Image\DeleteTrashAction
permanent_delete_image_ogrepository:
shortName: OgRepository Server
description: Delete Image in OgRepository
class: ApiPlatform\Metadata\Post
method: POST
input: false
uriTemplate: /image-image-repositories/server/{uuid}/delete-permanent
controller: App\Controller\OgRepository\Image\DeletePermanentAction
recover_image_ogrepository:
shortName: OgRepository Server
description: Recover Image in OgRepository
class: ApiPlatform\Metadata\Post
method: POST
input: false
uriTemplate: /image-image-repositories/server/{uuid}/recover
controller: App\Controller\OgRepository\Image\RecoverAction
transfer_image_ogrepository:
shortName: OgRepository Server
description: Export Image in OgRepository
class: ApiPlatform\Metadata\Post
method: POST
input: App\Dto\Input\ExportImportImageRepositoryInput
uriTemplate: /image-image-repositories/{uuid}/transfer-image
controller: App\Controller\OgRepository\Image\TransferAction
properties:
App\Entity\ImageImageRepository:
id:
identifier: false
uuid:
identifier: true

View File

@ -13,6 +13,8 @@ resources:
filters:
- 'api_platform.filter.repository.order'
- 'api_platform.filter.repository.search'
- 'repository.not_equal_filter'
ApiPlatform\Metadata\Get:
provider: App\State\Provider\ImageRepositoryProvider
ApiPlatform\Metadata\Put:
@ -24,10 +26,10 @@ resources:
image_ogrepository_sync:
shortName: OgRepository Server
class: ApiPlatform\Metadata\Get
method: GET
class: ApiPlatform\Metadata\Post
method: POST
input: false
uriTemplate: /image-repositories/server/sync
uriTemplate: /image-repositories/server/{uuid}/sync
controller: App\Controller\OgRepository\SyncAction
wol_client:
@ -40,10 +42,10 @@ resources:
get_collection_images_ogrepository:
shortName: OgRepository Server
description: Get collection of image in OgRepository
class: ApiPlatform\Metadata\Get
method: GET
class: ApiPlatform\Metadata\Post
method: POST
input: false
uriTemplate: /image-repositories/server/get-collection
uriTemplate: /image-repositories/server/{uuid}/get-collection
controller: App\Controller\OgRepository\GetCollectionAction
images_ogrepository_status:
@ -64,15 +66,6 @@ resources:
uriTemplate: /image-repositories/{uuid}/export-image
controller: App\Controller\OgRepository\Image\ExportAction
import_image_ogrepository:
shortName: OgRepository Server
description: Export Image in OgRepository
class: ApiPlatform\Metadata\Post
method: POST
input: App\Dto\Input\ExportImportImageRepositoryInput
uriTemplate: /image-repositories/{uuid}/import-image
controller: App\Controller\OgRepository\Image\ImportAction
properties:
App\Entity\ImageRepository:
id:

View File

@ -3,7 +3,7 @@ resources:
processor: App\State\Processor\PartitionProcessor
input: App\Dto\Input\PartitionPostInput
output: App\Dto\Output\PartitionOutput
orderBy:
order:
partitionNumber: 'ASC'
normalizationContext:
groups: ['default', 'partition:read']

View File

@ -2,6 +2,7 @@ lexik_jwt_authentication:
secret_key: '%env(resolve:JWT_SECRET_KEY)%'
public_key: '%env(resolve:JWT_PUBLIC_KEY)%'
pass_phrase: '%env(JWT_PASSPHRASE)%'
token_ttl: 86400 # 1 day
api_platform:
check_path: /auth/login
username_path: username

View File

@ -151,3 +151,8 @@ services:
bind:
$collectionProvider: '@api_platform.doctrine.orm.state.collection_provider'
$itemProvider: '@api_platform.doctrine.orm.state.item_provider'
App\State\Provider\ImageImageRepositoryProvider:
bind:
$collectionProvider: '@api_platform.doctrine.orm.state.collection_provider'
$itemProvider: '@api_platform.doctrine.orm.state.item_provider'

View File

@ -69,6 +69,10 @@ services:
arguments: [ { 'created': ~ } ]
tags: [ 'api_platform.filter' ]
image.repository_filter:
parent: 'App\Filter\ImageSearchRepositoryFilter'
tags: [ 'api_platform.filter' ]
api_platform.filter.og_live.order:
parent: 'api_platform.doctrine.orm.order_filter'
arguments:
@ -187,7 +191,23 @@ services:
api_platform.filter.repository.search:
parent: 'api_platform.doctrine.orm.search_filter'
arguments: [ { 'id': 'exact', 'name': 'partial'} ]
arguments: [ { 'id': 'exact', 'name': 'partial', 'ip': 'partial', 'status': 'exact'} ]
tags: [ 'api_platform.filter' ]
api_platform.filter.image_image_repository.order:
parent: 'api_platform.doctrine.orm.order_filter'
arguments:
$properties: { 'id': ~, 'name': ~ }
$orderParameterName: 'order'
tags: [ 'api_platform.filter' ]
api_platform.filter.image_image_repository.search:
parent: 'api_platform.doctrine.orm.search_filter'
arguments: [ { 'id': 'exact', 'name': 'partial', 'ip': 'partial', 'status': 'exact', 'repository.id': 'exact'} ]
tags: [ 'api_platform.filter' ]
repository.not_equal_filter:
parent: 'App\Filter\NotEqualIdFilter'
tags: [ 'api_platform.filter' ]
api_platform.filter.software.order:

View File

@ -1,12 +1,12 @@
{
"vars": {
"OG_BOOT_API_URL": "192.168.68.60:8082",
"OG_DHCP_API_URL": "192.168.68.60:8081",
"OG_BOOT_API_URL": "192.168.68.51:8082",
"OG_DHCP_API_URL": "192.168.68.51:8081",
"OG_CORE_IP": "192.168.68.62",
"OG_LOG_IP": "192.168.68.61",
"UDS_AUTH_LOGIN": "Usuarios locales",
"UDS_AUTH_USERNAME": "natiqindel",
"UDS_AUTH_PASSWORD": "correct horse battery staple",
"OG_LOG_IP": "192.168.68.51",
"UDS_AUTH_LOGIN": "test",
"UDS_AUTH_USERNAME": "test",
"UDS_AUTH_PASSWORD": "test",
"UDS_URL": "https:\/\/localhost:8087\/uds\/rest\/"
}
}

View File

@ -0,0 +1,41 @@
<?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 Version20250206075246 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 image_image_repository (image_id INT NOT NULL, image_repository_id INT NOT NULL, INDEX IDX_B78513373DA5256D (image_id), INDEX IDX_B785133714C736FC (image_repository_id), PRIMARY KEY(image_id, image_repository_id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB');
$this->addSql('ALTER TABLE image_image_repository ADD CONSTRAINT FK_B78513373DA5256D FOREIGN KEY (image_id) REFERENCES image (id) ON DELETE CASCADE');
$this->addSql('ALTER TABLE image_image_repository ADD CONSTRAINT FK_B785133714C736FC FOREIGN KEY (image_repository_id) REFERENCES image_repository (id) ON DELETE CASCADE');
$this->addSql('ALTER TABLE image DROP FOREIGN KEY FK_C53D045F50C9D4F7');
$this->addSql('DROP INDEX IDX_C53D045F50C9D4F7 ON image');
$this->addSql('ALTER TABLE image DROP repository_id');
}
public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE image_image_repository DROP FOREIGN KEY FK_B78513373DA5256D');
$this->addSql('ALTER TABLE image_image_repository DROP FOREIGN KEY FK_B785133714C736FC');
$this->addSql('DROP TABLE image_image_repository');
$this->addSql('ALTER TABLE image ADD repository_id INT NOT NULL');
$this->addSql('ALTER TABLE image ADD CONSTRAINT FK_C53D045F50C9D4F7 FOREIGN KEY (repository_id) REFERENCES image_repository (id)');
$this->addSql('CREATE INDEX IDX_C53D045F50C9D4F7 ON image (repository_id)');
}
}

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 Version20250211073126 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 image_image_repository DROP FOREIGN KEY FK_B785133714C736FC');
$this->addSql('ALTER TABLE image_image_repository DROP FOREIGN KEY FK_B78513373DA5256D');
$this->addSql('DROP TABLE image_image_repository');
}
public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('CREATE TABLE image_image_repository (image_id INT NOT NULL, image_repository_id INT NOT NULL, INDEX IDX_B78513373DA5256D (image_id), INDEX IDX_B785133714C736FC (image_repository_id), PRIMARY KEY(image_id, image_repository_id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB COMMENT = \'\' ');
$this->addSql('ALTER TABLE image_image_repository ADD CONSTRAINT FK_B785133714C736FC FOREIGN KEY (image_repository_id) REFERENCES image_repository (id) ON DELETE CASCADE');
$this->addSql('ALTER TABLE image_image_repository ADD CONSTRAINT FK_B78513373DA5256D FOREIGN KEY (image_id) REFERENCES image (id) ON DELETE CASCADE');
}
}

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 Version20250211073801 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 image_image_repository (id INT AUTO_INCREMENT NOT NULL, image_id INT DEFAULT NULL, repository_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, UNIQUE INDEX UNIQ_B7851337D17F50A6 (uuid), INDEX IDX_B78513373DA5256D (image_id), INDEX IDX_B785133750C9D4F7 (repository_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB');
$this->addSql('ALTER TABLE image_image_repository ADD CONSTRAINT FK_B78513373DA5256D FOREIGN KEY (image_id) REFERENCES image (id)');
$this->addSql('ALTER TABLE image_image_repository ADD CONSTRAINT FK_B785133750C9D4F7 FOREIGN KEY (repository_id) REFERENCES 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 image_image_repository DROP FOREIGN KEY FK_B78513373DA5256D');
$this->addSql('ALTER TABLE image_image_repository DROP FOREIGN KEY FK_B785133750C9D4F7');
$this->addSql('DROP TABLE image_image_repository');
}
}

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 Version20250211081319 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 image_image_repository DROP FOREIGN KEY FK_B785133750C9D4F7');
$this->addSql('ALTER TABLE image_image_repository ADD CONSTRAINT FK_B785133750C9D4F7 FOREIGN KEY (repository_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 image_image_repository DROP FOREIGN KEY FK_B785133750C9D4F7');
$this->addSql('ALTER TABLE image_image_repository ADD CONSTRAINT FK_B785133750C9D4F7 FOREIGN KEY (repository_id) REFERENCES image_repository (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 Version20250211081406 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 image_image_repository DROP FOREIGN KEY FK_B785133750C9D4F7');
$this->addSql('ALTER TABLE image_image_repository ADD CONSTRAINT FK_B785133750C9D4F7 FOREIGN KEY (repository_id) REFERENCES 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 image_image_repository DROP FOREIGN KEY FK_B785133750C9D4F7');
$this->addSql('ALTER TABLE image_image_repository ADD CONSTRAINT FK_B785133750C9D4F7 FOREIGN KEY (repository_id) REFERENCES image_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 Version20250211103630 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 UNIQUE INDEX UNIQ_IDENTIFIER_IMAGE_REPOSITORY ON image_image_repository (image_id, repository_id)');
}
public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('DROP INDEX UNIQ_IDENTIFIER_IMAGE_REPOSITORY ON image_image_repository');
}
}

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 Version20250211105319 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 image_image_repository CHANGE image_id image_id INT NOT NULL');
}
public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE image_image_repository CHANGE image_id image_id INT DEFAULT 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 Version20250211162339 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 image DROP path, DROP type, DROP revision, DROP info, DROP size, DROP status');
}
public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE image ADD path VARCHAR(255) DEFAULT NULL, ADD type VARCHAR(255) DEFAULT NULL, ADD revision VARCHAR(255) DEFAULT NULL, ADD info VARCHAR(255) DEFAULT NULL, ADD size INT DEFAULT NULL, ADD status VARCHAR(255) NOT NULL');
}
}

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 Version20250211164155 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 image DROP created, DROP image_fullsum');
$this->addSql('ALTER TABLE image_image_repository ADD created TINYINT(1) DEFAULT NULL, ADD image_fullsum VARCHAR(255) DEFAULT NULL');
}
public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE image_image_repository DROP created, DROP image_fullsum');
$this->addSql('ALTER TABLE image ADD created TINYINT(1) DEFAULT NULL, ADD image_fullsum VARCHAR(255) DEFAULT NULL');
}
}

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 Version20250214083512 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 DROP FOREIGN KEY FK_315BD5A119EB6921');
$this->addSql('ALTER TABLE trace ADD CONSTRAINT FK_315BD5A119EB6921 FOREIGN KEY (client_id) REFERENCES client (id) ON DELETE CASCADE');
}
public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE trace DROP FOREIGN KEY FK_315BD5A119EB6921');
$this->addSql('ALTER TABLE trace ADD CONSTRAINT FK_315BD5A119EB6921 FOREIGN KEY (client_id) REFERENCES client (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 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

@ -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 Version20250217095913 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 organizational_unit ADD exclude_parent_changes TINYINT(1) DEFAULT NULL');
}
public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE organizational_unit DROP exclude_parent_changes');
}
}

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 Version20250217115241 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 ADD progress 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 DROP progress');
}
}

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 Version20250217120940 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 network_settings DROP validation, DROP og_log');
}
public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE network_settings ADD validation TINYINT(1) DEFAULT NULL, ADD og_log VARCHAR(255) DEFAULT NULL');
}
}

View File

@ -0,0 +1,49 @@
<?php
namespace App\Command;
use App\Entity\Client;
use App\Entity\Trace;
use App\Model\CommandTypes;
use App\Model\TraceStatus;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
#[AsCommand(name: 'opengnsys:load-traces', description: 'Load traces')]
class ChargeExampleTraceCommand extends Command
{
public function __construct(
private readonly EntityManagerInterface $entityManager
)
{
parent::__construct();
}
protected function execute(InputInterface $input, OutputInterface $output): int
{
$clients = $this->entityManager->getRepository(Client::class)->findAll();
$traces = TraceStatus::getStatusKeys();
foreach ($clients as $client) {
foreach ($traces as $traceStatus) {
$trace = new Trace();
$trace->setClient($client);
$trace->setJobId('CreateAuxiliarFiles_' . $client->getId());
$trace->setStatus($traceStatus);
$trace->setCommand(CommandTypes::CREATE_IMAGE_AUX_FILE);
$trace->setExecutedAt(new \DateTime());
$this->entityManager->persist($trace);
}
}
$this->entityManager->flush();
return 1;
}
}

View File

@ -8,6 +8,7 @@ use ApiPlatform\Validator\ValidatorInterface;
use App\Dto\Input\DeployImageInput;
use App\Entity\Command;
use App\Entity\Image;
use App\Entity\ImageImageRepository;
use App\Entity\OrganizationalUnit;
use App\Entity\Partition;
use App\Model\CommandTypes;
@ -42,7 +43,7 @@ class DeployImageAction extends AbstractController
* @throws ClientExceptionInterface
* @throws ServerExceptionInterface
*/
public function __invoke(DeployImageInput $input, Image $image): JsonResponse
public function __invoke(DeployImageInput $input, ImageImageRepository $image): JsonResponse
{
$this->validator->validate($input);
@ -68,7 +69,6 @@ class DeployImageAction extends AbstractController
case DeployMethodTypes::MULTICAST_UFTP_DIRECT:
case DeployMethodTypes::MULTICAST_UDPCAST:
case DeployMethodTypes::MULTICAST_UDPCAST_DIRECT:
case DeployMethodTypes::MULTICAST:
foreach ($input->clients as $client) {
$inputData = [
'method' => $input->method,

View File

@ -7,6 +7,7 @@ namespace App\Controller\OgAgent;
use App\Entity\Client;
use App\Entity\Command;
use App\Entity\Image;
use App\Entity\ImageImageRepository;
use App\Entity\Trace;
use App\Model\ClientStatus;
use App\Model\CommandTypes;
@ -53,13 +54,22 @@ class CreateImageAction extends AbstractController
$partitionInfo = json_decode($image->getPartitionInfo(), true);
$repository = $image->getClient()->getRepository();
$imageImageRepository = new ImageImageRepository();
$imageImageRepository->setImage($image);
$imageImageRepository->setRepository($repository);
$imageImageRepository->setStatus(ImageStatus::IN_PROGRESS);
$this->entityManager->persist($imageImageRepository);
$data = [
'dsk' => (string) $partitionInfo['numDisk'],
'par' => (string) $partitionInfo['numPartition'],
'cpt' => null,
'idi' => $image->getUuid(),
'idi' => $imageImageRepository->getUuid(),
'nci' => $image->getName(),
'ipr' => $image->getRepository()->getIp(),
'ipr' => $repository->getIp(),
'nfn' => 'CrearImagen',
'ids' => '0'
];
@ -100,9 +110,6 @@ class CreateImageAction extends AbstractController
$jobId = json_decode($response->getContent(), true)['job_id'];
$image->setStatus(ImageStatus::IN_PROGRESS);
$this->entityManager->persist($image);
$client = $image->getClient();
$client->setStatus(ClientStatus::BUSY);
$this->entityManager->persist($client);

View File

@ -8,6 +8,7 @@ use App\Dto\Input\DeployImageInput;
use App\Entity\Client;
use App\Entity\Command;
use App\Entity\Image;
use App\Entity\ImageImageRepository;
use App\Entity\Partition;
use App\Entity\Trace;
use App\Model\ClientStatus;
@ -38,8 +39,10 @@ class DeployImageAction extends AbstractController
{
}
public function __invoke(Image $image, DeployImageInput $input, Client $client, string $method)
public function __invoke(ImageImageRepository $imageImageRepository, DeployImageInput $input, Client $client, string $method)
{
$image = $imageImageRepository->getImage();
if (!$image->getClient()->getIp()) {
throw new ValidatorException('IP is required');
}
@ -69,13 +72,15 @@ class DeployImageAction extends AbstractController
default => throw new ValidatorException('Invalid method'),
};
$repository = $imageImageRepository->getRepository();
$data = [
'dsk' => (string) $input->diskNumber,
'par' => (string) $input->partitionNumber,
'ifs' => "1",
'idi' => $image->getUuid(),
'nci' => $image->getName(),
'ipr' => $image->getRepository()->getIp(),
'ipr' => $repository->getIp(),
'nfn' => 'RestaurarImagen',
'ptc' => $ptcValue,
'ids' => '0'

View File

@ -47,11 +47,16 @@ class StatusAction extends AbstractController
throw new ValidatorException('IP is required');
}
if ($client->getStatus() === ClientStatus::OG_LIVE || $client->getStatus() === ClientStatus::OFF || $client->getStatus() === ClientStatus::BUSY || $client->getStatus() === ClientStatus::INITIALIZING) {
if ($client->getStatus() === ClientStatus::OG_LIVE
|| $client->getStatus() === ClientStatus::OFF
|| $client->getStatus() === ClientStatus::BUSY
|| $client->getStatus() === ClientStatus::INITIALIZING) {
$response = $this->getOgLiveStatus($client);
}
if ($client->getStatus() === ClientStatus::LINUX) {
if ($client->getStatus() === ClientStatus::LINUX
|| $client->getStatus() === ClientStatus::MACOS
|| $client->getStatus() === ClientStatus::WINDOWS) {
$response = $this->getSOStatus($client);
}
@ -112,9 +117,6 @@ class StatusAction extends AbstractController
],
'json' => [],
]);
$statusCode = $response->getStatusCode();
$client->setStatus($statusCode === Response::HTTP_OK ? ClientStatus::LINUX : ClientStatus::OFF);
} catch (TransportExceptionInterface $e) {
$client->setStatus(ClientStatus::OFF);
$this->logger->error('Error checking client status', ['client' => $client->getId(), 'error' => $e->getMessage()]);

View File

@ -4,6 +4,7 @@ namespace App\Controller\OgAgent\Webhook;
use App\Controller\OgRepository\Image\CreateAuxFilesAction;
use App\Entity\Image;
use App\Entity\ImageImageRepository;
use App\Entity\OperativeSystem;
use App\Entity\Partition;
use App\Entity\Software;
@ -65,9 +66,10 @@ class ClientsController extends AbstractController
if ($data['nfn'] === 'RESPUESTA_CrearImagen') {
$trace = $this->entityManager->getRepository(Trace::class)->findOneBy(['jobId' => $data['job_id']]);
$image = $this->entityManager->getRepository(Image::class)->findOneBy(['uuid' => $data['idi']]);
/** @var ImageImageRepository $imageImageRepository */
$imageImageRepository = $this->entityManager->getRepository(ImageImageRepository::class)->findOneBy(['uuid' => $data['idi']]);
if (!$image) {
if (!$imageImageRepository) {
$this->logger->error('Image not found', $data);
return new JsonResponse(['message' => 'Image not found'], Response::HTTP_NOT_FOUND);
}
@ -80,37 +82,41 @@ class ClientsController extends AbstractController
if ($data['res'] === 1) {
$trace->setStatus(TraceStatus::SUCCESS);
$trace->setFinishedAt(new \DateTime());
$image->setStatus(ImageStatus::AUX_FILES_PENDING);
$image->setCreated(true);
$this->logger->info('Start partition creation. ', ['image' => (string) $image->getUuid()]);
$imageImageRepository->setStatus(ImageStatus::AUX_FILES_PENDING);
$imageImageRepository->setCreated(true);
$this->entityManager->persist($imageImageRepository);
$this->logger->info('Start partition creation. ', ['image' => (string) $imageImageRepository->getUuid()]);
if (isset($data['cfg'])) {
$this->createPartitionService->__invoke($data, $image->getClient());
$this->createPartitionService->__invoke($data, $imageImageRepository->getImage()->getClient());
}
$this->logger->info('Starting software profile creation. ', ['image' => (string) $image->getUuid()]);
$this->createSoftwareProfile($data['inv_sft'], $image);
$this->logger->info('Start aux files ogrepo API ', ['image' => (string) $image->getUuid()]);
$this->logger->info('Starting software profile creation. ', ['image' => (string) $imageImageRepository->getUuid()]);
$this->createSoftwareProfile($data['inv_sft'], $imageImageRepository);
$this->logger->info('Start aux files ogrepo API ', ['image' => (string) $imageImageRepository->getUuid()]);
try {
$this->createAuxFilesAction->__invoke($image);
$this->createAuxFilesAction->__invoke($imageImageRepository);
} catch (\Exception $e) {
$this->logger->error('Error creating aux files', ['image' => (string) $image->getUuid(), 'error' => $e->getMessage()]);
$this->logger->error('Error creating aux files', ['image' => (string) $imageImageRepository->getUuid(), 'error' => $e->getMessage()]);
}
$this->logger->info('End aux files ogrepo API ', ['image' => (string) $image->getUuid()]);
$this->logger->info('End aux files ogrepo API ', ['image' => (string) $imageImageRepository->getUuid()]);
} else {
$trace->setStatus(TraceStatus::FAILED);
$trace->setFinishedAt(new \DateTime());
$trace->setOutput($data['der']);
$image->setCreated(false);
$image->setStatus(ImageStatus::FAILED);
$imageImageRepository->setCreated(false);
$imageImageRepository->setStatus(ImageStatus::FAILED);
$this->logger->error('Image updated failed', $data);
}
$this->entityManager->persist($image);
$this->entityManager->persist($imageImageRepository);
$client = $trace->getClient();
$client->setStatus(ClientStatus::OG_LIVE);
$this->entityManager->persist($client);
$this->entityManager->persist($trace);
$this->entityManager->flush();
$this->logger->info('Image updated. Success.', ['image' => (string) $image->getUuid()]);
$this->logger->info('Image updated. Success.', ['image' => (string) $imageImageRepository->getUuid()]);
}
if ($data['nfn'] === 'RESPUESTA_RestaurarImagen'|| $data['nfn'] === 'RESPUESTA_Configurar') {
@ -139,7 +145,7 @@ class ClientsController extends AbstractController
return new JsonResponse(data: 'Webhook finished', status: Response::HTTP_OK);
}
public function createSoftwareProfile(string $base64Data, Image $image): void
public function createSoftwareProfile(string $base64Data, ImageImageRepository $imageImageRepository): void
{
$decodedData = base64_decode($base64Data);
$this->logger->info('Software profile decoded', ['data' => '']);
@ -156,6 +162,8 @@ class ClientsController extends AbstractController
$this->entityManager->persist($softwareEntity);
}
$image = $imageImageRepository->getImage();
$softwareProfile = new SoftwareProfile();
$softwareProfile->setDescription('Perfil software: ' . $image->getClient()->getName());
$softwareProfile->setOrganizationalUnit($image->getClient()->getOrganizationalUnit());
@ -167,6 +175,7 @@ class ClientsController extends AbstractController
$image->setSoftwareProfile($softwareProfile);
$this->entityManager->persist($image);
$this->entityManager->persist($imageImageRepository);
$this->entityManager->persist($softwareProfile);
$this->entityManager->flush();
}

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

@ -60,7 +60,7 @@ class PostAction extends AbstractOgBootController
'ogntp' => $client->getOrganizationalUnit()->getNetworkSettings()?->getNtp(),
'ogdns' => $client->getOrganizationalUnit()->getNetworkSettings()?->getDns(),
'ogProxy' => $client->getOrganizationalUnit()->getNetworkSettings()?->getProxy(),
'resolution' => '788'
'resolution' => '791'
]
];

View File

@ -38,26 +38,34 @@ abstract class AbstractOgRepositoryController extends AbstractController
* @throws RedirectionExceptionInterface
* @throws ClientExceptionInterface
*/
public function createRequest (string $method, string $url, array $params = []): JsonResponse|array
public function createRequest(string $method, string $url, array $params = []): array
{
$params = array_merge($params, [
'headers' => [
'accept' => 'application/json',
'Content-Type' => 'application/json'
],
'timeout' => 10,
]);
try {
$response = $this->httpClient->request($method, $url, $params);
return json_decode($response->getContent(), true);
} catch (ClientExceptionInterface | ServerExceptionInterface $e) {
$response = $e->getResponse();
$content = json_decode($response->getContent(false), true);
$this->logger->error(json_encode($content));
throw new HttpException($response->getStatusCode(), $content['error'] ?? 'An error occurred');
$this->logger->error(sprintf('Client/Server error in request to %s: %s', $url, $e->getMessage()));
return [
'error' => 'Client/Server error',
'details' => $e->getMessage(),
];
} catch (TransportExceptionInterface $e) {
throw new HttpException(Response::HTTP_INTERNAL_SERVER_ERROR, $e->getMessage());
$this->logger->error(sprintf('Transport error in request to %s: %s', $url, $e->getMessage()));
return [
'error' => 'Transport error',
'details' => $e->getMessage(),
];
}
}
}

View File

@ -5,6 +5,7 @@ namespace App\Controller\OgRepository\Image;
use App\Controller\OgRepository\AbstractOgRepositoryController;
use App\Entity\Command;
use App\Entity\Image;
use App\Entity\ImageImageRepository;
use App\Model\CommandTypes;
use App\Model\ImageStatus;
use App\Model\TraceStatus;
@ -28,32 +29,36 @@ class CreateAuxFilesAction extends AbstractOgRepositoryController
* @throws RedirectionExceptionInterface
* @throws ClientExceptionInterface
*/
public function __invoke(Image $data): JsonResponse
public function __invoke(ImageImageRepository $data): JsonResponse
{
if (!$data->getName()) {
$image = $data->getImage();
if (!$image->getName()) {
throw new ValidatorException('Name is required');
}
$params = [
'json' => [
'image' => $data->getName().'.img'
'image' => $image->getName().'.img'
]
];
$this->logger->info('Creating aux files', ['image' => $data->getName()]);
$this->logger->info('Creating aux files', ['image' => $image->getName()]);
$content = $this->createRequest('POST', 'http://'.$data->getRepository()->getIp().':8006/ogrepository/v1/images/torrentsum', $params);
$repository = $image->getClient()->getRepository();
$content = $this->createRequest('POST', 'http://'.$repository->getIp().':8006/ogrepository/v1/images/torrentsum', $params);
$inputData = [
'imageName' => $data->getName(),
'imageName' => $image->getName(),
'imageUuid' => $data->getUuid(),
];
$this->createService->__invoke($data->getClient(), CommandTypes::CREATE_IMAGE_AUX_FILE, TraceStatus::IN_PROGRESS, $content['job_id'], $inputData);
$this->createService->__invoke($image->getClient(), CommandTypes::CREATE_IMAGE_AUX_FILE, TraceStatus::IN_PROGRESS, $content['job_id'], $inputData);
$this->logger->info('Aux files created successfully', ['image' => $data->getName()]);
$this->logger->info('Aux files created successfully', ['image' => $image->getName()]);
$data->setStatus(ImageStatus::IN_PROGRESS);
$data->setStatus(ImageStatus::AUX_FILES_PENDING);
$this->entityManager->persist($data);
$this->entityManager->flush();

View File

@ -4,6 +4,7 @@ namespace App\Controller\OgRepository\Image;
use App\Controller\OgRepository\AbstractOgRepositoryController;
use App\Entity\Image;
use App\Entity\ImageImageRepository;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Attribute\AsController;
@ -23,17 +24,21 @@ class DeletePermanentAction extends AbstractOgRepositoryController
* @throws RedirectionExceptionInterface
* @throws ClientExceptionInterface
*/
public function __invoke(Image $data, HttpClientInterface $httpClient): JsonResponse
public function __invoke(ImageImageRepository $data, HttpClientInterface $httpClient): JsonResponse
{
if (!$data->getImageFullsum()) {
throw new ValidatorException('Fullsum is required');
}
$this->logger->info('Deleting image', ['image' => $data->getName()]);
$image = $data->getImage();
$content = $this->createRequest( 'DELETE', 'http://'.$data->getRepository()->getIp().':8006/ogrepository/v1/images/'.$data->getImageFullsum().'?method=permanent');
$this->logger->info('Deleting image', ['image' => $image->getName()]);
$this->logger->info('Image deleted', ['image' => $data->getName()]);
$repository = $data->getRepository();
$content = $this->createRequest( 'DELETE', 'http://'.$repository->getIp().':8006/ogrepository/v1/images/'.$data->getImageFullsum().'?method=permanent');
$this->logger->info('Image deleted', ['image' => $image->getName()]);
$this->entityManager->remove($data);
$this->entityManager->flush();

View File

@ -3,7 +3,10 @@
namespace App\Controller\OgRepository\Image;
use App\Controller\OgRepository\AbstractOgRepositoryController;
use App\Dto\Input\DeleteImageInput;
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;
@ -13,7 +16,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 DeleteTrashAction extends AbstractOgRepositoryController
@ -24,20 +26,25 @@ class DeleteTrashAction extends AbstractOgRepositoryController
* @throws RedirectionExceptionInterface
* @throws ClientExceptionInterface
*/
public function __invoke(Image $data, HttpClientInterface $httpClient): JsonResponse
public function __invoke(ImageImageRepository $imageImageRepository): JsonResponse
{
if (!$data->getImageFullsum()) {
$repository = $imageImageRepository->getRepository();
$image = $imageImageRepository->getImage();
if (!$imageImageRepository->getImageFullsum()) {
throw new ValidatorException('Fullsum is required');
}
$this->logger->info('Deleting image', ['image' => $data->getName()]);
$this->logger->info('Deleting image', ['image' => $image->getName()]);
$content = $this->createRequest('DELETE', 'http://'.$data->getRepository()->getIp().':8006/ogrepository/v1/images/'.$data->getImageFullsum().'?method=trash');
$repository = $image->getClient()->getRepository();
$this->logger->info('Image deleted', ['image' => $data->getName()]);
$content = $this->createRequest('DELETE', 'http://'.$repository->getIp().':8006/ogrepository/v1/images/'.$imageImageRepository->getImageFullsum().'?method=trash');
$data->setStatus(ImageStatus::TRASH);
$this->entityManager->persist($data);
$this->logger->info('Image deleted', ['image' => $image->getName()]);
$imageImageRepository->setStatus(ImageStatus::TRASH);
$this->entityManager->persist($image);
$this->entityManager->flush();
return new JsonResponse(data: $content, status: Response::HTTP_OK);

View File

@ -7,6 +7,7 @@ use App\Dto\Input\DeployImageInput;
use App\Entity\Client;
use App\Entity\Command;
use App\Entity\Image;
use App\Entity\ImageImageRepository;
use App\Model\CommandTypes;
use App\Model\DeployImageTypes;
use App\Model\DeployMethodTypes;
@ -29,7 +30,7 @@ class DeployImageAction extends AbstractOgRepositoryController
* @throws ClientExceptionInterface
* @throws TransportExceptionInterface
*/
public function __invoke(DeployImageInput $input, Image $data, Client $client, HttpClientInterface $httpClient): JsonResponse
public function __invoke(DeployImageInput $input, ImageImageRepository $data, Client $client, HttpClientInterface $httpClient): JsonResponse
{
$params = [
'json' => [
@ -49,7 +50,9 @@ class DeployImageAction extends AbstractOgRepositoryController
default => DeployMethodTypes::MULTICAST_UFTP,
};
$content = $this->createRequest('POST', 'http://'.$data->getRepository()->getIp().':8006/ogrepository/v1/'.$type, $params);
$repository = $client->getRepository();
$content = $this->createRequest('POST', 'http://'.$repository->getIp().':8006/ogrepository/v1/'.$type, $params);
return new JsonResponse(data: [], status: Response::HTTP_OK);
}

View File

@ -4,6 +4,7 @@ namespace App\Controller\OgRepository\Image;
use App\Controller\OgRepository\AbstractOgRepositoryController;
use App\Entity\Image;
use App\Entity\ImageImageRepository;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Attribute\AsController;
@ -23,7 +24,7 @@ class GetAction extends AbstractOgRepositoryController
* @throws RedirectionExceptionInterface
* @throws ClientExceptionInterface
*/
public function __invoke(Image $data): JsonResponse
public function __invoke(ImageImageRepository $data): JsonResponse
{
if (!$data->getImageFullsum()) {
throw new ValidatorException('Fullsum is required');

View File

@ -5,6 +5,7 @@ namespace App\Controller\OgRepository\Image;
use App\Controller\OgRepository\AbstractOgRepositoryController;
use App\Dto\Input\DeployImageInput;
use App\Entity\Image;
use App\Entity\ImageImageRepository;
use App\Model\CommandTypes;
use App\Model\ImageStatus;
use App\Model\TraceStatus;
@ -27,23 +28,27 @@ class RecoverAction extends AbstractOgRepositoryController
* @throws RedirectionExceptionInterface
* @throws ClientExceptionInterface
*/
public function __invoke(Image $data, HttpClientInterface $httpClient): JsonResponse
public function __invoke(ImageImageRepository $data, HttpClientInterface $httpClient): JsonResponse
{
if (!$data->getImageFullsum()) {
throw new ValidatorException('Fullsum is required');
}
$image = $data->getImage();
$params = [
'json' => [
'ID_img' => $data->getImageFullsum()
]
];
$this->logger->info('Recovering image', ['image' => $data->getName()]);
$this->logger->info('Recovering image', ['image' => $image->getName()]);
$content = $this->createRequest('POST', 'http://'.$data->getRepository()->getIp().':8006/ogrepository/v1/trash/images', $params);
$repository = $image->getClient()->getRepository();
$this->logger->info('Image recovered successfully', ['image' => $data->getName()]);
$content = $this->createRequest('POST', 'http://'.$repository->getIp().':8006/ogrepository/v1/trash/images', $params);
$this->logger->info('Image recovered successfully', ['image' => $image->getName()]);
$data->setStatus(ImageStatus::SUCCESS);
$this->entityManager->persist($data);

View File

@ -5,6 +5,7 @@ namespace App\Controller\OgRepository\Image;
use App\Controller\OgRepository\AbstractOgRepositoryController;
use App\Dto\Input\ExportImportImageRepositoryInput;
use App\Entity\Image;
use App\Entity\ImageImageRepository;
use App\Entity\ImageRepository;
use App\Model\CommandTypes;
use App\Model\ImageStatus;
@ -19,7 +20,7 @@ use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
#[AsController]
class ImportAction extends AbstractOgRepositoryController
class TransferAction extends AbstractOgRepositoryController
{
/**
* @throws TransportExceptionInterface
@ -27,39 +28,46 @@ class ImportAction extends AbstractOgRepositoryController
* @throws RedirectionExceptionInterface
* @throws ClientExceptionInterface
*/
public function __invoke(ExportImportImageRepositoryInput $input, ImageRepository $repository): JsonResponse
public function __invoke(ExportImportImageRepositoryInput $input, ImageImageRepository $imageImageRepository): JsonResponse
{
$images = $input->images;
$repositories = $input->repositories;
foreach ($images as $imageEntity) {
/** @var Image $image */
$image = $imageEntity->getEntity();
foreach ($repositories as $repositoryEntity) {
/** @var ImageRepository $repository */
$repository = $repositoryEntity->getEntity();
/* @var Image $image */
$image = $imageImageRepository->getImage();
if (!$image->getImageFullsum()) {
if (!$imageImageRepository->getImageFullsum()) {
throw new ValidatorException('Fullsum is required');
}
$params = [
'json' => [
'image' => $image->getName().'.img',
'repo_ip' => $repository->getIp(),
'repo_ip' => $image->getClient()->getRepository()->getIp(),
'user' => 'opengnsys',
]
];
$this->logger->info('Importing image', ['image' => $image->getName(), 'repository' => $repository->getIp()]);
$content = $this->createRequest('POST', 'http://'.$image->getRepository()->getIp().':8006/ogrepository/v1/repo/images', $params);
$content = $this->createRequest('POST', 'http://'.$repository->getIp().':8006/ogrepository/v1/repo/images', $params);
if (!isset($content['job_id'])) {
throw new ValidatorException('Job ID not found');
}
$inputData = [
'imageName' => $image->getName(),
'imageUuid' => $image->getUuid(),
'imageImageRepositoryUuid' => $imageImageRepository->getUuid(),
'repositoryUuid' => $repository->getUuid(),
];
$this->createService->__invoke($image->getClient(), CommandTypes::IMPORT_IMAGE, TraceStatus::IN_PROGRESS, $content['job_id'], $inputData);
$this->createService->__invoke($image->getClient(), CommandTypes::TRANSFER_IMAGE, TraceStatus::IN_PROGRESS, $content['job_id'], $inputData);
$image->setStatus(ImageStatus::TRANSFERING);
$imageImageRepository->setStatus(ImageStatus::TRANSFERRING);
$this->entityManager->persist($image);
$this->entityManager->flush();
}

View File

@ -0,0 +1,80 @@
<?php
namespace App\Controller\OgRepository\Image;
use App\Controller\OgRepository\AbstractOgRepositoryController;
use App\Dto\Input\ExportImportImageRepositoryInput;
use App\Entity\Image;
use App\Entity\ImageImageRepository;
use App\Entity\ImageRepository;
use App\Model\CommandTypes;
use App\Model\ImageStatus;
use App\Model\TraceStatus;
use Doctrine\Common\Collections\ArrayCollection;
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 TransferIsGlobalAction extends AbstractOgRepositoryController
{
/**
* @throws TransportExceptionInterface
* @throws ServerExceptionInterface
* @throws RedirectionExceptionInterface
* @throws ClientExceptionInterface
*/
public function __invoke(?array $repositories = [], Image $image): JsonResponse
{
foreach ($repositories as $repository) {
try {
$imageImageRepository = $this->entityManager->getRepository(ImageImageRepository::class)->findOneBy(['image' => $image, 'repository' => $repository]);
if ($imageImageRepository) {
$content = $this->createRequest('GET', 'http://'.$repository->getIp().':8006/ogrepository/v1/images/'.$imageImageRepository->getImageFullsum());
$this->logger->info('Image already exists', ['image' => $imageImageRepository->getImage()->getName(), 'repository' => $repository->getIp()]);
continue;
}
} catch ( \Exception $e) {
}
$params = [
'json' => [
'image' => $image->getName().'.img',
'repo_ip' => $image->getClient()->getRepository()->getIp(),
'user' => 'opengnsys',
]
];
$this->logger->info('Importing image', ['image' => $image->getName(), 'repository' => $repository->getIp()]);
$content = $this->createRequest('POST', 'http://'.$repository->getIp().':8006/ogrepository/v1/repo/images', $params);
if (!isset($content['job_id'])) {
throw new ValidatorException('Job ID not found');
}
$inputData = [
'imageName' => $image->getName(),
'imageUuid' => $image->getUuid(),
//'imageImageRepositoryUuid' => $imageImageRepository?->getUuid(),
'repositoryUuid' => $repository->getUuid(),
];
$this->createService->__invoke($image->getClient(), CommandTypes::TRANSFER_IMAGE, TraceStatus::IN_PROGRESS, $content['job_id'], $inputData);
//$imageImageRepository->setStatus(ImageStatus::TRANSFERRING);
$this->entityManager->persist($image);
$this->entityManager->flush();
}
return new JsonResponse(data: [], status: Response::HTTP_OK);
}
}

View File

@ -21,7 +21,7 @@ class StatusAction extends AbstractOgRepositoryController
* @throws RedirectionExceptionInterface
* @throws ClientExceptionInterface
*/
public function __invoke(ImageRepository $data, HttpClientInterface $httpClient): JsonResponse
public function __invoke(ImageRepository $data): JsonResponse
{
$content = $this->createRequest('GET', 'http://'.$data->getIp(). ':8006/ogrepository/v1/status');

View File

@ -3,6 +3,7 @@
namespace App\Controller\OgRepository;
use App\Entity\Image;
use App\Entity\ImageImageRepository;
use App\Entity\ImageRepository;
use App\Model\ImageStatus;
use Symfony\Component\HttpFoundation\JsonResponse;
@ -22,26 +23,37 @@ class SyncAction extends AbstractOgRepositoryController
* @throws RedirectionExceptionInterface
* @throws ClientExceptionInterface
*/
public function __invoke(ImageRepository $data): JsonResponse
public function __invoke(ImageRepository $input): JsonResponse
{
$content = $this->createRequest('GET', 'http://'.$data->getIp(). ':8006/ogrepository/v1/images');
$content = $this->createRequest('GET', 'http://'.$input->getIp(). ':8006/ogrepository/v1/images');
if (!isset($content['output']['REPOSITORY']['images'])) {
return new JsonResponse(data: 'No images found', status: Response::HTTP_NOT_FOUND);
}
foreach ($content['output']['REPOSITORY']['images'] as $image) {
$imageEntity = $this->entityManager->getRepository(Image::class)->findOneBy(['imageFullsum' => $image['fullsum']]);
$imageImageRepositoryEntity = $this->entityManager->getRepository(ImageImageRepository::class)->findOneBy(['imageFullsum' => $image['fullsum'], 'repository' => $input]);
$imageEntity = $this->entityManager->getRepository(Image::class)->findOneBy(['name' => $image['name']]);
if (!$imageEntity) {
$imageEntity = new Image();
$imageEntity->setName($image['name'].$image['type']);
$imageEntity->setStatus(ImageStatus::SUCCESS);
$imageEntity->setRepository($data);
$imageEntity->setCreated(true );
$imageEntity->setImageFullsum($image['fullsum']);
$imageEntity->setName($image['name']);
$imageEntity->setRemotePc(false);
$imageEntity->setIsGlobal(false);
$this->entityManager->persist($imageEntity);
}
$this->entityManager->persist($imageEntity);
if (!$imageImageRepositoryEntity) {
$imageImageRepositoryEntity = new ImageImageRepository();
$imageImageRepositoryEntity->setImageFullsum($image['fullsum']);
$imageImageRepositoryEntity->setStatus(ImageStatus::SUCCESS);
$imageImageRepositoryEntity->setImage($imageEntity);
$imageImageRepositoryEntity->setRepository($input);
$this->entityManager->persist($imageImageRepositoryEntity);
}
}
$this->entityManager->flush();

View File

@ -4,6 +4,7 @@ namespace App\Controller\OgRepository\Webhook;
use App\Controller\OgRepository\AbstractOgRepositoryController;
use App\Entity\Image;
use App\Entity\ImageImageRepository;
use App\Entity\ImageRepository;
use App\Entity\Trace;
use App\Model\CommandTypes;
@ -44,10 +45,10 @@ class ResponseController extends AbstractOgRepositoryController
if (str_starts_with($action, "CreateAuxiliarFiles_")) {
$this->handleCreateAuxFiles($data);
} elseif (str_starts_with($action, "TransferImage_")) {
$this->processImageAction($data, 'transfer');
} elseif (str_starts_with($action, "ExportImage_")) {
$this->processImageAction($data, 'export');
} elseif (str_starts_with($action, "ImportImage_")) {
$this->processImageAction($data, 'import');
} else {
return new JsonResponse(['message' => 'Invalid action'], Response::HTTP_BAD_REQUEST);
}
@ -60,21 +61,21 @@ class ResponseController extends AbstractOgRepositoryController
$trace = $this->entityManager->getRepository(Trace::class)->findOneBy(['jobId' => $data['job_id']]);
$imageUuid = $trace->getInput()['imageUuid'];
$image = $this->entityManager->getRepository(Image::class)->findOneBy(['uuid' => $imageUuid]);
/* @var ImageImageRepository $imageImageRepository */
$imageImageRepository = $this->entityManager->getRepository(ImageImageRepository::class)->findOneBy(['uuid' => $imageUuid]);
if ($image === null) {
if ($imageImageRepository === null) {
$this->updateTraceStatus($trace, TraceStatus::FAILED, 'Image not found');
return;
}
$image->setImageFullsum($data['image_id']);
$image->setStatus(ImageStatus::SUCCESS);
$this->entityManager->persist($image);
$imageImageRepository->setImageFullsum($data['image_id']);
$imageImageRepository->setStatus(ImageStatus::SUCCESS);
$this->entityManager->persist($imageImageRepository);
$this->updateTraceStatus($trace, TraceStatus::SUCCESS);
}
/**
* @throws TransportExceptionInterface
* @throws ServerExceptionInterface
@ -90,31 +91,41 @@ class ResponseController extends AbstractOgRepositoryController
$image = $this->entityManager->getRepository(Image::class)->findOneBy(['uuid' => $imageUuid]);
$repository = $this->entityManager->getRepository(ImageRepository::class)->findOneBy(['uuid' => $repositoryUuid]);
if ($data['success'] !== true) {
$this->updateTraceStatus($trace, TraceStatus::FAILED, 'Action failed');
return;
}
if ($image === null) {
$this->updateTraceStatus($trace, TraceStatus::FAILED, 'Image not found');
return;
}
$this->logger->info("Image $actionType", ['image' => $image->getName()]);
if ($repository === null) {
$this->updateTraceStatus($trace, TraceStatus::FAILED, 'Repository not found');
return;
}
$params = [
'json' => [
'image' => $image->getName().'.img'
]
];
if (isset($trace->getInput()['imageImageRepositoryUuid'])) {
$imageImageRepositoryUuid = $trace->getInput()['imageImageRepositoryUuid'];
$imageImageRepository = $this->entityManager->getRepository(ImageImageRepository::class)->findOneBy(['uuid' => $imageImageRepositoryUuid]);
$this->logger->info('Creating aux files', ['image' => $image->getName()]);
$content = $this->createRequest('POST', 'http://'.$repository->getIp().':8006/ogrepository/v1/images/torrentsum', $params);
if ($imageImageRepository) {
$this->updateTraceStatus($trace, TraceStatus::FAILED, 'Image repository not found');
$imageImageRepository->setStatus(ImageStatus::SUCCESS);
}
}
$inputData = [
'imageName' => $image->getName(),
'imageUuid' => $image->getUuid(),
];
$this->logger->info("Image $actionType successful", ['image' => $image->getName()]);
$this->createService->__invoke($image->getClient(), CommandTypes::CREATE_IMAGE_AUX_FILE, TraceStatus::IN_PROGRESS, $content['job_id'], $inputData);
// Creamos un objeto imagen nuevo, en el repositorio destino
$newImageImageRepository = new ImageImageRepository();
$newImageImageRepository->setImage($image);
$newImageImageRepository->setRepository($repository);
$newImageImageRepository->setStatus(ImageStatus::SUCCESS);
$image->setRepository($repository);
$image->setStatus(ImageStatus::SUCCESS);
// Cambiamos el estado de la imagen anterior a SUCCESS
$this->entityManager->persist($newImageImageRepository);
$this->entityManager->persist($image);
$this->updateTraceStatus($trace, TraceStatus::SUCCESS);

View File

@ -161,6 +161,11 @@ final class ClientInput
$client = new Client();
}
$menu = $this->menu?->getEntity() ?? $client->getOrganizationalUnit()?->getNetworkSettings()?->getMenu();
$ogLive = $this->ogLive?->getEntity() ?? $client->getOrganizationalUnit()?->getNetworkSettings()?->getOgLive();
$hardwareProfile = $this->hardwareProfile?->getEntity() ?? $client->getOrganizationalUnit()?->getNetworkSettings()?->getHardwareProfile();
$repository = $this->repository?->getEntity() ?? $client->getOrganizationalUnit()?->getNetworkSettings()?->getRepository();
$client->setName($this->name);
$client->setSerialNumber($this->serialNumber);
$client->setNetiface($this->netiface);
@ -168,10 +173,10 @@ final class ClientInput
$client->setNetDriver($this->netDriver);
$client->setMac($this->mac);
$client->setIp($this->ip);
$client->setMenu($this->menu?->getEntity());
$client->setOgLive($this->ogLive?->getEntity());
$client->setHardwareProfile($this->hardwareProfile?->getEntity());
$client->setRepository($this->repository?->getEntity());
$client->setMenu($menu);
$client->setOgLive($ogLive);
$client->setHardwareProfile($hardwareProfile);
$client->setRepository($repository);
$client->setTemplate($this->template?->getEntity());
$client->setPosition($this->position);
$client->setStatus($this->status);

View File

@ -0,0 +1,13 @@
<?php
namespace App\Dto\Input;
use App\Dto\Output\ImageRepositoryOutput;
use Symfony\Component\Serializer\Annotation\Groups;
use Symfony\Component\Validator\Constraints as Assert;
class DeleteImageInput
{
#[Assert\NotNull]
#[Groups(['image:write'])]
public ImageRepositoryOutput $repository;
}

View File

@ -15,52 +15,51 @@ use Symfony\Component\Serializer\Annotation\Groups;
#[ClientsHaveSamePartitionCount]
class DeployImageInput
{
#[Groups(['image:write'])]
#[Groups(['image-image-repository:write'])]
#[ApiProperty(description: 'The type of the image deployment', example: "")]
public ?string $type = null;
#[Groups(['image:write'])]
#[Groups(['image-image-repository:write'])]
#[ApiProperty(description: 'The type of the image deployment', example: "")]
public ?string $method = null;
/**
* @var ClientOutput[]
*/
#[Groups(['image:write'])]
#[Groups(['image-image-repository:write'])]
#[ApiProperty(description: 'The client to deploy the image')]
public ?array $clients = [];
#[Groups(['image:write'])]
#[Groups(['image-image-repository:write'])]
public ?int $diskNumber = null;
#[Groups(['image:write'])]
#[Groups(['image-image-repository:write'])]
public ?int $partitionNumber = null;
#[OrganizationalUnitP2PMode]
#[Groups(['image:write'])]
#[Groups(['image-image-repository:write'])]
public ?string $p2pMode = null;
#[Groups(['image:write'])]
#[Groups(['image-image-repository:write'])]
public ?int $p2pTime = null;
#[Groups(['image:write'])]
#[Groups(['image-image-repository:write'])]
public ?string $mcastIp = null;
#[Groups(['image:write'])]
#[Groups(['image-image-repository:write'])]
public ?int $mcastSpeed = null;
#[OrganizationalUnitMulticastPort]
#[Groups(['image:write'])]
#[Groups(['image-image-repository:write'])]
public ?int $mcastPort = null;
#[OrganizationalUnitMulticastMode]
#[Groups(['image:write'])]
#[Groups(['image-image-repository:write'])]
public ?string $mcastMode = null;
#[Groups(['image:write'])]
#[Groups(['image-image-repository:write'])]
public ?int $maxClients = null;
#[Groups(['image:write'])]
#[Groups(['image-image-repository:write'])]
public ?int $maxTime = null;
}

View File

@ -13,6 +13,6 @@ class ExportImportImageRepositoryInput
* @var ImageOutput[]
*/
#[Assert\NotNull]
#[Groups(['repository:write'])]
public array $images = [];
#[Groups(['image-image-repository:write'])]
public array $repositories = [];
}

View File

@ -0,0 +1,44 @@
<?php
namespace App\Dto\Input;
use ApiPlatform\Metadata\ApiProperty;
use App\Dto\Output\ImageOutput;
use App\Dto\Output\ImageRepositoryOutput;
use App\Entity\ImageImageRepository;
use App\Entity\PxeTemplate;
use Symfony\Component\Serializer\Annotation\Groups;
use Symfony\Component\Validator\Constraints as Assert;
final class ImageImageRepositoryInput
{
#[Assert\NotNull]
#[Groups(['image-image-repository:write'])]
public ?ImageRepositoryOutput $imageRepository = null;
#[Assert\NotNull]
#[Groups(['image-image-repository:write'])]
public ?string $status = '';
public function __construct(?ImageImageRepository $imageImageRepository = null)
{
if (!$imageImageRepository) {
return;
}
$this->imageRepository = new ImageRepositoryOutput($imageImageRepository->getRepository());
$this->status = $imageImageRepository->getStatus();
}
public function createOrUpdateEntity(?ImageImageRepository $imageImageRepository = null): ImageImageRepository
{
if (!$imageImageRepository) {
$imageImageRepository = new ImageImageRepository();
}
$imageImageRepository->setRepository($this->imageRepository);
$imageImageRepository->setStatus($this->status);
return $imageImageRepository;
}
}

View File

@ -4,11 +4,14 @@ namespace App\Dto\Input;
use ApiPlatform\Metadata\ApiProperty;
use App\Dto\Output\ClientOutput;
use App\Dto\Output\ImageImageRepositoryOutput;
use App\Dto\Output\ImageRepositoryOutput;
use App\Dto\Output\OrganizationalUnitOutput;
use App\Dto\Output\PartitionOutput;
use App\Dto\Output\RemoteCalendarRuleOutput;
use App\Dto\Output\SoftwareProfileOutput;
use App\Entity\Image;
use App\Entity\ImageImageRepository;
use App\Entity\OrganizationalUnit;
use App\Entity\Partition;
use App\Model\ImageStatus;
@ -30,25 +33,20 @@ final class ImageInput
#[ApiProperty(description: 'The comments of the image', example: "Image 1 comments")]
public ?string $comments = null;
#[Groups(['image:write'])]
#[ApiProperty(description: 'The type of the image', example: "Server")]
public ?string $type = null;
#[Groups(['image:write'])]
#[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;
/**
* @var ImageRepositoryOutput[]
*/
#[Groups(['image:write'])]
#[ApiProperty(description: 'The image repository of the image')]
public ?ImageRepositoryOutput $imageRepository = null;
public ?array $imageRepositories = [];
#[Groups(['image:write'])]
#[ApiProperty(description: 'The client of the image')]
@ -70,7 +68,6 @@ final class ImageInput
#[ApiProperty(description: 'The global property of the image')]
public ?bool $isGlobal = false;
public function __construct(?Image $image = null)
{
if (!$image) {
@ -80,23 +77,21 @@ final class ImageInput
$this->name = $image->getName();
$this->description = $image->getDescription();
$this->comments = $image->getComments();
$this->type = $image->getType();
$this->remotePc = $image->isRemotePc();
$this->isGlobal = $image->isGlobal();
$this->status = $image->getStatus();
if ($image->getSoftwareProfile()) {
$this->softwareProfile = new SoftwareProfileOutput($image->getSoftwareProfile());
}
if ($image->getRepository()) {
$this->imageRepository = new ImageRepositoryOutput($image->getRepository());
}
if ($image->getClient()) {
$this->client = new ClientOutput($image->getClient());
}
if ($image->getImageImageRepositories()) {
$this->imageRepositories = array_map(fn($imageImageRepository) => new ImageImageRepositoryOutput($imageImageRepository), $image->getImageImageRepositories()->toArray());
}
if ($image->getParent()) {
$this->parent = new self($image->getParent());
}
@ -106,32 +101,34 @@ 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);
if ($this->softwareProfile) {
$image->setSoftwareProfile($this->softwareProfile->getEntity());
}
$image->setRepository($this->imageRepository ? $this->imageRepository->getEntity()
: $this->client->getEntity()->getRepository());
if ($this->client) {
$image->setClient($this->client->getEntity());
}
if ($this->parent) {
$image->setParent($this->parent->getEntity());
if ($this->imageRepositories) {
foreach ($this->imageRepositories as $imageRepository) {
$aux = new ImageImageRepository();
$aux->setImage($image);
$aux->setRepository($imageRepository->getEntity());
$aux->setStatus('');
if (!$image->containsImageImageRepository($aux)) {
$image->addImageImageRepository($aux);
}
}
}
$image->setRemotePc($this->remotePc);
$image->setIsGlobal($this->isGlobal);
$image->setCreated(false);
$partitionInfo = [];

View File

@ -77,12 +77,6 @@ class NetworkSettingsInput
#[Groups(['organizational-unit:write'])]
public ?ImageRepositoryOutput $repository = null;
#[Groups(['organizational-unit:write'])]
public ?bool $validation = null;
#[Groups(['organizational-unit:write'])]
public ?string $oglog = null;
#[Groups(['organizational-unit:write'])]
public ?string $ogshare = null;
@ -105,7 +99,6 @@ class NetworkSettingsInput
$this->mcastSpeed = $networkSettings->getMcastSpeed();
$this->mcastPort = $networkSettings->getMcastPort();
$this->mcastMode = $networkSettings->getMcastMode();
$this->oglog = $networkSettings->getOglog();
$this->ogshare = $networkSettings->getOgshare();
if ($networkSettings->getMenu()) {
@ -123,8 +116,6 @@ class NetworkSettingsInput
if ($networkSettings->getRepository()) {
$this->repository = new ImageRepositoryOutput($networkSettings->getRepository());
}
$this->validation = $networkSettings->getValidation();
}
public function createOrUpdateEntity(?NetworkSettings $networkSettings = null): NetworkSettings
@ -146,7 +137,6 @@ class NetworkSettingsInput
$networkSettings->setMcastSpeed($this->mcastSpeed);
$networkSettings->setMcastPort($this->mcastPort);
$networkSettings->setMcastMode($this->mcastMode);
$networkSettings->setOglog($this->oglog);
$networkSettings->setOgshare($this->ogshare);
if ($this->menu) {
@ -165,8 +155,6 @@ class NetworkSettingsInput
$networkSettings->setRepository($this->repository->getEntity());
}
$networkSettings->setValidation($this->validation);
return $networkSettings;
}
}

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

@ -57,6 +57,9 @@ class OrganizationalUnitInput
#[Groups(['organizational-unit:write'])]
public ?bool $remotePc = false;
#[Groups(['organizational-unit:write'])]
public ?bool $excludeParentChanges = null;
public function __construct(?OrganizationalUnit $organizationalUnit = null)
{
if (!$organizationalUnit) {
@ -102,6 +105,7 @@ class OrganizationalUnitInput
$organizationalUnit->setComments($this->comments);
$organizationalUnit->setType($this->type);
$organizationalUnit->setRemotePc($this->remotePc);
$organizationalUnit->setExcludeParentChanges($this->excludeParentChanges);
if ($this->networkSettings){
$organizationalUnit->setNetworkSettings($this->networkSettings->createOrUpdateEntity($organizationalUnit->getNetworkSettings()));

View File

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

View File

@ -4,12 +4,15 @@ namespace App\Dto\Output;
use ApiPlatform\Metadata\Get;
use App\Entity\Image;
use App\Entity\ImageImageRepository;
use App\Entity\ImageRepository;
use App\Entity\Software;
use Symfony\Component\Serializer\Annotation\Groups;
#[Get(shortName: 'Image')]
final class ImageOutput extends AbstractOutput
{
#[Groups(['image:read'])]
#[Groups(['image:read', 'image-image-repository:read'])]
public ?string $name = '';
#[Groups(['image:read'])]
@ -18,45 +21,24 @@ final class ImageOutput extends AbstractOutput
#[Groups(['image:read'])]
public ?string $comments = '';
#[Groups(['image:read'])]
public ?string $type = null;
#[Groups(['image:read'])]
public ?string $path = '';
#[Groups(['image:read'])]
public ?string $revision = '';
#[Groups(['image:read'])]
public ?string $info = '';
#[Groups(['image:read'])]
public ?int $size = null;
#[Groups(['image:read'])]
public ?bool $remotePc = null;
#[Groups(['image:read'])]
public ?bool $isGlobal = null;
#[Groups(['image:read'])]
public ?bool $created = null;
#[Groups(['image:read'])]
public ?SoftwareProfileOutput $softwareProfile = null;
/**
* @var ImageRepositoryOutput[]|null
*/
#[Groups(['image:read'])]
public ?ImageRepositoryOutput $imageRepository = null;
public ?array $imageRepositories = [];
#[Groups(['image:read'])]
public ?array $partitionInfo = null;
#[Groups(['image:read'])]
public ?string $imageFullsum = '';
#[Groups(['image:read'])]
public ?string $status = null;
#[Groups(['image:read'])]
public \DateTime $createdAt;
@ -70,19 +52,15 @@ final class ImageOutput extends AbstractOutput
$this->name = $image->getName();
$this->description = $image->getDescription();
$this->comments = $image->getComments();
$this->type = $image->getType();
$this->path = $image->getPath();
$this->revision = $image->getRevision();
$this->info = $image->getInfo();
$this->size = $image->getSize();
$this->imageFullsum = $image->getImageFullsum();
$this->status = $image->getStatus();
$this->softwareProfile = $image->getSoftwareProfile() ? new SoftwareProfileOutput($image->getSoftwareProfile()) : null;
$this->imageRepository = $image->getRepository() ? new ImageRepositoryOutput($image->getRepository()) : null;
$this->imageRepositories = $image->getImageImageRepositories()->map(
fn(ImageImageRepository $image) => new ImageImageRepositoryOutput($image)
)->toArray();
$this->partitionInfo = json_decode($image->getPartitionInfo(), true);
$this->remotePc = $image->isRemotePc();
$this->isGlobal = $image->isGlobal();
$this->created = $image->isCreated();
$this->createdAt = $image->getCreatedAt();
$this->createdBy = $image->getCreatedBy();
}

View File

@ -9,7 +9,7 @@ use Symfony\Component\Serializer\Annotation\Groups;
#[Get(shortName: 'ImageRepository')]
class ImageRepositoryOutput extends AbstractOutput
{
#[Groups(['repository:read', 'image:read', 'client:read', "organizational-unit:read"])]
#[Groups(['repository:read', 'image:read', 'client:read', "organizational-unit:read", "image-image-repository:read"])]
public ?string $name = '';
#[Groups(['repository:read'])]
@ -18,19 +18,23 @@ class ImageRepositoryOutput extends AbstractOutput
#[Groups(['repository:read'])]
public ?string $comments = '';
#[Groups(['repository:read'])]
public ?bool $status = true;
#[Groups(['repository:read'])]
public \DateTime $createdAt;
#[Groups(['repository:read'])]
public ?string $createdBy = null;
public function __construct(ImageRepository $imageRepository)
public function __construct(ImageRepository $imageRepository, bool $status = true)
{
parent::__construct($imageRepository);
$this->name = $imageRepository->getName();
$this->ip = $imageRepository->getIp();
$this->comments = $imageRepository->getComments();
$this->status = $status;
$this->createdAt = $imageRepository->getCreatedAt();
$this->createdBy = $imageRepository->getCreatedBy();
}

View File

@ -34,7 +34,7 @@ final class MenuOutput extends AbstractOutput
#[Groups(['menu:read'])]
public ?string $createdBy = null;
public function __construct(Menu $menu)
public function __construct(Menu $menu)
{
parent::__construct($menu);

View File

@ -60,15 +60,9 @@ final class NetworkSettingsOutput extends AbstractOutput
#[Groups(['network-settings:read', "organizational-unit:read", "client:read"])]
public ?ImageRepositoryOutput $repository = null;
#[Groups(['network-settings:read', "organizational-unit:read", "client:read"])]
public ?string $oglog = null;
#[Groups(['network-settings:read', "organizational-unit:read", "client:read"])]
public ?string $ogshare = null;
#[Groups(['network-settings:read', "organizational-unit:read", "client:read"])]
public ?bool $validation = null;
#[Groups(['organizational-unit:read'])]
public \DateTime $createdAt;
@ -92,7 +86,6 @@ final class NetworkSettingsOutput extends AbstractOutput
$this->mcastSpeed = $networkSettings->getMcastSpeed();
$this->mcastPort = $networkSettings->getMcastPort();
$this->mcastMode = $networkSettings->getMcastMode();
$this->oglog = $networkSettings->getOglog();
$this->ogshare = $networkSettings->getOgshare();
if ($networkSettings->getMenu()) {
@ -111,7 +104,6 @@ final class NetworkSettingsOutput extends AbstractOutput
$this->repository = new ImageRepositoryOutput($networkSettings->getRepository());
}
$this->validation = $networkSettings->getValidation();
$this->createdAt = $networkSettings->getCreatedAt();
$this->createdBy = $networkSettings->getCreatedBy();
}

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

@ -61,6 +61,9 @@ final class OrganizationalUnitOutput extends AbstractOutput
#[Groups(['organizational-unit:read'])]
public ?bool $available = null;
#[Groups(['organizational-unit:read'])]
public ?bool $excludeParentChanges = null;
#[Groups(['organizational-unit:read'])]
public \DateTime $createdAt;
@ -99,6 +102,7 @@ final class OrganizationalUnitOutput extends AbstractOutput
)->toArray();
}
$this->excludeParentChanges = $organizationalUnit->isExcludeParentChanges();
$this->path = $organizationalUnit->getPath();
$this->createdAt = $organizationalUnit->getCreatedAt();
$this->createdBy = $organizationalUnit->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;
@ -34,6 +34,9 @@ final class TraceOutput extends AbstractOutput
#[Groups(['trace:read'])]
public ?\DateTimeInterface $finishedAt = null;
#[Groups(['trace:read'])]
public ?int $progress = null;
#[Groups(['trace:read'])]
public \DateTime $createdAt;
@ -45,13 +48,18 @@ 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();
$this->output = $trace->getOutput();
$this->input = $trace->getInput();
$this->finishedAt = $trace->getFinishedAt();
$this->progress = $trace->getProgress();
$this->createdAt = $trace->getCreatedAt();
$this->createdBy = $trace->getCreatedBy();
}

View File

@ -15,8 +15,6 @@ use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
#[UniqueEntity(fields: ['mac'], message: 'This MAC address is already in use.')]
class Client extends AbstractEntity
{
// TODO nueva variable bool isTeacher
use NameableTrait;
#[ORM\Column(length: 255, nullable: true)]
@ -266,7 +264,7 @@ class Client extends AbstractEntity
public function getRepository(): ?ImageRepository
{
return $this->repository;
return $this->repository ?? $this->getOrganizationalUnit()->getNetworkSettings()?->getRepository();
}
public function setRepository(?ImageRepository $repository): static

View File

@ -21,21 +21,6 @@ class Image extends AbstractEntity
#[ORM\Column(length: 255, nullable: true)]
private ?string $comments = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $path = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $type = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $revision = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $info = null;
#[ORM\Column(length: 255, nullable: true)]
private ?int $size = null;
#[ORM\ManyToOne]
#[ORM\JoinColumn(nullable: true)]
private ?SoftwareProfile $softwareProfile = null;
@ -43,10 +28,6 @@ class Image extends AbstractEntity
#[ORM\Column]
private ?bool $remotePc = null;
#[ORM\ManyToOne(inversedBy: 'images')]
#[ORM\JoinColumn(nullable: false)]
private ?\App\Entity\ImageRepository $repository = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $partitionInfo = null;
@ -56,22 +37,19 @@ class Image extends AbstractEntity
#[ORM\ManyToOne]
private ?Client $client = null;
#[ORM\Column(nullable: true)]
private ?bool $created = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $imageFullsum = null;
#[ORM\Column(length: 255)]
private ?string $status = null;
#[ORM\Column]
private ?bool $isGlobal = null;
/**
* @var Collection<int, ImageImageRepository>
*/
#[ORM\OneToMany(mappedBy: 'image', targetEntity: ImageImageRepository::class, cascade: ['persist'], orphanRemoval: true)]
private Collection $imageImageRepositories;
public function __construct()
{
parent::__construct();
$this->imageImageRepositories = new ArrayCollection();
}
public function getDescription(): ?string
@ -98,66 +76,6 @@ class Image extends AbstractEntity
return $this;
}
public function getPath(): ?string
{
return $this->path;
}
public function setPath(?string $path): static
{
$this->path = $path;
return $this;
}
public function getType(): ?string
{
return $this->type;
}
public function setType(?string $type): static
{
$this->type = $type;
return $this;
}
public function getRevision(): ?string
{
return $this->revision;
}
public function setRevision(?string $revision): static
{
$this->revision = $revision;
return $this;
}
public function getInfo(): ?string
{
return $this->info;
}
public function setInfo(?string $info): static
{
$this->info = $info;
return $this;
}
public function getSize(): ?int
{
return $this->size;
}
public function setSize(?int $size): static
{
$this->size = $size;
return $this;
}
public function getSoftwareProfile(): ?SoftwareProfile
{
return $this->softwareProfile;
@ -182,18 +100,6 @@ class Image extends AbstractEntity
return $this;
}
public function getRepository(): ?\App\Entity\ImageRepository
{
return $this->repository;
}
public function setRepository(?\App\Entity\ImageRepository $repository): static
{
$this->repository = $repository;
return $this;
}
public function getPartitionInfo(): ?string
{
return $this->partitionInfo;
@ -230,42 +136,6 @@ class Image extends AbstractEntity
return $this;
}
public function isCreated(): ?bool
{
return $this->created;
}
public function setCreated(?bool $created): static
{
$this->created = $created;
return $this;
}
public function getImageFullsum(): ?string
{
return $this->imageFullsum;
}
public function setImageFullsum(?string $imageFullsum): static
{
$this->imageFullsum = $imageFullsum;
return $this;
}
public function getStatus(): ?string
{
return $this->status;
}
public function setStatus(string $status): static
{
$this->status = $status;
return $this;
}
public function isGlobal(): ?bool
{
return $this->isGlobal;
@ -277,4 +147,48 @@ class Image extends AbstractEntity
return $this;
}
/**
* @return Collection<int, ImageImageRepository>
*/
public function getImageImageRepositories(): Collection
{
return $this->imageImageRepositories;
}
public function addImageImageRepository(ImageImageRepository $imageImageRepository): static
{
if (!$this->imageImageRepositories->contains($imageImageRepository)) {
$this->imageImageRepositories->add($imageImageRepository);
$imageImageRepository->setImage($this);
}
return $this;
}
public function removeImageImageRepository(ImageImageRepository $imageImageRepository): static
{
if ($this->imageImageRepositories->removeElement($imageImageRepository)) {
// set the owning side to null (unless already changed)
if ($imageImageRepository->getImage() === $this) {
$imageImageRepository->setImage(null);
}
}
return $this;
}
public function containsImageImageRepository(ImageImageRepository $imageImageRepository): bool
{
foreach ($this->imageImageRepositories as $existing) {
if (
$existing->getImage()->getId() === $imageImageRepository->getImage()->getId() &&
$existing->getRepository()->getId() === $imageImageRepository->getRepository()->getId()
) {
return true;
}
}
return false;
}
}

View File

@ -0,0 +1,90 @@
<?php
namespace App\Entity;
use App\Repository\ImageImageRepositoryRepository;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
#[ORM\Entity(repositoryClass: ImageImageRepositoryRepository::class)]
#[ORM\UniqueConstraint(name: 'UNIQ_IDENTIFIER_IMAGE_REPOSITORY', columns: ['image_id', 'repository_id'])]
#[UniqueEntity(fields: ['image', 'repository'], message: 'This image is already associated with this repository')]
class ImageImageRepository extends AbstractEntity
{
#[ORM\ManyToOne(targetEntity: Image::class, cascade: ['persist'], inversedBy: 'imageImageRepositories')]
#[ORM\JoinColumn(nullable: false)]
private ?Image $image = null;
#[ORM\ManyToOne(targetEntity: ImageRepository::class, cascade: ['persist'], inversedBy: 'imageImageRepositories')]
#[ORM\JoinColumn(nullable: false)]
private ?ImageRepository $repository = null;
#[ORM\Column(length: 255)]
private ?string $status = null;
#[ORM\Column(nullable: true)]
private ?bool $created = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $imageFullsum = null;
public function getImage(): ?Image
{
return $this->image;
}
public function setImage(?Image $image): static
{
$this->image = $image;
return $this;
}
public function getRepository(): ?ImageRepository
{
return $this->repository;
}
public function setRepository(?ImageRepository $repository): static
{
$this->repository = $repository;
return $this;
}
public function getStatus(): ?string
{
return $this->status;
}
public function setStatus(string $status): static
{
$this->status = $status;
return $this;
}
public function getCreated(): ?bool
{
return $this->created;
}
public function setCreated(?bool $created): static
{
$this->created = $created;
return $this;
}
public function getImageFullsum(): ?string
{
return $this->imageFullsum;
}
public function setImageFullsum(?string $imageFullsum): static
{
$this->imageFullsum = $imageFullsum;
return $this;
}
}

View File

@ -19,15 +19,15 @@ class ImageRepository extends AbstractEntity
private ?string $comments = null;
/**
* @var Collection<int, Image>
* @var Collection<int, ImageImageRepository>
*/
#[ORM\OneToMany(mappedBy: 'repository', targetEntity: Image::class)]
private Collection $images;
#[ORM\OneToMany(mappedBy: 'repository', targetEntity: ImageImageRepository::class)]
private Collection $imageImageRepositories;
public function __construct()
{
parent::__construct();
$this->images = new ArrayCollection();
$this->imageImageRepositories = new ArrayCollection();
}
public function getIp(): ?string
@ -55,29 +55,29 @@ class ImageRepository extends AbstractEntity
}
/**
* @return Collection<int, Image>
* @return Collection<int, ImageImageRepository>
*/
public function getImages(): Collection
public function getImageImageRepositories(): Collection
{
return $this->images;
return $this->imageImageRepositories;
}
public function addImage(Image $image): static
public function addImageImageRepository(ImageImageRepository $imageImageRepository): static
{
if (!$this->images->contains($image)) {
$this->images->add($image);
$image->setRepository($this);
if (!$this->imageImageRepositories->contains($imageImageRepository)) {
$this->imageImageRepositories->add($imageImageRepository);
$imageImageRepository->setRepository($this);
}
return $this;
}
public function removeImage(Image $image): static
public function removeImageImageRepository(ImageImageRepository $imageImageRepository): static
{
if ($this->images->removeElement($image)) {
if ($this->imageImageRepositories->removeElement($imageImageRepository)) {
// set the owning side to null (unless already changed)
if ($image->getRepository() === $this) {
$image->setRepository(null);
if ($imageImageRepository->getRepository() === $this) {
$imageImageRepository->setRepository(null);
}
}

View File

@ -63,9 +63,6 @@ class NetworkSettings extends AbstractEntity
#[ORM\JoinColumn(nullable: true)]
private ?HardwareProfile $hardwareProfile = null;
#[ORM\Column(nullable: true)]
private ?bool $validation = null;
#[ORM\ManyToOne]
private ?ImageRepository $repository = null;
@ -73,9 +70,6 @@ class NetworkSettings extends AbstractEntity
#[ORM\JoinColumn( onDelete: 'SET NULL')]
private ?OgLive $ogLive = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $ogLog = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $ogShare = null;
@ -293,18 +287,6 @@ class NetworkSettings extends AbstractEntity
return $this;
}
public function getValidation(): ?bool
{
return $this->validation;
}
public function setValidation(?bool $validation): static
{
$this->validation = $validation;
return $this;
}
public function getRepository(): ?ImageRepository
{
return $this->repository;
@ -329,18 +311,6 @@ class NetworkSettings extends AbstractEntity
return $this;
}
public function getOgLog(): ?string
{
return $this->ogLog;
}
public function setOgLog(?string $ogLog): static
{
$this->ogLog = $ogLog;
return $this;
}
public function getOgShare(): ?string
{
return $this->ogShare;

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

@ -97,6 +97,9 @@ class OrganizationalUnit extends AbstractEntity
#[ORM\Column]
private ?bool $reserved = false;
#[ORM\Column(nullable: true)]
private ?bool $excludeParentChanges = null;
public function __construct()
{
parent::__construct();
@ -344,7 +347,6 @@ class OrganizationalUnit extends AbstractEntity
foreach ($this->getClients() as $client) {
$client->setMenu($networkSettings->getMenu());
$client->setHardwareProfile($networkSettings->getHardwareProfile());
$client->setValidation($networkSettings->getValidation());
}
foreach ($this->getOrganizationalUnits() as $childUnit) {
@ -429,4 +431,16 @@ class OrganizationalUnit extends AbstractEntity
return $this;
}
public function isExcludeParentChanges(): ?bool
{
return $this->excludeParentChanges ?? false;
}
public function setExcludeParentChanges(?bool $excludeParentChanges): static
{
$this->excludeParentChanges = $excludeParentChanges;
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)]
#[ORM\JoinColumn(nullable: true, onDelete: 'CASCADE')]
private ?Client $client = null;
#[ORM\Column(length: 255, nullable: true)]
@ -34,6 +34,9 @@ class Trace extends AbstractEntity
#[ORM\Column(type: "json", nullable: true)]
private ?array $input = null;
#[ORM\Column(nullable: true)]
private ?int $progress = null;
public function getClient(): ?Client
{
return $this->client;
@ -129,4 +132,16 @@ class Trace extends AbstractEntity
return $this;
}
public function getProgress(): ?int
{
return $this->progress;
}
public function setProgress(?int $progress): static
{
$this->progress = $progress;
return $this;
}
}

View File

@ -0,0 +1,60 @@
<?php
namespace App\EventSubscriber;
use ApiPlatform\Symfony\EventListener\EventPriorities;
use App\Controller\OgRepository\Image\TransferIsGlobalAction;
use App\Dto\Output\ImageRepositoryOutput;
use App\Dto\Output\OrganizationalUnitOutput;
use App\Entity\Image;
use App\Entity\ImageRepository;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Event\ViewEvent;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
final readonly class ImageRepositorySubscriber implements EventSubscriberInterface
{
public function __construct(
private EntityManagerInterface $entityManager,
private readonly TransferIsGlobalAction $transferIsGlobalAction,
)
{
}
public static function getSubscribedEvents(): array
{
return [
KernelEvents::VIEW => ['transferImages', EventPriorities::POST_WRITE],
];
}
/**
* @throws TransportExceptionInterface
* @throws ServerExceptionInterface
* @throws RedirectionExceptionInterface
* @throws ClientExceptionInterface
*/
public function transferImages(ViewEvent $event): void
{
$imageRepositoryOutput = $event->getControllerResult();
$method = $event->getRequest()->getMethod();
if (!$imageRepositoryOutput instanceof ImageRepositoryOutput ||
$method != Request::METHOD_POST) {
return;
}
$imagesToImport = $this->entityManager->getRepository(Image::class)->findBy(['isGlobal' => true]);
foreach($imagesToImport as $imageToImport) {
$this->transferIsGlobalAction->__invoke([$imageToImport], $imageRepositoryOutput->getEntity());
}
}
}

View File

@ -0,0 +1,100 @@
<?php
namespace App\EventSubscriber;
use ApiPlatform\Symfony\EventListener\EventPriorities;
use App\Controller\OgBoot\PxeBootFile\PostAction;
use App\Dto\Output\OrganizationalUnitOutput;
use App\Entity\NetworkSettings;
use App\Entity\OrganizationalUnit;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Event\ViewEvent;
use Symfony\Component\HttpKernel\KernelEvents;
final readonly class OrganizationalUnitSubscriber implements EventSubscriberInterface
{
public function __construct(
private EntityManagerInterface $entityManager,
)
{
}
public static function getSubscribedEvents(): array
{
return [
KernelEvents::VIEW => ['updateNetworkSettings', EventPriorities::POST_WRITE],
];
}
public function updateNetworkSettings(ViewEvent $event): void
{
$organizationalUnitOutput = $event->getControllerResult();
$method = $event->getRequest()->getMethod();
if (!$organizationalUnitOutput instanceof OrganizationalUnitOutput ||
!in_array($method, [Request::METHOD_POST, Request::METHOD_PUT, Request::METHOD_PATCH])) {
return;
}
/** @var OrganizationalUnit $organizationalUnitEntity */
$organizationalUnitEntity = $organizationalUnitOutput->getEntity();
if ($organizationalUnitEntity->getNetworkSettings() === null || $organizationalUnitEntity->isExcludeParentChanges()) {
return;
}
$newNetworkSettings = $this->buildNetworkSettings($organizationalUnitEntity);
$this->updateChildrenNetworkSettings($organizationalUnitEntity, $newNetworkSettings);
$this->entityManager->flush();
}
private function updateChildrenNetworkSettings(OrganizationalUnit $parentUnit, NetworkSettings $networkSettings): void
{
/** @var OrganizationalUnit $childUnit */
foreach ($parentUnit->getOrganizationalUnits() as $childUnit) {
//var_dump($childUnit->getNetworkSettings()->getMcastPort());
if ($childUnit->isExcludeParentChanges()) {
$childUnit->setNetworkSettings(null);
} else{
$childUnit->setNetworkSettings($networkSettings);
}
$this->entityManager->persist($childUnit);
$this->updateChildrenNetworkSettings($childUnit, $networkSettings);
}
}
private function buildNetworkSettings($organizationalUnitEntity): NetworkSettings
{
if ($organizationalUnitEntity->getNetworkSettings() === null) {
$newNetworkSettings = new NetworkSettings();
} else {
$newNetworkSettings = $organizationalUnitEntity->getNetworkSettings();
}
$newNetworkSettings->setNextServer($organizationalUnitEntity->getNetworkSettings()->getNextServer());
$newNetworkSettings->setBootFileName($organizationalUnitEntity->getNetworkSettings()->getBootFileName());
$newNetworkSettings->setProxy($organizationalUnitEntity->getNetworkSettings()->getProxy());
$newNetworkSettings->setDns($organizationalUnitEntity->getNetworkSettings()->getDns());
$newNetworkSettings->setNetmask($organizationalUnitEntity->getNetworkSettings()->getNetmask());
$newNetworkSettings->setRouter($organizationalUnitEntity->getNetworkSettings()->getRouter());
$newNetworkSettings->setP2pTime($organizationalUnitEntity->getNetworkSettings()->getP2pTime());
$newNetworkSettings->setP2pMode($organizationalUnitEntity->getNetworkSettings()->getP2pMode());
$newNetworkSettings->setMcastMode($organizationalUnitEntity->getNetworkSettings()->getMcastMode());
$newNetworkSettings->setMcastIp($organizationalUnitEntity->getNetworkSettings()->getMcastIp());
$newNetworkSettings->setMcastPort($organizationalUnitEntity->getNetworkSettings()->getMcastPort());
$newNetworkSettings->setMcastSpeed($organizationalUnitEntity->getNetworkSettings()->getMcastSpeed());
$newNetworkSettings->setMenu($organizationalUnitEntity->getNetworkSettings()->getMenu());
$newNetworkSettings->setRepository($organizationalUnitEntity->getNetworkSettings()->getRepository());
$newNetworkSettings->setOgLive($organizationalUnitEntity->getNetworkSettings()->getOgLive());
return $newNetworkSettings;
}
}

View File

@ -35,12 +35,10 @@ final class ImageFactory extends ModelFactory
return [
'createdAt' => self::faker()->dateTime(),
'name' => self::faker()->text(255),
'status' => self::faker()->randomElement(['IN_PROGRESS', 'FINISHED', 'ERROR']),
'softwareProfile' => SoftwareProfileFactory::new(),
'repository' => ImageRepositoryFactory::new(),
'updatedAt' => self::faker()->dateTime(),
'remotePc' => self::faker()->boolean(),
'isGlobal' => self::faker()->boolean(),
'isGlobal' => false,
];
}

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

@ -0,0 +1,43 @@
<?php
namespace App\Filter;
use ApiPlatform\Doctrine\Orm\Filter\AbstractFilter;
use ApiPlatform\Doctrine\Orm\Util\QueryNameGeneratorInterface;
use ApiPlatform\Metadata\Operation;
use Symfony\Component\PropertyInfo\Type;
use Doctrine\ORM\QueryBuilder;
class ImageSearchRepositoryFilter extends AbstractFilter
{
protected function filterProperty(string $property, $value, QueryBuilder $queryBuilder, QueryNameGeneratorInterface $queryNameGenerator, string $resourceClass, ?Operation $operation = null, array $context = []): void
{
if ($property !== 'repositoryId') {
return;
}
if (null === $value || '' === $value || 'undefined' === $value) {
return;
}
$alias = $queryBuilder->getRootAliases()[0];
$joinAlias = $queryNameGenerator->generateJoinAlias('repositoryId');
$queryBuilder
->innerJoin(sprintf('%s.repositories', $alias), $joinAlias)
->andWhere(sprintf('%s.id = :repositoryId', $joinAlias))
->setParameter('repositoryId', $value);
}
public function getDescription(string $resourceClass): array
{
return [
'repositoryId' => [
'property' => 'repositoryId',
'type' => Type::BUILTIN_TYPE_INT,
'required' => false,
'description' => 'Filter images by repository ID.',
],
];
}
}

View File

@ -0,0 +1,51 @@
<?php
namespace App\Filter;
use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\QueryBuilder;
use ApiPlatform\Doctrine\Orm\Filter\AbstractFilter;
use ApiPlatform\Metadata\Operation;
use ApiPlatform\Doctrine\Orm\Util\QueryNameGeneratorInterface;
use Symfony\Component\PropertyInfo\Type;
class NotEqualIdFilter extends AbstractFilter
{
protected function filterProperty(string $property, $value, QueryBuilder $queryBuilder, QueryNameGeneratorInterface $queryNameGenerator, string $resourceClass, ?Operation $operation = null, array $context = []): void
{
if ($property !== 'id') {
return;
}
if (is_array($value) && isset($value['neq'])) {
$value = $value['neq'];
}
if (is_string($value)) {
$value = array_map('intval', explode(',', $value));
}
if (!is_array($value) || empty($value)) {
return;
}
$alias = $queryBuilder->getRootAliases()[0];
$paramName = $queryNameGenerator->generateParameterName('id');
$queryBuilder
->andWhere(sprintf('%s.%s NOT IN (:%s)', $alias, $property, $paramName))
->setParameter($paramName, $value);
}
public function getDescription(string $resourceClass): array
{
return [
'id[neq]' => [
'property' => 'id',
'type' => Type::BUILTIN_TYPE_INT,
'required' => false,
'description' => 'Exclude records where id is in the given list.',
],
];
}
}

View File

@ -10,6 +10,7 @@ final class CommandTypes
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 TRANSFER_IMAGE = 'transfer-image';
public const string POWER_ON = 'power-on';
public const string REBOOT = 'reboot';
public const string SHUTDOWN = 'shutdown';
@ -17,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',
@ -30,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

@ -10,7 +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';
public const string TRANSFERRING = 'transferring';
private const array STATUS = [
self::PENDING => 'Pendiente',
@ -19,7 +19,7 @@ final class ImageStatus
self::TRASH => 'Papelera',
self::SUCCESS => 'Completado',
self::FAILED => 'Fallido',
self::TRANSFERING => 'Transferiendo',
self::TRANSFERRING => 'Transferiendo',
];
public static function getStatus(): array

View File

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

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;
}
}

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\ImageImageRepositoryInput;
use App\Dto\Output\ImageImageRepositoryOutput;
use App\Repository\ImageImageRepositoryRepository;
readonly class ImageImageRepositoryProcessor implements ProcessorInterface
{
public function __construct(
private ImageImageRepositoryRepository $imageRepository,
private ValidatorInterface $validator,
)
{
}
/**
* @throws \Exception
*/
public function process(mixed $data, Operation $operation, array $uriVariables = [], array $context = []): ImageImageRepositoryOutput|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 = []): ImageImageRepositoryOutput
{
if (!($data instanceof ImageImageRepositoryInput)) {
throw new \Exception(sprintf('data is not instance of %s', ImageImageRepositoryInput::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 ImageImageRepositoryOutput($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

@ -10,22 +10,31 @@ use ApiPlatform\Metadata\Put;
use ApiPlatform\State\ProcessorInterface;
use ApiPlatform\Validator\ValidatorInterface;
use App\Controller\OgAgent\CreateImageAction;
use App\Controller\OgRepository\Image\TransferAction;
use App\Controller\OgRepository\Image\TransferIsGlobalAction;
use App\Dto\Input\ImageInput;
use App\Dto\Input\ImageRepositoryInput;
use App\Dto\Output\ImageOutput;
use App\Entity\ImageImageRepository;
use App\Repository\ImageRepository;
use App\Repository\ImageRepositoryRepository as ImageRepositoryRepository;
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
readonly class ImageProcessor implements ProcessorInterface
{
public function __construct(
private ImageRepository $imageRepository,
private ValidatorInterface $validator,
private CreateImageAction $createImageActionController
private ImageRepositoryRepository $imageRepositoryRepository,
private ImageRepository $imageRepository,
private ValidatorInterface $validator,
private CreateImageAction $createImageActionController,
private TransferIsGlobalAction $transferActionController
)
{
}
/**
* @throws \Exception
* @throws TransportExceptionInterface
*/
public function process(mixed $data, Operation $operation, array $uriVariables = [], array $context = []): ImageOutput|null
{
@ -41,6 +50,7 @@ readonly class ImageProcessor implements ProcessorInterface
/**
* @throws \Exception
* @throws TransportExceptionInterface
*/
private function processCreateOrUpdate($data, Operation $operation, array $uriVariables = [], array $context = []): ImageOutput
{
@ -58,6 +68,11 @@ readonly class ImageProcessor implements ProcessorInterface
if ($data->source !== 'input') {
$response = $this->createImageActionController->__invoke($image);
} else {
if ($data->isGlobal === true) {
$repositories = $this->imageRepositoryRepository->findAll();
$this->transferActionController->__invoke($repositories, $image);
}
}
$this->imageRepository->save($image);

View File

@ -0,0 +1,56 @@
<?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\Output\ImageImageRepositoryOutput;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
readonly class ImageImageRepositoryProvider 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 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 ImageImageRepositoryOutput($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 ImageImageRepositoryOutput($item);
}
}

View File

@ -9,17 +9,23 @@ use ApiPlatform\Metadata\Patch;
use ApiPlatform\Metadata\Put;
use ApiPlatform\State\Pagination\TraversablePaginator;
use ApiPlatform\State\ProviderInterface;
use App\Controller\OgRepository\StatusAction;
use App\Dto\Input\ImageInput;
use App\Dto\Input\ImageRepositoryInput;
use App\Dto\Output\ImageOutput;
use App\Dto\Output\ImageRepositoryOutput;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
readonly class ImageRepositoryProvider implements ProviderInterface
{
public function __construct(
private ProviderInterface $collectionProvider,
private ProviderInterface $itemProvider
private ProviderInterface $collectionProvider,
private ProviderInterface $itemProvider,
private StatusAction $statusAction
)
{
}
@ -37,13 +43,23 @@ readonly class ImageRepositoryProvider implements ProviderInterface
}
}
/**
* @throws TransportExceptionInterface
* @throws ServerExceptionInterface
* @throws RedirectionExceptionInterface
* @throws ClientExceptionInterface
*/
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 ImageRepositoryOutput($item);
$statusResponse = $this->statusAction->__invoke($item);
$content = json_decode($statusResponse->getContent(), true);
$status = !isset($content['error']);
$items[] = new ImageRepositoryOutput($item, $status);
}
return new TraversablePaginator($items, $paginator->getCurrentPage(), $paginator->getItemsPerPage(), $paginator->getTotalItems());

View File

@ -55,6 +55,7 @@ class ImageTest extends AbstractTest
]);
}
/**
* @throws RedirectionExceptionInterface
* @throws DecodingExceptionInterface
@ -69,15 +70,12 @@ class ImageTest extends AbstractTest
SoftwareProfileFactory::createOne(['description' => self::SOFTWARE_PROFILE]);
$swPIri = $this->findIriBy(SoftwareProfile::class, ['description' => self::SOFTWARE_PROFILE]);
ImageRepositoryFactory::createOne(['name' => 'repository-test']);
$irIri = $this->findIriBy(ImageRepository::class, ['name' => 'repository-test']);
$imageRepositories = ImageRepositoryFactory::createMany(5);
$this->createClientWithCredentials()->request('POST', '/images',['json' => [
'name' => self::IMAGE_CREATE,
'size' => 123,
'path' => '/path/to/image',
'softwareProfile' => $swPIri,
'imageRepository' => $irIri
'imageRepositories' => array_map(fn($repo) => '/image-repositories/'. $repo->getUuid(), $imageRepositories)
]]);
$this->assertResponseStatusCodeSame(201);
@ -89,6 +87,7 @@ class ImageTest extends AbstractTest
]);
}
/**
* @throws RedirectionExceptionInterface
* @throws DecodingExceptionInterface
@ -103,8 +102,11 @@ class ImageTest extends AbstractTest
ImageFactory::createOne(['name' => self::IMAGE_CREATE]);
$iri = $this->findIriBy(Image::class, ['name' => self::IMAGE_CREATE]);
$imageRepositories = ImageRepositoryFactory::createMany(5);
$this->createClientWithCredentials()->request('PUT', $iri, ['json' => [
'name' => self::IMAGE_UPDATE,
'imageRepositories' => array_map(fn($repo) => '/image-repositories/'. $repo->getUuid(), $imageRepositories)
]]);
$this->assertResponseIsSuccessful();