Merge OGBoot branch
testing/ogcore-api/pipeline/head There was a failure building this commit Details

develop-jenkins
Manuel Aranda Rosales 2024-09-30 11:22:30 +02:00
commit 4cfa700e91
57 changed files with 1345 additions and 604 deletions

2
.env
View File

@ -24,7 +24,7 @@ APP_SECRET=e95c7f17da15ce1b03d77ad655379c34
# IMPORTANT: You MUST configure your server version, either here or in config/packages/doctrine.yaml
#
# DATABASE_URL="sqlite:///%kernel.project_dir%/var/data.db"
# DATABASE_URL="mysql://app:!ChangeMe!@127.0.0.1:3306/app?serverVersion=8.0.32&charset=utf8mb4"
#DATABASE_URL="mysql://root:root@127.0.0.1:3336/dimio?serverVersion=8.0.32&charset=utf8mb4"
DATABASE_URL="mysql://root:root@ogcore-database:3306/ogcore?serverVersion=10.11.2-MariaDB&charset=utf8mb4"
OG_1_DATABASE_URL="mysql://root:root@ogcore-database:3306/ogcore_old_og?serverVersion=10.11.2-MariaDB&charset=utf8mb4"

View File

@ -7,7 +7,7 @@
"php": ">=8.1",
"ext-ctype": "*",
"ext-iconv": "*",
"api-platform/core": "^3.3",
"api-platform/core": "^3.2",
"doctrine/dbal": "^3",
"doctrine/doctrine-bundle": "^2.12",
"doctrine/doctrine-migrations-bundle": "^3.3",

624
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -13,7 +13,7 @@ resources:
filters:
- 'api_platform.filter.client.order'
- 'api_platform.filter.client.search'
- 'api_platform.filter.client.boolean'
ApiPlatform\Metadata\Get:
provider: App\State\Provider\ClientProvider
ApiPlatform\Metadata\Put:

View File

@ -13,6 +13,7 @@ resources:
filters:
- 'api_platform.filter.og_live.order'
- 'api_platform.filter.og_live.search'
- 'api_platform.filter.og_live.boolean'
ApiPlatform\Metadata\Get:
provider: App\State\Provider\OgLiveProvider
@ -23,7 +24,14 @@ resources:
ApiPlatform\Metadata\Post: ~
ApiPlatform\Metadata\Delete: ~
get_collection:
sync:
class: ApiPlatform\Metadata\Post
method: POST
input: false
uriTemplate: /og-lives/sync
controller: App\Controller\OgBoot\OgLive\SyncAction
get_collection_oglives:
shortName: OgLive Server
description: Get collection of OgLive
class: ApiPlatform\Metadata\GetCollection
@ -32,7 +40,7 @@ resources:
uriTemplate: /og-lives/server/get-collection
controller: App\Controller\OgBoot\OgLive\GetCollectionAction
get:
get_oglive:
shortName: OgLive Server
description: Get OgLive
class: ApiPlatform\Metadata\Get
@ -80,8 +88,8 @@ resources:
uninstall:
shortName: OgLive Server
description: Uninstall OgLive
class: ApiPlatform\Metadata\Get
method: GET
class: ApiPlatform\Metadata\Post
method: POST
input: false
uriTemplate: /og-lives/server/{uuid}/uninstall
controller: App\Controller\OgBoot\OgLive\UninstallAction

View File

@ -13,6 +13,7 @@ resources:
filters:
- 'api_platform.filter.organizational_unit.order'
- 'api_platform.filter.organizational_unit.search'
ApiPlatform\Metadata\Get:
security: 'is_granted("ORGANIZATIONAL_UNIT_VIEW", object)'
provider: App\State\Provider\OrganizationalUnitProvider

View File

@ -15,14 +15,23 @@ resources:
- 'api_platform.filter.pxe_boot_file.search'
ApiPlatform\Metadata\Get:
provider: App\State\Provider\PxeTemplateProvider
provider: App\State\Provider\PxeBootFileProvider
ApiPlatform\Metadata\Put:
provider: App\State\Provider\PxeTemplateProvider
provider: App\State\Provider\PxeBootFileProvider
ApiPlatform\Metadata\Patch:
provider: App\State\Provider\PxeTemplateProvider
provider: App\State\Provider\PxeBootFileProvider
ApiPlatform\Metadata\Post: ~
ApiPlatform\Metadata\Delete: ~
get_all:
shortName: PxeBootFile Server
description: Get collection of PxeBootFile
class: ApiPlatform\Metadata\GetCollection
method: GET
input: false
uriTemplate: /pxe-boot-files/server/get-collection
controller: App\Controller\OgBoot\PxeBootFile\GetCollectionAction
properties:
App\Entity\PxeBootFile:
id:

View File

@ -13,6 +13,7 @@ resources:
filters:
- 'api_platform.filter.pxe_template.order'
- 'api_platform.filter.pxe_template.search'
- 'api_platform.filter.pxe_template.boolean'
ApiPlatform\Metadata\Get:
provider: App\State\Provider\PxeTemplateProvider

View File

@ -2,39 +2,20 @@ api_platform:
title: 'OgCore Api'
description: 'Api Documentation for OgCore'
version: 1.0.0
path_segment_name_generator: 'api_platform.path_segment_name_generator.dash'
path_segment_name_generator: api_platform.path_segment_name_generator.dash
defaults:
pagination_client_items_per_page: true
collection:
pagination:
items_per_page_parameter_name: 'itemsPerPage'
formats:
jsonld: [ 'application/ld+json' ]
jsonhal: [ 'application/hal+json' ]
jsonapi: [ 'application/vnd.api+json' ]
json: [ 'application/json' ]
xml: [ 'application/xml', 'text/xml' ]
yaml: [ 'application/x-yaml' ]
csv: [ 'text/csv' ]
html: [ 'text/html' ]
json: [ 'application/json' ]
csv: [ 'text/csv' ]
patch_formats:
jsonld: ['application/ld+json', 'application/json']
mapping:
paths: ['%kernel.project_dir%/config/api_platform', '%kernel.project_dir%/src/Dto']
use_symfony_listeners: true
collection:
pagination:
items_per_page_parameter_name: 'itemsPerPage'
defaults:
pagination_client_items_per_page: true
denormalization_context:
allow_extra_attributes: false
cache_headers:
vary: [ 'Content-Type', 'Authorization', 'Origin' ]
extra_properties:
standard_put: true
rfc_7807_compliant_errors: true
event_listeners_backward_compatibility_layer: false
keep_legacy_inflector: true
docs_formats:
jsonld: ['application/ld+json']
jsonopenapi: ['application/vnd.openapi+json']
html: ['text/html']
swagger:
versions: [3]
api_keys:

View File

@ -30,6 +30,7 @@ security:
- { path: ^/docs, roles: PUBLIC_ACCESS } # Allows accessing the Swagger UI docs
- { path: ^/auth/login, roles: PUBLIC_ACCESS }
- { path: ^/opengnsys/rest/, roles: PUBLIC_ACCESS }
- { path: ^/og-lives/install/webhook, roles: PUBLIC_ACCESS }
- { path: ^/auth/refresh, roles: PUBLIC_ACCESS }
- { path: ^/, roles: IS_AUTHENTICATED_FULLY }

View File

