#152 First commit ogdhcp
parent
101133fa65
commit
dfbda46490
|
@ -2,9 +2,7 @@ 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` pueden incluir la capacidad de:
|
||||
Las funciones proporcionadas por la API `ogdhcp` permiten:
|
||||
|
||||
- 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.
|
||||
|
|
|
@ -0,0 +1,104 @@
|
|||
{
|
||||
"type": "project",
|
||||
"license": "proprietary",
|
||||
"minimum-stability": "stable",
|
||||
"prefer-stable": true,
|
||||
"require": {
|
||||
"php": ">=7.2.5",
|
||||
"ext-ctype": "*",
|
||||
"ext-iconv": "*",
|
||||
"doctrine/annotations": "^2.0",
|
||||
"doctrine/doctrine-bundle": "^2.11",
|
||||
"doctrine/doctrine-migrations-bundle": "^3.3",
|
||||
"doctrine/orm": "^2.17",
|
||||
"phpdocumentor/reflection-docblock": "^5.3",
|
||||
"phpstan/phpdoc-parser": "^1.24",
|
||||
"zircote/swagger-php": "dev-master",
|
||||
"symfony/asset": "5.4.*",
|
||||
"symfony/console": "5.4.*",
|
||||
"symfony/doctrine-messenger": "5.4.*",
|
||||
"symfony/dotenv": "5.4.*",
|
||||
"symfony/expression-language": "5.4.*",
|
||||
"symfony/flex": "^1.17|^2",
|
||||
"symfony/form": "5.4.*",
|
||||
"symfony/framework-bundle": "5.4.*",
|
||||
"symfony/http-client": "5.4.*",
|
||||
"symfony/intl": "5.4.*",
|
||||
"symfony/mailer": "5.4.*",
|
||||
"symfony/mime": "5.4.*",
|
||||
"symfony/monolog-bundle": "^3.0",
|
||||
"symfony/notifier": "5.4.*",
|
||||
"symfony/process": "5.4.*",
|
||||
"symfony/property-access": "5.4.*",
|
||||
"symfony/property-info": "5.4.*",
|
||||
"symfony/runtime": "5.4.*",
|
||||
"symfony/security-bundle": "5.4.*",
|
||||
"symfony/serializer": "5.4.*",
|
||||
"symfony/string": "5.4.*",
|
||||
"symfony/translation": "5.4.*",
|
||||
"symfony/twig-bundle": "5.4.*",
|
||||
"symfony/validator": "5.4.*",
|
||||
"symfony/web-link": "5.4.*",
|
||||
"symfony/yaml": "5.4.*",
|
||||
"twig/extra-bundle": "^2.12|^3.0",
|
||||
"twig/twig": "^2.12|^3.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^9.5",
|
||||
"symfony/browser-kit": "5.4.*",
|
||||
"symfony/css-selector": "5.4.*",
|
||||
"symfony/debug-bundle": "5.4.*",
|
||||
"symfony/maker-bundle": "^1.0",
|
||||
"symfony/phpunit-bridge": "^7.0",
|
||||
"symfony/stopwatch": "5.4.*",
|
||||
"symfony/web-profiler-bundle": "5.4.*"
|
||||
},
|
||||
"config": {
|
||||
"allow-plugins": {
|
||||
"composer/package-versions-deprecated": true,
|
||||
"symfony/flex": true,
|
||||
"symfony/runtime": true
|
||||
},
|
||||
"optimize-autoloader": true,
|
||||
"preferred-install": {
|
||||
"*": "dist"
|
||||
},
|
||||
"sort-packages": true
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"App\\": "src/"
|
||||
}
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"App\\Tests\\": "tests/"
|
||||
}
|
||||
},
|
||||
"replace": {
|
||||
"symfony/polyfill-ctype": "*",
|
||||
"symfony/polyfill-iconv": "*",
|
||||
"symfony/polyfill-php72": "*"
|
||||
},
|
||||
"scripts": {
|
||||
"auto-scripts": {
|
||||
"cache:clear": "symfony-cmd",
|
||||
"assets:install %PUBLIC_DIR%": "symfony-cmd"
|
||||
},
|
||||
"post-install-cmd": [
|
||||
"@auto-scripts"
|
||||
],
|
||||
"post-update-cmd": [
|
||||
"@auto-scripts"
|
||||
]
|
||||
},
|
||||
"conflict": {
|
||||
"symfony/symfony": "*"
|
||||
},
|
||||
"extra": {
|
||||
"symfony": {
|
||||
"allow-contrib": false,
|
||||
"require": "5.4.*"
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,15 @@
|
|||
<?php
|
||||
|
||||
return [
|
||||
Symfony\Bundle\FrameworkBundle\FrameworkBundle::class => ['all' => true],
|
||||
Doctrine\Bundle\DoctrineBundle\DoctrineBundle::class => ['all' => true],
|
||||
Doctrine\Bundle\MigrationsBundle\DoctrineMigrationsBundle::class => ['all' => true],
|
||||
Symfony\Bundle\DebugBundle\DebugBundle::class => ['dev' => true],
|
||||
Symfony\Bundle\TwigBundle\TwigBundle::class => ['all' => true],
|
||||
Symfony\Bundle\WebProfilerBundle\WebProfilerBundle::class => ['dev' => true, 'test' => true],
|
||||
Twig\Extra\TwigExtraBundle\TwigExtraBundle::class => ['all' => true],
|
||||
Symfony\Bundle\SecurityBundle\SecurityBundle::class => ['all' => true],
|
||||
Symfony\Bundle\MonologBundle\MonologBundle::class => ['all' => true],
|
||||
Symfony\Bundle\MakerBundle\MakerBundle::class => ['dev' => true],
|
||||
App\DhcpBundle\DhcpBundle::class => ['all' => true],
|
||||
];
|
|
@ -0,0 +1,19 @@
|
|||
framework:
|
||||
cache:
|
||||
# Unique name of your app: used to compute stable namespaces for cache keys.
|
||||
#prefix_seed: your_vendor_name/app_name
|
||||
|
||||
# The "app" cache stores to the filesystem by default.
|
||||
# The data in this cache should persist between deploys.
|
||||
# Other options include:
|
||||
|
||||
# Redis
|
||||
#app: cache.adapter.redis
|
||||
#default_redis_provider: redis://localhost
|
||||
|
||||
# APCu (not recommended with heavy random-write workloads as memory fragmentation can cause perf issues)
|
||||
#app: cache.adapter.apcu
|
||||
|
||||
# Namespaced pools use the above "app" backend by default
|
||||
#pools:
|
||||
#my.dedicated.cache: null
|
|
@ -0,0 +1,5 @@
|
|||
when@dev:
|
||||
debug:
|
||||
# Forwards VarDumper Data clones to a centralized server allowing to inspect dumps on CLI or in your browser.
|
||||
# See the "server:dump" command to start a new server.
|
||||
dump_destination: "tcp://%env(VAR_DUMPER_SERVER)%"
|
|
@ -0,0 +1,43 @@
|
|||
doctrine:
|
||||
dbal:
|
||||
url: '%env(resolve:DATABASE_URL)%'
|
||||
|
||||
# IMPORTANT: You MUST configure your server version,
|
||||
# either here or in the DATABASE_URL env var (see .env file)
|
||||
#server_version: '15'
|
||||
orm:
|
||||
auto_generate_proxy_classes: true
|
||||
naming_strategy: doctrine.orm.naming_strategy.underscore_number_aware
|
||||
auto_mapping: true
|
||||
mappings:
|
||||
App:
|
||||
is_bundle: false
|
||||
dir: '%kernel.project_dir%/src/Entity'
|
||||
prefix: 'App\Entity'
|
||||
alias: App
|
||||
|
||||
when@test:
|
||||
doctrine:
|
||||
dbal:
|
||||
# "TEST_TOKEN" is typically set by ParaTest
|
||||
dbname_suffix: '_test%env(default::TEST_TOKEN)%'
|
||||
|
||||
when@prod:
|
||||
doctrine:
|
||||
orm:
|
||||
auto_generate_proxy_classes: false
|
||||
proxy_dir: '%kernel.build_dir%/doctrine/orm/Proxies'
|
||||
query_cache_driver:
|
||||
type: pool
|
||||
pool: doctrine.system_cache_pool
|
||||
result_cache_driver:
|
||||
type: pool
|
||||
pool: doctrine.result_cache_pool
|
||||
|
||||
framework:
|
||||
cache:
|
||||
pools:
|
||||
doctrine.result_cache_pool:
|
||||
adapter: cache.app
|
||||
doctrine.system_cache_pool:
|
||||
adapter: cache.system
|
|
@ -0,0 +1,6 @@
|
|||
doctrine_migrations:
|
||||
migrations_paths:
|
||||
# namespace is arbitrary but should be different from App\Migrations
|
||||
# as migrations classes should NOT be autoloaded
|
||||
'DoctrineMigrations': '%kernel.project_dir%/migrations'
|
||||
enable_profiler: false
|
|
@ -0,0 +1,24 @@
|
|||
# see https://symfony.com/doc/current/reference/configuration/framework.html
|
||||
framework:
|
||||
secret: '%env(APP_SECRET)%'
|
||||
#csrf_protection: true
|
||||
http_method_override: false
|
||||
|
||||
# Enables session support. Note that the session will ONLY be started if you read or write from it.
|
||||
# Remove or comment this section to explicitly disable session support.
|
||||
session:
|
||||
handler_id: null
|
||||
cookie_secure: auto
|
||||
cookie_samesite: lax
|
||||
storage_factory_id: session.storage.factory.native
|
||||
|
||||
#esi: true
|
||||
#fragments: true
|
||||
php_errors:
|
||||
log: true
|
||||
|
||||
when@test:
|
||||
framework:
|
||||
test: true
|
||||
session:
|
||||
storage_factory_id: session.storage.factory.mock_file
|
|
@ -0,0 +1,3 @@
|
|||
framework:
|
||||
mailer:
|
||||
dsn: '%env(MAILER_DSN)%'
|
|
@ -0,0 +1,24 @@
|
|||
framework:
|
||||
messenger:
|
||||
failure_transport: failed
|
||||
|
||||
transports:
|
||||
# https://symfony.com/doc/current/messenger.html#transport-configuration
|
||||
async:
|
||||
dsn: '%env(MESSENGER_TRANSPORT_DSN)%'
|
||||
options:
|
||||
use_notify: true
|
||||
check_delayed_interval: 60000
|
||||
retry_strategy:
|
||||
max_retries: 3
|
||||
multiplier: 2
|
||||
failed: 'doctrine://default?queue_name=failed'
|
||||
# sync: 'sync://'
|
||||
|
||||
routing:
|
||||
Symfony\Component\Mailer\Messenger\SendEmailMessage: async
|
||||
Symfony\Component\Notifier\Message\ChatMessage: async
|
||||
Symfony\Component\Notifier\Message\SmsMessage: async
|
||||
|
||||
# Route your messages to the transports
|
||||
# 'App\Message\YourMessage': async
|
|
@ -0,0 +1,61 @@
|
|||
monolog:
|
||||
channels:
|
||||
- deprecation # Deprecations are logged in the dedicated "deprecation" channel when it exists
|
||||
|
||||
when@dev:
|
||||
monolog:
|
||||
handlers:
|
||||
main:
|
||||
type: stream
|
||||
path: "%kernel.logs_dir%/%kernel.environment%.log"
|
||||
level: debug
|
||||
channels: ["!event"]
|
||||
# uncomment to get logging in your browser
|
||||
# you may have to allow bigger header sizes in your Web server configuration
|
||||
#firephp:
|
||||
# type: firephp
|
||||
# level: info
|
||||
#chromephp:
|
||||
# type: chromephp
|
||||
# level: info
|
||||
console:
|
||||
type: console
|
||||
process_psr_3_messages: false
|
||||
channels: ["!event", "!doctrine", "!console"]
|
||||
|
||||
when@test:
|
||||
monolog:
|
||||
handlers:
|
||||
main:
|
||||
type: fingers_crossed
|
||||
action_level: error
|
||||
handler: nested
|
||||
excluded_http_codes: [404, 405]
|
||||
channels: ["!event"]
|
||||
nested:
|
||||
type: stream
|
||||
path: "%kernel.logs_dir%/%kernel.environment%.log"
|
||||
level: debug
|
||||
|
||||
when@prod:
|
||||
monolog:
|
||||
handlers:
|
||||
main:
|
||||
type: fingers_crossed
|
||||
action_level: error
|
||||
handler: nested
|
||||
excluded_http_codes: [404, 405]
|
||||
buffer_size: 50 # How many messages should be saved? Prevent memory leaks
|
||||
nested:
|
||||
type: stream
|
||||
path: php://stderr
|
||||
level: debug
|
||||
formatter: monolog.formatter.json
|
||||
console:
|
||||
type: console
|
||||
process_psr_3_messages: false
|
||||
channels: ["!event", "!doctrine"]
|
||||
deprecation:
|
||||
type: stream
|
||||
channels: [deprecation]
|
||||
path: php://stderr
|
|
@ -0,0 +1,12 @@
|
|||
framework:
|
||||
notifier:
|
||||
chatter_transports:
|
||||
texter_transports:
|
||||
channel_policy:
|
||||
# use chat/slack, chat/telegram, sms/twilio or sms/nexmo
|
||||
urgent: ['email']
|
||||
high: ['email']
|
||||
medium: ['email']
|
||||
low: ['email']
|
||||
admin_recipients:
|
||||
- { email: admin@example.com }
|
|
@ -0,0 +1,12 @@
|
|||
framework:
|
||||
router:
|
||||
utf8: true
|
||||
|
||||
# Configure how to generate URLs in non-HTTP contexts, such as CLI commands.
|
||||
# See https://symfony.com/doc/current/routing.html#generating-urls-in-commands
|
||||
#default_uri: http://localhost
|
||||
|
||||
when@prod:
|
||||
framework:
|
||||
router:
|
||||
strict_requirements: null
|
|
@ -0,0 +1,40 @@
|
|||
security:
|
||||
enable_authenticator_manager: true
|
||||
# https://symfony.com/doc/current/security.html#registering-the-user-hashing-passwords
|
||||
password_hashers:
|
||||
Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface: 'auto'
|
||||
# https://symfony.com/doc/current/security.html#loading-the-user-the-user-provider
|
||||
providers:
|
||||
users_in_memory: { memory: null }
|
||||
firewalls:
|
||||
dev:
|
||||
pattern: ^/(_(profiler|wdt)|css|images|js)/
|
||||
security: false
|
||||
main:
|
||||
lazy: true
|
||||
provider: users_in_memory
|
||||
|
||||
# activate different ways to authenticate
|
||||
# https://symfony.com/doc/current/security.html#the-firewall
|
||||
|
||||
# https://symfony.com/doc/current/security/impersonating_user.html
|
||||
# switch_user: true
|
||||
|
||||
# Easy way to control access for large sections of your site
|
||||
# Note: Only the *first* access control that matches will be used
|
||||
access_control:
|
||||
# - { path: ^/admin, roles: ROLE_ADMIN }
|
||||
# - { path: ^/profile, roles: ROLE_USER }
|
||||
|
||||
when@test:
|
||||
security:
|
||||
password_hashers:
|
||||
# By default, password hashers are resource intensive and take time. This is
|
||||
# important to generate secure password hashes. In tests however, secure hashes
|
||||
# are not important, waste resources and increase test times. The following
|
||||
# reduces the work factor to the lowest possible values.
|
||||
Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface:
|
||||
algorithm: auto
|
||||
cost: 4 # Lowest possible value for bcrypt
|
||||
time_cost: 3 # Lowest possible value for argon
|
||||
memory_cost: 10 # Lowest possible value for argon
|
|
@ -0,0 +1,13 @@
|
|||
framework:
|
||||
default_locale: en
|
||||
translator:
|
||||
default_path: '%kernel.project_dir%/translations'
|
||||
fallbacks:
|
||||
- en
|
||||
# providers:
|
||||
# crowdin:
|
||||
# dsn: '%env(CROWDIN_DSN)%'
|
||||
# loco:
|
||||
# dsn: '%env(LOCO_DSN)%'
|
||||
# lokalise:
|
||||
# dsn: '%env(LOKALISE_DSN)%'
|
|
@ -0,0 +1,6 @@
|
|||
twig:
|
||||
default_path: '%kernel.project_dir%/templates'
|
||||
|
||||
when@test:
|
||||
twig:
|
||||
strict_variables: true
|
|
@ -0,0 +1,13 @@
|
|||
framework:
|
||||
validation:
|
||||
email_validation_mode: html5
|
||||
|
||||
# Enables validator auto-mapping support.
|
||||
# For instance, basic validation constraints will be inferred from Doctrine's metadata.
|
||||
#auto_mapping:
|
||||
# App\Entity\: []
|
||||
|
||||
when@test:
|
||||
framework:
|
||||
validation:
|
||||
not_compromised_password: false
|
|
@ -0,0 +1,15 @@
|
|||
when@dev:
|
||||
web_profiler:
|
||||
toolbar: true
|
||||
intercept_redirects: false
|
||||
|
||||
framework:
|
||||
profiler: { only_exceptions: false }
|
||||
|
||||
when@test:
|
||||
web_profiler:
|
||||
toolbar: false
|
||||
intercept_redirects: false
|
||||
|
||||
framework:
|
||||
profiler: { collect: false }
|
|
@ -0,0 +1,5 @@
|
|||
<?php
|
||||
|
||||
if (file_exists(dirname(__DIR__).'/var/cache/prod/App_KernelProdContainer.preload.php')) {
|
||||
require dirname(__DIR__).'/var/cache/prod/App_KernelProdContainer.preload.php';
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
#index:
|
||||
# path: /
|
||||
# controller: App\Controller\DefaultController::index
|
|
@ -0,0 +1,7 @@
|
|||
controllers:
|
||||
resource: ../../src/DhcpBundle/Controller/
|
||||
type: annotation
|
||||
|
||||
kernel:
|
||||
resource: ../../src/Kernel.php
|
||||
type: annotation
|
|
@ -0,0 +1,4 @@
|
|||
when@dev:
|
||||
_errors:
|
||||
resource: '@FrameworkBundle/Resources/config/routing/errors.xml'
|
||||
prefix: /_error
|
|
@ -0,0 +1,8 @@
|
|||
when@dev:
|
||||
web_profiler_wdt:
|
||||
resource: '@WebProfilerBundle/Resources/config/routing/wdt.xml'
|
||||
prefix: /_wdt
|
||||
|
||||
web_profiler_profiler:
|
||||
resource: '@WebProfilerBundle/Resources/config/routing/profiler.xml'
|
||||
prefix: /_profiler
|
|
@ -0,0 +1,27 @@
|
|||
# This file is the entry point to configure your own services.
|
||||
# Files in the packages/ subdirectory configure your dependencies.
|
||||
|
||||
# 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:
|
||||
|
||||
services:
|
||||
# default configuration for services in *this* file
|
||||
_defaults:
|
||||
autowire: true # Automatically injects dependencies in your services.
|
||||
autoconfigure: true # Automatically registers your services as commands, event subscribers, etc.
|
||||
|
||||
# makes classes in src/ available to be used as services
|
||||
# this creates a service per class whose id is the fully-qualified class name
|
||||
App\:
|
||||
resource: '../src/'
|
||||
exclude:
|
||||
- '../src/DependencyInjection/'
|
||||
- '../src/Entity/'
|
||||
- '../src/Kernel.php'
|
||||
|
||||
# add more service definitions when explicit configuration is needed
|
||||
# please note that last definitions always *replace* previous ones
|
||||
App\DhcpBundle\Controller\:
|
||||
resource: '../src/DhcpBundle/Controller'
|
||||
tags: ['controller.service_arguments']
|
|
@ -0,0 +1,8 @@
|
|||
|
||||
<?php
|
||||
use OpenApi\Annotations as OpenApi;
|
||||
require('vendor/autoload.php');
|
||||
|
||||
$openapi = OpenApi\scan('/path/to/your/project');
|
||||
header('Content-Type: application/x-yaml');
|
||||
echo $openapi->toYaml();
|
|
@ -0,0 +1,228 @@
|
|||
#!/bin/bash
|
||||
|
||||
#####################################################################
|
||||
####### Script instalador Ogclient
|
||||
####### Autor: Luis Gerardo Romero <lguillen@unizar.es>
|
||||
#####################################################################
|
||||
|
||||
function globalSetup ()
|
||||
{
|
||||
PROGRAMDIR=$(readlink -e "$(dirname "$0")")
|
||||
PROGRAMNAME=$(basename "$0")
|
||||
|
||||
# Comprobar si se ha descargado el paquete comprimido (REMOTE=0) o sólo el instalador (REMOTE=1).
|
||||
OPENGNSYS_SERVER="opengnsys.es"
|
||||
if [ -d "$PROGRAMDIR/../installer" ]; then
|
||||
echo REMOTE=0
|
||||
REMOTE=0
|
||||
else
|
||||
echo REMOTE=1
|
||||
REMOTE=1
|
||||
fi
|
||||
BRANCH=$1
|
||||
if [[ -z $BRANCH ]]; then
|
||||
BRANCH="main"
|
||||
fi
|
||||
GIT_REPO="ssh://git@ognproject.evlt.uma.es:21987/opengnsys/ogdhcp.git"
|
||||
|
||||
# Directorios de instalación y destino de OpenGnsys.
|
||||
WORKDIR=/tmp/ogclient_installer
|
||||
INSTALL_TARGET=/opt/ogclient
|
||||
PATH=$PATH:$INSTALL_TARGET/bin
|
||||
|
||||
# Registro de incidencias.
|
||||
OGLOGFILE=$INSTALL_TARGET/log/${PROGRAMNAME%.sh}.log
|
||||
LOG_FILE=/tmp/$(basename $OGLOGFILE)
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
# Función para instalar los paquetes necesarios para KEA-DHCP
|
||||
install_kea() {
|
||||
sudo apt-get install -y kea-dhcp4-server kea-dhcp6-server
|
||||
}
|
||||
|
||||
# Función para instalar PHP y las extensiones necesarias para Symfony
|
||||
install_php() {
|
||||
sudo apt-get install -y 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
|
||||
}
|
||||
|
||||
# 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 Symfony
|
||||
install_symfony() {
|
||||
composer global require symfony
|
||||
echo 'export PATH="$PATH:$HOME/.composer/vendor/bin"' >> ~/.bashrc
|
||||
source ~/.bashrc
|
||||
}
|
||||
|
||||
|
||||
# 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
|
||||
}
|
||||
|
||||
# Función para instalar el componente ogdhcp
|
||||
install_ogdhcp() {
|
||||
git clone <URL del repositorio de ogdhcp>
|
||||
sudo mv ogdhcp /opt/
|
||||
cd /opt/ogdhcp
|
||||
composer install
|
||||
}
|
||||
|
||||
|
||||
# Obtiene el código fuente del proyecto desde el repositorio de GitHub.
|
||||
function downloadCode()
|
||||
{
|
||||
if [ $# -ne 1 ]; then
|
||||
errorAndLog "${FUNCNAME}(): invalid number of parameters"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
local url="$1"
|
||||
|
||||
echoAndLog "${FUNCNAME}(): downloading code from '$url'..."
|
||||
|
||||
GIT_SSH_COMMAND="ssh -o StrictHostKeyChecking=accept-new" git archive --remote=$url --format zip --output opengnsys.zip --prefix=opengnsys/ $BRANCH && unzip opengnsys.zip
|
||||
if [ $? -ne 0 ]; then
|
||||
errorAndLog "${FUNCNAME}(): error getting OpenGnsys code from $url"
|
||||
return 1
|
||||
fi
|
||||
rm -f opengnsys.zip
|
||||
echoAndLog "${FUNCNAME}(): code was downloaded"
|
||||
return 0
|
||||
}
|
||||
|
||||
# Crea la estructura base de la instalación de opengnsys
|
||||
function createDirs()
|
||||
{
|
||||
if [ $# -ne 1 ]; then
|
||||
errorAndLog "${FUNCNAME}(): invalid number of parameters"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
local path_opengnsys_base="$1"
|
||||
|
||||
# Crear estructura de directorios.
|
||||
echoAndLog "${FUNCNAME}(): creating directory paths in $path_opengnsys_base"
|
||||
mkdir -p $path_opengnsys_base
|
||||
mkdir -p $path_opengnsys_base/bin
|
||||
mkdir -p $path_opengnsys_base/config
|
||||
mkdir -p $path_opengnsys_base/docs # Swagger documentation
|
||||
mkdir -p $path_opengnsys_base/public
|
||||
mkdir -p $path_opengnsys_base/src
|
||||
mkdir -p $path_opengnsys_base/templates
|
||||
mkdir -p $path_opengnsys_base/var/{cache,log}
|
||||
mkdir -p $path_opengnsys_base/vendor
|
||||
if [ $? -ne 0 ]; then
|
||||
errorAndLog "${FUNCNAME}(): error while creating dirs. Do you have write permissions?"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# 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"
|
||||
mv $LOG_FILE $path_opengnsys_base/var/log && LOG_FILE=$path_opengnsys_base/var/log
|
||||
chmod 600 $LOG_FILE
|
||||
|
||||
echoAndLog "${FUNCNAME}(): directory paths created"
|
||||
return 0
|
||||
}
|
||||
|
||||
|
||||
#####################################################################
|
||||
####### Algunas funciones útiles de propósito general:
|
||||
#####################################################################
|
||||
|
||||
function getDateTime()
|
||||
{
|
||||
date "+%Y%m%d-%H%M%S"
|
||||
}
|
||||
|
||||
# Escribe a fichero y muestra por pantalla
|
||||
function echoAndLog()
|
||||
{
|
||||
local DATETIME=`getDateTime`
|
||||
echo "$1"
|
||||
echo "$DATETIME;$SSH_CLIENT;$1" >> $LOG_FILE
|
||||
}
|
||||
|
||||
# Escribe a fichero y muestra mensaje de error
|
||||
function errorAndLog()
|
||||
{
|
||||
local DATETIME=`getDateTime`
|
||||
echo "ERROR: $1"
|
||||
echo "$DATETIME;$SSH_CLIENT;ERROR: $1" >> $LOG_FILE
|
||||
}
|
||||
|
||||
# Escribe a fichero y muestra mensaje de aviso
|
||||
function warningAndLog()
|
||||
{
|
||||
local DATETIME=`getDateTime`
|
||||
echo "Warning: $1"
|
||||
echo "$DATETIME;$SSH_CLIENT;Warning: $1" >> $LOG_FILE
|
||||
}
|
||||
|
||||
##########################################################################
|
||||
################################main######################################
|
||||
|
||||
|
||||
# Sólo ejecutable por usuario root
|
||||
if [ "$(whoami)" != 'root' ]; then
|
||||
echo "ERROR: this program must run under root privileges!!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
|
||||
# Si es necesario, descarga el repositorio de código en directorio temporal
|
||||
if [ $REMOTE -eq 1 ]; then
|
||||
downloadCode $GIT_REPO
|
||||
if [ $? -ne 0 ]; then
|
||||
errorAndLog "Error while getting code from the repository"
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
ln -fs "$(dirname $PROGRAMDIR)" opengnsys
|
||||
fi
|
||||
|
||||
globalSetup
|
||||
|
||||
# Arbol de directorios de OpenGnsys.
|
||||
createDirs ${INSTALL_TARGET}
|
||||
if [ $? -ne 0 ]; then
|
||||
errorAndLog "Error while creating directory paths!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
sudo apt-get update
|
||||
# install_kea
|
||||
# install_php
|
||||
# install_composer
|
||||
# install_symfony
|
||||
# install_swagger
|
||||
# Ahora puedes clonar e instalar el componente ogDhcp
|
||||
# git clone <URL del repositorio de ogDhcp>
|
||||
# cd <directorio de ogDhcp>
|
||||
# composer install
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<!-- https://phpunit.readthedocs.io/en/latest/configuration.html -->
|
||||
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:noNamespaceSchemaLocation="vendor/phpunit/phpunit/phpunit.xsd"
|
||||
backupGlobals="false"
|
||||
colors="true"
|
||||
bootstrap="tests/bootstrap.php"
|
||||
convertDeprecationsToExceptions="false"
|
||||
>
|
||||
<php>
|
||||
<ini name="display_errors" value="1" />
|
||||
<ini name="error_reporting" value="-1" />
|
||||
<server name="APP_ENV" value="test" force="true" />
|
||||
<server name="SHELL_VERBOSITY" value="-1" />
|
||||
<server name="SYMFONY_PHPUNIT_REMOVE" value="" />
|
||||
<server name="SYMFONY_PHPUNIT_VERSION" value="9.5" />
|
||||
</php>
|
||||
|
||||
<testsuites>
|
||||
<testsuite name="Project Test Suite">
|
||||
<directory>tests</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
|
||||
<coverage processUncoveredFiles="true">
|
||||
<include>
|
||||
<directory suffix=".php">src</directory>
|
||||
</include>
|
||||
</coverage>
|
||||
|
||||
<listeners>
|
||||
<listener class="Symfony\Bridge\PhpUnit\SymfonyTestsListener" />
|
||||
</listeners>
|
||||
|
||||
<extensions>
|
||||
</extensions>
|
||||
</phpunit>
|
Binary file not shown.
After Width: | Height: | Size: 665 B |
Binary file not shown.
After Width: | Height: | Size: 628 B |
|
@ -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;
|
||||
}
|
|
@ -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>
|
|
@ -0,0 +1,9 @@
|
|||
<?php
|
||||
|
||||
use App\Kernel;
|
||||
|
||||
require_once dirname(__DIR__).'/vendor/autoload_runtime.php';
|
||||
|
||||
return function (array $context) {
|
||||
return new Kernel($context['APP_ENV'], (bool) $context['APP_DEBUG']);
|
||||
};
|
|
@ -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>
|
|
@ -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://localhost:8001/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
|
@ -0,0 +1,549 @@
|
|||
{
|
||||
"openapi": "3.0.0",
|
||||
"info": {
|
||||
"title": "My API",
|
||||
"version": "1.0"
|
||||
},
|
||||
"paths": {
|
||||
"/opengnsys3/rest/dhcp/subnet": {
|
||||
"get": {
|
||||
"operationId": "ece42bc4084486aedf42734bdb0b84cb",
|
||||
"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": "36e86a6932056e774180d074d3d63ad0",
|
||||
"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/subnet/{subnetId}": {
|
||||
"put": {
|
||||
"summary": "Modify a DHCP subnet",
|
||||
"operationId": "c002afa59d07660be24fda34e1498c13",
|
||||
"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": "299c4287d729ca98c47ef613720051f4",
|
||||
"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/subnet/{subnetId}/host": {
|
||||
"get": {
|
||||
"summary": "Get all hosts in a subnet",
|
||||
"operationId": "2511366de74accc3d7356814ced1cf50",
|
||||
"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": "6106fe2802e2f913ddb35df61b5fde35",
|
||||
"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": "f5d3e1de64faa4e5b14cdc7d3bd0c427",
|
||||
"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": "542cc5fc093ff121c154504e9cad270f",
|
||||
"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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,905 @@
|
|||
<?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="My API", version="1.0")
|
||||
*/
|
||||
|
||||
private $curlKeaService;
|
||||
|
||||
public function __construct(CurlKeaService $curlKeaService, LoggerInterface $logger)
|
||||
{
|
||||
$this->curlKeaService = $curlKeaService;
|
||||
$this->logger = $logger;
|
||||
}
|
||||
|
||||
/**
|
||||
* @Route("/opengnsys3/rest/dhcp", methods={"GET"})
|
||||
*/
|
||||
public function getAllDhcp(): JsonResponse
|
||||
{
|
||||
$response = $this->curlKeaService->executeCurlCommand('config-get');
|
||||
return new JsonResponse($response);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// ...
|
||||
|
||||
/**
|
||||
* @Route("/opengnsys3/rest/dhcp/save", methods={"POST"})
|
||||
*/
|
||||
public function saveDhcpConfiguration(Request $request): JsonResponse
|
||||
{
|
||||
try {
|
||||
$input = json_decode($request->getContent());
|
||||
$configurationText = htmlspecialchars($input->configurationText);
|
||||
} catch (Exception $e) {
|
||||
$response["message"] = $e->getMessage();
|
||||
return new JsonResponse(['error' => $response], 400);
|
||||
}
|
||||
|
||||
$configurationParsed = str_replace(' ', '', $configurationText);
|
||||
$configurationParsed = str_replace("\n", '', $configurationParsed);
|
||||
$configurationParsed = str_replace('"', '"', $configurationParsed);
|
||||
$configuration = json_decode($configurationParsed);
|
||||
|
||||
if ($configuration === null || json_last_error() !== JSON_ERROR_NONE) {
|
||||
$responseError = "Error: El texto proporcionado no es un JSON válido.";
|
||||
return new JsonResponse(['error' => $responseError], 400);
|
||||
} else {
|
||||
try {
|
||||
$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 {
|
||||
$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);
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
$responseError = "Error al obtener la configuración de Kea DHCP: " . $e->getMessage();
|
||||
return new JsonResponse(['error' => $responseError], 400);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @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="/opengnsys3/rest/dhcp/subnet",
|
||||
* @OA\Response(
|
||||
* response=200,
|
||||
* description="Devuelve todas las subredes",
|
||||
* @OA\JsonContent(
|
||||
* type="array",
|
||||
* @OA\Items(ref="#/components/schemas/Subnet")
|
||||
* )
|
||||
* ),
|
||||
* @OA\Response(
|
||||
* response=400,
|
||||
* description="Error al obtener las subredes",
|
||||
* )
|
||||
* )
|
||||
* @Route("/opengnsys3/rest/dhcp/subnet", 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="/opengnsys3/rest/dhcp/subnet",
|
||||
* 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("/opengnsys3/rest/dhcp/subnet", 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 {
|
||||
$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("/opengnsys3/rest/dhcp/subnet/{subnetId}", methods={"DELETE"})
|
||||
* @OA\Delete(
|
||||
* path="/opengnsys3/rest/dhcp/subnet/{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")
|
||||
* )
|
||||
* )
|
||||
* )
|
||||
* @Route("/opengnsys3/rest/dhcp/subnet/{subnetId}", methods={"DELETE"})
|
||||
*/
|
||||
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 {
|
||||
$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("/opengnsys3/rest/dhcp/subnet/{subnetId}", methods={"PUT"})
|
||||
* @OA\Put(
|
||||
* path="/opengnsys3/rest/dhcp/subnet/{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")
|
||||
* )
|
||||
* )
|
||||
* )
|
||||
* @Route("/opengnsys3/rest/dhcp/subnet/{subnetId}", methods={"PUT"})
|
||||
*/
|
||||
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 {
|
||||
$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\Schema(
|
||||
* schema="Host",
|
||||
* 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\Get(
|
||||
* path="/opengnsys3/rest/dhcp/subnet/{subnetId}/host",
|
||||
* 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\JsonContent(
|
||||
* type="array",
|
||||
* @OA\Items(ref="#/components/schemas/Host")
|
||||
* )
|
||||
* ),
|
||||
* @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("/opengnsys3/rest/dhcp/subnet/{subnetId}/host", 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @Route("/opengnsys3/rest/dhcp/subnet/{subnetId}/host", methods={"POST"})
|
||||
* @OA\Post(
|
||||
* path="/opengnsys3/rest/dhcp/subnet/{subnetId}/host",
|
||||
* 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("/opengnsys3/rest/dhcp/subnet/{subnetId}/host", 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 {
|
||||
$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="/opengnsys3/rest/dhcp/subnet/{subnetId}/host",
|
||||
* 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("/opengnsys3/rest/dhcp/subnet/{subnetId}/host", 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 {
|
||||
$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="/opengnsys3/rest/dhcp/subnet/{subnetId}/host",
|
||||
* 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("/opengnsys3/rest/dhcp/subnet/{subnetId}/host", 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 {
|
||||
$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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @Route("/opengnsys3/rest/dhcp/backup", methods={"POST"})
|
||||
*/
|
||||
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);
|
||||
$responseSuccess = "última 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @Route("/opengnsys3/rest/info", methods={"GET"})
|
||||
*/
|
||||
public function phpInfo(): Response
|
||||
{
|
||||
ob_start();
|
||||
phpinfo();
|
||||
$phpinfo = ob_get_clean();
|
||||
|
||||
return new Response($phpinfo);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
<?php
|
||||
// src/DhcpBundle/DhcpBundle.php
|
||||
|
||||
namespace App\DhcpBundle;
|
||||
|
||||
use Symfony\Component\HttpKernel\Bundle\Bundle;
|
||||
|
||||
class DhcpBundle extends Bundle
|
||||
{
|
||||
}
|
|
@ -0,0 +1,103 @@
|
|||
<?php
|
||||
// src/DhcpBundle/Service/CurlKeaService.php
|
||||
|
||||
namespace App\DhcpBundle\Service;
|
||||
|
||||
use Exception;
|
||||
|
||||
class CurlKeaService
|
||||
{
|
||||
public function executeCurlCommand($command, $arguments = null, $create_backup = true)
|
||||
{
|
||||
$apiUrl = getenv('DHCP_IP');
|
||||
if (!$apiUrl) {
|
||||
$apiUrl = 'http://localhost:8000/';
|
||||
}
|
||||
|
||||
if ($command == 'config-get' || $command == 'config-write') {
|
||||
$requestData = array(
|
||||
'command' => $command,
|
||||
'service' => array('dhcp4'),
|
||||
);
|
||||
} elseif ($command == 'config-set' || $command == 'config-test') {
|
||||
$requestData = array(
|
||||
'command' => $command,
|
||||
'service' => array('dhcp4'),
|
||||
'arguments' => $arguments,
|
||||
);
|
||||
} else {
|
||||
return "Error: Comando no válido";
|
||||
}
|
||||
if (($command == 'config-set' || $command == 'config-write') && $create_backup) {
|
||||
$this->backupConfig();
|
||||
}
|
||||
$jsonData = json_encode($requestData);
|
||||
try {
|
||||
$ch = curl_init();
|
||||
curl_setopt($ch, CURLOPT_URL, $apiUrl);
|
||||
curl_setopt($ch, CURLOPT_POST, 1);
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, $jsonData);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/json', 'Expect:'));
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
|
||||
curl_setopt($ch, CURLOPT_TIMEOUT, 10);
|
||||
curl_setopt($ch, CURLOPT_POST, true);
|
||||
$response = curl_exec($ch);
|
||||
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||
$output = json_decode($response, true);
|
||||
|
||||
if ($httpCode >= 200 && $httpCode < 300) {
|
||||
|
||||
return $output;
|
||||
} else {
|
||||
$error = curl_error($ch);
|
||||
throw new Exception($error);
|
||||
//return false;
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
throw new Exception($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function convertMaskToCIDR($mask)
|
||||
{
|
||||
$bits = 0;
|
||||
$mask = explode(".", $mask);
|
||||
|
||||
foreach ($mask as $octect)
|
||||
$bits += strlen(str_replace("0", "", decbin($octect)));
|
||||
|
||||
return $bits;
|
||||
}
|
||||
|
||||
function backupConfig()
|
||||
{
|
||||
$get_command = 'config-get';
|
||||
$get_output = $this->executeCurlCommand($get_command);
|
||||
if ($get_output == false || $get_output[0]["result"] != 0) {
|
||||
throw new Exception('Error al obtener la configuración actual de Kea DHCP');
|
||||
}
|
||||
$config_text = json_encode($get_output[0]['arguments']);
|
||||
$configurationParsed = str_replace('\\', '', $config_text);
|
||||
|
||||
$backup_dir = '/opt/opengnsys/etc/kea/backup';
|
||||
if (!is_dir($backup_dir)) {
|
||||
throw new Exception('El directorio de backup no existe');
|
||||
}
|
||||
if (!is_writable($backup_dir)) {
|
||||
throw new Exception('El directorio de backup no tiene permisos de escritura');
|
||||
}
|
||||
$backup_files = glob($backup_dir . '/*.conf');
|
||||
if (count($backup_files) >= 10) {
|
||||
usort($backup_files, function ($a, $b) {
|
||||
return filemtime($a) - filemtime($b);
|
||||
});
|
||||
unlink($backup_files[0]);
|
||||
}
|
||||
$backup_file = $backup_dir . '/' . date('Y-m-d_H-i-s') . '.conf';
|
||||
if (!file_put_contents($backup_file, $configurationParsed)) {
|
||||
throw new Exception('Error al guardar la configuración de backup');
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
<?php
|
||||
|
||||
namespace App;
|
||||
|
||||
use Symfony\Bundle\FrameworkBundle\Kernel\MicroKernelTrait;
|
||||
use Symfony\Component\HttpKernel\Kernel as BaseKernel;
|
||||
|
||||
class Kernel extends BaseKernel
|
||||
{
|
||||
use MicroKernelTrait;
|
||||
}
|
|
@ -0,0 +1,130 @@
|
|||
{
|
||||
"openapi": "3.0.0",
|
||||
"info": {
|
||||
"title": "My API",
|
||||
"version": "1.0"
|
||||
},
|
||||
"paths": {
|
||||
"/opengnsys3/rest/dhcp/subnet": {
|
||||
"get": {
|
||||
"operationId": "ece42bc4084486aedf42734bdb0b84cb",
|
||||
"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"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/opengnsys3/rest/dhcp/subnet/add": {
|
||||
"post": {
|
||||
"summary": "Add a new DHCP subnet",
|
||||
"operationId": "c8d5e4a10918078f17ab2ad4b73fc453",
|
||||
"requestBody": {
|
||||
"description": "JSON payload",
|
||||
"required": true,
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"properties": {
|
||||
"subnetId": {
|
||||
"type": "integer"
|
||||
},
|
||||
"mask": {
|
||||
"type": "string"
|
||||
},
|
||||
"address": {
|
||||
"type": "string"
|
||||
},
|
||||
"nextServer": {
|
||||
"type": "string"
|
||||
},
|
||||
"bootFileName": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,261 @@
|
|||
{
|
||||
"doctrine/annotations": {
|
||||
"version": "2.0",
|
||||
"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": "013b823e7fee65890b23e40f31e6667a1ac519ac"
|
||||
},
|
||||
"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": "9.6",
|
||||
"recipe": {
|
||||
"repo": "github.com/symfony/recipes",
|
||||
"branch": "main",
|
||||
"version": "9.6",
|
||||
"ref": "7364a21d87e658eb363c5020c072ecfdc12e2326"
|
||||
},
|
||||
"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": "2bf89438209656b85b9a49238c4467bff1b1f939"
|
||||
},
|
||||
"files": [
|
||||
"config/packages/mailer.yaml"
|
||||
]
|
||||
},
|
||||
"symfony/maker-bundle": {
|
||||
"version": "1.43",
|
||||
"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": "213676c4ec929f046dfde5ea8e97625b81bc0578"
|
||||
},
|
||||
"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": "7.0",
|
||||
"recipe": {
|
||||
"repo": "github.com/symfony/recipes",
|
||||
"branch": "main",
|
||||
"version": "6.3",
|
||||
"ref": "1f5830c331065b6e4c9d5fa2105e322d29fcd573"
|
||||
},
|
||||
"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": "da64f5a2b6d96f5dc24914517c0350a5f91dee43"
|
||||
},
|
||||
"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"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,218 @@
|
|||
#!/usr/bin/env bash
|
||||
# Copyright (c) 2021-present Fabien Potencier <fabien@symfony.com>
|
||||
#
|
||||
# Symfony CLI installer: this file is part of Symfony CLI project.
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program 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 Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
set -euo pipefail
|
||||
|
||||
CLI_CONFIG_DIR=".symfony5"
|
||||
CLI_EXECUTABLE="symfony"
|
||||
CLI_TMP_NAME="$CLI_EXECUTABLE-"$(date +"%s")
|
||||
CLI_NAME="Symfony CLI"
|
||||
CLI_DOWNLOAD_URL_PATTERN="https://github.com/symfony-cli/symfony-cli/releases/latest/download/symfony-cli_~platform~.tar.gz"
|
||||
|
||||
function output {
|
||||
style_start=""
|
||||
style_end=""
|
||||
if [ "${2:-}" != "" ]; then
|
||||
case $2 in
|
||||
"success")
|
||||
style_start="\033[0;32m"
|
||||
style_end="\033[0m"
|
||||
;;
|
||||
"error")
|
||||
style_start="\033[31;31m"
|
||||
style_end="\033[0m"
|
||||
;;
|
||||
"info"|"warning")
|
||||
style_start="\033[33m"
|
||||
style_end="\033[39m"
|
||||
;;
|
||||
"heading")
|
||||
style_start="\033[1;33m"
|
||||
style_end="\033[22;39m"
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
builtin echo -e "${style_start}${1}${style_end}"
|
||||
}
|
||||
|
||||
output "${CLI_NAME} installer" "heading"
|
||||
|
||||
binary_dest="${HOME}/${CLI_CONFIG_DIR}/bin"
|
||||
custom_dir="false"
|
||||
|
||||
# Getops does not support long option names
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case $1 in
|
||||
--install-dir=*)
|
||||
binary_dest="${1#*=}"
|
||||
custom_dir="true"
|
||||
shift # past argument=value
|
||||
;;
|
||||
--install-dir)
|
||||
binary_dest="${2:-}"
|
||||
custom_dir="true"
|
||||
shift # past argument
|
||||
shift # past value
|
||||
;;
|
||||
*)
|
||||
output "Unknown option $1" "error"
|
||||
output "Usage: ${0} [--install-dir=dir]"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Run environment checks.
|
||||
output "\nEnvironment check" "heading"
|
||||
|
||||
# Check that cURL or wget is installed.
|
||||
downloader=""
|
||||
if command -v curl >/dev/null 2>&1; then
|
||||
downloader="curl"
|
||||
output " [*] cURL is installed" "success"
|
||||
elif command -v wget >/dev/null 2>&1; then
|
||||
downloader="wget"
|
||||
output " [*] wget is installed" "success"
|
||||
else
|
||||
output " [ ] ERROR: cURL or wget is required for installation." "error"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check that tar is installed.
|
||||
if command -v tar >/dev/null 2>&1; then
|
||||
output " [*] Tar is installed" "success"
|
||||
else
|
||||
output " [ ] ERROR: Tar is required for installation." "error"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check that Git is installed.
|
||||
if command -v git >/dev/null 2>&1; then
|
||||
output " [*] Git is installed" "success"
|
||||
else
|
||||
output " [ ] Warning: Git will be needed." "warning"
|
||||
fi
|
||||
|
||||
kernel=$(uname -s 2>/dev/null || /usr/bin/uname -s)
|
||||
case ${kernel} in
|
||||
"Linux"|"linux")
|
||||
kernel="linux"
|
||||
;;
|
||||
"Darwin"|"darwin")
|
||||
kernel="darwin"
|
||||
;;
|
||||
*)
|
||||
output "OS '${kernel}' not supported" "error"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
machine=$(uname -m 2>/dev/null || /usr/bin/uname -m)
|
||||
case ${machine} in
|
||||
arm|armv7*)
|
||||
machine="arm"
|
||||
;;
|
||||
aarch64*|armv8*|arm64)
|
||||
machine="arm64"
|
||||
;;
|
||||
i[36]86)
|
||||
machine="386"
|
||||
if [ "darwin" = "${kernel}" ]; then
|
||||
output " [ ] Your architecture (${machine}) is not supported anymore" "error"
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
x86_64)
|
||||
machine="amd64"
|
||||
;;
|
||||
*)
|
||||
output " [ ] Your architecture (${machine}) is not currently supported" "error"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
output " [*] Your architecture (${machine}) is supported" "success"
|
||||
|
||||
if [ "darwin" = "${kernel}" ]; then
|
||||
machine="all"
|
||||
fi
|
||||
|
||||
platform="${kernel}_${machine}"
|
||||
|
||||
# The necessary checks have passed. Start downloading the right version.
|
||||
output "\nDownload" "heading"
|
||||
|
||||
latest_url=${CLI_DOWNLOAD_URL_PATTERN/~platform~/${platform}}
|
||||
output " Downloading ${latest_url}...";
|
||||
case $downloader in
|
||||
"curl")
|
||||
curl --fail --location "${latest_url}" > "/tmp/${CLI_TMP_NAME}.tar.gz"
|
||||
;;
|
||||
"wget")
|
||||
wget -q --show-progress "${latest_url}" -O "/tmp/${CLI_TMP_NAME}.tar.gz"
|
||||
;;
|
||||
esac
|
||||
|
||||
# shellcheck disable=SC2181
|
||||
if [ $? != 0 ]; then
|
||||
output " The download failed." "error"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
output " Uncompress binary..."
|
||||
tar -xz --directory "/tmp" -f "/tmp/${CLI_TMP_NAME}.tar.gz"
|
||||
rm "/tmp/${CLI_TMP_NAME}.tar.gz"
|
||||
|
||||
if [ ! -d "${binary_dest}" ]; then
|
||||
if ! mkdir -p "${binary_dest}"; then
|
||||
binary_dest="."
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "${custom_dir}" == "true" ]; then
|
||||
output " Installing the binary into ${binary_dest} ..."
|
||||
else
|
||||
output " Installing the binary into your home directory..."
|
||||
fi
|
||||
|
||||
if mv "/tmp/${CLI_EXECUTABLE}" "${binary_dest}/${CLI_EXECUTABLE}"; then
|
||||
output " The binary was saved to: ${binary_dest}/${CLI_EXECUTABLE}"
|
||||
else
|
||||
output " Failed to move the binary to ${binary_dest}." "error"
|
||||
rm "/tmp/${CLI_EXECUTABLE}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
#output " Installing the shell auto-completion..."
|
||||
#"${binary_dest}/${CLI_EXECUTABLE}" self:shell-setup --silent
|
||||
#if [ $? != 0 ]; then
|
||||
# output " Failed to install the shell auto-completion." "warning"
|
||||
#fi
|
||||
|
||||
output "\nThe ${CLI_NAME} was installed successfully!" "success"
|
||||
|
||||
if [ "${custom_dir}" == "false" ]; then
|
||||
output "\nUse it as a local file:" "info"
|
||||
output " ${binary_dest}/${CLI_EXECUTABLE}"
|
||||
output "\nOr add the following line to your shell configuration file:" "info"
|
||||
output " export PATH=\"\$HOME/${CLI_CONFIG_DIR}/bin:\$PATH\""
|
||||
output "\nOr install it globally on your system:" "info"
|
||||
output " mv ${binary_dest}/${CLI_EXECUTABLE} /usr/local/bin/${CLI_EXECUTABLE}"
|
||||
output "\nThen start a new shell and run '${CLI_EXECUTABLE}'" "info"
|
||||
fi
|
|
@ -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>
|
|
@ -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 %}
|
|
@ -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');
|
||||
}
|
Loading…
Reference in New Issue