Compare commits

..

No commits in common. "main" and "dhcp-symfony" have entirely different histories.

90 changed files with 1960 additions and 3667 deletions

View File

18
.gitignore vendored
View File

@ -5,6 +5,7 @@
!app/cache/.gitkeep
!app/logs/.gitkeep
/app/phpunit.xml
/bin/
/build/
/composer.phar
/var/*
@ -30,20 +31,3 @@
.phpunit.result.cache
/phpunit.xml
###< symfony/phpunit-bridge ###
.venv
ogdhcp.code-workspace
output.xml
log.html
report.html
__pycache__
### Debian packaging
debian/ogdhcp
debian/*.substvars
debian/*.log
debian/.debhelper/
debian/files
debian/*.debhelper
debian/*.debhelper.log
debian/debhelper-build-stamp

View File

@ -1,48 +0,0 @@
# CHANGELOG
# [0.7.1] - 27/05/2025
### **Cambios principales**
1. Añade nuevo parámetro boot-file-name a los endpoints de añadir y actualizar host de una subred.
# [0.6.3] - 24/03/2025
### **Cambios principales**
1. Mueve directorios de symfony al directorio api
## [0.6.2] - 03/03/2025
### **Cambios principales**
1. Añade publicacion de paquetes debian a jenkins
## [0.6.1] - 03/03/2025
### **Cambios principales**
1. Añade publicacion de paquetes debian a jenkins
## [0.6.0] - 03/03/2025
### **Cambios principales**
1. Añade nuevos parametros a la subred: dns y subnetname, añadiendolos a la configuración de kea
2. Resuelve error de permisos en el instalador
### **Cambios principales**
1. Arregla bugs en la creacion del home `/opt/opengnsys`del usuario opengnsys
## [0.5.5] - 06/02/2025
### **Cambios principales**
1. Arregla bugs en la creacion del home `/opt/opengnsys`del usuario opengnsys
## [0.5.4] - 06/02/2025
### **Cambios principales**
1. Cambia el home del usuario opengnsys como `/opt/opengnsys`
## [0.5.3] - 13/01/2025
### **Cambios principales**
1. Añade logs para todos los endpoints siguiendo un formato json preestablecido.
2. Actualiza monolog.yaml para devolver logs al journal de la maquina.

View File

@ -1,40 +0,0 @@
# Changelog
## [0.7.2] - 2025-06-06
### Changed
- Corrige bug cuando no recibe parámetro boot-file-name.
## [0.7.1] - 2025-05-27
### Changed
- Añade nuevo parámetro boot-file-name a los endpoints de añadir y actualizar host de una subred.
## [0.7.0] - 2025-03-24
### Changed
- Mueve directorios de symfony al directorio api
## [0.6.1] - 2025-03-19
### Changed
- Modified Jenkinsfile to publish packages
## [0.6.0] - 2025-03-03
### Added
- Nuevos parámetros a la subred: `dns` y `subnetname`, añadiéndolos a la configuración de Kea.
### Fixed
- Error de permisos en el instalador.
- Bugs en la creación del home `/opt/opengnsys` del usuario `opengnsys`.
## [0.5.5] - 2025-02-06
### Fixed
- Bugs en la creación del home `/opt/opengnsys` del usuario `opengnsys`.
## [0.5.4] - 2025-02-06
### Changed
- Se cambia el home del usuario `opengnsys` a `/opt/opengnsys`.
## [0.5.3] - 2025-01-13
### Added
- Logs para todos los endpoints siguiendo un formato JSON preestablecido.
### Changed
- Se actualiza `monolog.yaml` para devolver logs al journal de la máquina.

View File

@ -1,112 +0,0 @@
@Library('jenkins-shared-library') _
pipeline {
agent {
label 'jenkins-slave'
}
environment {
DEBIAN_FRONTEND = 'noninteractive'
DEFAULT_DEV_NAME = 'Opengnsys Team'
DEFAULT_DEV_EMAIL = 'opengnsys@qindel.com'
}
options {
skipDefaultCheckout()
}
parameters {
string(name: 'DEV_NAME', defaultValue: '', description: 'Nombre del desarrollador')
string(name: 'DEV_EMAIL', defaultValue: '', description: 'Email del desarrollador')
}
stages {
stage('Prepare Workspace') {
steps {
script {
env.BUILD_DIR = "${WORKSPACE}/ogdhcp"
sh "mkdir -p ${env.BUILD_DIR}"
}
}
}
stage('Checkout') {
steps {
dir("${env.BUILD_DIR}") {
checkout scm
}
}
}
stage('Generate Changelog') {
when {
expression {
return env.TAG_NAME != null
}
}
steps {
script {
def devName = params.DEV_NAME ? params.DEV_NAME : env.DEFAULT_DEV_NAME
def devEmail = params.DEV_EMAIL ? params.DEV_EMAIL : env.DEFAULT_DEV_EMAIL
generateDebianChangelog(env.BUILD_DIR, devName, devEmail)
}
}
}
stage('Generate Changelog (Nightly)'){
when {
branch 'main'
}
steps {
script {
def devName = params.DEV_NAME ? params.DEV_NAME : env.DEFAULT_DEV_NAME
def devEmail = params.DEV_EMAIL ? params.DEV_EMAIL : env.DEFAULT_DEV_EMAIL
generateDebianChangelog(env.BUILD_DIR, devName, devEmail,"nightly")
}
}
}
stage('Build') {
steps {
script {
construirPaquete(env.BUILD_DIR, "../artifacts", "172.17.8.68", "/var/tmp/opengnsys/debian-repo/ogdhcp")
}
}
}
stage ('Publish to Debian Repository') {
when {
expression {
return env.TAG_NAME != null
}
}
agent { label 'debian-repo' }
steps {
script {
// Construir el patrón de versión esperado en el nombre del paquete
def versionPattern = "${env.TAG_NAME}-${env.BUILD_NUMBER}"
publicarEnAptly('/var/tmp/opengnsys/debian-repo/ogdhcp', 'opengnsys-devel', versionPattern)
}
}
}
stage ('Publish to Debian Repository (Nightly)') {
when {
branch 'main'
}
agent { label 'debian-repo' }
steps {
script {
// Construir el patrón de versión esperado en el nombre del paquete
def versionPattern = "-${env.BUILD_NUMBER}~nightly"
publicarEnAptly('/var/tmp/opengnsys/debian-repo/ogdhcp', 'nightly', versionPattern)
}
}
}
}
post {
always {
notifyBuildStatus('narenas@qindel.com')
}
}
}
// stage ('Publish to Debian Repository') {
// agent { label 'debian-repo' }
// steps {
// sh "aptly repo add opengnsys-devel /var/tmp/opengnsys/debian-repo/*.deb"
// }
// }

View File

@ -2,8 +2,9 @@ El proyecto `ogdhcp` es una API diseñada para gestionar la configuración de Ke
La API `ogdhcp` proporciona una interfaz para interactuar con Kea DHCP, permitiendo a los usuarios y aplicaciones como Opengnsys gestionar la configuración de Kea DHCP de manera remota en lugar de tener que modificar manualmente los archivos de configuración.
Las funciones proporcionadas por la API `ogdhcp` permiten:
Las funciones proporcionadas por la API `ogdhcp` pueden incluir la capacidad de:
- Consultar la configuración actual de Kea DHCP.
- Modificar la configuración de Kea DHCP, como agregar, eliminar o modificar subredes, reservas de IP, opciones de DHCP, etc.
- Realizar copias de seguridad de la configuración de Kea DHCP.
- Restaurar la configuración de Kea DHCP desde una copia de seguridad.

View File

@ -1,17 +0,0 @@
#!/usr/bin/env php
<?php
use App\Kernel;
use Symfony\Bundle\FrameworkBundle\Console\Application;
if (!is_file(dirname(__DIR__).'/vendor/autoload_runtime.php')) {
throw new LogicException('Symfony Runtime is missing. Try running "composer require symfony/runtime".');
}
require_once dirname(__DIR__).'/vendor/autoload_runtime.php';
return function (array $context) {
$kernel = new Kernel($context['APP_ENV'], (bool) $context['APP_DEBUG']);
return new Application($kernel);
};

View File

@ -1,48 +0,0 @@
nelmio_api_doc:
documentation:
info:
title: OgDHCP API
description: OgDHCP API documentation
version: 1.0.0
components:
schemas:
Host:
type: object
properties:
hostname:
type: string
description: The hostname of the device
example: "pc11"
hw-address:
type: string
description: The hardware address (MAC)
example: "56:6f:c7:4f:00:4f"
ip-address:
type: string
description: The IP address assigned to the host
example: "192.168.5.11"
Subnet:
type: object
properties:
id:
type: integer
description: The ID of the subnet
subnet:
type: string
description: The name of the subnet
next-server:
type: string
description: The next server in the subnet
boot-file-name:
type: string
description: The boot file name for the subnet
reservations:
type: array
items:
$ref: '#/components/schemas/Host'
description: The reservations in the subnet
areas: # to filter documented areas
path_patterns:
- ^/ogdhcp/ # Accepts routes under /api except /api/doc

View File

@ -1,7 +0,0 @@
#index:
# path: /
# controller: App\Controller\DefaultController::index
app.swagger_ui:
path: /ogdhcp/api/doc
methods: GET
defaults: { _controller: nelmio_api_doc.controller.swagger_ui }

File diff suppressed because it is too large Load Diff

View File

@ -1,261 +0,0 @@
{
"doctrine/annotations": {
"version": "1.14",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "main",
"version": "1.0",
"ref": "a2759dd6123694c8d901d0ec80006e044c2e6457"
},
"files": [
"config/routes/annotations.yaml"
]
},
"doctrine/doctrine-bundle": {
"version": "2.11",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "main",
"version": "2.4",
"ref": "191046a1fdd1a58fcca48d8bf2f58c45a93b1d00"
},
"files": [
"config/packages/doctrine.yaml",
"src/Entity/.gitignore",
"src/Repository/.gitignore"
]
},
"doctrine/doctrine-migrations-bundle": {
"version": "3.3",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "main",
"version": "3.1",
"ref": "1d01ec03c6ecbd67c3375c5478c9a423ae5d6a33"
},
"files": [
"config/packages/doctrine_migrations.yaml",
"migrations/.gitignore"
]
},
"phpunit/phpunit": {
"version": "8.5",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "main",
"version": "4.7",
"ref": "db276258424d15e572d35a4eb834b8f815662b25"
},
"files": [
".env.test",
"phpunit.xml.dist",
"tests/bootstrap.php"
]
},
"symfony/console": {
"version": "5.4",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "main",
"version": "5.3",
"ref": "da0c8be8157600ad34f10ff0c9cc91232522e047"
},
"files": [
"bin/console"
]
},
"symfony/debug-bundle": {
"version": "5.4",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "main",
"version": "5.3",
"ref": "5aa8aa48234c8eb6dbdd7b3cd5d791485d2cec4b"
},
"files": [
"config/packages/debug.yaml"
]
},
"symfony/flex": {
"version": "1.21",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "main",
"version": "1.0",
"ref": "146251ae39e06a95be0fe3d13c807bcf3938b172"
},
"files": [
".env"
]
},
"symfony/framework-bundle": {
"version": "5.4",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "main",
"version": "5.4",
"ref": "3cd216a4d007b78d8554d44a5b1c0a446dab24fb"
},
"files": [
"config/packages/cache.yaml",
"config/packages/framework.yaml",
"config/preload.php",
"config/routes/framework.yaml",
"config/services.yaml",
"public/index.php",
"src/Controller/.gitignore",
"src/Kernel.php"
]
},
"symfony/mailer": {
"version": "5.4",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "main",
"version": "4.3",
"ref": "df66ee1f226c46f01e85c29c2f7acce0596ba35a"
},
"files": [
"config/packages/mailer.yaml"
]
},
"symfony/maker-bundle": {
"version": "1.50",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "main",
"version": "1.0",
"ref": "fadbfe33303a76e25cb63401050439aa9b1a9c7f"
}
},
"symfony/messenger": {
"version": "5.4",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "main",
"version": "5.4",
"ref": "8bd5f27013fb1d7217191c548e340f0bdb11912c"
},
"files": [
"config/packages/messenger.yaml"
]
},
"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/notifier": {
"version": "5.4",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "main",
"version": "5.0",
"ref": "178877daf79d2dbd62129dd03612cb1a2cb407cc"
},
"files": [
"config/packages/notifier.yaml"
]
},
"symfony/phpunit-bridge": {
"version": "5.4",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "main",
"version": "5.3",
"ref": "07ce01a897311647520b43d4ddddad9537b99ba6"
},
"files": [
".env.test",
"bin/phpunit",
"phpunit.xml.dist",
"tests/bootstrap.php"
]
},
"symfony/routing": {
"version": "5.4",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "main",
"version": "5.3",
"ref": "85de1d8ae45b284c3c84b668171d2615049e698f"
},
"files": [
"config/packages/routing.yaml",
"config/routes.yaml"
]
},
"symfony/security-bundle": {
"version": "5.4",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "main",
"version": "5.3",
"ref": "98f1f2b0d635908c2b40f3675da2d23b1a069d30"
},
"files": [
"config/packages/security.yaml"
]
},
"symfony/translation": {
"version": "5.4",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "main",
"version": "5.3",
"ref": "e28e27f53663cc34f0be2837aba18e3a1bef8e7b"
},
"files": [
"config/packages/translation.yaml",
"translations/.gitignore"
]
},
"symfony/twig-bundle": {
"version": "5.4",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "main",
"version": "5.4",
"ref": "bb2178c57eee79e6be0b297aa96fc0c0def81387"
},
"files": [
"config/packages/twig.yaml",
"templates/base.html.twig"
]
},
"symfony/validator": {
"version": "5.4",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "main",
"version": "5.3",
"ref": "c32cfd98f714894c4f128bb99aa2530c1227603c"
},
"files": [
"config/packages/validator.yaml"
]
},
"symfony/web-profiler-bundle": {
"version": "5.4",
"recipe": {
"repo": "github.com/symfony/recipes",
"branch": "main",
"version": "5.3",
"ref": "24bbc3d84ef2f427f82104f766014e799eefcc3e"
},
"files": [
"config/packages/web_profiler.yaml",
"config/routes/web_profiler.yaml"
]
},
"twig/extra-bundle": {
"version": "v3.8.0"
}
}

View File

@ -12,6 +12,4 @@ return [
Symfony\Bundle\MonologBundle\MonologBundle::class => ['all' => true],
Symfony\Bundle\MakerBundle\MakerBundle::class => ['dev' => true],
App\DhcpBundle\DhcpBundle::class => ['all' => true],
Nelmio\ApiDocBundle\NelmioApiDocBundle::class => ['all' => true],
];

View File

@ -22,11 +22,6 @@ when@dev:
type: console
process_psr_3_messages: false
channels: ["!event", "!doctrine", "!console"]
syslog:
type: syslog
ident: "ogdhcp"
level: info
channels: ["!event"]
when@test:
monolog:

View File

@ -0,0 +1,9 @@
nelmio_api_doc:
documentation:
info:
title: My App
description: This is an awesome app!
version: 1.0.0
areas: # to filter documented areas
path_patterns:
- ^/ogdhcp/ # Accepts routes under /api except /api/doc

View File

@ -0,0 +1,3 @@
#index:
# path: /
# controller: App\Controller\DefaultController::index

View File

@ -4,7 +4,7 @@
# Put parameters here that don't need to change on each machine where the app is deployed
# https://symfony.com/doc/current/best_practices.html#use-parameters-for-application-configuration
parameters:
backup_dir: '%kernel.project_dir%/../etc/kea/backup'
services:
# default configuration for services in *this* file
_defaults:

6
debian/README vendored
View File

@ -1,6 +0,0 @@
The Debian Package ogdhcp
----------------------------
<Comments regarding the Package.>
-- vagrant <vagrant@build> Wed, 05 Mar 2025 19:49:47 +0000

View File

@ -1,6 +0,0 @@
ogdhcp for Debian
----------------
<Possible notes regarding this package - if none, delete this file.>
-- vagrant <vagrant@build> Wed, 05 Mar 2025 19:49:47 +0000

10
debian/README.source vendored
View File

@ -1,10 +0,0 @@
ogdhcp for Debian
----------------
<This file describes information about the source package, see Debian policy
manual section 4.14. You WILL either need to modify or delete this file.>
-- vagrant <vagrant@build> Wed, 05 Mar 2025 19:49:47 +0000

14
debian/changelog vendored
View File

@ -1,14 +0,0 @@
ogdhcp (1.0.2+pkg-deb20250310-1) unstable; urgency=medium
* Updates changelog 0.6.0
* Merge pull request 'new-parameters-subnet' (#3) from new-parameters-subnet into main
* refs #1543 fix swagger annotation
* refs #1568 adds new parameters subnetName and dns to kea dhcp
* refs #1581 fix backup permissions in installer
* refs #1468 update CHANGELOG
* refs #1468 fix bug and permissions in opt opengnsys
* refs #1468 updates CHANGELOG
* refs #1468 changes home of the opengnsys user
* Adds changelog
-- Tu Nombre <tuemail@example.com> Mon, 10 Mar 2025 19:58:42 +0000

38
debian/control vendored
View File

@ -1,38 +0,0 @@
Source: ogdhcp
Section: unknown
Priority: optional
Maintainer: vagrant <vagrant@build>
Rules-Requires-Root: no
Build-Depends:
debhelper-compat (= 13)
Standards-Version: 4.6.2
Homepage: <insert the upstream URL, if relevant>
#Vcs-Browser: https://salsa.debian.org/debian/ogdhcp
#Vcs-Git: https://salsa.debian.org/debian/ogdhcp.git
Package: ogdhcp
Architecture: any
Multi-Arch: foreign
Recommends: kea-dhcp4-server, kea-common, kea-ctrl-agent
Depends: ${shlibs:Depends}, ${misc:Depends}, debconf (>= 1.5.0),
php,
php-cli,
php-fpm,
php-json,
php-pdo,
php-mysql,
php-zip,
php-gd,
php-mbstring,
php-curl,
php-xml,
php-pear,
php-bcmath,
composer,
unzip,
jq,
net-tools,
nginx
Conflicts: apache2
Description: <insert up to 60 chars description>
<Insert long description, indented with spaces.>

43
debian/copyright vendored
View File

@ -1,43 +0,0 @@
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Source: <url://example.com>
Upstream-Name: ogdhcp
Upstream-Contact: <preferred name and address to reach the upstream project>
Files:
*
Copyright:
<years> <put author's name and email here>
<years> <likewise for another author>
License: GPL-3.0+
Files:
debian/*
Copyright:
2025 vagrant <vagrant@build>
License: GPL-3.0+
License: GPL-3.0+
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
.
This package is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
Comment:
On Debian systems, the complete text of the GNU General
Public License version 3 can be found in "/usr/share/common-licenses/GPL-3".
# Please also look if there are files or directories which have a
# different copyright/license attached and list them here.
# Please avoid picking licenses with terms that are more restrictive than the
# packaged work, as it may make Debian's contributions unacceptable upstream.
#
# If you need, there are some extra license texts available in two places:
# /usr/share/debhelper/dh_make/licenses/
# /usr/share/common-licenses/

11
debian/ogdhcp.config vendored
View File

@ -1,11 +0,0 @@
#!/bin/sh
set -e
. /usr/share/debconf/confmodule
db_input high opengnsys/ogdhcp_interfaces || true
db_input high opengnsys/ogdhcp_ip|| true
db_input high opengnsys/ogdhcp_ogbootIP || true
db_go

16
debian/ogdhcp.dirs vendored
View File

@ -1,16 +0,0 @@
/opt/opengnsys/ogdhcp/api
/opt/opengnsys/ogdhcp/api/bin
/opt/opengnsys/ogdhcp/api/config
/opt/opengnsys/ogdhcp/api/public
/opt/opengnsys/ogdhcp/api/src
/opt/opengnsys/ogdhcp/api/templates
/opt/opengnsys/ogdhcp/api/var/
/opt/opengnsys/ogdhcp/api/var/cache
/opt/opengnsys/ogdhcp/api/var/log
/opt/opengnsys/ogdhcp/api/vendor
/opt/opengnsys/ogdhcp/etc
/opt/opengnsys/ogdhcp/etc/kea/backup
/opt/opengnsys/ogdhcp/docs

View File

@ -1,4 +0,0 @@
api /opt/opengnsys/ogdhcp/
etc /opt/opengnsys/ogdhcp/
docs /opt/opengnsys/ogdhcp/
etc/systemd/system/kea-ctrl-agent.service.d/override.conf /etc/systemd/system/kea-ctrl-agent.service.d/

129
debian/ogdhcp.postinst vendored
View File

@ -1,129 +0,0 @@
#!/bin/bash
set -e
. /usr/share/debconf/confmodule
KEA_CTRL_AGENT_CONF="/etc/kea/kea-ctrl-agent.conf"
PUBLIC_DIR=/opt/opengnsys/ogdhcp/api/public
db_get opengnsys/ogdhcp_interfaces
OGDHCP_INTERFACES="$RET"
db_get opengnsys/ogdhcp_ip
OGDHCP_IP="$RET"
db_get opengnsys/ogdhcp_ogbootIP
OGBOOT_IP="$RET"
case "$1" in
configure)
echo "Configurando ogdhcp..."
# Configuración de kea-ctrl-agent
echo "Eliminando autenticación de kea-ctrl-agent..."
if [ -e "$KEA_CTRL_AGENT_CONF" ]; then
dpkg-divert --package ogdhcp --divert "$KEA_CTRL_AGENT_CONF.dpkg-dist" --rename "$KEA_CTRL_AGENT_CONF"
cp -a "$KEA_CTRL_AGENT_CONF.dpkg-dist" "$KEA_CTRL_AGENT_CONF"
if grep -q '^[^#]*"authentication": {' "$KEA_CTRL_AGENT_CONF"; then
sed -i '/"authentication": {/,/^[[:space:]]*},/ {
s/^\([[:space:]]*\)\([^#]\)/\1#\2/
}' "$KEA_CTRL_AGENT_CONF"
fi
fi
# Configuración de AppArmor
APPARMOR_LOCAL_PROFILE="/etc/apparmor.d/local/usr.sbin.kea-dhcp4"
echo "Añadiendo permisos personalizados a AppArmor para kea-dhcp4..."
mkdir -p "$(dirname "$APPARMOR_LOCAL_PROFILE")"
cat > "$APPARMOR_LOCAL_PROFILE" <<EOF
/etc/kea/ rw,
/etc/kea/** rw,
EOF
echo "Recargando perfiles de AppArmor..."
apparmor_parser -r /etc/apparmor.d/usr.sbin.kea-dhcp4
if [ $? -eq 0 ]; then
echo "El perfil de AppArmor se recargó correctamente."
else
echo "Error al recargar el perfil de AppArmor."
fi
# Configuración de nginx
echo "Configurando nginx..."
PHP_VERSION=$(php -r 'echo PHP_MAJOR_VERSION.".".PHP_MINOR_VERSION;')
if [ ! -f /etc/nginx/sites-available/ogdhcp.conf ]; then
cp /opt/opengnsys/ogdhcp/etc/nginxServer.conf.tmpl /etc/nginx/sites-available/ogdhcp.conf
sed -i "s|__PHPVERSION__|$PHP_VERSION|g" /etc/nginx/sites-available/ogdhcp.conf
sed -i "s|__SERVERIP__|$OGDHCP_IP|g" /etc/nginx/sites-available/ogdhcp.conf
sed -i "s|__PUBLICDIR__|$PUBLIC_DIR|g" /etc/nginx/sites-available/ogdhcp.conf
ln -s /etc/nginx/sites-available/ogdhcp.conf /etc/nginx/sites-enabled/ogdhcp.conf
else
echo "El archivo /etc/nginx/sites-available/ogdhcp.conf ya existe."
fi
# Configuración de php-fpm
echo "Configurando php-fpm..."
if [ ! -f /etc/php/$PHP_VERSION/fpm/pool.d/ogdhcp.conf ]; then
cp /opt/opengnsys/ogdhcp/etc/php/fpm/ogdhcp-fpm.conf /etc/php/$PHP_VERSION/fpm/pool.d/ogdhcp.conf
fi
# Configuración de kea-dhcp4
echo "Configurando kea-dhcp4..."
IFS=',' read -r -a INTERFACES <<< "$OGDHCP_INTERFACES"
KEA_CONFIG="/etc/kea/kea-dhcp4.conf"
if [ -e "$KEA_CONFIG" ]; then
dpkg-divert --package ogdhcp --divert "$KEA_CONFIG.dpkg-dist" --rename "$KEA_CONFIG"
cat > "$KEA_CONFIG" <<EOF
{
"Dhcp4": {
"interfaces-config": {
"interfaces": [ $(
for interface in "${INTERFACES[@]}"; do
echo "\"$interface\""
done | paste -sd "," -
) ]
},
"client-classes": [
{
"name": "UEFI-64",
"test": "not substring(option[60].hex,0,20) == 'PXEClient:Arch:00000'",
"boot-file-name": "ipxe.efi",
"next-server": "$OGBOOT_IP"
},
{
"name": "Legacy",
"test": "substring(option[60].hex,0,20) == 'PXEClient:Arch:00000'",
"boot-file-name": "undionly.kpxe",
"next-server": "$OGBOOT_IP"
}
],
"control-socket": {
"socket-name": "/run/kea/kea4-ctrl-socket",
"socket-type": "unix"
}
}
}
EOF
fi
;;
abort-upgrade|abort-remove|abort-deconfigure)
;;
*)
echo "postinst called with unknown argument '$1'" >&2
exit 1
;;
esac
chown opengnsys:www-data /opt/opengnsys/
chown -R opengnsys:www-data /opt/opengnsys/ogdhcp
chown -R _kea:_kea /etc/kea
# Reiniciar servicios
systemctl daemon-reload
systemctl restart nginx
systemctl restart kea-dhcp4-server
systemctl restart kea-ctrl-agent
systemctl restart php$PHP_VERSION-fpm
exit 0

15
debian/ogdhcp.preinst vendored
View File

@ -1,15 +0,0 @@
#!/bin/bash
set -e
# Asegurarse de que el usuario exista
USER="opengnsys"
HOME_DIR="/opt/opengnsys"
if id "$USER" &>/dev/null; then
echo "El usuario $USER ya existe."
else
echo "Creando el usuario $USER con home en $HOME_DIR."
useradd -m -d "$HOME_DIR" -s /bin/bash "$USER"
fi
exit 0

69
debian/ogdhcp.prerm vendored
View File

@ -1,69 +0,0 @@
#!/bin/bash
set -e
KEA_CTRL_AGENT_CONF="/etc/kea/kea-ctrl-agent.conf"
KEA_CONFIG="/etc/kea/kea-dhcp4.conf"
APPARMOR_LOCAL_PROFILE="/etc/apparmor.d/local/usr.sbin.kea-dhcp4"
NGINX_CONF="/etc/nginx/sites-available/ogdhcp.conf"
PHP_FPM_CONF="/etc/php/*/fpm/pool.d/ogdhcp.conf"
case "$1" in
remove)
echo "Preparando eliminación de ogdhcp..."
# Restaurar el archivo kea-ctrl-agent.conf original si se modificó
if [ -e "$KEA_CTRL_AGENT_CONF.dpkg-dist" ]; then
echo "Restaurando configuración original de kea-ctrl-agent..."
mv -f "$KEA_CTRL_AGENT_CONF.dpkg-dist" "$KEA_CTRL_AGENT_CONF"
dpkg-divert --package ogdhcp --remove --divert "$KEA_CTRL_AGENT_CONF.dpkg-dist" --rename "$KEA_CTRL_AGENT_CONF"
fi
# Restaurar el archivo kea-dhcp4.conf original si se modificó
if [ -e "$KEA_CONFIG.dpkg-dist" ]; then
echo "Restaurando configuración original de kea-dhcp4..."
mv -f "$KEA_CONFIG.dpkg-dist" "$KEA_CONFIG"
dpkg-divert --package ogdhcp --remove --divert "$KEA_CONFIG.dpkg-dist" --rename "$KEA_CONFIG"
fi
# Eliminar perfil personalizado de AppArmor
if [ -f "$APPARMOR_LOCAL_PROFILE" ]; then
echo "Eliminando perfil de AppArmor personalizado..."
rm -f "$APPARMOR_LOCAL_PROFILE"
apparmor_parser -r /etc/apparmor.d/usr.sbin.kea-dhcp4 || true
fi
# Eliminar configuración de nginx
if [ -f "$NGINX_CONF" ]; then
echo "Eliminando configuración de nginx..."
rm -f "$NGINX_CONF"
rm -f "/etc/nginx/sites-enabled/ogdhcp.conf"
fi
# Eliminar configuración de php-fpm
echo "Eliminando configuración de php-fpm..."
rm -f $PHP_FPM_CONF
# Restaurar permisos de directorios
echo "Restaurando permisos en /opt/opengnsys..."
chown root:root /opt/opengnsys/
chown -R root:root /opt/opengnsys/ogdhcp
# Detener servicios antes de eliminar el paquete
echo "Deteniendo servicios..."
systemctl stop nginx || true
systemctl stop kea-dhcp4-server || true
systemctl stop kea-ctrl-agent || true
systemctl stop php*-fpm || true
;;
upgrade|deconfigure)
echo "Preparando actualización o desconfiguración de ogdhcp..."
;;
*)
echo "prerm llamado con un argumento desconocido '$1'" >&2
exit 1
;;
esac
exit 0