@ -8,6 +8,7 @@ services:
api_platform.filter.client.search:
parent: 'api_platform.doctrine.orm.search_filter'
<<<<<<< HEAD
arguments: [ { 'id': 'exact', 'name': 'partial', 'serialNumber': 'exact', organizationalUnit.id: 'exact', mac: 'exact', ip: 'exact' } ]
tags: [ 'api_platform.filter' ]
@ -26,6 +27,9 @@ services:
api_platform.filter.command.boolean:
parent: 'api_platform.doctrine.orm.boolean_filter'
arguments: [ { 'enabled': ~ } ]
=======
arguments: [ { 'id': 'exact', 'name': 'partial', 'serialNumber': 'exact', organizationalUnit.id: 'exact', 'ip': exact, 'mac': exact } ]
>>>>>>> feature/integration-ogboot
tags: [ 'api_platform.filter' ]
api_platform.filter.hardware.order:
@ -35,6 +39,23 @@ services:
$orderParameterName: 'order'
tags: [ 'api_platform.filter' ]
api_platform.filter.og_live.order:
parent: 'api_platform.doctrine.orm.order_filter'
arguments:
$properties: { 'id': ~, 'name': ~ }
$orderParameterName: 'order'
tags: [ 'api_platform.filter' ]
api_platform.filter.og_live.search:
parent: 'api_platform.doctrine.orm.search_filter'
arguments: [ { 'id': 'exact', 'name': 'partial', } ]
tags: [ 'api_platform.filter' ]
api_platform.filter.og_live.boolean:
parent: 'api_platform.doctrine.orm.boolean_filter'
arguments: [ { 'isDefault': ~, 'installed': ~ } ]
tags: [ 'api_platform.filter' ]
api_platform.filter.hardware.search:
parent: 'api_platform.doctrine.orm.search_filter'
arguments: [ { 'id': 'exact', 'name': 'partial' } ]
@ -76,6 +97,28 @@ services:
arguments: [ { 'id': 'exact', 'usage': 'exact', 'diskNumber': 'exact' } ]
tags: [ 'api_platform.filter' ]
api_platform.filter.pxe_template.order:
parent: 'api_platform.doctrine.orm.order_filter'
arguments:
$properties: { 'id': ~, 'name': ~ }
$orderParameterName: 'order'
tags: [ 'api_platform.filter' ]
api_platform.filter.pxe_boot_file.search:
parent: 'api_platform.doctrine.orm.search_filter'
arguments: [ { 'id': 'exact', 'template': exact } ]
tags: [ 'api_platform.filter' ]
api_platform.filter.pxe_template.search:
parent: 'api_platform.doctrine.orm.search_filter'
arguments: [ { 'id': 'exact', 'name': 'partial', } ]
tags: [ 'api_platform.filter' ]
api_platform.filter.pxe_template.boolean:
parent: 'api_platform.doctrine.orm.boolean_filter'
arguments: [ { 'synchronized': ~ } ]
tags: [ 'api_platform.filter' ]
api_platform.filter.user.order:
parent: 'api_platform.doctrine.orm.order_filter'
arguments:

View File

@ -2,19 +2,19 @@ server {
listen 80;
server_name localhost;
root /var/www/html/public;
index index.html index.php;
location / {
try_files $uri /index.php?$is_args$args;
location / {
try_files $uri $uri/ /index.php?$args;
}
location ~ ^/index.php(/|$) {
location ~ \.php$ {
include fastcgi_params;
fastcgi_pass php:9000;
fastcgi_split_path_info ^(.+\.php)(/.*)$;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_param DOCUMENT_ROOT $document_root;
internal;
fastcgi_param PATH_TRANSLATED $document_root$fastcgi_script_name;
}
location ~ \.php$ {

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 Version20240814130427 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 pxe_template CHANGE template_content template_content TINYTEXT NOT NULL');
}
public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE pxe_template CHANGE template_content template_content 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 Version20240819062421 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 synchronized TINYINT(1) DEFAULT NULL');
$this->addSql('ALTER TABLE pxe_template ADD synchronized 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 og_live DROP synchronized');
$this->addSql('ALTER TABLE pxe_template DROP synchronized');
}
}

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 Version20240819140045 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 `default` TINYINT(1) DEFAULT NULL');
$this->addSql('ALTER TABLE pxe_boot_file ADD synchronized 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 og_live DROP `default`');
$this->addSql('ALTER TABLE pxe_boot_file DROP synchronized');
}
}

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 Version20240820063513 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 client ADD og_live_id INT DEFAULT NULL');
$this->addSql('ALTER TABLE client ADD CONSTRAINT FK_C7440455F7E54CF3 FOREIGN KEY (og_live_id) REFERENCES og_live (id)');
$this->addSql('CREATE INDEX IDX_C7440455F7E54CF3 ON client (og_live_id)');
$this->addSql('ALTER TABLE network_settings ADD og_live_id INT DEFAULT NULL');
$this->addSql('ALTER TABLE network_settings ADD CONSTRAINT FK_48869B54F7E54CF3 FOREIGN KEY (og_live_id) REFERENCES og_live (id)');
$this->addSql('CREATE INDEX IDX_48869B54F7E54CF3 ON network_settings (og_live_id)');
}
public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE network_settings DROP FOREIGN KEY FK_48869B54F7E54CF3');
$this->addSql('DROP INDEX IDX_48869B54F7E54CF3 ON network_settings');
$this->addSql('ALTER TABLE network_settings DROP og_live_id');
$this->addSql('ALTER TABLE client DROP FOREIGN KEY FK_C7440455F7E54CF3');
$this->addSql('DROP INDEX IDX_C7440455F7E54CF3 ON client');
$this->addSql('ALTER TABLE client DROP og_live_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 Version20240820064106 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 `default` is_default 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 og_live CHANGE is_default `default` TINYINT(1) 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 Version20240821065158 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 pxe_template CHANGE template_content template_content LONGTEXT NOT NULL');
}
public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE pxe_template CHANGE template_content template_content TINYTEXT NOT NULL');
}
}

View File

@ -0,0 +1,32 @@
<?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 Version20240905080435 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 status 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 status');
}
}

View File

@ -0,0 +1,56 @@
<?php
declare(strict_types=1);
namespace App\Controller\OgBoot;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Attribute\AsController;
use Symfony\Component\HttpKernel\Exception\HttpException;
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]
abstract class AbstractOgBootController extends AbstractController
{
public function __construct(
protected readonly string $ogBootApiUrl,
protected readonly EntityManagerInterface $entityManager
)
{
}
/**
* @throws TransportExceptionInterface
* @throws ServerExceptionInterface
* @throws RedirectionExceptionInterface
* @throws ClientExceptionInterface
*/
public function createRequest (HttpClientInterface $httpClient, string $method, string $url, array $params = []): JsonResponse|array
{
$params = array_merge($params, [
'headers' => [
'accept' => 'application/json',
'Content-Type' => 'application/json'
],
]);
try {
$response = $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);
throw new HttpException($response->getStatusCode(), $content['error'] ?? 'An error occurred');
} catch (TransportExceptionInterface $e) {
throw new HttpException(Response::HTTP_INTERNAL_SERVER_ERROR, $e->getMessage());
}
}
}

View File

@ -1,20 +0,0 @@
<?php
declare(strict_types=1);
namespace App\Controller\OgBoot;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpKernel\Attribute\AsController;
#[AsController]
abstract class AbstractOgLiveController extends AbstractController
{
public function __construct(
protected readonly string $ogBootApiUrl,
protected readonly EntityManagerInterface $entityManager
)
{
}
}

View File

