Compare commits

...

14 Commits

Author SHA1 Message Date
Manuel Aranda Rosales 54c0af3a24 Merge main and solve conflicts
testing/ogcore-api/pipeline/head This commit looks good Details
testing/ogcore-api/pipeline/pr-main Build started... Details
2024-11-26 10:51:22 +01:00
Manuel Aranda Rosales 49259255dd Updated pxe logic 2024-11-26 10:46:37 +01:00
Manuel Aranda Rosales 48b7225c01 Added monolog. Updated agent webhook
testing/ogcore-api/pipeline/head This commit looks good Details
2024-11-25 20:06:09 +01:00
Manuel Aranda Rosales 5c85d687e6 Fixed status when image fail
testing/ogcore-api/pipeline/head This commit looks good Details
2024-11-25 11:53:49 +01:00
Manuel Aranda Rosales 942c967d44 Fixed agent status connection
testing/ogcore-api/pipeline/head This commit looks good Details
2024-11-25 09:13:39 +01:00
Manuel Aranda Rosales d3b2da5f1b Fixed agent status connection
testing/ogcore-api/pipeline/head This commit looks good Details
2024-11-25 08:28:16 +01:00
Manuel Aranda Rosales 4638c07416 Big updates dhcp subnets
testing/ogcore-api/pipeline/head This commit looks good Details
testing/ogcore-api/pipeline/tag This commit looks good Details
2024-11-22 12:27:12 +01:00
Manuel Aranda Rosales 1c13c8fe7d Merge pull request 'Fixed ogAgent webhook data error 500' (#15) from develop into main
testing/ogcore-api/pipeline/head This commit looks good Details
Reviewed-on: #15
2024-11-22 10:46:12 +01:00
Manuel Aranda Rosales d11e6e0873 Merge pull request 'develop' (#14) from develop into main
testing/ogcore-api/pipeline/head This commit looks good Details
Reviewed-on: #14
2024-11-21 14:57:10 +01:00
Nicolas Arenas d06f29eda6 Merge branch 'develop'
testing/ogcore-api/pipeline/head This commit looks good Details
2024-11-20 19:52:10 +01:00
Manuel Aranda Rosales 4aeace65b5 Merge pull request 'develop' (#13) from develop into main
testing/ogcore-api/pipeline/head This commit looks good Details
Reviewed-on: #13
2024-11-20 19:26:16 +01:00
Manuel Aranda Rosales a2f35e8927 Update docker-compose-deploy.yml
testing/ogcore-api/pipeline/head This commit looks good Details
Fix tipo
2024-11-20 19:24:00 +01:00
Nicolas Arenas fb0af325c2 Fix merge
testing/ogcore-api/pipeline/head This commit looks good Details
2024-11-20 19:14:45 +01:00
Nicolas Arenas 3bfd65e909 Update yaml to deploy shared volume between php and nginx container
testing/ogcore-api/pipeline/tag This commit looks good Details
testing/ogcore-api/pipeline/head Something is wrong with the build of this commit Details
2024-11-04 12:02:35 +01:00
27 changed files with 513 additions and 150 deletions

View File

@ -27,6 +27,7 @@
"symfony/flex": "^2",
"symfony/framework-bundle": "6.4.*",
"symfony/http-client": "6.4.*",
"symfony/monolog-bundle": "^3.10",
"symfony/property-access": "6.4.*",
"symfony/property-info": "6.4.*",
"symfony/runtime": "6.4.*",

269
composer.lock generated
View File

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "aaa904068da3e39927da2e6658330011",
"content-hash": "2df97d4a1797242acadb47d83b3fbe98",
"packages": [
{
"name": "api-platform/core",
@ -2091,6 +2091,109 @@
],
"time": "2024-07-03T20:49:59+00:00"
},
{
"name": "monolog/monolog",
"version": "3.8.0",
"source": {
"type": "git",
"url": "https://github.com/Seldaek/monolog.git",
"reference": "32e515fdc02cdafbe4593e30a9350d486b125b67"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Seldaek/monolog/zipball/32e515fdc02cdafbe4593e30a9350d486b125b67",
"reference": "32e515fdc02cdafbe4593e30a9350d486b125b67",
"shasum": ""
},
"require": {
"php": ">=8.1",
"psr/log": "^2.0 || ^3.0"
},
"provide": {
"psr/log-implementation": "3.0.0"
},
"require-dev": {
"aws/aws-sdk-php": "^3.0",
"doctrine/couchdb": "~1.0@dev",
"elasticsearch/elasticsearch": "^7 || ^8",
"ext-json": "*",
"graylog2/gelf-php": "^1.4.2 || ^2.0",
"guzzlehttp/guzzle": "^7.4.5",
"guzzlehttp/psr7": "^2.2",
"mongodb/mongodb": "^1.8",
"php-amqplib/php-amqplib": "~2.4 || ^3",
"php-console/php-console": "^3.1.8",
"phpstan/phpstan": "^2",
"phpstan/phpstan-deprecation-rules": "^2",
"phpstan/phpstan-strict-rules": "^2",
"phpunit/phpunit": "^10.5.17 || ^11.0.7",
"predis/predis": "^1.1 || ^2",
"rollbar/rollbar": "^4.0",
"ruflin/elastica": "^7 || ^8",
"symfony/mailer": "^5.4 || ^6",
"symfony/mime": "^5.4 || ^6"
},
"suggest": {
"aws/aws-sdk-php": "Allow sending log messages to AWS services like DynamoDB",
"doctrine/couchdb": "Allow sending log messages to a CouchDB server",
"elasticsearch/elasticsearch": "Allow sending log messages to an Elasticsearch server via official client",
"ext-amqp": "Allow sending log messages to an AMQP server (1.0+ required)",
"ext-curl": "Required to send log messages using the IFTTTHandler, the LogglyHandler, the SendGridHandler, the SlackWebhookHandler or the TelegramBotHandler",
"ext-mbstring": "Allow to work properly with unicode symbols",
"ext-mongodb": "Allow sending log messages to a MongoDB server (via driver)",
"ext-openssl": "Required to send log messages using SSL",
"ext-sockets": "Allow sending log messages to a Syslog server (via UDP driver)",
"graylog2/gelf-php": "Allow sending log messages to a GrayLog2 server",
"mongodb/mongodb": "Allow sending log messages to a MongoDB server (via library)",
"php-amqplib/php-amqplib": "Allow sending log messages to an AMQP server using php-amqplib",
"rollbar/rollbar": "Allow sending log messages to Rollbar",
"ruflin/elastica": "Allow sending log messages to an Elastic Search server"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "3.x-dev"
}
},
"autoload": {
"psr-4": {
"Monolog\\": "src/Monolog"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Jordi Boggiano",
"email": "j.boggiano@seld.be",
"homepage": "https://seld.be"
}
],
"description": "Sends your logs to files, sockets, inboxes, databases and various web services",
"homepage": "https://github.com/Seldaek/monolog",
"keywords": [
"log",
"logging",
"psr-3"
],
"support": {
"issues": "https://github.com/Seldaek/monolog/issues",
"source": "https://github.com/Seldaek/monolog/tree/3.8.0"
},
"funding": [
{
"url": "https://github.com/Seldaek",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/monolog/monolog",
"type": "tidelift"
}
],
"time": "2024-11-12T13:57:08+00:00"
},
{
"name": "nelmio/cors-bundle",
"version": "2.5.0",
@ -4840,6 +4943,166 @@
],
"time": "2024-07-26T14:52:04+00:00"
},
{
"name": "symfony/monolog-bridge",
"version": "v6.4.13",
"source": {
"type": "git",
"url": "https://github.com/symfony/monolog-bridge.git",
"reference": "9d14621e59f22c2b6d030d92d37ffe5ae1e60452"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/monolog-bridge/zipball/9d14621e59f22c2b6d030d92d37ffe5ae1e60452",
"reference": "9d14621e59f22c2b6d030d92d37ffe5ae1e60452",
"shasum": ""
},
"require": {
"monolog/monolog": "^1.25.1|^2|^3",
"php": ">=8.1",
"symfony/deprecation-contracts": "^2.5|^3",
"symfony/http-kernel": "^5.4|^6.0|^7.0",
"symfony/service-contracts": "^2.5|^3"
},
"conflict": {
"symfony/console": "<5.4",
"symfony/http-foundation": "<5.4",
"symfony/security-core": "<5.4"
},
"require-dev": {
"symfony/console": "^5.4|^6.0|^7.0",
"symfony/http-client": "^5.4|^6.0|^7.0",
"symfony/mailer": "^5.4|^6.0|^7.0",
"symfony/messenger": "^5.4|^6.0|^7.0",
"symfony/mime": "^5.4|^6.0|^7.0",
"symfony/security-core": "^5.4|^6.0|^7.0",
"symfony/var-dumper": "^5.4|^6.0|^7.0"
},
"type": "symfony-bridge",
"autoload": {
"psr-4": {
"Symfony\\Bridge\\Monolog\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Provides integration for Monolog with various Symfony components",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/monolog-bridge/tree/v6.4.13"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2024-10-14T08:49:08+00:00"
},
{
"name": "symfony/monolog-bundle",
"version": "v3.10.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/monolog-bundle.git",
"reference": "414f951743f4aa1fd0f5bf6a0e9c16af3fe7f181"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/monolog-bundle/zipball/414f951743f4aa1fd0f5bf6a0e9c16af3fe7f181",
"reference": "414f951743f4aa1fd0f5bf6a0e9c16af3fe7f181",
"shasum": ""
},
"require": {
"monolog/monolog": "^1.25.1 || ^2.0 || ^3.0",
"php": ">=7.2.5",
"symfony/config": "^5.4 || ^6.0 || ^7.0",
"symfony/dependency-injection": "^5.4 || ^6.0 || ^7.0",
"symfony/http-kernel": "^5.4 || ^6.0 || ^7.0",
"symfony/monolog-bridge": "^5.4 || ^6.0 || ^7.0"
},
"require-dev": {
"symfony/console": "^5.4 || ^6.0 || ^7.0",
"symfony/phpunit-bridge": "^6.3 || ^7.0",
"symfony/yaml": "^5.4 || ^6.0 || ^7.0"
},
"type": "symfony-bundle",
"extra": {
"branch-alias": {
"dev-master": "3.x-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Bundle\\MonologBundle\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony MonologBundle",
"homepage": "https://symfony.com",
"keywords": [
"log",
"logging"
],
"support": {
"issues": "https://github.com/symfony/monolog-bundle/issues",
"source": "https://github.com/symfony/monolog-bundle/tree/v3.10.0"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2023-11-06T17:08:13+00:00"
},
{
"name": "symfony/password-hasher",
"version": "v6.4.8",
@ -9976,7 +10239,7 @@
],
"aliases": [],
"minimum-stability": "stable",
"stability-flags": [],
"stability-flags": {},
"prefer-stable": true,
"prefer-lowest": false,
"platform": {
@ -9984,6 +10247,6 @@
"ext-ctype": "*",
"ext-iconv": "*"
},
"platform-dev": [],
"platform-dev": {},
"plugin-api-version": "2.6.0"
}

View File

@ -16,4 +16,5 @@ return [
Symfony\Bundle\WebProfilerBundle\WebProfilerBundle::class => ['dev' => true, 'test' => true],
Stof\DoctrineExtensionsBundle\StofDoctrineExtensionsBundle::class => ['all' => true],
DAMA\DoctrineTestBundle\DAMADoctrineTestBundle::class => ['test' => true],
Symfony\Bundle\MonologBundle\MonologBundle::class => ['all' => true],
];

View File

@ -0,0 +1,62 @@
monolog:
channels:
- deprecation # Deprecations are logged in the dedicated "deprecation" channel when it exists
when@dev:
monolog:
handlers:
main:
type: stream
path: "%kernel.logs_dir%/%kernel.environment%.log"
level: debug
channels: ["!event"]
# uncomment to get logging in your browser
# you may have to allow bigger header sizes in your Web server configuration
#firephp:
# type: firephp
# level: info
#chromephp:
# type: chromephp
# level: info
console:
type: console
process_psr_3_messages: false
channels: ["!event", "!doctrine", "!console"]
when@test:
monolog:
handlers:
main:
type: fingers_crossed
action_level: error
handler: nested
excluded_http_codes: [404, 405]
channels: ["!event"]
nested:
type: stream
path: "%kernel.logs_dir%/%kernel.environment%.log"
level: debug
when@prod:
monolog:
handlers:
main:
type: fingers_crossed
action_level: error
handler: nested
excluded_http_codes: [404, 405]
buffer_size: 50 # How many messages should be saved? Prevent memory leaks
nested:
type: stream
path: php://stderr
level: debug
formatter: monolog.formatter.json
console:
type: console
process_psr_3_messages: false
channels: ["!event", "!doctrine"]
deprecation:
type: stream
channels: [deprecation]
path: php://stderr
formatter: monolog.formatter.json

View File

@ -39,11 +39,13 @@ class StatusAction extends AbstractController
*/
public function __invoke(Client $client): JsonResponse
{
$response = null;
if (!$client->getIp()) {
throw new ValidatorException('IP is required');
}
if ($client->getStatus() === ClientStatus::OG_LIVE || $client->getStatus() === ClientStatus::OFF) {
if ($client->getStatus() === ClientStatus::OG_LIVE || $client->getStatus() === ClientStatus::OFF || $client->getStatus() === ClientStatus::BUSY) {
$response = $this->getOgLiveStatus($client);
}
@ -57,7 +59,7 @@ class StatusAction extends AbstractController
);
}
public function getOgLiveStatus (Client $client): JsonResponse|int
public function getOgLiveStatus (Client $client): JsonResponse|int|string
{
try {
$response = $this->httpClient->request('POST', 'https://' . $client->getIp() . ':8000/ogAdmClient/status', [
@ -75,7 +77,7 @@ class StatusAction extends AbstractController
} catch (TransportExceptionInterface $e) {
$client->setStatus(ClientStatus::OFF);
return Response::HTTP_INTERNAL_SERVER_ERROR;
return $e->getMessage();
}
$data = json_decode($response->getContent(), true);

View File

@ -10,11 +10,14 @@ use App\Entity\Software;
use App\Entity\SoftwareProfile;
use App\Entity\Trace;
use App\Model\ClientStatus;
use App\Model\CommandTypes;
use App\Model\ImageStatus;
use App\Model\SoftwareTypes;
use App\Model\TraceStatus;
use App\Service\CreatePartitionService;
use App\Service\Trace\CreateService;
use Doctrine\ORM\EntityManagerInterface;
use Psr\Log\LoggerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
@ -33,7 +36,9 @@ class ClientsController extends AbstractController
public function __construct(
protected readonly EntityManagerInterface $entityManager,
public readonly CreateAuxFilesAction $createAuxFilesAction,
protected readonly CreatePartitionService $createPartitionService
protected readonly CreatePartitionService $createPartitionService,
protected readonly LoggerInterface $logger,
protected readonly CreateService $createService,
)
{
}
@ -56,37 +61,51 @@ class ClientsController extends AbstractController
}
}
$this->logger->info('Webhook data received', $data);
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']]);
if (!$image) {
$this->logger->error('Image not found', $data);
return new JsonResponse(['message' => 'Image not found'], Response::HTTP_NOT_FOUND);
}
if (!$trace) {
$this->logger->error('Trace not found', $data);
return new JsonResponse(['message' => 'Trace not found'], Response::HTTP_NOT_FOUND);
}
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()]);
if (isset($data['cfg'])) {
$this->createPartitionService->__invoke($data, $image->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->createAuxFilesAction->__invoke($image);
$this->logger->info('End aux files ogrepo API ', ['image' => (string) $image->getUuid()]);
} else {
$trace->setStatus(TraceStatus::FAILED);
$trace->setFinishedAt(new \DateTime());
$trace->setOutput($data['der']);
$image->setCreated(false);
$image->setStatus(ImageStatus::FAILED);
$this->logger->error('Image updated failed', $data);
}
$this->entityManager->persist($image);
$this->entityManager->persist($image);
$client = $trace->getClient();
$client->setStatus(ClientStatus::OG_LIVE);
$this->entityManager->persist($trace);
$this->entityManager->flush();
$this->logger->info('Image updated. Success.', ['image' => (string) $image->getUuid()]);
}
if ($data['nfn'] === 'RESPUESTA_RestaurarImagen') {
@ -111,26 +130,28 @@ class ClientsController extends AbstractController
return new JsonResponse([], Response::HTTP_OK);
}
public function createSoftwareProfile (string $base64Data, Image $image): void
public function createSoftwareProfile(string $base64Data, Image $image): void
{
$decodedData = base64_decode($base64Data);
$this->logger->info('Software profile decoded', ['data' => '']);
$softwareList = array_map('trim', explode(",", $decodedData));
$softwareList = array_filter($softwareList);
$existingSoftware = $this->entityManager->getRepository(Software::class)->findBy(['name' => $softwareList]);
$existingNames = array_map(fn($software) => $software->getName(), $existingSoftware);
$newSoftwareNames = array_diff($softwareList, $existingNames);
$softwareList = explode("\n", $decodedData);
foreach ($newSoftwareNames as $software) {
$softwareEntity = new Software();
$softwareEntity->setName($software);
$softwareEntity->setType(SoftwareTypes::APPLICATION);
$this->entityManager->persist($softwareEntity);
}
$softwareProfile = new SoftwareProfile();
$softwareProfile->setDescription('Perfil : '.$image->getName());
$softwareProfile->setDescription('Perfil: ' . $image->getName());
$softwareProfile->setOrganizationalUnit($image->getClient()->getOrganizationalUnit());
foreach ($softwareList as $software) {
$software = trim($software);
$softwareEntity = $this->entityManager->getRepository(Software::class)->findOneBy(['name' => $software]);
if (!$softwareEntity) {
$softwareEntity = new Software();
$softwareEntity->setName($software);
$softwareEntity->setType(SoftwareTypes::APPLICATION);
$this->entityManager->persist($softwareEntity);
}
foreach ($existingSoftware as $softwareEntity) {
$softwareEntity->addSoftwareProfile($softwareProfile);
}

View File

@ -4,6 +4,7 @@ declare(strict_types=1);
namespace App\Controller\OgBoot;
use App\Controller\OgBoot\PxeBootFile\PostAction;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\DependencyInjection\Attribute\Autowire;
@ -25,7 +26,8 @@ abstract class AbstractOgBootController extends AbstractController
protected string $ogBootApiUrl,
#[Autowire(env: 'OG_CORE_IP')]
protected string $ogCoreIP,
protected readonly EntityManagerInterface $entityManager
protected readonly EntityManagerInterface $entityManager,
protected readonly HttpClientInterface $httpClient,
)
{
}
@ -36,7 +38,7 @@ abstract class AbstractOgBootController extends AbstractController
* @throws RedirectionExceptionInterface
* @throws ClientExceptionInterface
*/
public function createRequest (HttpClientInterface $httpClient, string $method, string $url, array $params = []): JsonResponse|array
public function createRequest (string $method, string $url, array $params = []): JsonResponse|array
{
$params = array_merge($params, [
'headers' => [
@ -46,7 +48,7 @@ abstract class AbstractOgBootController extends AbstractController
]);
try {
$response = $httpClient->request($method, $url, $params);
$response = $this->httpClient->request($method, $url, $params);
return json_decode($response->getContent(), true);
} catch (ClientExceptionInterface | ServerExceptionInterface $e) {

View File

@ -54,7 +54,9 @@ class SyncAction extends AbstractOgBootController
*/
private function extracted(OgLive|null $ogLiveEntity, mixed $ogLive): void
{
$ogLiveEntity->setName(str_replace(self::OG_BOOT_DIRECTORY, '', $ogLive['directory']));
if (!$ogLiveEntity){
$ogLiveEntity->setName(str_replace(self::OG_BOOT_DIRECTORY, '', $ogLive['directory']));
}
$ogLiveEntity->setInstalled(true);
$ogLiveEntity->setArchitecture($ogLive['architecture']);
$ogLiveEntity->setDistribution($ogLive['distribution']);

View File

@ -26,57 +26,42 @@ class PostAction extends AbstractOgBootController
* @throws RedirectionExceptionInterface
* @throws ClientExceptionInterface
*/
public function __invoke(PxeTemplateSyncClientInput $input, PxeTemplate $pxeTemplate, HttpClientInterface $httpClient): JsonResponse
public function __invoke(Client $client, PxeTemplate $pxeTemplate): JsonResponse
{
/** @var Client $client */
$client = $input->client->getEntity();
$data = [
'template_name' => $pxeTemplate->getName(),
'mac' => strtolower($client->getMac()),
'lang' => 'es_ES.UTF_8',
'ip' => $client->getIp(),
'server_ip' => $this->ogBootApiUrl,
'router' => $client->getOrganizationalUnit()->getNetworkSettings()->getRouter(),
'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()->getIp() ,
'ogcore' => $this->ogCoreIP,
'oglive' => $this->ogBootApiUrl,
'oglog' => $client->getOrganizationalUnit()->getNetworkSettings()?->getOgLog(),
'ogshare' => $client->getOrganizationalUnit()->getNetworkSettings()?->getOgShare()
? $client->getOrganizationalUnit()->getNetworkSettings()?->getOgShare(): $this->ogBootApiUrl,
'oglivedir' => $client->getOgLive()->getFilename(),
'ogprof' => 'false',
'hardprofile' => $client->getHardwareProfile() ? $client->getHardwareProfile()->getDescription() : 'default',
'ogntp' => $client->getOrganizationalUnit()->getNetworkSettings()?->getNtp(), //optional
'ogdns' => $client->getOrganizationalUnit()->getNetworkSettings()?->getDns(), //optional
'ogProxy' => $client->getOrganizationalUnit()->getNetworkSettings()?->getProxy(), //optional
// 'ogunit' => '', //eliminar
'resolution' => '788'
$params = [
'json' => [
'template_name' => $pxeTemplate->getName(),
'mac' => strtolower($client->getMac()),
'lang' => 'es_ES.UTF_8',
'ip' => $client->getIp(),
'server_ip' => $this->ogBootApiUrl,
'router' => $client->getOrganizationalUnit()->getNetworkSettings()->getRouter(),
'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()?->getIp() ,
'ogcore' => $this->ogCoreIP,
'oglive' => $this->ogBootApiUrl,
'oglog' => $client->getOrganizationalUnit()->getNetworkSettings()?->getOgLog(),
'ogshare' => $client->getOrganizationalUnit()->getNetworkSettings()?->getOgShare()
? $client->getOrganizationalUnit()->getNetworkSettings()?->getOgShare(): $this->ogBootApiUrl,
'oglivedir' => $client->getOgLive()->getFilename(),
'ogprof' => 'false',
'hardprofile' => $client->getHardwareProfile() ? $client->getHardwareProfile()->getDescription() : 'default',
'ogntp' => $client->getOrganizationalUnit()->getNetworkSettings()?->getNtp(),
'ogdns' => $client->getOrganizationalUnit()->getNetworkSettings()?->getDns(),
'ogProxy' => $client->getOrganizationalUnit()->getNetworkSettings()?->getProxy(),
'resolution' => '788'
]
];
try {
$response = $httpClient->request('POST', 'http://'.$this->ogBootApiUrl.'/ogboot/v1/pxes', [
'headers' => [
'accept' => 'application/json',
'Content-Type' => 'application/json',
],
'json' => $data
]);
} catch (TransportExceptionInterface $e) {
$client->setPxeSync(false);
$this->entityManager->persist($client);
$this->entityManager->flush();
return new JsonResponse( data: $e->getMessage(), status: Response::HTTP_INTERNAL_SERVER_ERROR);
}
$content = $this->createRequest('POST', 'http://'.$this->ogBootApiUrl.'/ogboot/v1/pxes', $params);
$client->setPxeSync(true);
$this->entityManager->persist($client);
$this->entityManager->flush();
return new JsonResponse(data: json_decode($response->getContent(), true), status: Response::HTTP_OK);
return new JsonResponse(data: $content, status: Response::HTTP_OK);
}
}

View File

@ -2,10 +2,13 @@
namespace App\Controller\OgBoot\PxeTemplate;
use App\Controller\OgBoot\AbstractOgBootController;
use App\Controller\OgDhcp\AbstractOgDhcpController;
use App\Dto\Input\PxeTemplateAddClientsInput;
use App\Entity\Client;
use App\Entity\PxeTemplate;
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;
@ -16,8 +19,15 @@ use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
use Symfony\Contracts\HttpClient\HttpClientInterface;
#[AsController]
class AddClientAction extends AbstractOgDhcpController
class AddClientAction extends AbstractController
{
public function __construct(
private readonly \App\Controller\OgBoot\PxeBootFile\PostAction $postAction,
private readonly EntityManagerInterface $entityManager,
)
{
}
/**
* @throws TransportExceptionInterface
@ -25,11 +35,13 @@ class AddClientAction extends AbstractOgDhcpController
* @throws RedirectionExceptionInterface
* @throws ClientExceptionInterface
*/
public function __invoke(PxeTemplateAddClientsInput $input, PxeTemplate $pxeTemplate, HttpClientInterface $httpClient): JsonResponse
public function __invoke(PxeTemplateAddClientsInput $input, PxeTemplate $pxeTemplate): JsonResponse
{
$clients = $input->clients;
foreach ($clients as $client) {
$this->postAction->__invoke($client->getEntity(), $pxeTemplate);
/** @var Client $clientEntity */
$clientEntity = $client->getEntity();
$clientEntity->setTemplate($pxeTemplate);

View File

@ -24,22 +24,12 @@ class DeleteAction extends AbstractOgBootController
* @throws RedirectionExceptionInterface
* @throws ClientExceptionInterface
*/
public function __invoke(PxeTemplate $data, HttpClientInterface $httpClient, EntityManagerInterface $entityManager): JsonResponse
public function __invoke(PxeTemplate $data): JsonResponse
{
try {
$response = $httpClient->request('DELETE', 'http://'.$this->ogBootApiUrl.'/ogboot/v1/pxe-templates/'.$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('DELETE', 'http://'.$this->ogBootApiUrl.'/ogboot/v1/pxe-templates/'.$data->getName());
if ($response->getStatusCode() === Response::HTTP_OK) {
$entityManager->remove($data);
$entityManager->flush();
}
$this->entityManager->remove($data);
$this->entityManager->flush();
return new JsonResponse(status: Response::HTTP_OK);
}

View File

@ -24,39 +24,21 @@ class PostAction extends AbstractOgBootController
* @throws RedirectionExceptionInterface
* @throws ClientExceptionInterface
*/
public function __invoke(PxeTemplate $data, HttpClientInterface $httpClient, EntityManagerInterface $entityManager): JsonResponse
public function __invoke(PxeTemplate $data): JsonResponse
{
try {
$response = $httpClient->request('POST', 'http://'.$this->ogBootApiUrl.'/ogboot/v1/pxe-templates', [
'headers' => [
'accept' => 'application/json',
'Content-Type' => 'application/json',
],
'json' => [
'name_template' => $data->getName(),
'content_template' => $data->getTemplateContent(),
],
]);
$params = [
'json' => [
'name_template' => $data->getName(),
'content_template' => $data->getTemplateContent(),
]
];
if ($response->getStatusCode() === Response::HTTP_OK) {
$data->setSynchronized(true);
$entityManager->persist($data);
$entityManager->flush();
}
$content = $this->createRequest('POST', 'http://'.$this->ogBootApiUrl.'/ogboot/v1/pxe-templates' , $params);
$data = json_decode($response->getContent(), true);
return new JsonResponse($data, Response::HTTP_OK);
$data->setSynchronized(true);
$this->entityManager->persist($data);
$this->entityManager->flush();
} catch (ClientExceptionInterface $e) {
$errorResponse = $e->getResponse();
$errorContent = $errorResponse ? $errorResponse->getContent(false) : 'Client error occurred';
return new JsonResponse(['error' => $errorContent], Response::HTTP_BAD_REQUEST);
} catch (ServerExceptionInterface $e) {
$errorResponse = $e->getResponse();
$errorContent = $errorResponse ? $errorResponse->getContent(false) : 'Server error occurred';
return new JsonResponse(['error' => $errorContent], Response::HTTP_INTERNAL_SERVER_ERROR);
} catch (TransportExceptionInterface $e) {
return new JsonResponse(['error' => 'Transport error occurred'], Response::HTTP_INTERNAL_SERVER_ERROR);
}
return new JsonResponse(data: $content, status: Response::HTTP_OK);
}
}

View File

@ -26,19 +26,24 @@ class SyncAction extends AbstractOgBootController
* @throws RedirectionExceptionInterface
* @throws ClientExceptionInterface
*/
public function __invoke(HttpClientInterface $httpClient, EntityManagerInterface $entityManager): JsonResponse
public function __invoke(): JsonResponse
{
$content = $this->createRequest($httpClient, 'GET', 'http://'.$this->ogBootApiUrl . '/ogboot/v1/pxe-templates');
$content = $this->createRequest('GET', 'http://'.$this->ogBootApiUrl . '/ogboot/v1/pxe-templates');
foreach ($content['message'] as $template) {
$templateEntity = $this->entityManager->getRepository(PxeTemplate::class)->findOneBy(['name' => $template]);
if ($templateEntity) {
$this->entityManager->persist($templateEntity);
} else {
$templateEntity = new PxeTemplate();
$templateEntity->setName($template);
$templateEntity->setTemplateContent('');
}
$templateContent = $this->createRequest('GET', 'http://'.$this->ogBootApiUrl . '/ogboot/v1/pxe-templates/'.$templateEntity->getName());
$templateEntity->setTemplateContent($templateContent['template_content']);
$templateEntity->setSynchronized(true);
$this->entityManager->persist($templateEntity);
}
$this->entityManager->flush();

View File

@ -4,6 +4,7 @@ declare(strict_types=1);
namespace App\Controller\OgDhcp;
use App\Controller\OgBoot\PxeBootFile\PostAction;
use App\Service\Utils\GetIpAddressAndNetmaskFromCIDRService;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
@ -23,9 +24,10 @@ abstract class AbstractOgDhcpController extends AbstractController
{
public function __construct(
#[Autowire(env: 'OG_DHCP_API_URL')]
protected readonly string $ogDhcpApiUrl,
protected readonly EntityManagerInterface $entityManager,
protected readonly GetIpAddressAndNetmaskFromCIDRService $getIpAddressAndNetmaskFromCIDRService,
protected readonly string $ogDhcpApiUrl,
protected readonly EntityManagerInterface $entityManager,
protected readonly GetIpAddressAndNetmaskFromCIDRService $getIpAddressAndNetmaskFromCIDRService,
protected readonly HttpClientInterface $httpClient,
)
{
}
@ -36,7 +38,7 @@ abstract class AbstractOgDhcpController extends AbstractController
* @throws RedirectionExceptionInterface
* @throws ClientExceptionInterface
*/
public function createRequest (HttpClientInterface $httpClient, string $method, string $url, array $params = []): JsonResponse|array
public function createRequest (string $method, string $url, array $params = []): JsonResponse|array
{
$params = array_merge($params, [
'headers' => [
@ -46,7 +48,7 @@ abstract class AbstractOgDhcpController extends AbstractController
]);
try {
$response = $httpClient->request($method, $url, $params);
$response = $this->httpClient->request($method, $url, $params);
return json_decode($response->getContent(), true);
} catch (ClientExceptionInterface | ServerExceptionInterface $e) {

View File

@ -29,7 +29,7 @@ class DeleteAction extends AbstractOgDhcpController
throw new ValidatorException('Data Id is required');
}
$content = $this->createRequest($httpClient, 'DELETE', 'http://'.$this->ogDhcpApiUrl.'/ogdhcp/v1/subnets/'.$data->getServerId());
$content = $this->createRequest('DELETE', 'http://'.$this->ogDhcpApiUrl.'/ogdhcp/v1/subnets/'.$data->getServerId());
$this->entityManager->remove($data);
$this->entityManager->flush();

View File

@ -24,7 +24,7 @@ class DeleteHostAction extends AbstractOgDhcpController
* @throws RedirectionExceptionInterface
* @throws ClientExceptionInterface
*/
public function __invoke(Subnet $data, string $clientUuid, HttpClientInterface $httpClient): JsonResponse
public function __invoke(Subnet $data, string $clientUuid): JsonResponse
{
$client = $this->entityManager->getRepository(Client::class)->findOneBy(['uuid' => $clientUuid]);
@ -42,7 +42,7 @@ class DeleteHostAction extends AbstractOgDhcpController
]
];
$content = $this->createRequest($httpClient, 'DELETE', 'http://'.$this->ogDhcpApiUrl.'/ogdhcp/v1/subnets/'.$data->getServerId().'/hosts', $params);
$content = $this->createRequest('DELETE', 'http://'.$this->ogDhcpApiUrl.'/ogdhcp/v1/subnets/'.$data->getServerId().'/hosts', $params);
$data->removeClient($client);
$this->entityManager->persist($data);

View File

@ -23,13 +23,13 @@ class GetAction extends AbstractOgDhcpController
* @throws RedirectionExceptionInterface
* @throws ClientExceptionInterface
*/
public function __invoke(Subnet $data, HttpClientInterface $httpClient): JsonResponse
public function __invoke(Subnet $data): JsonResponse
{
if (!$data->getId()) {
throw new ValidatorException('Checksum is required');
}
$content = $this->createRequest($httpClient, 'GET', 'http://'.$this->ogDhcpApiUrl.'/ogdhcp/v1/subnets/'.$data->getServerId());
$content = $this->createRequest('GET', 'http://'.$this->ogDhcpApiUrl.'/ogdhcp/v1/subnets/'.$data->getServerId());
return new JsonResponse(data: $content, status: Response::HTTP_OK);
}

View File

@ -21,9 +21,9 @@ class GetCollectionAction extends AbstractOgDhcpController
* @throws RedirectionExceptionInterface
* @throws ClientExceptionInterface
*/
public function __invoke(HttpClientInterface $httpClient): JsonResponse
public function __invoke(): JsonResponse
{
$content = $this->createRequest($httpClient, 'GET', 'http://'.$this->ogDhcpApiUrl . '/ogdhcp/v1/subnets');
$content = $this->createRequest('GET', 'http://'.$this->ogDhcpApiUrl . '/ogdhcp/v1/subnets');
return new JsonResponse(data: $content, status: Response::HTTP_OK);
}

View File

@ -23,13 +23,13 @@ class GetHostsAction extends AbstractOgDhcpController
* @throws RedirectionExceptionInterface
* @throws ClientExceptionInterface
*/
public function __invoke(Subnet $data, HttpClientInterface $httpClient): JsonResponse
public function __invoke(Subnet $data): JsonResponse
{
if (!$data->getId()) {
throw new ValidatorException('Checksum is required');
}
$content = $this->createRequest($httpClient, 'GET', 'http://'.$this->ogDhcpApiUrl.'/ogdhcp/v1/subnets/'.$data->getServerId().'/hosts');
$content = $this->createRequest('GET', 'http://'.$this->ogDhcpApiUrl.'/ogdhcp/v1/subnets/'.$data->getServerId().'/hosts');
return new JsonResponse(data: $content, status: Response::HTTP_OK);
}

View File

@ -23,11 +23,11 @@ class PostAction extends AbstractOgDhcpController
* @throws RedirectionExceptionInterface
* @throws ClientExceptionInterface
*/
public function __invoke(Subnet $data, HttpClientInterface $httpClient): JsonResponse
public function __invoke(Subnet $data): JsonResponse
{
$params = [
'json' => [
'subnetId' => $data->getId(),
'subnetId' => rand(1, 1000),
'mask' => $data->getNetmask(),
'address' => $data->getIpAddress(),
'nextServer' => $data->getNextServer(),
@ -35,7 +35,7 @@ class PostAction extends AbstractOgDhcpController
]
];
$content = $this->createRequest($httpClient, 'POST', 'http://'.$this->ogDhcpApiUrl.'/ogdhcp/v1/subnets' , $params);
$content = $this->createRequest('POST', 'http://'.$this->ogDhcpApiUrl.'/ogdhcp/v1/subnets' , $params);
$data->setServerId($content['message']['id']);
$data->setSynchronized(true);

View File

@ -27,7 +27,7 @@ class PostHostAction extends AbstractOgDhcpController
* @throws RedirectionExceptionInterface
* @throws ClientExceptionInterface
*/
public function __invoke(SubnetAddHostInput $input, Subnet $subnet, HttpClientInterface $httpClient): JsonResponse
public function __invoke(SubnetAddHostInput $input, Subnet $subnet): JsonResponse
{
$client = $input->client;
@ -44,7 +44,7 @@ class PostHostAction extends AbstractOgDhcpController
'json' => $data
];
$content = $this->createRequest($httpClient, 'POST', 'http://'.$this->ogDhcpApiUrl.'/ogdhcp/v1/subnets/'.$subnet->getServerId().'/hosts', $params);
$content = $this->createRequest('POST', 'http://'.$this->ogDhcpApiUrl.'/ogdhcp/v1/subnets/'.$subnet->getServerId().'/hosts', $params);
$subnet->addClient($clientEntity);
$this->entityManager->persist($subnet);

View File

@ -23,7 +23,7 @@ class PutAction extends AbstractOgDhcpController
* @throws RedirectionExceptionInterface
* @throws ClientExceptionInterface
*/
public function __invoke(Subnet $data, HttpClientInterface $httpClient): JsonResponse
public function __invoke(Subnet $data): JsonResponse
{
if (!$data->getId()) {
throw new ValidatorException('Id is required');
@ -38,7 +38,7 @@ class PutAction extends AbstractOgDhcpController
]
];
$content = $this->createRequest($httpClient, 'PUT', 'http://'.$this->ogDhcpApiUrl.'/ogdhcp/v1/subnets/'.$data->getServerId(), $params);
$content = $this->createRequest('PUT', 'http://'.$this->ogDhcpApiUrl.'/ogdhcp/v1/subnets/'.$data->getServerId(), $params);
$this->entityManager->persist($data);
$this->entityManager->flush();

View File

@ -24,7 +24,7 @@ class PutHostAction extends AbstractOgDhcpController
* @throws RedirectionExceptionInterface
* @throws ClientExceptionInterface
*/
public function __invoke(SubnetAddHostInput $input, Subnet $subnet, HttpClientInterface $httpClient): JsonResponse
public function __invoke(SubnetAddHostInput $input, Subnet $subnet): JsonResponse
{
$clients = $input->clients;
@ -42,7 +42,7 @@ class PutHostAction extends AbstractOgDhcpController
'json' => $data
];
$content = $this->createRequest($httpClient, 'PUT', 'http://'.$this->ogDhcpApiUrl.'/ogdhcp/v1/subnets/'.$subnet->getId().'/hosts', $params);
$content = $this->createRequest('PUT', 'http://'.$this->ogDhcpApiUrl.'/ogdhcp/v1/subnets/'.$subnet->getId().'/hosts', $params);
}
return new JsonResponse(status: Response::HTTP_OK);

View File

@ -24,9 +24,9 @@ class SyncAction extends AbstractOgDhcpController
* @throws RedirectionExceptionInterface
* @throws ClientExceptionInterface
*/
public function __invoke(HttpClientInterface $httpClient, EntityManagerInterface $entityManager): JsonResponse
public function __invoke(EntityManagerInterface $entityManager): JsonResponse
{
$content = $this->createRequest($httpClient, 'GET', 'http://'.$this->ogDhcpApiUrl . '/ogdhcp/v1/subnets');
$content = $this->createRequest('GET', 'http://'.$this->ogDhcpApiUrl . '/ogdhcp/v1/subnets');
$arraySync = [];
@ -63,11 +63,11 @@ class SyncAction extends AbstractOgDhcpController
{
$getParsedData = $this->getIpAddressAndNetmaskFromCIDRService->__invoke($subnet['subnet']);
$subnetEntity->setName($subnet['boot-file-name']);
$subnetEntity->setBootFileName($subnet['boot-file-name']);
$subnetEntity->setName($subnet['id'].' - '.$subnet['subnet']);
$subnetEntity->setBootFileName($subnet['boot-file-name'] ?? null);
$subnetEntity->setIpAddress($getParsedData['ip']);
$subnetEntity->setNetmask($getParsedData['mask']);
$subnetEntity->setNextServer($subnet['next-server']);
$subnetEntity->setNextServer($subnet['next-server'] ?? null);
foreach ($subnet['reservations'] as $host) {
$hostEntity = $this->entityManager->getRepository(Client::class)->findOneBy(['mac' => $host['hw-address']]);

View File

@ -9,15 +9,18 @@ use ApiPlatform\Metadata\Post;
use ApiPlatform\Metadata\Put;
use ApiPlatform\State\ProcessorInterface;
use ApiPlatform\Validator\ValidatorInterface;
use App\Controller\OgBoot\PxeTemplate\PostAction;
use App\Dto\Input\PxeTemplateInput;
use App\Dto\Output\PxeTemplateOutput;
use App\Repository\PxeTemplateRepository;
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
readonly class PxeTemplateProcessor implements ProcessorInterface
{
public function __construct(
private PxeTemplateRepository $pxeTemplateRepository,
private ValidatorInterface $validator
private ValidatorInterface $validator,
private PostAction $postAction,
)
{
}
@ -39,6 +42,7 @@ readonly class PxeTemplateProcessor implements ProcessorInterface
/**
* @throws \Exception
* @throws TransportExceptionInterface
*/
private function processCreateOrUpdate($data, Operation $operation, array $uriVariables = [], array $context = []): PxeTemplateOutput
{
@ -53,6 +57,11 @@ readonly class PxeTemplateProcessor implements ProcessorInterface
$pxeTemplate = $data->createOrUpdateEntity($entity);
$this->validator->validate($pxeTemplate);
if (!$pxeTemplate->getId() ) {
$this->postAction->__invoke($pxeTemplate);
}
$this->pxeTemplateRepository->save($pxeTemplate);
return new PxeTemplateOutput($pxeTemplate);

View File

@ -9,16 +9,20 @@ use ApiPlatform\Metadata\Post;
use ApiPlatform\Metadata\Put;
use ApiPlatform\State\ProcessorInterface;
use ApiPlatform\Validator\ValidatorInterface;
use App\Controller\OgDhcp\Subnet\PostAction;
use App\Controller\OgDhcp\Subnet\PutAction;
use App\Dto\Input\SubnetInput;
use App\Dto\Output\SubnetOutput;
use App\Repository\SubnetRepository;
use App\Service\OgBoot\PxeBootFile\PostService;
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
readonly class SubnetProcessor implements ProcessorInterface
{
public function __construct(
private SubnetRepository $subnetRepository,
private ValidatorInterface $validator
private ValidatorInterface $validator,
private PostAction $postAction,
private PutAction $putAction,
)
{
}
@ -40,6 +44,7 @@ readonly class SubnetProcessor implements ProcessorInterface
/**
* @throws \Exception
* @throws TransportExceptionInterface
*/
private function processCreateOrUpdate($data, Operation $operation, array $uriVariables = [], array $context = []): SubnetOutput
{
@ -54,6 +59,13 @@ readonly class SubnetProcessor implements ProcessorInterface
$subnet = $data->createOrUpdateEntity($entity);
$this->validator->validate($subnet);
if (!$subnet->getId() ) {
$this->postAction->__invoke($subnet);
} else {
$this->putAction->__invoke($subnet);
}
$this->subnetRepository->save($subnet);
return new SubnetOutput($subnet);

View File

@ -178,6 +178,18 @@
"ref": "fadbfe33303a76e25cb63401050439aa9b1a9c7f"
}
},
"symfony/monolog-bundle": {
"version": "3.10",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "main",
"version": "3.7",
"ref": "aff23899c4440dd995907613c1dd709b6f59503f"
},
"files": [
"config/packages/monolog.yaml"
]
},
"symfony/phpunit-bridge": {
"version": "7.1",
"recipe": {