View File

@ -1,19 +0,0 @@
Template: opengnsys/ogdhcp_interfaces
Type: string
Default: eth0
Description: Interfaces para DHCP
Template: opengnsys/ogdhcp_ip
Type: string
Default: 127.0.0.1
Description: IP para el servicio de ogdhcp
Template: opengnsys/ogboot_ogliveUrl
Type: string
Default: 127.0.0.1
Description: URL del OgLive a instalar
Template: opengnsys/ogdhcp_ogbootIP
Type: string
Default: 127.0.0.1
Description: Ip para el servicio de ogBoot

28
debian/rules vendored
View File

@ -1,28 +0,0 @@
#!/usr/bin/make -f
# See debhelper(7) (uncomment to enable).
# Output every command that modifies files on the build system.
#export DH_VERBOSE = 1
# See FEATURE AREAS in dpkg-buildflags(1).
#export DEB_BUILD_MAINT_OPTIONS = hardening=+all
# See ENVIRONMENT in dpkg-buildflags(1).
# Package maintainers to append CFLAGS.
#export DEB_CFLAGS_MAINT_APPEND = -Wall -pedantic
# Package maintainers to append LDFLAGS.
#export DEB_LDFLAGS_MAINT_APPEND = -Wl,--as-needed
%:
dh $@
override_dh_auto_build:
cd api; \
rm -rf var/cache/*; \
mkdir -p bin/; \
mkdir -p public; \
COMPOSER_ALLOW_SUPERUSER=1 APP_ENV=prod composer install --no-interaction --no-progress --optimize-autoloader; \
COMPOSER_ALLOW_SUPERUSER=1 APP_ENV=prod composer update doctrine/dbal;

View File

@ -1 +0,0 @@
3.0 (native)

View File

@ -2,7 +2,6 @@
<VirtualHost *:80>
ServerName localhost
ServerAlias api-test
DocumentRoot /opt/ogdhcp/public
<Directory /opt/ogdhcp/public>
@ -22,7 +21,7 @@
</IfModule>
<FilesMatch \.php$>
SetHandler "proxy:unix:/run/php/php8.3-fpm.sock|fcgi://localhost/"
SetHandler "proxy:unix:/run/php/php8.1-fpm.sock|fcgi://localhost/"
</FilesMatch>
ErrorLog ${APACHE_LOG_DIR}/ogdhcp_error.log

View File

@ -1,42 +0,0 @@
server {
listen 8081;
server_name __SERVERIP__ localhost; # IP del servidor
# Raíz del documento para el proyecto Symfony
root __PUBLICDIR__;
# Bloque para manejar las solicitudes a /ogdhcp
location /ogdhcp {
try_files $uri $uri/ /index.php?$query_string;
# Aumentar el tiempo de espera por el install ogdhcp (si es necesario)
proxy_read_timeout 600;
proxy_connect_timeout 600;
proxy_send_timeout 600;
send_timeout 600;
}
# Bloque para manejar las solicitudes a index.php
location ~ ^/index.php(/|$) {
include fastcgi_params;
fastcgi_pass unix:/run/php/php__PHPVERSION__-fpm-ogdhcp.sock;
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;
}
# Bloque para devolver 404 en cualquier solicitud a archivos PHP que no sean index.php
location ~ \.php$ {
return 404;
}
# Logs de error y acceso para el proyecto Symfony
error_log /var/log/nginx/ogdhcp_error.log;
access_log /var/log/nginx/ogdhcp_access.log;
# Manejo de la ruta para la documentación de la API (Swagger)
location /ogdhcp/api/doc {
try_files $uri /index.php?$query_string;
}
}

View File

@ -1,12 +0,0 @@
[ogdhcp]
user = opengnsys
group = www-data
listen = /var/run/php/php8.3-fpm-ogdhcp.sock
listen.owner = opengnsys
listen.group = www-data
pm = dynamic
pm.max_children = 5
pm.start_servers = 2
pm.min_spare_servers = 1
pm.max_spare_servers = 3

View File

@ -1,4 +0,0 @@
[Unit]
# Eliminamos la condición de existencia del archivo de contraseña
ConditionFileNotEmpty=

View File

@ -1,7 +0,0 @@
{
"interfaces": ["eth0", "eth1"],
"ogbootIP": "172.17.8.37",
"ogDhcpIP": "172.17.8.37",
"ogDhcp_Dir": "/opt/opengnsys/ogdhcp"
}

View File

@ -10,13 +10,7 @@ function globalSetup() {
current_dir=$(dirname "$0")
PROGRAMDIR=$(readlink -e "$current_dir")
PROGRAMNAME=$(basename "$0")
OPENGNSYS_CLIENT_USER="opengnsys"
current_dir=$(dirname "$0")
PROGRAMDIR=$(readlink -e "$current_dir")
# Ruta del archivo config_ogdhcp.json proporcionado por el usuario
CONFIG_FILE="$PROGRAMDIR/config_ogdhcp.json"
OPENGNSYS_CLIENT_USER="ogdhcp"
# Comprobar si se ha descargado el paquete comprimido (REMOTE=0) o sólo el instalador (REMOTE=1).
if [ -d "$PROGRAMDIR/../installer" ]; then
@ -33,8 +27,7 @@ function globalSetup() {
# Directorios de instalación y destino de OpenGnsys.
WORKDIR=/tmp/ogdhcp_installer
INSTALL_TARGET=$(jq -r '.ogDhcp_Dir' "$CONFIG_FILE")
SYMFONY_TARGET=$INSTALL_TARGET/api
INSTALL_TARGET=/opt/ogdhcp
PATH=$PATH:$INSTALL_TARGET/bin
if command -v service &>/dev/null; then
@ -48,17 +41,21 @@ function globalSetup() {
ENABLESERVICE="eval update-rc.d \$service defaults"
DISABLESERVICE="eval update-rc.d \$service disable"
# Variables globales
DEFAULTDEV=""
NGINX_TEMPLATE="$INSTALL_TARGET/etc/nginxServer.conf.tmpl"
NGINX_OUTPUT="/etc/nginx/sites-available/ogdhcp.conf"
NGINX_CONF_PATH="/etc/nginx/nginx.conf"
PHP_FPM_CONF_PATH="/etc/php/__PHPVERSION__/fpm/pool.d/www.conf"
NEW_FPM_CONF_PATH="/etc/php/__PHPVERSION__/fpm/pool.d/ogdhcp.conf"
SOCKET_PATH="/run/php/php__PHPVERSION__-fpm-ogdhcp.sock"
APACHESERV=apache2
APACHECFGDIR=/etc/apache2
APACHESITESDIR=sites-available
APACHEOGSITE=ogdhcp
APACHEUSER="www-data"
APACHEGROUP="www-data"
APACHEENABLEMODS="a2enmod headers ssl rewrite proxy_fcgi fastcgi actions alias"
APACHEENABLESSL="a2ensite default-ssl"
APACHEENABLEOG="a2ensite $APACHEENABLEOG"
APACHEMAKECERT="make-ssl-cert generate-default-snakeoil --force-overwrite"
PHPFPMSERV=php7.2-fpm
# Registro de incidencias.
OGLOGFILE="$SYMFONY_TARGET/var/log/${PROGRAMNAME%.sh}.log"
OGLOGFILE="$INSTALL_TARGET/var/log/${PROGRAMNAME%.sh}.log"
LOG_FILE="/tmp/$(basename "$OGLOGFILE")"
}
@ -83,32 +80,47 @@ function checkDependencies() {
php-bcmath
composer
unzip
apache2
libapache2-mod-php
kea-dhcp4-server
kea-common
kea-ctrl-agent
jq
net-tools
nginx
)
export DEBIAN_FRONTEND=noninteractive
apt-get update -y
# Comprobar cada dependencia
for dep in "${DEPENDENCIES[@]}"; do
if ! dpkg -s "$dep" >/dev/null 2>&1; then
echoAndLog "$dep is not installed. Installing..."
apt-get install -y --no-install-recommends "$dep"
sudo apt-get install -y "$dep"
else
echoAndLog "$dep is already installed."
fi
done
sed -i '/ConditionFileNotEmpty=\/etc\/kea\/kea-api-password/d' /usr/lib/systemd/system/kea-ctrl-agent.service
chown -R _kea:_kea /etc/kea
systemctl daemon-reload
systemctl restart kea-ctrl-agent.service
echoAndLog "Dependencies checked."
}
# Función para instalar los paquetes necesarios para KEA-DHCP
install_kea() {
sudo apt-get install -y isc-kea-common isc-kea-ctrl-agent isc-kea-dhcp4-server isc-kea-dhcp6-server isc-kea-admin
}
# Función para instalar Composer
install_composer() {
curl -sS https://getcomposer.org/installer | php
sudo mv composer.phar /usr/local/bin/composer
}
# Función para instalar Swagger UI
install_swagger() {
sudo apt-get install -y unzip
wget https://github.com/swagger-api/swagger-ui/archive/master.zip
unzip master.zip -d /var/www/html/
sudo mv /var/www/html/swagger-ui-master /var/www/html/swagger-ui
}
# Obtiene el código fuente del proyecto desde el repositorio de GitHub.
function downloadCode() {
@ -139,26 +151,37 @@ function createDirs() {
fi
local path_opengnsys_base="$1"
local symfony_target="$path_opengnsys_base/api"
# Crear estructura de directorios.
echoAndLog "${FUNCNAME}(): creating directory paths in $path_opengnsys_base"
mkdir -p "$symfony_target"/{bin,config,docs,public,src,templates,var/{cache,log},vendor}
mkdir -p "$path_opengnsys_base"/etc/kea/backup
mkdir -p "$path_opengnsys_base"/{bin,config,docs,public,src,etc/kea/backup,templates,var/{cache,log},vendor}
if [ $? -ne 0 ]; then
errorAndLog "${FUNCNAME}(): error while creating dirs. Do you have write permissions?"
return 1
fi
# Mover el fichero de registro de instalación al directorio de logs.
echoAndLog "${FUNCNAME}(): moving installation log file"
mv "$LOG_FILE" "$symfony_target/var/log" && LOG_FILE="$OGLOGFILE"
usermod -aG $OPENGNSYS_CLIENT_USER _kea
# Crear usuario ficticio.
if id -u "$OPENGNSYS_CLIENT_USER" &>/dev/null; then
echoAndLog "${FUNCNAME}(): user \"$OPENGNSYS_CLIENT_USER\" is already created"
else
echoAndLog "${FUNCNAME}(): creating OpenGnsys user"
useradd "$OPENGNSYS_CLIENT_USER" 2>/dev/null
if [ $? -ne 0 ]; then
errorAndLog "${FUNCNAME}(): error creating OpenGnsys user"
return 1
fi
fi
# Mover el fichero de registro de instalación al directorio de logs.
echoAndLog "${FUNCNAME}(): moving installation log file"
touch "$symfony_target/var/log/dev.log"
mv "$LOG_FILE" "$path_opengnsys_base/var/log" && LOG_FILE="$OGLOGFILE"
chmod 777 "$LOG_FILE"
sudo chmod -R 777 "$path_opengnsys_base/etc"
# Mover el fichero de registro de instalación al directorio de logs.
echoAndLog "${FUNCNAME}(): moving installation log file"
touch "$path_opengnsys_base/var/log/dev.log"
chmod 777 "$path_opengnsys_base/var/log/dev.log"
echoAndLog "${FUNCNAME}(): directory paths created"
return 0
@ -166,56 +189,23 @@ function createDirs() {
# Cambiar permisos de usuario
echoAndLog "Changing user permission"
chown -R "$OPENGNSYS_CLIENT_USER:$OPENGNSYS_CLIENT_USER" "$INSTALL_TARGET"
}
# Copiar .env
cp -a "$WORKDIR/ogdhcp/.env" "${path_opengnsys_base}/.env"
}
function create_ogdhcp_project {
# Crea el usuario ogdhcp si no existe
echo "Creating ogdhcp user..."
# Cambia al usuario ogdhcp y crea el proyecto Symfony
local path_opengnsys_base="$1"
local symfony_target="$path_opengnsys_base/api"
echo $symfony_target
# Verificar si el usuario OPENGNSYS_CLIENT_USER existe
if id -u "$OPENGNSYS_CLIENT_USER" &>/dev/null; then
# Salida de getent passwd -> opengnsys:x:1001:1001::/opt/opengnsys:/bin/sh
CURRENT_HOME=$(getent passwd "$OPENGNSYS_CLIENT_USER" | cut -d: -f6)
echoAndLog "${FUNCNAME[0]}(): user \"$OPENGNSYS_CLIENT_USER\" already exists with home \"$CURRENT_HOME\""
# Si el home no es correcto, cambiarlo
if [ "$CURRENT_HOME" != "/opt/opengnsys" ]; then
echoAndLog "${FUNCNAME[0]}(): updating home directory for \"$OPENGNSYS_CLIENT_USER\" to \"/opt/opengnsys\""
usermod -d "/opt/opengnsys" -m "$OPENGNSYS_CLIENT_USER"
if [ $? -ne 0 ]; then
errorAndLog "${FUNCNAME[0]}(): error updating home for \"$OPENGNSYS_CLIENT_USER\""
return 1
fi
fi
else
# Crear usuario si no existe
echoAndLog "${FUNCNAME[0]}(): creating OpenGnsys user \"$OPENGNSYS_CLIENT_USER\""
useradd --create-home -d "/opt/opengnsys" --shell "/bin/bash" "$OPENGNSYS_CLIENT_USER"
if [ $? -ne 0 ]; then
errorAndLog "${FUNCNAME[0]}(): error creating user \"$OPENGNSYS_CLIENT_USER\""
return 1
fi
fi
# Asegurar que todos los usuarios puedan entrar y leer /opt/opengnsys
echoAndLog "${FUNCNAME[0]}(): setting permissions for /opt/opengnsys"
# sudo chmod 755 /opt/opengnsys
# Crea el directorio path_opengnsys_base con el usuario opengnsys
echoAndLog "${FUNCNAME}(): creating directory $path_opengnsys_base with opengnsys user"
sudo mkdir -p "$path_opengnsys_base"
sudo chown opengnsys:opengnsys $path_opengnsys_base
if [ $? -ne 0 ]; then
errorAndLog "${FUNCNAME}(): error while creating directory $path_opengnsys_base"
return 1
fi
echoAndLog "Directory $path_opengnsys_base created with opengnsys user"
composer create-project symfony/website-skeleton "$path_opengnsys_base"
pushd "$path_opengnsys_base" || return
# Elimina el archivo composer.lock
rm composer.lock
popd || return
echoAndLog "Esqueleto de la aplicación creado y archivo composer.lock eliminado."
}
function copyServerFiles() {
if [ $# -ne 1 ]; then
errorAndLog "${FUNCNAME}(): invalid number of parameters"
@ -223,17 +213,19 @@ function copyServerFiles() {
fi
local path_opengnsys_base="$1"
local symfony_target="$path_opengnsys_base/api"
local etc_target="$path_opengnsys_base/etc"
# Lista de ficheros y directorios origen y de directorios destino.
local SOURCES=(
config
#public
src
etc
templates
tests
vendor
.env
bin
composer.json
composer.lock
phpunit.xml.dist
symfony.lock
)
@ -241,9 +233,13 @@ function copyServerFiles() {
config
#public
src
etc
templates
tests
vendor
.env
bin
composer.json
composer.lock
phpunit.xml.dist
symfony.lock
)
@ -256,42 +252,72 @@ function copyServerFiles() {
# Copiar ficheros.
echoAndLog "${FUNCNAME}(): copying files to server directories"
pushd "$WORKDIR/ogdhcp/api" || return
pushd "$WORKDIR/ogdhcp" || return
local i
for (( i = 0; i < ${#SOURCES[@]}; i++ )); do
if [ -f "${SOURCES[$i]}" ]; then
echoAndLog "Copying ${SOURCES[$i]} to $symfony_target/${TARGETS[$i]}"
cp -a "${SOURCES[$i]}" "$symfony_target/${TARGETS[$i]}"
echoAndLog "Copying ${SOURCES[$i]} to $path_opengnsys_base/${TARGETS[$i]}"
cp -a "${SOURCES[$i]}" "$path_opengnsys_base/${TARGETS[$i]}"
elif [ -d "${SOURCES[$i]}" ]; then
echoAndLog "Copying content of ${SOURCES[$i]} to $symfony_target/${TARGETS[$i]}"
cp -a "${SOURCES[$i]}"/* "$symfony_target/${TARGETS[$i]}"
echoAndLog "Copying content of ${SOURCES[$i]} to $path_opengnsys_base/${TARGETS[$i]}"
cp -a "${SOURCES[$i]}"/* "$path_opengnsys_base/${TARGETS[$i]}"
else
warningAndLog "Unable to copy ${SOURCES[$i]} to $symfony_target/${TARGETS[$i]}"
warningAndLog "Unable to copy ${SOURCES[$i]} to $path_opengnsys_base/${TARGETS[$i]}"
fi
done
pushd "$WORKDIR/ogdhcp" || return
# Copiar el directorio etc
echoAndLog "Copying etc directory to $path_opengnsys_base"
cp -a etc "$path_opengnsys_base"
if [ $? -ne 0 ]; then
errorAndLog "Error while copying etc directory to $path_opengnsys_base"
return 1
fi
echoAndLog "Changing user permission"
chown -R "$OPENGNSYS_CLIENT_USER:$OPENGNSYS_CLIENT_USER" "$INSTALL_TARGET"
popd || return
}
function downloadComposer() {
echoAndLog "Downloading composer.phar..."
# Crear el directorio de trabajo si no existe
mkdir -p "$WORKDIR/ogdhcp/bin" || return
# Cambiar al directorio de trabajo
pushd "$WORKDIR/ogdhcp/bin" || return
# Descargar composer.phar
curl -sS https://getcomposer.org/installer | php
# Comprobar si la descarga fue exitosa
if [ ! -f composer.phar ]; then
errorAndLog "Failed to download composer.phar"
popd
return 1
fi
# Crear el directorio de destino si no existe
mkdir -p "/opt/ogdhcp/bin" || return
# Mover composer.phar a /opt/ogdhcp/bin
mv composer.phar "/opt/ogdhcp/bin/"
# Comprobar si el movimiento fue exitoso
if [ ! -f "/opt/ogdhcp/bin/composer.phar" ]; then
errorAndLog "Failed to move composer.phar to /opt/ogdhcp/bin"
popd
return 1
fi
# Volver al directorio original
popd || return
echoAndLog "composer.phar downloaded and moved to /opt/ogdhcp/bin"
return 0
}
function runComposer() {
echoAndLog "Running composer.phar to install dependencies..."
local path_opengnsys_base="$1"
local symfony_target="$path_opengnsys_base/api"
pushd $symfony_target
pwd
# Cambiar al directorio donde está composer.phar
pushd /opt/ogdhcp/bin || return
# Ejecutar composer.phar
sudo -u "$OPENGNSYS_CLIENT_USER" composer --no-interaction install
sudo -u "$OPENGNSYS_CLIENT_USER" php composer.phar install
# Comprobar si la ejecución fue exitosa
if [ $? -ne 0 ]; then
@ -300,271 +326,92 @@ function runComposer() {
return 1
fi
# Volver al directorio original
popd || return
echoAndLog "composer.phar ran successfully and dependencies were installed"
return 0
}
function install_swagger_ui {
# Define la URL del archivo de Swagger UI que quieres descargar
swagger_ui_url="https://github.com/swagger-api/swagger-ui/archive/refs/heads/master.zip"
get_first_network_interface_with_traffic() {
while read -r line; do
if [[ "$line" == *:* ]]; then
interface=$(echo "$line" | cut -d ':' -f 1 | xargs)
if [[ "$interface" != "lo" ]]; then
received_bytes=$(echo "$line" | awk '{print $2}')
transmitted_bytes=$(echo "$line" | awk '{print $10}')
if (( received_bytes > 0 || transmitted_bytes > 0 )); then
DEFAULTDEV="$interface"
break
fi
fi
fi
done < /proc/net/dev
# Define la ruta donde quieres descomprimir Swagger UI
swagger_ui_path="/tmp/swagger-ui"
# Define la ruta de destino para los archivos de Swagger UI
destination_path="/opt/ogdhcp/public"
# Crea los directorios si no existen
mkdir -p "$swagger_ui_path"
mkdir -p "$destination_path"
# Descarga el archivo de Swagger UI
wget "$swagger_ui_url" -O /tmp/swagger-ui.zip
# Descomprime el archivo de Swagger UI en la ruta especificada
unzip /tmp/swagger-ui.zip -d "$swagger_ui_path"
# Copia los archivos de Swagger UI al directorio de destino
cp -r "$swagger_ui_path"/swagger-ui-master/dist/* "$destination_path"
# Elimina el archivo descargado y el directorio temporal
rm /tmp/swagger-ui.zip
rm -r "$swagger_ui_path"
/opt/ogdhcp/vendor/bin/openapi /opt/ogdhcp/src/DhcpBundle/Controller/ -o "$destination_path/swagger.json"
echo "Swagger UI instalado en $destination_path."
}
comment_auth_kea() {
KEA_CTRL_AGENT_CONF="/etc/kea/kea-ctrl-agent.conf"
# Verificar si el bloque de "authentication" ya está comentado
if grep -q '^[^#]*"authentication": {' "$KEA_CTRL_AGENT_CONF"; then
echo "Comentando el bloque de autenticación en $KEA_CTRL_AGENT_CONF..."
# Comentar solo el bloque de authentication desde la apertura hasta la línea con '},'
sed -i '/"authentication": {/,/^[[:space:]]*},/ {
s/^\([[:space:]]*\)\([^#]\)/\1#\2/
}' "$KEA_CTRL_AGENT_CONF"
echo "Bloque de autenticación comentado correctamente."
else
echo "El bloque de autenticación ya está comentado."
function installWebConsoleApacheConf() {
if [ $# -ne 2 ]; then
errorAndLog "${FUNCNAME}(): invalid number of parameters"
exit 1
fi
# Verificar si el bloque fue comentado correctamente
if grep -q '^#\s*"authentication": {' "$KEA_CTRL_AGENT_CONF"; then
echo "Confirmación: Bloque de autenticación comentado correctamente."
# Reiniciar el servicio de Kea Control Agent para aplicar los cambios
echo "Reiniciando el agente de Kea Control Agent..."
sudo systemctl restart kea-ctrl-agent.service
if systemctl is-active --quiet kea-ctrl-agent.service; then
echo "El agente de Kea Control Agent se ha reiniciado correctamente."
else
echo "Error: No se pudo reiniciar el agente de Kea Control Agent."
fi
else
echo "Error: No se pudo comentar correctamente el bloque de autenticación."
fi
}
# Función para obtener la dirección IP de una interfaz
get_ip_address() {
local interface="$1"
ip -4 addr show "$interface" | grep -oP "(?<=inet\s)\d+(\.\d+){3}"
}
# Función para obtener la versión de PHP instalada
get_php_fpm_version() {
php -v | grep -oP "PHP \K\d+\.\d+"
}
add_write_permission_apparmor() {
APPARMOR_PROFILE="/etc/apparmor.d/usr.sbin.kea-dhcp4"
# Comprobar si las líneas existen
if grep -q "/etc/kea/ r," "$APPARMOR_PROFILE" && grep -q "/etc/kea/** r," "$APPARMOR_PROFILE"; then
echo "Modificando permisos en $APPARMOR_PROFILE..."
# Modificar las líneas /etc/kea/ r, y /etc/kea/** r, añadiendo w
sed -i 's#/etc/kea/ r,#/etc/kea/ rw,#g' "$APPARMOR_PROFILE"
sed -i 's#/etc/kea/\*\* r,#/etc/kea/** rw,#g' "$APPARMOR_PROFILE"
echo "Permisos de escritura añadidos correctamente a $APPARMOR_PROFILE."
else
echo "Las líneas no fueron encontradas o ya están modificadas."
fi
# Recargar el perfil de AppArmor para aplicar los cambios
echo "Recargando el perfil de AppArmor para kea-dhcp4..."
sudo apparmor_parser -r "$APPARMOR_PROFILE"
if [ $? -eq 0 ]; then
echo "El perfil de AppArmor se recargó correctamente."
else
echo "Error al recargar el perfil de AppArmor."
fi
}
# Función para configurar Nginx
setup_nginx() {
local path_opengnsys_base="$1"
local symfony_target="$path_opengnsys_base/api"
local public_dir="$symfony_target/public"
#ip_address_server=$(get_ip_address "$DEFAULTDEV")
if [[ ! -f "$CONFIG_FILE" ]]; then
echo "Error: El archivo de configuración no se encontró."
exit 1
local path_apache2_confd="$2"
local OGHDPCDIR="${path_opengnsys_base}/public"
local sockfile
if [ ! -d "$path_apache2_confd" ]; then
errorAndLog "${FUNCNAME}(): path to apache2 conf.d can not found, verify your server installation"
return 1
fi
ip_address_server=$(jq -r '.ogDhcpIP' "$CONFIG_FILE")
mkdir -p "$path_apache2_confd/{sites-available,sites-enabled}"
if [[ -z "$ip_address_server" ]]; then
echo "Error: No se pudo obtener la dirección IP del servidor desde el archivo de configuración."
exit 1
fi
php_version=$(get_php_fpm_version)
echoAndLog "${FUNCNAME}(): creating apache2 config file.."
if [[ -z "$php_version" ]]; then
echo "Error: No se pudo obtener la versión de PHP."
exit 1
fi
# Activar PHP-FPM.
echoAndLog "${FUNCNAME}(): configuring PHP-FPM"
service="$PHPFPMSERV"
$ENABLESERVICE; $STARTSERVICE
sockfile=$(find /run/php -name "php*.sock" -type s -print 2>/dev/null | tail -1)
# Leer y modificar la plantilla de configuración de nginx
if [[ ! -f "$NGINX_TEMPLATE" ]]; then
echo "Error: La plantilla de Nginx no se encontró."
exit 1
fi
nginx_content=$(<"$NGINX_TEMPLATE")
nginx_content="${nginx_content//__SERVERIP__/$ip_address_server}"
nginx_content="${nginx_content//__PHPVERSION__/$php_version}"
nginx_content="${nginx_content//__PUBLICDIR__/$public_dir}"
# Activar módulos de Apache.
$APACHEENABLEMODS
# Crear el archivo de configuración de Nginx
echo "$nginx_content" > "$NGINX_OUTPUT"
echo "Archivo de configuración de Nginx creado en $NGINX_OUTPUT."
# Crear el enlace simbólico
ln -sf "$NGINX_OUTPUT" /etc/nginx/sites-enabled/ogdhcp.conf
echo "Enlace simbólico creado en /etc/nginx/sites-enabled/ogdhcp.conf."
# Modificar nginx.conf para ejecutar como opengnsys
sed -i 's/user www-data;/user opengnsys;/g' "$NGINX_CONF_PATH"
echo "Nginx configurado para ejecutarse como opengnsys."
# Reiniciar Nginx
systemctl restart nginx.service
echo "Servicio Nginx reiniciado."
}
# Función para modificar el archivo de configuración PHP-FPM
modify_php_fpm_config() {
php_version=$(get_php_fpm_version)
if [[ -z "$php_version" ]]; then
echo "Error: No se pudo obtener la versión de PHP."
exit 1
fi
php_fpm_conf_path="/etc/php/$php_version/fpm/pool.d/www.conf"
new_fpm_conf_path="/etc/php/$php_version/fpm/pool.d/ogdhcp.conf"
socket_path="/run/php/php$php_version-fpm-ogdhcp.sock"
# Verificar si el archivo new_fpm_conf_path ya existe
if [[ -f "$new_fpm_conf_path" ]]; then
echo "El archivo $new_fpm_conf_path ya existe. No se realizarán modificaciones."
return
fi
# Copiar el archivo www.conf a opengnsys.conf
cp "$php_fpm_conf_path" "$new_fpm_conf_path"
# Modificar el archivo ogdhcp.conf
sed -i 's/\[www\]/[ogdhcp]/g' "$new_fpm_conf_path"
sed -i 's/user = www-data/user = opengnsys/g' "$new_fpm_conf_path"
sed -i 's/group = www-data/group = opengnsys/g' "$new_fpm_conf_path"
sed -i "s|listen =.*|listen = $socket_path|g" "$new_fpm_conf_path"
sed -i 's/listen.owner = www-data/listen.owner = opengnsys/g' "$new_fpm_conf_path"
sed -i 's/listen.group = www-data/listen.group = opengnsys/g' "$new_fpm_conf_path"
# Reiniciar PHP-FPM
systemctl restart php"$php_version"-fpm.service
echo "PHP-FPM reiniciado."
# Verificar la creación del socket
if [[ -S "$socket_path" ]]; then
echo "Socket PHP-FPM $socket_path creado correctamente."
# Generar configuración de consola web a partir del archivo de plantilla.
if [ -n "$sockfile" ]; then
sed -e "s,OGHDPCDIR,$OGHDPCDIR,g" \
-e "s,proxy:fcgi:.*,proxy:unix:${sockfile%% *}|fcgi://localhost\",g" \
"$WORKDIR/ogdhcp/etc/apache.conf.tmpl" > "$path_apache2_confd/$APACHESITESDIR/${APACHEOGSITE}.conf"
else
echo "Error: El socket PHP-FPM $socket_path no se ha creado."
exit 1
sed -e "s,OGHDPCDIR,$OGHDPCDIR,g" \
"$WORKDIR/ogdhcp/server/etc/apache.conf.tmpl" > "$path_apache2_confd/$APACHESITESDIR/${APACHEOGSITE}.conf"
fi
$APACHEENABLEOG
if [ $? -ne 0 ]; then
errorAndLog "${FUNCNAME}(): config file can't be linked to apache conf, verify your server installation"
return 1
fi
echoAndLog "${FUNCNAME}(): config file created and linked, restarting apache daemon"
service="$APACHESERV"
$ENABLESERVICE; $STARTSERVICE
return 0
}
configure_kea() {
# Verificar si jq está instalado
if ! command -v jq &> /dev/null; then
echo "jq no está instalado. Por favor, instala jq para continuar."
exit 1
fi
# Verificar si el archivo de configuración existe
if [ ! -f "$CONFIG_FILE" ]; then
echo "El archivo $CONFIG_FILE no se encuentra. Asegúrate de que esté disponible antes de la instalación."
exit 1
fi
# Leer los parámetros del archivo JSON usando jq
INTERFACES=$(jq -r '.interfaces[]' "$CONFIG_FILE")
OGBOOT_IP=$(jq -r '.ogbootIP' "$CONFIG_FILE")
# Crear la configuración mínima de Kea DHCP
KEA_CONFIG="/etc/kea/kea-dhcp4.conf"
# Hacer una copia de seguridad del archivo kea-dhcp4.conf si ya existe
if [ -f "$KEA_CONFIG" ]; then
cp "$KEA_CONFIG" "$KEA_CONFIG.backup"
echo "Se ha creado una copia de seguridad del archivo de configuración actual en $KEA_CONFIG.backup"
fi
# Generar la configuración mínima para Kea DHCP
cat > "$KEA_CONFIG" << EOL
{
"Dhcp4": {
"interfaces-config": {
"interfaces": [ $(
for interface in $INTERFACES; do
echo "\"$interface\""
done | paste -sd "," -
) ]
},
"client-classes": [
{
"name": "UEFI-64",
"test": "not substring(option[60].hex,0,20) == 'PXEClient:Arch:00000'",
"boot-file-name": "ipxe.efi",
"next-server": "$OGBOOT_IP"
},
{
"name": "Legacy",
"test": "substring(option[60].hex,0,20) == 'PXEClient:Arch:00000'",
"boot-file-name": "undionly.kpxe",
"next-server": "$OGBOOT_IP"
}
],
"control-socket": {
"socket-name": "/run/kea/kea4-ctrl-socket",
"socket-type": "unix"
}
}
}
EOL
echo "Se ha generado la configuración mínima de Kea DHCP en $KEA_CONFIG"
# Reiniciar el servicio de Kea DHCP y verificar si se reinicia correctamente
echo "Reiniciando el servicio Kea DHCP..."
sudo systemctl restart kea-dhcp4-server.service
# Comprobar el estado del servicio Kea DHCP
if systemctl is-active --quiet kea-dhcp4-server.service; then
echo "Kea DHCP reiniciado correctamente."
else
echo "Error al reiniciar Kea DHCP."
exit 1
fi
}
#####################################################################
####### Algunas funciones útiles de propósito general:
#####################################################################
@ -604,18 +451,6 @@ if [ "$(whoami)" != 'root' ]; then
exit 1
fi
# Verificar si jq está instalado, si no, instalarlo
if ! command -v jq &> /dev/null; then
echo "jq no está instalado. Instalando jq..."
apt-get update -y
apt-get install -y jq
if [ $? -ne 0 ]; then
echo "Error al instalar jq. Por favor, instala jq manualmente y vuelve a intentarlo."
exit 1
fi
echo "jq instalado correctamente."
fi
globalSetup
echoAndLog "OpenGnsys installation begins at $(date)"
@ -624,8 +459,8 @@ mkdir -p $WORKDIR
pushd $WORKDIR
checkDependencies
install_kea
# Si es necesario, descarga el repositorio de código en directorio temporal
if [ $REMOTE -eq 1 ]; then
downloadCode $GIT_REPO
if [ $? -ne 0 ]; then
@ -636,7 +471,6 @@ else
ln -fs "$(dirname $PROGRAMDIR)" ogdhcp
fi
create_ogdhcp_project ${INSTALL_TARGET}
if [ $? -ne 0 ]; then
errorAndLog "Error while creating skeleton directory!"
@ -658,39 +492,18 @@ if [ $? -ne 0 ]; then
exit 1
fi
downloadComposer
comment_auth_kea
runComposer
install_swagger_ui
# Creando configuración de Apache.
installWebConsoleApacheConf $INSTALL_TARGET $APACHECFGDIR
if [ $? -ne 0 ]; then
errorAndLog "Error while commenting auth block!"
errorAndLog "Error configuring Apache for OpenGnsys Admin"
exit 1
fi
runComposer ${INSTALL_TARGET}
setup_nginx $INSTALL_TARGET
if [ $? -ne 0 ]; then
errorAndLog "Error configuring Nginx for OpenGnsys Admin"
exit 1
fi
modify_php_fpm_config
if [ $? -ne 0 ]; then
errorAndLog "Error configuring PHP-FPM for OpenGnsys Admin"
exit 1
fi
add_write_permission_apparmor
if [ $? -ne 0 ]; then
errorAndLog "Error adding write permission to AppArmor profile"
exit 1
fi
configure_kea
if [ $? -ne 0 ]; then
errorAndLog "Error configuring Kea DHCP initial configuration"
exit 1
fi
sudo apt-get update
# install_kea
# install_php
# install_composer
@ -699,4 +512,4 @@ fi
# Ahora puedes clonar e instalar el componente ogDhcp
# git clone <URL del repositorio de ogDhcp>
# cd <directorio de ogDhcp>
# composer install
# composer install

View File

@ -1,25 +0,0 @@
#!/bin/bash
set -x
URL_REPO="https://ognproject.evlt.uma.es/gitea/opengnsys/ogdhcp.git"
BRANCH=${OGDHCP_BRANCH:-"main"}
DOWNLOADDIR=${OGDHCP_DOWNLOADDIR:-"/tmp/ogdhcp"}
apt install -y git vim
git config --global http.sslVerify false
git clone -b $BRANCH $URL_REPO $DOWNLOADDIR
cd $DOWNLOADDIR/installer
ogBoot_ServerIP=${1:-"172.17.8.82"}
ogDhcp_ServerIP=${2:-"172.17.8.37"}
ogDhcp_Dir=${3:-"/opt/opengnsys/ogdhcp"}
cat > config_ogdhcp.json <<EOF
{
"interfaces": ["eth0", "eth1"],
"ogbootIP": "$ogBoot_ServerIP",
"ogDhcpIP": "$ogDhcp_ServerIP",
"ogDhcp_Dir": "$ogDhcp_Dir"
}
EOF
chmod 755 ogdhcp_installer.sh
./ogdhcp_installer.sh

Binary file not shown.

After

Width:  |  Height:  |  Size: 665 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 628 B

16
public/index.css 100644
View File

@ -0,0 +1,16 @@
html {
box-sizing: border-box;
overflow: -moz-scrollbars-vertical;
overflow-y: scroll;
}
*,
*:before,
*:after {
box-sizing: inherit;
}
body {
margin: 0;
background: #fafafa;
}

19
public/index.html 100644
View File

@ -0,0 +1,19 @@
<!-- HTML for static distribution bundle build -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Swagger UI</title>
<link rel="stylesheet" type="text/css" href="./swagger-ui.css" />
<link rel="stylesheet" type="text/css" href="index.css" />
<link rel="icon" type="image/png" href="./favicon-32x32.png" sizes="32x32" />
<link rel="icon" type="image/png" href="./favicon-16x16.png" sizes="16x16" />
</head>
<body>
<div id="swagger-ui"></div>
<script src="./swagger-ui-bundle.js" charset="UTF-8"> </script>
<script src="./swagger-ui-standalone-preset.js" charset="UTF-8"> </script>
<script src="./swagger-initializer.js" charset="UTF-8"> </script>
</body>
</html>

View File

@ -0,0 +1,79 @@
<!doctype html>
<html lang="en-US">
<head>
<title>Swagger UI: OAuth2 Redirect</title>
</head>
<body>
<script>
'use strict';
function run () {
var oauth2 = window.opener.swaggerUIRedirectOauth2;
var sentState = oauth2.state;
var redirectUrl = oauth2.redirectUrl;
var isValid, qp, arr;
if (/code|token|error/.test(window.location.hash)) {
qp = window.location.hash.substring(1).replace('?', '&');
} else {
qp = location.search.substring(1);
}
arr = qp.split("&");
arr.forEach(function (v,i,_arr) { _arr[i] = '"' + v.replace('=', '":"') + '"';});
qp = qp ? JSON.parse('{' + arr.join() + '}',
function (key, value) {
return key === "" ? value : decodeURIComponent(value);
}
) : {};
isValid = qp.state === sentState;
if ((
oauth2.auth.schema.get("flow") === "accessCode" ||
oauth2.auth.schema.get("flow") === "authorizationCode" ||
oauth2.auth.schema.get("flow") === "authorization_code"
) && !oauth2.auth.code) {
if (!isValid) {
oauth2.errCb({
authId: oauth2.auth.name,
source: "auth",
level: "warning",
message: "Authorization may be unsafe, passed state was changed in server. The passed state wasn't returned from auth server."
});
}
if (qp.code) {
delete oauth2.state;
oauth2.auth.code = qp.code;
oauth2.callback({auth: oauth2.auth, redirectUrl: redirectUrl});
} else {
let oauthErrorMsg;
if (qp.error) {
oauthErrorMsg = "["+qp.error+"]: " +
(qp.error_description ? qp.error_description+ ". " : "no accessCode received from the server. ") +
(qp.error_uri ? "More info: "+qp.error_uri : "");
}
oauth2.errCb({
authId: oauth2.auth.name,
source: "auth",
level: "error",
message: oauthErrorMsg || "[Authorization failed]: no accessCode received from the server."
});
}
} else {
oauth2.callback({auth: oauth2.auth, token: qp, isValid: isValid, redirectUrl: redirectUrl});
}
window.close();
}
if (document.readyState !== 'loading') {
run();
} else {
document.addEventListener('DOMContentLoaded', function () {
run();
});
}
</script>
</body>
</html>

View File

@ -0,0 +1,20 @@
window.onload = function() {
//<editor-fold desc="Changeable Configuration Block">
// the following lines will be replaced by docker/configurator, when it runs in a docker-container
window.ui = SwaggerUIBundle({
url: "http://192.168.0.27:8080/swagger.json",
dom_id: '#swagger-ui',
deepLinking: true,
presets: [
SwaggerUIBundle.presets.apis,
SwaggerUIStandalonePreset
],
plugins: [
SwaggerUIBundle.plugins.DownloadUrl
],
layout: "StandaloneLayout"
});
//</editor-fold>
};

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

549
public/swagger.json 100644
View File

@ -0,0 +1,549 @@
{
"openapi": "3.0.0",
"info": {
"title": "Ogdhcp API",
"version": "1.0"
},
"paths": {
"/opengnsys3/rest/dhcp/subnets": {
"get": {
"operationId": "8f92a1cbcb8cd176bdc4ae272b3ad303",
"responses": {
"200": {
"description": "Devuelve todas las subredes",
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/Subnet"
}
}
}
}
},
"400": {
"description": "Error al obtener las subredes"
}
}
},
"post": {
"summary": "Add a new DHCP subnet",
"operationId": "88949bae5e7784ce2721ffafe7c88c0a",
"requestBody": {
"description": "JSON payload",
"required": true,
"content": {
"application/json": {
"schema": {
"properties": {
"subnetId": {
"type": "integer",
"example": 2
},
"mask": {
"type": "string",
"example": "255.255.255.0"
},
"address": {
"type": "string",
"example": "192.168.1.0"
},
"nextServer": {
"type": "string",
"example": "192.168.1.1"
},
"bootFileName": {
"type": "string",
"example": "pxelinux.0"
}
},
"type": "object"
}
}
}
},
"responses": {
"200": {
"description": "Subnet added successfully",
"content": {
"application/json": {
"schema": {
"properties": {
"success": {
"type": "string"
}
},
"type": "object"
}
}
}
},
"400": {
"description": "Error occurred",
"content": {
"application/json": {
"schema": {
"properties": {
"error": {
"type": "string"
}
},
"type": "object"
}
}
}
}
}
}
},
"/opengnsys3/rest/dhcp/subnets/{subnetId}": {
"put": {
"summary": "Modify a DHCP subnet",
"operationId": "548b55fc0e1ad59ea5b5c909dfd07c71",
"parameters": [
{
"name": "subnetId",
"in": "path",
"description": "ID of the subnet to modify",
"required": true,
"schema": {
"type": "integer"
}
}
],
"requestBody": {
"description": "Data to modify the subnet",
"required": true,
"content": {
"application/json": {
"schema": {
"properties": {
"mask": {
"type": "string"
},
"address": {
"type": "string"
},
"nextServer": {
"type": "string"
},
"bootFileName": {
"type": "string"
}
},
"type": "object"
}
}
}
},
"responses": {
"200": {
"description": "Subnet modified successfully",
"content": {
"application/json": {
"schema": {
"properties": {
"success": {
"type": "string"
}
},
"type": "object"
}
}
}
},
"400": {
"description": "Error occurred",
"content": {
"application/json": {
"schema": {
"properties": {
"error": {
"type": "string"
}
},
"type": "object"
}
}
}
}
}
},
"delete": {
"summary": "Delete a DHCP subnet",
"operationId": "c1c1c34729bdd85857b22e6e2bdc41de",
"parameters": [
{
"name": "subnetId",
"in": "path",
"description": "ID of the subnet to delete",
"required": true,
"schema": {
"type": "integer"
}
}
],
"responses": {
"200": {
"description": "Subnet deleted successfully",
"content": {
"application/json": {
"schema": {
"properties": {
"success": {
"type": "string"
}
},
"type": "object"
}
}
}
},
"400": {
"description": "Error occurred",
"content": {
"application/json": {
"schema": {
"properties": {
"error": {
"type": "string"
}
},
"type": "object"
}
}
}
}
}
}
},
"/opengnsys3/rest/dhcp/subnets/{subnetId}/hosts": {
"get": {
"summary": "Get all hosts in a subnet",
"operationId": "0989ca622a6a7e23f5af8e3bdd6f6b05",
"parameters": [
{
"name": "subnetId",
"in": "path",
"description": "The ID of the subnet",
"required": true,
"schema": {
"type": "integer"
}
}
],
"responses": {
"200": {
"description": "List of hosts in the subnet",
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/Host"
}
}
}
}
},
"400": {
"description": "Error occurred",
"content": {
"application/json": {
"schema": {
"properties": {
"error": {
"type": "string"
}
},
"type": "object"
}
}
}
},
"500": {
"description": "Server error",
"content": {
"application/json": {
"schema": {
"properties": {
"error": {
"type": "string"
}
},
"type": "object"
}
}
}
}
}
},
"put": {
"summary": "Update a DHCP host",
"operationId": "1541441cd53685aaf6df45ab48befaa8",
"parameters": [
{
"name": "subnetId",
"in": "path",
"description": "The ID of the subnet",
"required": true,
"schema": {
"type": "integer"
}
}
],
"requestBody": {
"description": "Data for the host to update",
"required": true,
"content": {
"application/json": {
"schema": {
"properties": {
"host": {
"type": "string",
"example": "pc11"
},
"oldMacAddress": {
"type": "string",
"example": "56:6f:c7:4f:00:4f"
},
"oldAddress": {
"type": "string",
"example": "192.168.1.11"
},
"macAddress": {
"type": "string",
"example": "56:6f:c7:4f:01:01"
},
"address": {
"type": "string",
"example": "192.168.1.11"
}
},
"type": "object"
}
}
}
},
"responses": {
"200": {
"description": "Host updated successfully",
"content": {
"application/json": {
"schema": {
"properties": {
"success": {
"type": "string"
}
},
"type": "object"
}
}
}
},
"400": {
"description": "Error occurred",
"content": {
"application/json": {
"schema": {
"properties": {
"error": {
"type": "string"
}
},
"type": "object"
}
}
}
}
}
},
"post": {
"summary": "Add a DHCP host to a subnet",
"operationId": "3f897dcd7c04787ac9c42ddbb57cb800",
"parameters": [
{
"name": "subnetId",
"in": "path",
"description": "ID of the subnet to add the host to",
"required": true,
"schema": {
"type": "integer"
}
}
],
"requestBody": {
"description": "Data for the new host",
"required": true,
"content": {
"application/json": {
"schema": {
"properties": {
"host": {
"type": "string",
"example": "pc11"
},
"macAddress": {
"type": "string",
"example": "56:6f:c7:4f:00:4f"
},
"address": {
"type": "string",
"example": "172.30.4.11"
}
},
"type": "object"
}
}
}
},
"responses": {
"200": {
"description": "Host added successfully",
"content": {
"application/json": {
"schema": {
"properties": {
"success": {
"type": "string"
}
},
"type": "object"
}
}
}
},
"400": {
"description": "Error occurred",
"content": {
"application/json": {
"schema": {
"properties": {
"error": {
"type": "string"
}
},
"type": "object"
}
}
}
}
}
},
"delete": {
"summary": "Delete a DHCP host from a specific subnet",
"operationId": "f652c52b39d57d283401df66a7930b5f",
"parameters": [
{
"name": "subnetId",
"in": "path",
"description": "The ID of the subnet",
"required": true,
"schema": {
"type": "integer"
}
}
],
"requestBody": {
"description": "Data for the host to delete",
"required": true,
"content": {
"application/json": {
"schema": {
"properties": {
"host": {
"type": "string",
"example": "pc11"
}
},
"type": "object"
}
}
}
},
"responses": {
"200": {
"description": "Host deleted successfully",
"content": {
"application/json": {
"schema": {
"properties": {
"success": {
"type": "string"
}
},
"type": "object"
}
}
}
},
"400": {
"description": "Error occurred",
"content": {
"application/json": {
"schema": {
"properties": {
"error": {
"type": "string"
}
},
"type": "object"
}
}
}
}
}
}
}
},
"components": {
"schemas": {
"Subnet": {
"properties": {
"id": {
"description": "The ID of the subnet",
"type": "integer"
},
"subnet": {
"description": "The name of the subnet",
"type": "string"
},
"next-server": {
"description": "The next server in the subnet",
"type": "string"
},
"boot-file-name": {
"description": "The boot file name for the subnet",
"type": "string"
},
"reservations": {
"type": "array",
"items": {
"description": "The reservations in the subnet",
"type": "object"
}
}
},
"type": "object"
},
"Host": {
"properties": {
"host": {
"type": "string",
"example": "pc11"
},
"macAddress": {
"type": "string",
"example": "56:6f:c7:4f:00:4f"
},
"address": {
"type": "string",
"example": "172.30.4.11"
}
},
"type": "object"
}
}
}
}

View File

@ -0,0 +1,982 @@
<?php
// src/DhcpBundle/Controller/DhcpController.php
namespace App\DhcpBundle\Controller;
use OpenApi\Annotations as OA;
use Psr\Log\LoggerInterface;
use App\DhcpBundle\Service\CurlKeaService;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\HttpFoundation\JsonResponse;
use Exception;
class DhcpController
{
private $logger;
/**
* @OA\Info(title="Ogdhcp API", version="1.0")
*/
/**
* @OA\Schema(
* schema="Subnet",
* type="object",
* @OA\Property(property="id", type="integer", description="The ID of the subnet"),
* @OA\Property(property="subnet", type="string", description="The name of the subnet"),
* @OA\Property(property="next-server", type="string", description="The next server in the subnet"),
* @OA\Property(property="boot-file-name", type="string", description="The boot file name for the subnet"),
* @OA\Property(
* property="reservations",
* type="array",
* @OA\Items(type="object", description="The reservations in the subnet")
* )
* )
*/
private $curlKeaService;
public function __construct(CurlKeaService $curlKeaService, LoggerInterface $logger)
{
$this->curlKeaService = $curlKeaService;
$this->logger = $logger;
}
/**
* @Route("/ogdhcp/v1/status", name="getDhcpStatus", methods={"GET"})
* @OA\Get(
* path="/ogdhcp/v1/status",
* summary="Get ogDHCP status",
* @OA\Response(
* response=200,
* description="Status retrieved successfully",
* @OA\JsonContent(
* type="object",
* @OA\Property(property="disk_usage", type="object",
* @OA\Property(property="total", type="string"),
* @OA\Property(property="used", type="string"),
* @OA\Property(property="available", type="string"),
* @OA\Property(property="percentage", type="string")
* ),
* @OA\Property(property="default_oglive", type="string"),
* @OA\Property(property="installed_oglives", type="array", @OA\Items(type="string")),
* @OA\Property(property="services_status", type="object",
* @OA\Property(property="dhcp_daemon", type="string"),
* @OA\Property(property="nginx", type="string"),
* @OA\Property(property="tftpboot", type="string")
* )
* )
* )
* )
*/
public function getDhcpStatus(): Response
{
// Obtener el uso de disco
$diskUsageResult = $this->getDiskUsage();
if (!$diskUsageResult) {
return new JsonResponse(['error' => 'Failed to retrieve disk usage'], Response::HTTP_INTERNAL_SERVER_ERROR);
}
// Obtener el estado de los servicios de ogDHCP (similar a check_services_status en ogboot)
$servicesStatusResult = $this->getServicesStatus();
if (!$servicesStatusResult) {
return new JsonResponse(['error' => 'Failed to retrieve services status'], Response::HTTP_INTERNAL_SERVER_ERROR);
}
// Obtener las subredes y las reservas asociadas
$subnetsResult = $this->getSubnetsService();
if (!$subnetsResult) {
return new JsonResponse(['error' => 'Failed to retrieve subnets'], Response::HTTP_INTERNAL_SERVER_ERROR);
}
// Componer la respuesta
$response = [
'disk_usage' => $diskUsageResult,
'subnets' => $subnetsResult,
'services_status' => $servicesStatusResult
];
return new JsonResponse($response, Response::HTTP_OK);
}
private function getDiskUsage(): array
{
// Simular la salida del comando df para obtener el uso del disco
$output = shell_exec("df -h /opt/ogdhcp | tail -1 | awk '{print $2, $3, $4, $5}'");
if (!$output) {
$this->logger->error("Failed to execute disk usage command");
return null;
}
list($total, $used, $available, $percentage) = explode(' ', $output);
return [
'total' => trim($total),
'used' => trim($used),
'available' => trim($available),
'percentage' => trim($percentage),
];
}
private function getServicesStatus(): array
{
$services = [
'tftpboot' => 'active',
'nginx' => 'active',
];
return $services;
}
private function getSubnetsService(): ?array
{
try {
$response = $this->curlRequestService->executeCurlCommand('config-get');
if (!$response) {
$this->logger->error('Error: No se pudo acceder al archivo de configuración Kea.');
return null;
}
$result_code = $response[0]["result"];
if ($result_code == 0) {
if (!isset($response[0]['arguments']['Dhcp4']['subnet4'])) {
$this->logger->error("El campo 'subnet4' no está inicializado");
return null;
} else {
return $response[0]['arguments']['Dhcp4']['subnet4']; // Subredes y sus reservas
}
} else {
$this->logger->error("Error en la configuración Kea: " . $response[0]["text"]);
return null;
}
} catch (\Exception $e) {
$this->logger->error("Error al obtener la configuración de Kea DHCP: " . $e->getMessage());
return null;
}
}
/**
* @OA\Schema(
* schema="Subnet",
* type="object",
* @OA\Property(property="id", type="integer", description="The ID of the subnet"),
* @OA\Property(property="subnet", type="string", description="The name of the subnet"),
* @OA\Property(property="next-server", type="string", description="The next server in the subnet"),
* @OA\Property(property="boot-file-name", type="string", description="The boot file name for the subnet"),
* @OA\Property(
* property="reservations",
* type="array",
* @OA\Items(type="object", description="The reservations in the subnet")
* )
* )
*/
/**
* @OA\Get(
* path="/ogdhcp/v1/subnets",
* @OA\Response(
* response=200,
* description="Devuelve todas las subredes",
* ),
* @OA\Response(
* response=400,
* description="Error al obtener las subredes",
* )
* )
* @Route("/ogdhcp/v1/subnets", methods={"GET"})
*/
public function getSubnets(): JsonResponse
{
try {
$response = $this->curlKeaService->executeCurlCommand('config-get');
if (!$response) {
$responseError = 'Error: No se pudo acceder al archivo dhcpd.conf';
return new JsonResponse(['error' => $responseError], 400);
} else {
$result_code = $response[0]["result"];
if ($result_code == 0) {
if (!isset($response[0]['arguments']['Dhcp4']['subnet4'])) {
$responseError = 'El campo \'subnet4\' no está inicializado';
return new JsonResponse(['error' => $responseError], 400);
} else {
$arrayReservations = $response[0]['arguments']['Dhcp4']['subnet4'];
return new JsonResponse($arrayReservations, 200);
}
} else {
$responseError = "Error kea configuration invalid: " . $response[0]["text"];
return new JsonResponse(['error' => $responseError], 400);
}
}
} catch (Exception $e) {
$responseError = "Error al obtener la configuración de Kea DHCP: " . $e->getMessage();
return new JsonResponse(['error' => $responseError], 400);
}
}
/**
* @OA\Post(
* path="/ogdhcp/v1/subnets",
* summary="Add a new DHCP subnet",
* @OA\RequestBody(
* description="JSON payload",
* required=true,
* @OA\JsonContent(
* type="object",
* @OA\Property(property="subnetId", type="integer", example=2),
* @OA\Property(property="mask", type="string", example="255.255.255.0"),
* @OA\Property(property="address", type="string", example="192.168.1.0"),
* @OA\Property(property="nextServer", type="string", example="192.168.1.1"),
* @OA\Property(property="bootFileName", type="string", example="pxelinux.0")
* )
* ),
* @OA\Response(
* response=200,
* description="Subnet added successfully",
* @OA\JsonContent(
* type="object",
* @OA\Property(property="success", type="string")
* )
* ),
* @OA\Response(
* response=400,
* description="Error occurred",
* @OA\JsonContent(
* type="object",
* @OA\Property(property="error", type="string")
* )
* )
* )
* @Route("/ogdhcp/v1/subnets", methods={"POST"})
*/
public function addDhcpSubnet(Request $request): JsonResponse
{
try {
$input = json_decode($request->getContent());
$subnetId = (int) htmlspecialchars($input->subnetId);
$mask = htmlspecialchars($input->mask);
$address = htmlspecialchars($input->address);
$nextServer = htmlspecialchars($input->nextServer);
$bootFileName = htmlspecialchars($input->bootFileName);
} catch (Exception $e) {
$response["message"] = $e->getMessage();
return new JsonResponse(['error' => $response], 400);
}
try {
$response = $this->curlKeaService->executeCurlCommand('config-get');
$subnetName = $address . '/' . $this->curlKeaService->convertMaskToCIDR($mask);
$newSubnet = [
"id" => $subnetId,
"subnet" => $subnetName,
"next-server" => $nextServer,
"boot-file-name" => $bootFileName,
"reservations" => []
];
if (!isset($response[0]['arguments']['Dhcp4']['subnet4'])) {
$response[0]['arguments']['Dhcp4']['subnet4'] = [];
}
$exists = array_reduce($response[0]['arguments']['Dhcp4']['subnet4'], function ($exists, $subnetElement) use ($subnetName, $subnetId) {
return $exists || ($subnetElement['subnet'] === $subnetName) || ($subnetElement['id'] === $subnetId);;
});
if ($exists) {
$responseError = "Error: La subred el subnet '$subnetName' ya existe en las subredes";
return new JsonResponse(['error' => $responseError], 400);
} else {
$response[0]['arguments']['Dhcp4']['subnet4'][] = $newSubnet;
$array_encoded = json_encode($response[0]['arguments']);
$configurationParsed = str_replace('\\', '', $array_encoded);
$configuration = json_decode($configurationParsed);
$responseTest = $this->curlKeaService->executeCurlCommand('config-test', $configuration);
if ($responseTest[0]["result"] == 0) {
$responseSet = $this->curlKeaService->executeCurlCommand('config-set', $configuration);
if ($responseSet == false || $responseSet[0]["result"] != 0) {
$responseError = "Error al guardar la configuración en Kea DHCP: " . $responseSet[0]["text"];
return new JsonResponse(['error' => $responseError], 400);
} else {
$responseWrite = $this->curlKeaService->executeCurlCommand('config-write', $configuration);
if ($responseWrite == false || $responseWrite[0]["result"] != 0) {
$responseError = "Error al guardar la configuración en Kea DHCP: " . $responseWrite[0]["text"];
return new JsonResponse(['error' => $responseError], 400);
} else {
$responseSuccess = "Configuración cargada correctamente";
return new JsonResponse(['success' => $responseSuccess], 200);
}
}
} else {
$responseError = "Error kea configuration invalid: " . $responseTest[0]["text"];
return new JsonResponse(['error' => $responseError], 400);
}
}
} catch (Exception $e) {
$responseError = "Error al obtener la configuración de Kea DHCP: " . $e->getMessage();
return new JsonResponse(['error' => $responseError], 400);
}
}
/**
* @Route("/ogdhcp/v1/subnets/{subnetId}", methods={"DELETE"})
* @OA\Delete(
* path="/ogdhcp/v1/subnets/{subnetId}",
* summary="Delete a DHCP subnet",
* @OA\Parameter(
* name="subnetId",
* in="path",
* description="ID of the subnet to delete",
* required=true,
* @OA\Schema(
* type="integer"
* )
* ),
* @OA\Response(
* response=200,
* description="Subnet deleted successfully",
* @OA\JsonContent(
* type="object",
* @OA\Property(property="success", type="string")
* )
* ),
* @OA\Response(
* response=400,
* description="Error occurred",
* @OA\JsonContent(
* type="object",
* @OA\Property(property="error", type="string")
* )
* )
* )
*/
public function deleteDhcpSubnet(Request $request): JsonResponse
{
$subnetId = (int) $request->get('subnetId');
try {
$response = $this->curlKeaService->executeCurlCommand('config-get');
if (!isset($response[0]['arguments']['Dhcp4']['subnet4'])) {
$responseError = "Error: No hay subredes definidas";
return new JsonResponse(['error' => $responseError], 400);
}
$subnetIndex = array_search($subnetId, array_column($response[0]['arguments']['Dhcp4']['subnet4'], 'id'));
if ($subnetIndex === false) {
$responseError = "Error: La subred con el id '$subnetId' no existe";
return new JsonResponse(['error' => $responseError], 400);
} else {
unset($response[0]['arguments']['Dhcp4']['subnet4'][$subnetIndex]);
$response[0]['arguments']['Dhcp4']['subnet4'] = array_values($response[0]['arguments']['Dhcp4']['subnet4']);
$array_encoded = json_encode($response[0]['arguments']);
$configurationParsed = str_replace('\\', '', $array_encoded);
$configuration = json_decode($configurationParsed);
$responseTest = $this->curlKeaService->executeCurlCommand('config-test', $configuration);
if ($responseTest[0]["result"] == 0) {
$responseSet = $this->curlKeaService->executeCurlCommand('config-set', $configuration);
if ($responseSet == false || $responseSet[0]["result"] != 0) {
$responseError = "Error al guardar la configuración en Kea DHCP: " . $responseSet[0]["text"];
return new JsonResponse(['error' => $responseError], 400);
} else {
$responseWrite = $this->curlKeaService->executeCurlCommand('config-write', $configuration);
if ($responseWrite == false || $responseWrite[0]["result"] != 0) {
$responseError = "Error al guardar la configuración en Kea DHCP: " . $responseWrite[0]["text"];
return new JsonResponse(['error' => $responseError], 400);
} else {
$responseSuccess = "Subred eliminada correctamente";
return new JsonResponse(['success' => $responseSuccess], 200);
}
}
} else {
$responseError = "Error kea configuration invalid: " . $responseTest[0]["text"];
return new JsonResponse(['error' => $responseError], 400);
}
}
} catch (Exception $e) {
$responseError = "Error al obtener la configuración de Kea DHCP: " . $e->getMessage();
return new JsonResponse(['error' => $responseError], 400);
}
}
/**
* @Route("/ogdhcp/v1/subnets/{subnetId}", methods={"PUT"})
* @OA\Put(
* path="/ogdhcp/v1/subnets/{subnetId}",
* summary="Modify a DHCP subnet",
* @OA\Parameter(
* name="subnetId",
* in="path",
* description="ID of the subnet to modify",
* required=true,
* @OA\Schema(
* type="integer"
* )
* ),
* @OA\RequestBody(
* description="Data to modify the subnet",
* required=true,
* @OA\JsonContent(
* type="object",
* @OA\Property(property="mask", type="string"),
* @OA\Property(property="address", type="string"),
* @OA\Property(property="nextServer", type="string"),
* @OA\Property(property="bootFileName", type="string")
* )
* ),
* @OA\Response(
* response=200,
* description="Subnet modified successfully",
* @OA\JsonContent(
* type="object",
* @OA\Property(property="success", type="string")
* )
* ),
* @OA\Response(
* response=400,
* description="Error occurred",
* @OA\JsonContent(
* type="object",
* @OA\Property(property="error", type="string")
* )
* )
* )
*/
public function modifyDhcpSubnet(Request $request): JsonResponse
{
$subnetId = (int) $request->get('subnetId');
try {
$input = json_decode($request->getContent());
$mask = htmlspecialchars($input->mask);
$address = htmlspecialchars($input->address);
$nextServer = htmlspecialchars($input->nextServer);
$bootFileName = htmlspecialchars($input->bootFileName);
} catch (Exception $e) {
$response["message"] = $e->getMessage();
return new JsonResponse(['error' => $response], 400);
}
try {
$response = $this->curlKeaService->executeCurlCommand('config-get');
$subnetName = $address . '/' . $this->curlKeaService->convertMaskToCIDR($mask);
if (!isset($response[0]['arguments']['Dhcp4']['subnet4'])) {
$responseError = "Error: No hay subredes definidas";
return new JsonResponse(['error' => $responseError], 400);
}
$subnetIndex = array_search($subnetId, array_column($response[0]['arguments']['Dhcp4']['subnet4'], 'id'));
if ($subnetIndex === false) {
$responseError = "Error: La subred con el id '$subnetId' no existe";
return new JsonResponse(['error' => $responseError], 400);
} else {
$response[0]['arguments']['Dhcp4']['subnet4'][$subnetIndex] = [
"id" => $subnetId,
"subnet" => $subnetName,
"next-server" => $nextServer,
"boot-file-name" => $bootFileName,
"reservations" => []
];
$array_encoded = json_encode($response[0]['arguments']);
$configurationParsed = str_replace('\\', '', $array_encoded);
$configuration = json_decode($configurationParsed);
$responseTest = $this->curlKeaService->executeCurlCommand('config-test', $configuration);
if ($responseTest[0]["result"] == 0) {
$responseSet = $this->curlKeaService->executeCurlCommand('config-set', $configuration);
if ($responseSet == false || $responseSet[0]["result"] != 0) {
$responseError = "Error al guardar la configuración en Kea DHCP: " . $responseSet[0]["text"];
return new JsonResponse(['error' => $responseError], 400);
} else {
$responseWrite = $this->curlKeaService->executeCurlCommand('config-write', $configuration);
if ($responseWrite == false || $responseWrite[0]["result"] != 0) {
$responseError = "Error al guardar la configuración en Kea DHCP: " . $responseWrite[0]["text"];
return new JsonResponse(['error' => $responseError], 400);
} else {
$responseSuccess = "Subred modificada correctamente";
return new JsonResponse(['success' => $responseSuccess], 200);
}
}
} else {
$responseError = "Error kea configuration invalid: " . $responseTest[0]["text"];
return new JsonResponse(['error' => $responseError], 400);
}
}
} catch (Exception $e) {
$responseError = "Error al obtener la configuración de Kea DHCP: " . $e->getMessage();
return new JsonResponse(['error' => $responseError], 400);
}
}
/**
* @OA\Get(
* path="/ogdhcp/v1/subnets/{subnetId}/hosts",
* summary="Get all hosts in a subnet",
* @OA\Parameter(
* name="subnetId",
* in="path",
* description="The ID of the subnet",
* required=true,
* @OA\Schema(type="integer")
* ),
* @OA\Response(
* response=200,
* description="List of hosts in the subnet",
* ),
* @OA\Response(
* response=400,
* description="Error occurred",
* @OA\JsonContent(
* type="object",
* @OA\Property(property="error", type="string")
* )
* ),
* @OA\Response(
* response=500,
* description="Server error",
* @OA\JsonContent(
* type="object",
* @OA\Property(property="error", type="string")
* )
* )
* )
* @Route("/ogdhcp/v1/subnets/{subnetId}/hosts", methods={"GET"})
*/
public function getHosts($subnetId): JsonResponse
{
try {
$response = $this->curlKeaService->executeCurlCommand('config-get');
if (!$response) {
$responseError = 'Error: No se pudo acceder al archivo dhcpd.conf';
return new JsonResponse(['error' => $responseError], 400);
} else {
$result_code = $response[0]["result"];
if ($result_code == 0) {
if (!isset($response[0]['arguments']['Dhcp4']['subnet4'])) {
$responseError = 'El campo \'subnet4\' no está inicializado';
return new JsonResponse(['error' => $responseError], 400);
} else {
$subnets = $response[0]['arguments']['Dhcp4']['subnet4'];
foreach ($subnets as $subnet) {
if ($subnet['id'] == $subnetId) {
return new JsonResponse($subnet['reservations'], 200);
}
}
$responseError = 'Error: La subred con el id \'' . $subnetId . '\' no existe.';
return new JsonResponse(['error' => $responseError], 400);
}
} else {
$responseError = "Error kea configuration invalid: " . $response[0]["text"];
return new JsonResponse(['error' => $responseError], 400);
}
}
} catch (Exception $e) {
$responseError = "Error al obtener la configuración de Kea DHCP: " . $e->getMessage();
return new JsonResponse(['error' => $responseError], 400);
}
}
/**
* @OA\Post(
* path="/ogdhcp/v1/subnets/{subnetId}/hosts",
* summary="Add a DHCP host to a subnet",
* @OA\Parameter(
* name="subnetId",
* in="path",
* description="ID of the subnet to add the host to",
* required=true,
* @OA\Schema(
* type="integer"
* )
* ),
* @OA\RequestBody(
* description="Data for the new host",
* required=true,
* @OA\JsonContent(
* type="object",
* @OA\Property(property="host", type="string", example="pc11"),
* @OA\Property(property="macAddress", type="string", example="56:6f:c7:4f:00:4f"),
* @OA\Property(property="address", type="string", example="172.30.4.11")
* )
* ),
* @OA\Response(
* response=200,
* description="Host added successfully",
* @OA\JsonContent(
* type="object",
* @OA\Property(property="success", type="string")
* )
* ),
* @OA\Response(
* response=400,
* description="Error occurred",
* @OA\JsonContent(
* type="object",
* @OA\Property(property="error", type="string")
* )
* )
* )
* @Route("/ogdhcp/v1/subnets/{subnetId}/hosts", methods={"POST"})
*/
public function addDhcpHost(Request $request): JsonResponse
{
$subnetId = (int) $request->get('subnetId');
try {
$input = json_decode($request->getContent());
$host = htmlspecialchars($input->host);
$macAddress = htmlspecialchars($input->macAddress);
$address = htmlspecialchars($input->address);
} catch (Exception $e) {
$response["message"] = $e->getMessage();
return new JsonResponse(['error' => $response], 400);
}
try {
$response = $this->curlKeaService->executeCurlCommand('config-get');
$newHost = [
"hostname" => $host,
"hw-address" => $macAddress,
"ip-address" => $address
];
$subnetFound = false;
foreach ($response[0]['arguments']['Dhcp4']['subnet4'] as &$subnet) {
if ($subnet['id'] == $subnetId) {
$subnetFound = true;
if (!isset($subnet['reservations'])) {
$subnet['reservations'] = [];
}
$exists = array_reduce($subnet['reservations'], function ($exists, $reservation) use ($host) {
return $exists || ($reservation['hostname'] === $host);
});
if ($exists) {
$responseError = "Error: El host con el hostname '$host' ya existe en las reservaciones.";
return new JsonResponse(['error' => $responseError], 400);
} else {
$subnet['reservations'][] = $newHost;
break;
}
}
}
if (!$subnetFound) {
$responseError = "Error: No se encontró la subnet con id '$subnetId'.";
return new JsonResponse(['error' => $responseError], 400);
}
$array_encoded = json_encode($response[0]['arguments']);
$configurationParsed = str_replace('\\', '', $array_encoded);
$configuration = json_decode($configurationParsed);
$responseTest = $this->curlKeaService->executeCurlCommand('config-test', $configuration);
if ($responseTest[0]["result"] == 0) {
$responseSet = $this->curlKeaService->executeCurlCommand('config-set', $configuration);
if ($responseSet == false || $responseSet[0]["result"] != 0) {
$responseError = "Error al guardar la configuración en Kea DHCP: " . $responseSet[0]["text"];
return new JsonResponse(['error' => $responseError], 400);
} else {
$responseWrite = $this->curlKeaService->executeCurlCommand('config-write', $configuration);
if ($responseWrite == false || $responseWrite[0]["result"] != 0) {
$responseError = "Error al guardar la configuración en Kea DHCP: " . $responseWrite[0]["text"];
return new JsonResponse(['error' => $responseError], 400);
} else {
$responseSuccess = "Configuración cargada correctamente";
return new JsonResponse(['success' => $responseSuccess], 200);
}
}
} else {
$responseError = "Error kea configuration invalid: " . $responseTest[0]["text"];
return new JsonResponse(['error' => $responseError], 400);
}
} catch (Exception $e) {
$responseError = "Error al obtener la configuración de Kea DHCP: " . $e->getMessage();
return new JsonResponse(['error' => $responseError], 400);
}
}
/**
* @OA\Delete(
* path="/ogdhcp/v1/subnets/{subnetId}/hosts",
* summary="Delete a DHCP host from a specific subnet",
* @OA\Parameter(
* name="subnetId",
* in="path",
* description="The ID of the subnet",
* required=true,
* @OA\Schema(type="integer")
* ),
* @OA\RequestBody(
* description="Data for the host to delete",
* required=true,
* @OA\JsonContent(
* type="object",
* @OA\Property(property="host", type="string", example="pc11")
* )
* ),
* @OA\Response(
* response=200,
* description="Host deleted successfully",
* @OA\JsonContent(
* type="object",
* @OA\Property(property="success", type="string")
* )
* ),
* @OA\Response(
* response=400,
* description="Error occurred",
* @OA\JsonContent(
* type="object",
* @OA\Property(property="error", type="string")
* )
* )
* )
* @Route("/ogdhcp/v1/subnets/{subnetId}/hosts", methods={"DELETE"})
*/
public function deleteDhcpHost(Request $request, $subnetId): JsonResponse
{
try {
$input = json_decode($request->getContent());
$host = htmlspecialchars($input->host);
} catch (Exception $e) {
$response["message"] = $e->getMessage();
return new JsonResponse(['error' => $response], 400);
}
try {
$response = $this->curlKeaService->executeCurlCommand('config-get');
$subnetFound = false;
foreach ($response[0]['arguments']['Dhcp4']['subnet4'] as &$subnet) {
if ($subnet['id'] == $subnetId) {
$subnetFound = true;
if (!isset($subnet['reservations'])) {
$subnet['reservations'] = [];
}
foreach ($subnet['reservations'] as $key => $reservation) {
if (isset($reservation['hostname']) && $reservation['hostname'] === $host) {
unset($subnet['reservations'][$key]);
$subnet['reservations'] = array_values($subnet['reservations']);
break;
}
}
}
}
if ($subnetFound) {
$array_encoded = json_encode($response[0]['arguments']);
$configurationParsed = str_replace('\\', '', $array_encoded);
$configuration = json_decode($configurationParsed);
$responseTest = $this->curlKeaService->executeCurlCommand('config-test', $configuration);
if ($responseTest[0]["result"] == 0) {
$responseSet = $this->curlKeaService->executeCurlCommand('config-set', $configuration);
if ($responseSet == false || $responseSet[0]["result"] != 0) {
$responseError = "Error al guardar la configuración en Kea DHCP: " . $responseSet[0]["text"];
return new JsonResponse(['error' => $responseError], 400);
} else {
$responseWrite = $this->curlKeaService->executeCurlCommand('config-write', $configuration);
if ($responseWrite == false || $responseWrite[0]["result"] != 0) {
$responseError = "Error al guardar la configuración en Kea DHCP: " . $responseWrite[0]["text"];
return new JsonResponse(['error' => $responseError], 400);
} else {
$responseSuccess = "Configuración cargada correctamente";
return new JsonResponse(['success' => $responseSuccess], 200);
}
}
} else {
$responseError = "Error al guardar la configuración en Kea DHCP: " . $responseTest[0]["text"];
return new JsonResponse(['error' => $responseError], 400);
}
} else {
$responseError = "Error: El host con el hostname '$host' no existe en las reservaciones.";
return new JsonResponse(['error' => $responseError], 400);
}
} catch (Exception $e) {
$responseError = "Error al obtener la configuración de Kea DHCP: " . $e->getMessage();
return new JsonResponse(['error' => $responseError], 400);
}
}
/**
* @OA\Put(
* path="/ogdhcp/v1/subnets/{subnetId}/hosts",
* summary="Update a DHCP host",
* @OA\Parameter(
* name="subnetId",
* in="path",
* description="The ID of the subnet",
* required=true,
* @OA\Schema(type="integer")
* ),
* @OA\RequestBody(
* description="Data for the host to update",
* required=true,
* @OA\JsonContent(
* type="object",
* @OA\Property(property="host", type="string", example="pc11"),
* @OA\Property(property="oldMacAddress", type="string", example="56:6f:c7:4f:00:4f"),
* @OA\Property(property="oldAddress", type="string", example="192.168.1.11"),
* @OA\Property(property="macAddress", type="string", example="56:6f:c7:4f:01:01"),
* @OA\Property(property="address", type="string", example="192.168.1.11")
* )
* ),
* @OA\Response(
* response=200,
* description="Host updated successfully",
* @OA\JsonContent(
* type="object",
* @OA\Property(property="success", type="string")
* )
* ),
* @OA\Response(
* response=400,
* description="Error occurred",
* @OA\JsonContent(
* type="object",
* @OA\Property(property="error", type="string")
* )
* )
* )
*
* @Route("/ogdhcp/v1/subnets/{subnetId}/hosts", methods={"PUT"})
*/
public function updateDhcpHost(Request $request, $subnetId): JsonResponse
{
try {
$input = json_decode($request->getContent());
$host = htmlspecialchars($input->host);
$oldMacAddress = htmlspecialchars($input->oldMacAddress);
$oldAddress = htmlspecialchars($input->oldAddress);
$macAddress = htmlspecialchars($input->macAddress);
$address = htmlspecialchars($input->address);
} catch (Exception $e) {
$response["message"] = $e->getMessage();
return new JsonResponse(['error' => $response], 400);
}
try {
$response = $this->curlKeaService->executeCurlCommand('config-get');
$subnetFound = false;
$hostFound = false;
foreach ($response[0]['arguments']['Dhcp4']['subnet4'] as &$subnet) {
if ($subnet['id'] == $subnetId) {
$this->logger->info('FOUND SUBNET');
$subnetFound = true;
if (!isset($subnet['reservations'])) {
$subnet['reservations'] = [];
}
foreach ($subnet['reservations'] as &$reservation) {
$this->logger->info('LOOKING FOR HOST');
if ($reservation['hw-address'] == $oldMacAddress && $reservation['ip-address'] == $oldAddress) {
$this->logger->info('FOUND HOST');
$hostFound = true;
$reservation['hw-address'] = $macAddress;
$reservation['ip-address'] = $address;
$reservation['hostname'] = $host;
break;
}
}
}
}
if ($subnetFound && $hostFound) {
$this->logger->info('UPDATING HOST');
$array_encoded = json_encode($response[0]['arguments']);
$configurationParsed = str_replace('\\', '', $array_encoded);
$configuration = json_decode($configurationParsed);
$responseTest = $this->curlKeaService->executeCurlCommand('config-test', $configuration);
if ($responseTest[0]["result"] == 0) {
$responseSet = $this->curlKeaService->executeCurlCommand('config-set', $configuration);
if ($responseSet == false || $responseSet[0]["result"] != 0) {
$responseError = "Error al guardar la configuración en Kea DHCP: " . $responseSet[0]["text"];
return new JsonResponse(['error' => $responseError], 400);
} else {
$responseWrite = $this->curlKeaService->executeCurlCommand('config-write', $configuration);
if ($responseWrite == false || $responseWrite[0]["result"] != 0) {
$responseError = "Error al guardar la configuración en Kea DHCP: " . $responseWrite[0]["text"];
return new JsonResponse(['error' => $responseError], 400);
} else {
$responseSuccess = "Configuración cargada correctamente";
return new JsonResponse(['success' => $responseSuccess], 200);
}
}
} else {
$responseError = "Error al guardar la configuración en Kea DHCP: " . $responseTest[0]["text"];
return new JsonResponse(['error' => $responseError], 400);
}
} elseif (!$subnetFound) {
$responseError = "Error: La subred con el id '$subnetId' no existe.";
return new JsonResponse(['error' => $responseError], 400);
} elseif (!$hostFound) {
$responseError = "Error: La IP " . $oldAddress . " y la MAC " . $oldMacAddress . " no existe en las reservaciones.";
return new JsonResponse(['error' => $responseError], 400);
}
} catch (Exception $e) {
$responseError = "Error al obtener la configuración de Kea DHCP: " . $e->getMessage();
return new JsonResponse(['error' => $responseError], 400);
}
}
public function restoreDhcpConfiguration(): JsonResponse
{
$backup_dir = '/opt/opengnsys/etc/kea/backup';
try {
$backup_files = glob($backup_dir . '/*.conf');
if (empty($backup_files)) {
$response = "No se encontraron archivos de backup";
return new JsonResponse(['error' => $response], 400);
} else {
usort($backup_files, function ($a, $b) {
return filemtime($b) - filemtime($a);
});
$backup_file = reset($backup_files);
$config = file_get_contents($backup_file);
$configuration = json_decode($config);
$test_command = 'config-test';
$test_output = $this->curlKeaService->executeCurlCommand($test_command, $configuration);
if ($test_output == false || $test_output[0]["result"] != 0) {
$responseError = "Error al comprobar la configuración de Kea: " . $test_output[0]["text"];
return new JsonResponse(['error' => $responseError], 400);
} else {
$set_command = 'config-set';
$set_output = $this->curlKeaService->executeCurlCommand($set_command, $configuration, false);
if ($set_output == false || $set_output[0]["result"] != 0) {
$responseError = "Error al guardar la última configuración de Kea: " . $set_output[0]["text"];
return new JsonResponse(['error' => $responseError], 400);
} else {
unlink($backup_file);
$responseWrite = $this->curlKeaService->executeCurlCommand('config-write', $configuration);
if ($responseWrite == false || $responseWrite[0]["result"] != 0) {
$responseError = "Error al guardar la configuración en Kea DHCP: " . $responseWrite[0]["text"];
return new JsonResponse(['error' => $responseError], 400);
} else {
$responseSuccess = "Configuración cargada correctamente";
return new JsonResponse(['success' => $responseSuccess], 200);
}
}
}
}
} catch (Exception $e) {
$responseError = "Error al restaurar la configuración: " . $e->getMessage();
return new JsonResponse(['error' => $responseError], 400);
}
}
}