@ -2,11 +2,12 @@
namespace App\Controller\OgBoot\OgLive;
use App\Controller\OgBoot\AbstractOgLiveController;
use App\Controller\OgBoot\AbstractOgBootController;
use App\Entity\OgLive;
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;
@ -14,7 +15,7 @@ use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
use Symfony\Contracts\HttpClient\HttpClientInterface;
#[AsController]
class GetAction extends AbstractOgLiveController
class GetAction extends AbstractOgBootController
{
/**
* @throws TransportExceptionInterface
@ -24,18 +25,12 @@ class GetAction extends AbstractOgLiveController
*/
public function __invoke(OgLive $data, HttpClientInterface $httpClient): JsonResponse
{
try {
$response = $httpClient->request('GET', $this->ogBootApiUrl.'/ogboot/v1/oglives/'.$data->getChecksum(), [
'headers' => [
'accept' => 'application/json',
],
]);
} catch (TransportExceptionInterface $e) {
return new JsonResponse( data: 'An error occurred', status: Response::HTTP_INTERNAL_SERVER_ERROR);
if (!$data->getChecksum()) {
throw new ValidatorException('Checksum is required');
}
$data = json_decode($response->getContent(), true);
$content = $this->createRequest($httpClient, 'GET', $this->ogBootApiUrl.'/ogboot/v1/oglives/'.$data->getChecksum());
return new JsonResponse( data: $data, status: Response::HTTP_OK);
return new JsonResponse(data: $content, status: Response::HTTP_OK);
}
}

View File

@ -2,10 +2,11 @@
namespace App\Controller\OgBoot\OgLive;
use App\Controller\OgBoot\AbstractOgLiveController;
use App\Controller\OgBoot\AbstractOgBootController;
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;
@ -13,7 +14,7 @@ use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
use Symfony\Contracts\HttpClient\HttpClientInterface;
#[AsController]
class GetCollectionAction extends AbstractOgLiveController
class GetCollectionAction extends AbstractOgBootController
{
/**
* @throws TransportExceptionInterface
@ -23,18 +24,8 @@ class GetCollectionAction extends AbstractOgLiveController
*/
public function __invoke(HttpClientInterface $httpClient): JsonResponse
{
try {
$response = $httpClient->request('GET', $this->ogBootApiUrl.'/ogboot/v1/oglives', [
'headers' => [
'accept' => 'application/json',
],
]);
} catch (TransportExceptionInterface $e) {
return new JsonResponse( data: 'An error occurred', status: Response::HTTP_INTERNAL_SERVER_ERROR);
}
$content = $this->createRequest($httpClient, 'GET', $this->ogBootApiUrl.'/ogboot/v1/oglives');
$data = json_decode($response->getContent(), true);
return new JsonResponse( data: $data, status: Response::HTTP_OK);
return new JsonResponse(data: $content, status: Response::HTTP_OK);
}
}

View File

@ -2,7 +2,7 @@
namespace App\Controller\OgBoot\OgLive;
use App\Controller\OgBoot\AbstractOgLiveController;
use App\Controller\OgBoot\AbstractOgBootController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Attribute\AsController;
@ -13,7 +13,7 @@ use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
use Symfony\Contracts\HttpClient\HttpClientInterface;
#[AsController]
class GetDefaultAction extends AbstractOgLiveController
class GetDefaultAction extends AbstractOgBootController
{
/**
* @throws TransportExceptionInterface
@ -23,18 +23,8 @@ class GetDefaultAction extends AbstractOgLiveController
*/
public function __invoke(HttpClientInterface $httpClient): JsonResponse
{
try {
$response = $httpClient->request('GET', $this->ogBootApiUrl.'/ogboot/v1/oglives/default', [
'headers' => [
'accept' => 'application/json',
],
]);
} catch (TransportExceptionInterface $e) {
return new JsonResponse( data: 'An error occurred', status: Response::HTTP_INTERNAL_SERVER_ERROR);
}
$content = $this->createRequest($httpClient, 'GET', $this->ogBootApiUrl.'/ogboot/v1/oglives/default');
$data = json_decode($response->getContent(), true);
return new JsonResponse( data: $data, status: Response::HTTP_OK);
return new JsonResponse(status: Response::HTTP_OK);
}
}

View File

@ -2,7 +2,7 @@
namespace App\Controller\OgBoot\OgLive;
use App\Controller\OgBoot\AbstractOgLiveController;
use App\Controller\OgBoot\AbstractOgBootController;
use App\Entity\OgLive;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
@ -14,7 +14,7 @@ use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
use Symfony\Contracts\HttpClient\HttpClientInterface;
#[AsController]
class GetIsosAction extends AbstractOgLiveController
class GetIsosAction extends AbstractOgBootController
{
/**
* @throws TransportExceptionInterface
@ -24,49 +24,8 @@ class GetIsosAction extends AbstractOgLiveController
*/
public function __invoke(HttpClientInterface $httpClient): JsonResponse
{
$ogLivesInserted = 0;
$content = $this->createRequest($httpClient, 'GET', $this->ogBootApiUrl.'/ogboot/v1/oglives/isos');
try {
$response = $httpClient->request('GET', $this->ogBootApiUrl.'/ogboot/v1/oglives/isos', [
'headers' => [
'accept' => 'application/json',
],
]);
} catch (TransportExceptionInterface $e) {
return new JsonResponse( data: 'An error occurred', status: Response::HTTP_INTERNAL_SERVER_ERROR);
}
$data = json_decode($response->getContent(), true);
if (!empty($data['downloads'])) {
$ogLivesInserted = $this->insertOglives($data);
}
return new JsonResponse( data: [ 'data' => $data, 'ogLivesInserted' => $ogLivesInserted], status: Response::HTTP_OK);
}
public function insertOglives(array $data): int
{
$count = 0;
foreach ($data['downloads'] as $ogLive ) {
$ogLiveEntity = $this->entityManager->getRepository(OgLive::class)->findOneBy(['name' => $ogLive['filename']]);
if ($ogLiveEntity) {
continue;
}
$ogLiveEntity = new OgLive();
$ogLiveEntity->setName($ogLive['filename']);
$ogLiveEntity->setInstalled($ogLive['installed']);
$ogLiveEntity->setFilename($ogLive['filename']);
$this->entityManager->persist($ogLiveEntity);
$count++;
}
$this->entityManager->flush();
return $count;
return new JsonResponse(data: $content, status: Response::HTTP_OK);
}
}

View File

@ -2,11 +2,14 @@
namespace App\Controller\OgBoot\OgLive;
use App\Controller\OgBoot\AbstractOgLiveController;
use App\Controller\OgBoot\AbstractOgBootController;
use App\Entity\OgLive;
use App\Model\OgLiveStatus;
use Doctrine\ORM\EntityManagerInterface;
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;
@ -14,7 +17,7 @@ use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
use Symfony\Contracts\HttpClient\HttpClientInterface;
#[AsController]
class InstallAction extends AbstractOgLiveController
class InstallAction extends AbstractOgBootController
{
/**
* @throws TransportExceptionInterface
@ -22,24 +25,25 @@ class InstallAction extends AbstractOgLiveController
* @throws RedirectionExceptionInterface
* @throws ClientExceptionInterface
*/
public function __invoke(OgLive $data, HttpClientInterface $httpClient): JsonResponse
public function __invoke(OgLive $data, HttpClientInterface $httpClient, EntityManagerInterface $entityManager): JsonResponse
{
try {
$response = $httpClient->request('POST', $this->ogBootApiUrl.'/ogboot/v1/oglives/install', [
'headers' => [
'accept' => 'application/json',
'Content-Type' => 'application/json',
],
'json' => [
'isoname' => $data->getName()
]
]);
} catch (TransportExceptionInterface $e) {
return new JsonResponse( data: 'An error occurred', status: Response::HTTP_INTERNAL_SERVER_ERROR);
if (!$data->getDownloadUrl()) {
throw new ValidatorException('Download URL is required');
}
$data = json_decode($response->getContent(), true);
$params = [
'json' => [
'url' => $data->getDownloadUrl(),
'id' => $data->getUuid()
]
];
return new JsonResponse( data: $data, status: Response::HTTP_OK);
$content = $this->createRequest($httpClient, 'POST', $this->ogBootApiUrl.'/ogboot/v1/oglives/install', $params);
$data->setStatus(OgLiveStatus::PENDING);
$entityManager->persist($data);
$entityManager->flush();
return new JsonResponse(data: $content, status: Response::HTTP_OK);
}
}

View File

@ -2,11 +2,13 @@
namespace App\Controller\OgBoot\OgLive;
use App\Controller\OgBoot\AbstractOgLiveController;
use App\Controller\OgBoot\AbstractOgBootController;
use App\Entity\OgLive;
use Doctrine\ORM\EntityManagerInterface;
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;
@ -14,7 +16,7 @@ use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
use Symfony\Contracts\HttpClient\HttpClientInterface;
#[AsController]
class SetDefaultAction extends AbstractOgLiveController
class SetDefaultAction extends AbstractOgBootController
{
/**
* @throws TransportExceptionInterface
@ -22,23 +24,24 @@ class SetDefaultAction extends AbstractOgLiveController
* @throws RedirectionExceptionInterface
* @throws ClientExceptionInterface
*/
public function __invoke(OgLive $data, HttpClientInterface $httpClient): JsonResponse
public function __invoke(OgLive $data, HttpClientInterface $httpClient, EntityManagerInterface $entityManager): JsonResponse
{
try {
$response = $httpClient->request('POST', $this->ogBootApiUrl.'/ogboot/v1/oglives/default', [
'headers' => [
'accept' => 'application/json',
],
'json' => [
'checksum' => $data->getChecksum()
]
]);
} catch (TransportExceptionInterface $e) {
return new JsonResponse( data: 'An error occurred', status: Response::HTTP_INTERNAL_SERVER_ERROR);
if (!$data->getChecksum()) {
throw new ValidatorException('Checksum URL is required');
}
$data = json_decode($response->getContent(), true);
$params = [
'json' => [
'checksum' => $data->getChecksum()
]
];
return new JsonResponse( data: $data, status: Response::HTTP_OK);
$content = $this->createRequest($httpClient, 'PUT', $this->ogBootApiUrl.'/ogboot/v1/oglives/default', $params);
$data->setIsDefault(true);
$entityManager->persist($data);
$entityManager->flush();
return new JsonResponse(status: Response::HTTP_OK);
}
}

View File

@ -0,0 +1,80 @@
<?php
namespace App\Controller\OgBoot\OgLive;
use App\Controller\OgBoot\AbstractOgBootController;
use App\Entity\OgLive;
use App\Model\OgLiveStatus;
use Doctrine\ORM\EntityManagerInterface;
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;
use Symfony\Contracts\HttpClient\HttpClientInterface;
#[AsController]
class SyncAction extends AbstractOgBootController
{
/**
* @throws TransportExceptionInterface
* @throws ServerExceptionInterface
* @throws RedirectionExceptionInterface
* @throws ClientExceptionInterface
*/
public function __invoke(HttpClientInterface $httpClient, EntityManagerInterface $entityManager): JsonResponse
{
$content = $this->createRequest($httpClient, 'GET', $this->ogBootApiUrl . '/ogboot/v1/oglives');
foreach ($content['installed_ogLives'] as $ogLive) {
$ogLiveEntity = $this->entityManager->getRepository(OgLive::class)->findOneBy(['checksum' => $ogLive['id']]);
if ($ogLiveEntity) {
$this->extracted($ogLiveEntity, $ogLive);
$this->entityManager->persist($ogLiveEntity);
} else {
$ogLiveEntity = new OgLive();
$this->extracted($ogLiveEntity, $ogLive);
}
$this->entityManager->persist($ogLiveEntity);
}
$this->entityManager->flush();
$this->serDefaultOgLive($content['default_oglive']);
return new JsonResponse(data: $content, status: Response::HTTP_OK);
}
/**
* @param OgLive|null $ogLiveEntity
* @param mixed $ogLive
* @return void
*/
private function extracted(OgLive|null $ogLiveEntity, mixed $ogLive): void
{
$ogLiveEntity->setName($ogLive['filename']);
$ogLiveEntity->setInstalled(true);
$ogLiveEntity->setArchitecture($ogLive['architecture']);
$ogLiveEntity->setDistribution($ogLive['distribution']);
$ogLiveEntity->setFilename($ogLive['filename']);
$ogLiveEntity->setKernel($ogLive['kernel']);
$ogLiveEntity->setRevision($ogLive['revision']);
$ogLiveEntity->setDirectory($ogLive['directory']);
$ogLiveEntity->setChecksum($ogLive['id']);
$ogLiveEntity->setStatus(OgLiveStatus::ACTIVE);
}
private function serDefaultOgLive(string $defaultOgLive): void
{
$ogLiveEntity = $this->entityManager->getRepository(OgLive::class)->findOneBy(['name' => $defaultOgLive]);
if (!$ogLiveEntity) {
return;
}
$ogLiveEntity->setIsDefault(true);
$this->entityManager->persist($ogLiveEntity);
$this->entityManager->flush();
}
}

View File

@ -2,11 +2,14 @@
namespace App\Controller\OgBoot\OgLive;
use App\Controller\OgBoot\AbstractOgLiveController;
use App\Controller\OgBoot\AbstractOgBootController;
use App\Entity\OgLive;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Attribute\AsController;
use Symfony\Component\HttpKernel\Exception\HttpException;
use Symfony\Component\Validator\Exception\ValidatorException;
use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface;
@ -14,28 +17,25 @@ use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
use Symfony\Contracts\HttpClient\HttpClientInterface;
#[AsController]
class UninstallAction extends AbstractOgLiveController
class UninstallAction extends AbstractOgBootController
{
/**
* @throws TransportExceptionInterface
* @throws ServerExceptionInterface
* @throws RedirectionExceptionInterface
* @throws ClientExceptionInterface
* @throws TransportExceptionInterface
*/
public function __invoke(OgLive $data, HttpClientInterface $httpClient): JsonResponse
public function __invoke(OgLive $data, HttpClientInterface $httpClient, EntityManagerInterface $entityManager): JsonResponse
{
try {
$response = $httpClient->request('DELETE', $this->ogBootApiUrl.'/ogboot/v1/oglives/'.$data->getChecksum(), [
'headers' => [
'accept' => 'application/json',
],
]);
} catch (TransportExceptionInterface $e) {
return new JsonResponse( data: 'An error occurred', status: Response::HTTP_INTERNAL_SERVER_ERROR);
if (!$data->getChecksum()) {
throw new ValidatorException('Checksum is required');
}
$data = json_decode($response->getContent(), true);
$content = $this->createRequest($httpClient, 'DELETE', $this->ogBootApiUrl.'/ogboot/v1/oglives/'.$data->getChecksum());
return new JsonResponse( data: $data, status: Response::HTTP_OK);
$entityManager->remove($data);
$entityManager->flush();
return new JsonResponse(status: Response::HTTP_OK);
}
}

View File

@ -0,0 +1,85 @@
<?php
namespace App\Controller\OgBoot\OgLive\Webhook;
use App\Controller\OgBoot\AbstractOgBootController;
use App\Entity\OgLive;
use App\Model\OgLiveStatus;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Attribute\AsController;
use Symfony\Component\Routing\Annotation\Route;
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;
use Symfony\Contracts\HttpClient\HttpClientInterface;
#[AsController]
class InstallOgLiveResponseAction extends AbstractController
{
public CONST string OG_LIVE_INSTALL_SUCCESS = 'success';
public CONST string OG_LIVE_INSTALL_FAILED = 'failure';
public function __construct(
protected readonly EntityManagerInterface $entityManager
)
{
}
#[Route('/og-lives/install/webhook', name: 'install_webhook', methods: ['POST'])]
public function installWebhook(Request $request): JsonResponse
{
$data = json_decode($request->getContent(), true);
if ($data === null || !isset($data['message'], $data['ogCoreId'], $data['details'])) {
return new JsonResponse(['error' => 'Invalid or incomplete JSON data'], Response::HTTP_BAD_REQUEST);
}
$message = $data['message'];
$ogCoreId = $data['ogCoreId'];
$details = $data['details'];
$status = $data['status'];
$result = $status === self::OG_LIVE_INSTALL_SUCCESS ? $details['result'] : [];
$ogLive = $this->entityManager->getRepository(OgLive::class)->findOneBy(['uuid' => $ogCoreId]);
if (!$ogLive) {
return new JsonResponse(['error' => 'OgLive not found'], Response::HTTP_NOT_FOUND);
}
if ($ogLive->getStatus() === OgLiveStatus::ACTIVE) {
return new JsonResponse(['error' => 'OgLive is already active'], Response::HTTP_BAD_REQUEST);
}
$this->updateOgLive($ogLive, $details, $result, $status);
return new JsonResponse(data: sprintf('OgLive %s updated successfully', $ogLive->getChecksum()), status: Response::HTTP_OK);
}
private function updateOgLive (OgLive $ogLive, array $details, array $result, string $status): void
{
if ($status === self::OG_LIVE_INSTALL_SUCCESS) {
$ogLive->setInstalled(true);
$ogLive->setSynchronized(true);
$ogLive->setChecksum($result['id']);
$ogLive->setDistribution($result['distribution']);
$ogLive->setKernel($result['kernel']);
$ogLive->setArchitecture($result['architecture']);
$ogLive->setRevision($result['revision']);
$ogLive->setDirectory($result['directory']);
}
$ogLive->setStatus($status === self::OG_LIVE_INSTALL_SUCCESS ? OgLiveStatus::ACTIVE : OgLiveStatus::FAILED);
$ogLive->setInstalled($status === self::OG_LIVE_INSTALL_SUCCESS);
$this->entityManager->persist($ogLive);
$this->entityManager->flush();
}
}

View File

@ -2,7 +2,7 @@
namespace App\Controller\OgBoot\PxeBootFile;
use App\Controller\OgBoot\AbstractOgLiveController;
use App\Controller\OgBoot\AbstractOgBootController;
use App\Entity\PxeBootFile;
use App\Entity\PxeTemplate;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
@ -16,7 +16,7 @@ use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
use Symfony\Contracts\HttpClient\HttpClientInterface;
#[AsController]
class GetAction extends AbstractOgLiveController
class GetCollectionAction extends AbstractOgBootController
{
/**
* @throws TransportExceptionInterface
@ -24,20 +24,10 @@ class GetAction extends AbstractOgLiveController
* @throws RedirectionExceptionInterface
* @throws ClientExceptionInterface
*/
public function __invoke(PxeBootFile $data, HttpClientInterface $httpClient): JsonResponse
public function __invoke(HttpClientInterface $httpClient): JsonResponse
{
try {
$response = $httpClient->request('GET', $this->ogBootApiUrl.'/ogboot/v1/pxes/'.$data->getName(), [
'headers' => [
'accept' => 'application/json',
],
]);
} catch (TransportExceptionInterface $e) {
return new JsonResponse( data: 'An error occurred', status: Response::HTTP_INTERNAL_SERVER_ERROR);
}
$content = $this->createRequest($httpClient, 'GET', $this->ogBootApiUrl.'/ogboot/v1/pxes');
$data = json_decode($response->getContent(), true);
return new JsonResponse( data: $data, status: Response::HTTP_OK);
return new JsonResponse(data: $content, status: Response::HTTP_OK);
}
}

View File

@ -2,8 +2,9 @@
namespace App\Controller\OgBoot\PxeTemplate;
use App\Controller\OgBoot\AbstractOgLiveController;
use App\Controller\OgBoot\AbstractOgBootController;
use App\Entity\PxeTemplate;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
@ -15,7 +16,7 @@ use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
use Symfony\Contracts\HttpClient\HttpClientInterface;
#[AsController]
class DeleteAction extends AbstractOgLiveController
class DeleteAction extends AbstractOgBootController
{
/**
* @throws TransportExceptionInterface
@ -23,7 +24,7 @@ class DeleteAction extends AbstractOgLiveController
* @throws RedirectionExceptionInterface
* @throws ClientExceptionInterface
*/
public function __invoke(PxeTemplate $data, HttpClientInterface $httpClient): JsonResponse
public function __invoke(PxeTemplate $data, HttpClientInterface $httpClient, EntityManagerInterface $entityManager): JsonResponse
{
try {
$response = $httpClient->request('DELETE', $this->ogBootApiUrl.'/ogboot/v1/pxe-templates/'.$data->getName(), [
@ -35,8 +36,11 @@ class DeleteAction extends AbstractOgLiveController
return new JsonResponse( data: 'An error occurred', status: Response::HTTP_INTERNAL_SERVER_ERROR);
}
$data = json_decode($response->getContent(), true);
if ($response->getStatusCode() === Response::HTTP_OK) {
$entityManager->remove($data);
$entityManager->flush();
}
return new JsonResponse( data: $data, status: Response::HTTP_OK);
return new JsonResponse(status: Response::HTTP_OK);
}
}

View File

@ -2,7 +2,7 @@
namespace App\Controller\OgBoot\PxeTemplate;
use App\Controller\OgBoot\AbstractOgLiveController;
use App\Controller\OgBoot\AbstractOgBootController;
use App\Entity\PxeTemplate;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
@ -15,7 +15,7 @@ use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
use Symfony\Contracts\HttpClient\HttpClientInterface;
#[AsController]
class GetAction extends AbstractOgLiveController
class GetAction extends AbstractOgBootController
{
/**
* @throws TransportExceptionInterface

View File

@ -2,7 +2,7 @@
namespace App\Controller\OgBoot\PxeTemplate;
use App\Controller\OgBoot\AbstractOgLiveController;
use App\Controller\OgBoot\AbstractOgBootController;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
@ -14,7 +14,7 @@ use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
use Symfony\Contracts\HttpClient\HttpClientInterface;
#[AsController]
class GetCollectionAction extends AbstractOgLiveController
class GetCollectionAction extends AbstractOgBootController
{
/**
* @throws TransportExceptionInterface

View File

@ -2,8 +2,9 @@
namespace App\Controller\OgBoot\PxeTemplate;
use App\Controller\OgBoot\AbstractOgLiveController;
use App\Controller\OgBoot\AbstractOgBootController;
use App\Entity\PxeTemplate;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
@ -15,7 +16,7 @@ use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
use Symfony\Contracts\HttpClient\HttpClientInterface;
#[AsController]
class PostAction extends AbstractOgLiveController
class PostAction extends AbstractOgBootController
{
/**
* @throws TransportExceptionInterface
@ -23,7 +24,7 @@ class PostAction extends AbstractOgLiveController
* @throws RedirectionExceptionInterface
* @throws ClientExceptionInterface
*/
public function __invoke(PxeTemplate $data, HttpClientInterface $httpClient): JsonResponse
public function __invoke(PxeTemplate $data, HttpClientInterface $httpClient, EntityManagerInterface $entityManager): JsonResponse
{
try {
$response = $httpClient->request('POST', $this->ogBootApiUrl.'/ogboot/v1/pxe-templates', [
@ -37,6 +38,12 @@ class PostAction extends AbstractOgLiveController
],
]);
if ($response->getStatusCode() === Response::HTTP_OK) {
$data->setSynchronized(true);
$entityManager->persist($data);
$entityManager->flush();
}
$data = json_decode($response->getContent(), true);
return new JsonResponse($data, Response::HTTP_OK);

View File

@ -5,6 +5,7 @@ namespace App\Dto\Input;
use ApiPlatform\Metadata\ApiProperty;
use App\Dto\Output\HardwareProfileOutput;
use App\Dto\Output\MenuOutput;
use App\Dto\Output\OgLiveOutput;
use App\Dto\Output\OrganizationalUnitOutput;
use App\Entity\Client;
use App\Entity\OgRepository;
@ -76,6 +77,12 @@ final class ClientInput
)]
public ?HardwareProfileOutput $hardwareProfile = null;
#[Groups(['client:write'])]
#[ApiProperty(
description: 'OgLive del cliente'
)]
public ?OgLiveOutput $ogLive = null;
#[Groups(['client:write'])]
#[ApiProperty(
description: 'La posición del cliente dentro del aula'
@ -107,6 +114,10 @@ final class ClientInput
$this->menu = new MenuOutput($client->getMenu());
}
if ($client->getOgLive()) {
$this->ogLive = new OgLiveOutput($client->getOgLive());
}
if ($client->getHardwareProfile()) {
$this->hardwareProfile = new HardwareProfileOutput($client->getHardwareProfile());
}
@ -126,6 +137,7 @@ final class ClientInput
$client->setMac($this->mac);
$client->setIp($this->ip);
$client->setMenu($this->menu?->getEntity());
$client->setOgLive($this->ogLive?->getEntity());
$client->setHardwareProfile($this->hardwareProfile?->getEntity());
$client->setPosition($this->position);

View File

@ -2,8 +2,10 @@
namespace App\Dto\Input;
use ApiPlatform\Metadata\ApiProperty;
use App\Dto\Output\HardwareProfileOutput;
use App\Dto\Output\MenuOutput;
use App\Dto\Output\OgLiveOutput;
use App\Entity\HardwareProfile;
use App\Entity\Menu;
use App\Entity\NetworkSettings;
@ -68,6 +70,9 @@ class NetworkSettingsInput
#[Groups(['organizational-unit:write'])]
public ?HardwareProfileOutput $hardwareProfile = null;
#[Groups(['organizational-unit:write'])]
public ?OgLiveOutput $ogLive = null;
#[Groups(['organizational-unit:write'])]
public ?bool $validation = null;
@ -99,6 +104,10 @@ class NetworkSettingsInput
$this->hardwareProfile = new HardwareProfileOutput($networkSettings->getHardwareProfile());
}
if ($networkSettings->getOgLive()) {
$this->ogLive = new OgLiveOutput($networkSettings->getOgLive());
}
$this->validation = $networkSettings->getValidation();
}
@ -130,6 +139,10 @@ class NetworkSettingsInput
$networkSettings->setHardwareProfile($this->hardwareProfile->getEntity());
}
if ($this->ogLive) {
$networkSettings->setOgLive($this->ogLive->getEntity());
}
$networkSettings->setValidation($this->validation);
return $networkSettings;

View File

@ -4,6 +4,7 @@ namespace App\Dto\Input;
use ApiPlatform\Metadata\ApiProperty;
use App\Entity\OgLive;
use App\Model\OgLiveStatus;
use Symfony\Component\Serializer\Annotation\Groups;
use Symfony\Component\Validator\Constraints as Assert;
@ -36,6 +37,7 @@ final class OgLiveInput
$ogLive->setName($this->name);
$ogLive->setDownloadUrl($this->downloadUrl);
$ogLive->setStatus(OgLiveStatus::INACTIVE);
return $ogLive;
}

View File

@ -43,7 +43,7 @@ final class PxeBootFileInput
$bootFile = new PxeBootFile();
}
$bootFile->setTemplate($this->template);
$bootFile->setTemplate($this->template->getEntity());
foreach ($this->clients as $client) {
$clientsToAdd[] = $client->getEntity();

View File

@ -13,16 +13,27 @@ final class ClientOutput extends AbstractOutput
{
CONST string TYPE = 'client';
<<<<<<< HEAD
#[Groups(['client:read', 'organizational-unit:read', 'trace:read'])]
=======
#[Groups(['client:read', 'organizational-unit:read', 'pxe-boot-file:read'])]
>>>>>>> feature/integration-ogboot
public string $name;
#[Groups(['client:read', 'organizational-unit:read'])]
public string $type = self::TYPE;
<<<<<<< HEAD
#[Groups(['client:read', 'organizational-unit:read', 'trace:read'])]
public ?string $ip = '';
#[Groups(['client:read', 'organizational-unit:read', 'trace:read'])]
=======
#[Groups(['client:read', 'organizational-unit:read', 'pxe-boot-file:read'])]
public ?string $ip = '';
#[Groups(['client:read', 'organizational-unit:read', 'pxe-boot-file:read'])]
>>>>>>> feature/integration-ogboot
public ?string $mac = '';
#[Groups(['client:read', 'organizational-unit:read', 'trace:read'])]
@ -48,6 +59,10 @@ final class ClientOutput extends AbstractOutput
#[ApiProperty(readableLink: true )]
public ?HardwareProfileOutput $hardwareProfile = null;
#[Groups(['client:read'])]
#[ApiProperty(readableLink: true )]
public ?OgLiveOutput $ogLive = null;
#[Groups(['client:read'])]
public ?array $position = ['x' => 0, 'y' => 0];
@ -79,6 +94,7 @@ final class ClientOutput extends AbstractOutput
$this->menu = $client->getMenu() ? new MenuOutput($client->getMenu()) : null;
$this->position = $client->getPosition();
$this->hardwareProfile = $client->getHardwareProfile() ? new HardwareProfileOutput($client->getHardwareProfile()) : null;
$this->ogLive = $client->getOgLive() ? new OgLiveOutput($client->getOgLive()) : null;
$this->createdAt = $client->getCreatedAt();
$this->createdBy = $client->getCreatedBy();
}

View File

@ -54,6 +54,9 @@ final class NetworkSettingsOutput extends AbstractOutput
#[Groups(['network-settings:read', "organizational-unit:read", "client:read"])]
public ?HardwareProfileOutput $hardwareProfile = null;
#[Groups(['network-settings:read', "organizational-unit:read", "client:read"])]
public ?OgLiveOutput $ogLive = null;
#[Groups(['network-settings:read', "organizational-unit:read", "client:read"])]
public ?bool $validation = null;
@ -89,6 +92,10 @@ final class NetworkSettingsOutput extends AbstractOutput
$this->hardwareProfile = new HardwareProfileOutput($networkSettings->getHardwareProfile());
}
if ($networkSettings->getOgLive()) {
$this->ogLive = new OgLiveOutput($networkSettings->getOgLive());
}
$this->validation = $networkSettings->getValidation();
$this->createdAt = $networkSettings->getCreatedAt();
$this->createdBy = $networkSettings->getCreatedBy();