View File

@ -28,8 +28,7 @@ class CurlKeaService
} else {
return "Error: Comando no válido";
}
//f (($command == 'config-set' || $command == 'config-write') && $create_backup) {
if ($command == 'config-set' && $create_backup) {
if (($command == 'config-set' || $command == 'config-write') && $create_backup) {
$this->backupConfig();
}
$jsonData = json_encode($requestData);
@ -82,7 +81,7 @@ class CurlKeaService
$config_text = json_encode($get_output[0]['arguments']);
$configurationParsed = str_replace('\\', '', $config_text);
$backup_dir = __DIR__ . '/../../../../etc/kea/backup';
$backup_dir = __DIR__ . '/../../../etc/kea/backup';
if (!is_dir($backup_dir)) {
throw new Exception('El directorio de backup no existe');
}

View File

@ -0,0 +1,19 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>{% block title %}Welcome!{% endblock %}</title>
<link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 128 128%22><text y=%221.2em%22 font-size=%2296%22>⚫️</text></svg>">
{# Run `composer require symfony/webpack-encore-bundle` to start using Symfony UX #}
{% block stylesheets %}
{{ encore_entry_link_tags('app') }}
{% endblock %}
{% block javascripts %}
{{ encore_entry_script_tags('app') }}
{% endblock %}
</head>
<body>
{% block body %}{% endblock %}
</body>
</html>

View File

@ -0,0 +1,20 @@
{% extends 'base.html.twig' %}
{% block title %}Hello DhcpController!{% endblock %}
{% block body %}
<style>
.example-wrapper { margin: 1em auto; max-width: 800px; width: 95%; font: 18px/1.5 sans-serif; }
.example-wrapper code { background: #F5F5F5; padding: 2px 6px; }
</style>
<div class="example-wrapper">
<h1>Hello {{ controller_name }}! ✅</h1>
This friendly message is coming from:
<ul>
<li>Your controller at <code><a href="{{ '/home/luis/dhcp_symfony/src/Controller/DhcpController.php'|file_link(0) }}">src/Controller/DhcpController.php</a></code></li>
<li>Your template at <code><a href="{{ '/home/luis/dhcp_symfony/templates/dhcp/index.html.twig'|file_link(0) }}">templates/dhcp/index.html.twig</a></code></li>
</ul>
</div>
{% endblock %}

View File

@ -0,0 +1,11 @@
<?php
use Symfony\Component\Dotenv\Dotenv;
require dirname(__DIR__).'/vendor/autoload.php';
if (file_exists(dirname(__DIR__).'/config/bootstrap.php')) {
require dirname(__DIR__).'/config/bootstrap.php';
} elseif (method_exists(Dotenv::class, 'bootEnv')) {
(new Dotenv())->bootEnv(dirname(__DIR__).'/.env');
}

0
translations/.gitignore vendored 100644
View File