View File

@ -13,9 +13,21 @@ final class OgLiveOutput extends AbstractOutput
#[Groups(['og-live:read'])]
public string $name;
#[Groups(['og-live:read'])]
public ?bool $synchronized = false;
#[Groups(['og-live:read'])]
public ?bool $installed = false;
#[Groups(['og-live:read'])]
public ?bool $isDefault = false;
#[Groups(['og-live:read'])]
public ?string $downloadUrl = '';
#[Groups(['og-live:read'])]
public ?string $status = '';
#[Groups(['og-live:read'])]
public \DateTime $createdAt;
@ -27,7 +39,11 @@ final class OgLiveOutput extends AbstractOutput
parent::__construct($ogLive);
$this->name = $ogLive->getName();
$this->synchronized = $ogLive->isSynchronized();
$this->installed = $ogLive->isInstalled();
$this->isDefault = $ogLive->getIsDefault();
$this->downloadUrl = $ogLive->getDownloadUrl();
$this->status = $ogLive->getStatus();
$this->createdAt = $ogLive->getCreatedAt();
$this->createdBy = $ogLive->getCreatedBy();
}

View File

@ -17,6 +17,9 @@ final class PxeBootFileOutput extends AbstractOutput
#[Groups(['pxe-boot-file:read'])]
public array $clients;
#[Groups(['pxe-boot-file:read'])]
public ?bool $synchronized = null;
#[Groups(['pxe-boot-file:read'])]
public \DateTime $createdAt;
@ -32,6 +35,7 @@ final class PxeBootFileOutput extends AbstractOutput
fn(Client $client) => new ClientOutput($client)
)->toArray();
$this->synchronized = $bootFile->isSynchronized();
$this->createdAt = $bootFile->getCreatedAt();
$this->createdBy = $bootFile->getCreatedBy();
}

View File

@ -10,9 +10,12 @@ use Symfony\Component\Serializer\Annotation\Groups;
#[Get(shortName: 'PxeTemplate')]
final class PxeTemplateOutput extends AbstractOutput
{
#[Groups(['pxe-template:read'])]
#[Groups(['pxe-template:read', 'pxe-boot-file:read'])]
public string $name;
#[Groups(['pxe-template:read'])]
public ?bool $synchronized = null;
#[Groups(['pxe-template:read'])]
public ?string $templateContent = '';
@ -27,6 +30,7 @@ final class PxeTemplateOutput extends AbstractOutput
parent::__construct($pxeTemplate);
$this->name = $pxeTemplate->getName();
$this->synchronized = $pxeTemplate->isSynchronized();
$this->templateContent = $pxeTemplate->getTemplateContent();
$this->createdAt = $pxeTemplate->getCreatedAt();
$this->createdBy = $pxeTemplate->getCreatedBy();

View File

@ -64,7 +64,11 @@ class Client extends AbstractEntity
private ?OgRepository $repository = null;
#[ORM\ManyToOne(inversedBy: 'clients')]
<<<<<<< HEAD
private ?Subnet $subnet = null;
=======
private ?OgLive $ogLive = null;
>>>>>>> feature/integration-ogboot
public function __construct()
{
@ -258,6 +262,7 @@ class Client extends AbstractEntity
return $this;
}
<<<<<<< HEAD
public function getSubnet(): ?Subnet
{
return $this->subnet;
@ -266,6 +271,16 @@ class Client extends AbstractEntity
public function setSubnet(?Subnet $subnet): static
{
$this->subnet = $subnet;
=======
public function getOgLive(): ?OgLive
{
return $this->ogLive;
}
public function setOgLive(?OgLive $ogLive): static
{
$this->ogLive = $ogLive;
>>>>>>> feature/integration-ogboot
return $this;
}

View File

@ -69,6 +69,9 @@ class NetworkSettings extends AbstractEntity
#[ORM\ManyToOne]
private ?OgRepository $repository = null;
#[ORM\ManyToOne]
private ?OgLive $ogLive = null;
public function __construct()
{
parent::__construct();
@ -306,4 +309,16 @@ class NetworkSettings extends AbstractEntity
return $this;
}
public function getOgLive(): ?OgLive
{
return $this->ogLive;
}
public function setOgLive(?OgLive $ogLive): static
{
$this->ogLive = $ogLive;
return $this;
}
}

View File

@ -3,6 +3,8 @@
namespace App\Entity;
use App\Repository\OgLiveRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
@ -12,6 +14,7 @@ use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
class OgLive extends AbstractEntity
{
use NameableTrait;
use SynchronizedTrait;
#[ORM\Column(length: 255, nullable: true)]
private ?string $downloadUrl = null;
@ -38,7 +41,25 @@ class OgLive extends AbstractEntity
private ?string $filename = null;
#[ORM\Column(nullable: true)]
private ?bool $installed = null;
private ?bool $installed = false;
#[ORM\Column(nullable: true)]
private ?bool $isDefault = false;
/**
* @var Collection<int, Client>
*/
#[ORM\OneToMany(mappedBy: 'ogLive', targetEntity: Client::class)]
private Collection $clients;
#[ORM\Column(length: 255)]
private ?string $status = null;
public function __construct()
{
parent::__construct();
$this->clients = new ArrayCollection();
}
public function getDownloadUrl(): ?string
{
@ -147,4 +168,56 @@ class OgLive extends AbstractEntity
return $this;
}
public function getIsDefault(): ?bool
{
return $this->isDefault;
}
public function setIsDefault(?bool $isDefault): void
{
$this->isDefault = $isDefault;
}
/**
* @return Collection<int, Client>
*/
public function getClients(): Collection
{
return $this->clients;
}
public function addClient(Client $client): static
{
if (!$this->clients->contains($client)) {
$this->clients->add($client);
$client->setOgLive($this);
}
return $this;
}
public function removeClient(Client $client): static
{
if ($this->clients->removeElement($client)) {
// set the owning side to null (unless already changed)
if ($client->getOgLive() === $this) {
$client->setOgLive(null);
}
}
return $this;
}
public function getStatus(): ?string
{
return $this->status;
}
public function setStatus(string $status): static
{
$this->status = $status;
return $this;
}
}

View File

@ -10,6 +10,8 @@ use Doctrine\ORM\Mapping as ORM;
#[ORM\Entity(repositoryClass: PxeBootFileRepository::class)]
class PxeBootFile extends AbstractEntity
{
use SynchronizedTrait;
#[ORM\ManyToOne]
private ?PxeTemplate $template = null;

View File

@ -3,6 +3,7 @@
namespace App\Entity;
use App\Repository\PxeTemplateRepository;
use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
@ -12,8 +13,9 @@ use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
class PxeTemplate extends AbstractEntity
{
use NameableTrait;
use SynchronizedTrait;
#[ORM\Column(length: 255)]
#[ORM\Column(type: Types::TEXT)]
private ?string $templateContent = null;
public function getTemplateContent(): ?string

View File

@ -0,0 +1,23 @@
<?php
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
trait SynchronizedTrait
{
#[ORM\Column(type: 'boolean', nullable: true)]
private bool $synchronized = false;
public function isSynchronized(): ?bool
{
return $this->synchronized;
}
public function setSynchronized(?bool $synchronized): self
{
$this->synchronized = $synchronized;
return $this;
}
}

View File

@ -0,0 +1,36 @@
<?php
namespace App\Model;
final class OgLiveStatus
{
public const string PENDING = 'pending';
public const string ACTIVE = 'active';
public const string INACTIVE = 'inactive';
public const string DELETED = 'deleted';
public const string FAILED = 'failed';
private const array OG_LIVE_STATUSES = [
self::PENDING => 'Pendiente',
self::ACTIVE => 'Activo',
self::INACTIVE => 'Inactivo',
self::DELETED => 'Eliminado',
self::FAILED => 'Fallido',
];
public static function getOgLiveStatuses(): array
{
return self::OG_LIVE_STATUSES;
}
public static function getOgLiveStatus(string $ogLiveStatus): ?string
{
return self::OG_LIVE_STATUSES[$ogLiveStatus] ?? null;
}
public static function getOgLiveStatusKeys(): array
{
return array_keys(self::OG_LIVE_STATUSES);
}
}

View File

@ -19,8 +19,9 @@ final readonly class OpenApiFactory implements OpenApiFactoryInterface
$openApi = $this->decorated->__invoke($context);
$this->addRefreshToken($openApi);
$this->addSearchEndpoint($openApi);
$this->addOgAgentEndpoints($openApi);
$this->addStatusEndpoint($openApi);
$this->addInstallOgLiveWebhookEndpoint($openApi);
return $openApi;
}
@ -77,55 +78,6 @@ final readonly class OpenApiFactory implements OpenApiFactoryInterface
)
));
}
private function addSearchEndpoint(OpenApi $openApi): void
{
$openApi
->getPaths()
->addPath('/search', (new Model\PathItem())->withGet(
(new Model\Operation('getSearch'))
->withTags(['Search'])
->withResponses([
Response::HTTP_OK => [
'description' => 'Search results',
'content' => [
'application/json' => [
'schema' => [
'type' => 'object',
'properties' => [
'results' => [
'type' => 'array',
'items' => [
'type' => 'object',
'properties' => [
'id' => [
'type' => 'integer',
'example' => 1,
],
'name' => [
'type' => 'string',
'example' => 'Item name',
],
],
],
],
],
],
],
],
],
])
->withSummary('Search for items')
->withParameters([
new Model\Parameter(
'query',
'query',
'Search query parameter',
true,
false,
),
])
));
}
private function addOgAgentEndpoints(OpenApi $openApi): void
{
@ -702,4 +654,116 @@ final readonly class OpenApiFactory implements OpenApiFactoryInterface
])
));
}
private function addStatusEndpoint(OpenApi $openApi): void
{
$openApi
->getPaths()
->addPath('/og-boot/status', (new Model\PathItem())->withGet(
(new Model\Operation('getStatus'))
->withTags(['OgBoot'])
->withResponses([
Response::HTTP_OK => [
'description' => 'Service status',
'content' => [
'application/json' => [
'schema' => [
'type' => 'object',
'properties' => [
'status' => [
'type' => 'string',
'example' => 'ok',
],
'uptime' => [
'type' => 'integer',
'example' => 12345,
],
],
],
],
],
],
Response::HTTP_SERVICE_UNAVAILABLE => [
'description' => 'Service unavailable',
'content' => [
'application/json' => [
'schema' => [
'type' => 'object',
'properties' => [
'error' => [
'type' => 'string',
'example' => 'Service is down',
],
],
],
],
],
],
])
->withSummary('Get service status')
));
}
private function addInstallOgLiveWebhookEndpoint(OpenApi $openApi): void
{
$openApi
->getPaths()
->addPath('/og-lives/install/webhook', (new Model\PathItem())->withPost(
(new Model\Operation('postInstallOgLiveWebhook'))
->withTags(['OgLive'])
->withResponses([
Response::HTTP_OK => [
'description' => 'Webhook installation successful',
'content' => [
'application/json' => [
'schema' => [
'type' => 'object',
'properties' => [
'message' => [
'type' => 'string',
'example' => 'Webhook installed successfully',
],
],
],
],
],
],
Response::HTTP_BAD_REQUEST => [
'description' => 'Invalid request data',
'content' => [
'application/json' => [
'schema' => [
'type' => 'object',
'properties' => [
'error' => [
'type' => 'string',
'example' => 'Invalid input data',
],
],
],
],
],
],
])
->withSummary('Install a webhook for OgLive')
->withRequestBody(
(new Model\RequestBody())
->withDescription('Data required for installing the webhook')
->withContent(new \ArrayObject([
'application/json' => new Model\MediaType(new \ArrayObject([
'type' => 'object',
'properties' => [
'da' => [
'type' => 'string',
'description' => 'The URL to set for the webhook',
'example' => 'https://example.com/webhook',
],
],
'required' => ['url'],
]))
]))
->withRequired(true)
)
));
}
}

View File

@ -35,31 +35,40 @@ readonly class PostService
foreach ($bootFile->getClients() as $client) {
$data = [
'template_name' => $bootFile->getTemplate()->getName(),
'template_name' => 'pxe_default',
'mac' => $client->getMac(),
'lang' => 'es_ES.UTF_8',
'ip' => $client->getIp(),
'server_ip' => '',
'server_ip' => '92.168.2.1',
'router' => $client->getOrganizationalUnit()->getNetworkSettings()->getRouter(),
'netmask' => $client->getOrganizationalUnit()->getNetworkSettings()->getNetmask(),
'netmask' => $client->getOrganizationalUnit()->getNetworkSettings() ? $client->getOrganizationalUnit()->getNetworkSettings()->getNetmask() : '255.255.255.0',
'computer_name' => $client->getName(),
'netiface' => $client->getNetiface(),
'group' => $client->getOrganizationalUnit()->getName(),
'ogrepo' => $client->getRepository() ? $client->getRepository()->getIpAddress() : $client->getOrganizationalUnit()->getNetworkSettings()->getRepository()->getIpAddress(),
'oglive' => '',
'ogdns' => $client->getOrganizationalUnit()->getNetworkSettings()->getDns(),
'ogProxy' => $client->getOrganizationalUnit()->getNetworkSettings()->getProxy(),
'ogunit' => ''
'ogrepo' => $client->getRepository() ? $client->getRepository()->getIpAddress() : '192.168.2.1',
'oglive' => '127.0.0.1',
'oglog' => '192.168.2.1',
'ogshare' => '192.168.2.1',
'oglivedir' => 'ogLive',
'ogprof' => 'false',
'hardprofile' => $client->getHardwareProfile() ? $client->getHardwareProfile()->getDescription() : 'default',
'ogntp' => $client->getOrganizationalUnit()->getNetworkSettings()?->getNtp(),
'ogdns' => $client->getOrganizationalUnit()->getNetworkSettings()?->getDns(),
'ogProxy' => $client->getOrganizationalUnit()->getNetworkSettings()?->getProxy(),
'ogunit' => '',
'resolution' => '788'
];
try {
$response = $httpClient->request('POST', $this->ogBootApiUrl.'/ogboot/v1/pxes', [
'headers' => [
'accept' => 'application/json',
'Content-Type' => 'application/json',
],
'json' => $data
]);
} catch (TransportExceptionInterface $e) {
return new JsonResponse( data: 'An error occurred', status: Response::HTTP_INTERNAL_SERVER_ERROR);
return new JsonResponse( data: $e->getMessage(), status: Response::HTTP_INTERNAL_SERVER_ERROR);
}
return json_decode($response->getContent(), true);

View File

@ -21,12 +21,12 @@ use App\Repository\OrganizationalUnitRepository;
use App\Service\ChangeClientNetworkSettingsService;
use Doctrine\ORM\EntityManagerInterface;
class OrganizationalUnitProcessor implements ProcessorInterface
readonly class OrganizationalUnitProcessor implements ProcessorInterface
{
public function __construct(
private readonly OrganizationalUnitRepository $organizationalUnitRepository,
private readonly ValidatorInterface $validator,
private readonly ChangeClientNetworkSettingsService $changeClientNetworkSettingsService,
private OrganizationalUnitRepository $organizationalUnitRepository,
private ValidatorInterface $validator,
private ChangeClientNetworkSettingsService $changeClientNetworkSettingsService,
)
{
}

View File

@ -13,6 +13,7 @@ use App\Dto\Input\PxeBootFileInput;
use App\Dto\Output\PxeBootFileOutput;
use App\Repository\PxeBootFileRepository;
use App\Service\OgBoot\PxeBootFile\PostService;
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
readonly class PxeBootFileProcessor implements ProcessorInterface
{
@ -41,6 +42,7 @@ readonly class PxeBootFileProcessor implements ProcessorInterface
/**
* @throws \Exception
* @throws TransportExceptionInterface
*/
private function processCreateOrUpdate($data, Operation $operation, array $uriVariables = [], array $context = []): PxeBootFileOutput
{
@ -57,7 +59,11 @@ readonly class PxeBootFileProcessor implements ProcessorInterface
$this->validator->validate($pxeTemplate);
$this->bootFileRepository->save($pxeTemplate);
$this->postService->__invoke($pxeTemplate);
try {
$this->postService->__invoke($pxeTemplate);
} catch (\Exception $e) {
}
return new PxeBootFileOutput($pxeTemplate);
}

View File

@ -13,11 +13,11 @@ use App\Dto\Input\ClientInput;
use App\Dto\Output\ClientOutput;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
class ClientProvider implements ProviderInterface
readonly class ClientProvider implements ProviderInterface
{
public function __construct(
private readonly ProviderInterface $collectionProvider,
private readonly ProviderInterface $itemProvider
private ProviderInterface $collectionProvider,
private ProviderInterface $itemProvider
)
{
}

View File

@ -14,7 +14,7 @@ use App\Dto\Output\OrganizationalUnitOutput;
use App\Entity\OrganizationalUnit;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
readonly class OrganizationalUnitProvider implements ProviderInterface
final readonly class OrganizationalUnitProvider implements ProviderInterface
{
public function __construct(
private ProviderInterface $collectionProvider,