Merged branch 'nginx_conf' into 'main', ignoring conflicts and keeping 'nginx_conf' changes
testing/og-dhcp-API/pipeline/head There was a failure building this commit
Details
testing/og-dhcp-API/pipeline/head There was a failure building this commit
Details
parent
3ca7ddd20b
commit
d58744c595
|
@ -31,3 +31,10 @@
|
|||
.phpunit.result.cache
|
||||
/phpunit.xml
|
||||
###< symfony/phpunit-bridge ###
|
||||
|
||||
.venv
|
||||
ogdhcp.code-workspace
|
||||
output.xml
|
||||
log.html
|
||||
report.html
|
||||
__pycache__
|
||||
|
|
|
@ -4,17 +4,16 @@
|
|||
"minimum-stability": "stable",
|
||||
"prefer-stable": true,
|
||||
"require": {
|
||||
"php": ">=7.2.0",
|
||||
"php": ">=8.1",
|
||||
"ext-ctype": "*",
|
||||
"ext-iconv": "*",
|
||||
"doctrine/annotations": "^1.6",
|
||||
"doctrine/doctrine-bundle": "^2.0",
|
||||
"doctrine/doctrine-migrations-bundle": "^3.0",
|
||||
"doctrine/orm": "^2.7",
|
||||
"nelmio/api-doc-bundle": "^4.9",
|
||||
"phpdocumentor/reflection-docblock": "^5.0",
|
||||
"phpstan/phpdoc-parser": "^0.4",
|
||||
"zircote/swagger-php": "3.*",
|
||||
"symfony/runtime": "5.*",
|
||||
"symfony/asset": "5.*",
|
||||
"symfony/console": "5.*",
|
||||
"symfony/doctrine-messenger": "5.*",
|
||||
|
@ -32,6 +31,7 @@
|
|||
"symfony/process": "5.*",
|
||||
"symfony/property-access": "5.*",
|
||||
"symfony/property-info": "5.*",
|
||||
"symfony/runtime": "5.*",
|
||||
"symfony/security-bundle": "5.*",
|
||||
"symfony/serializer": "5.*",
|
||||
"symfony/string": "5.*",
|
||||
|
@ -41,7 +41,8 @@
|
|||
"symfony/web-link": "5.*",
|
||||
"symfony/yaml": "5.*",
|
||||
"twig/extra-bundle": "^2.12|^3.0",
|
||||
"twig/twig": "^2.12|^3.0"
|
||||
"twig/twig": "^2.12|^3.0",
|
||||
"zircote/swagger-php": "3.*"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^8.5",
|
||||
|
|
|
@ -12,4 +12,6 @@ return [
|
|||
Symfony\Bundle\MonologBundle\MonologBundle::class => ['all' => true],
|
||||
Symfony\Bundle\MakerBundle\MakerBundle::class => ['dev' => true],
|
||||
App\DhcpBundle\DhcpBundle::class => ['all' => true],
|
||||
Nelmio\ApiDocBundle\NelmioApiDocBundle::class => ['all' => true],
|
||||
|
||||
];
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
nelmio_api_doc:
|
||||
documentation:
|
||||
info:
|
||||
title: OgDHCP API
|
||||
description: OgDHCP API documentation
|
||||
version: 1.0.0
|
||||
components:
|
||||
schemas:
|
||||
Host:
|
||||
type: object
|
||||
properties:
|
||||
hostname:
|
||||
type: string
|
||||
description: The hostname of the device
|
||||
example: "pc11"
|
||||
hw-address:
|
||||
type: string
|
||||
description: The hardware address (MAC)
|
||||
example: "56:6f:c7:4f:00:4f"
|
||||
ip-address:
|
||||
type: string
|
||||
description: The IP address assigned to the host
|
||||
example: "192.168.5.11"
|
||||
Subnet:
|
||||
type: object
|
||||
properties:
|
||||
id:
|
||||
type: integer
|
||||
description: The ID of the subnet
|
||||
subnet:
|
||||
type: string
|
||||
description: The name of the subnet
|
||||
next-server:
|
||||
type: string
|
||||
description: The next server in the subnet
|
||||
boot-file-name:
|
||||
type: string
|
||||
description: The boot file name for the subnet
|
||||
reservations:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/Host'
|
||||
description: The reservations in the subnet
|
||||
|
||||
|
||||
areas: # to filter documented areas
|
||||
path_patterns:
|
||||
- ^/ogdhcp/ # Accepts routes under /api except /api/doc
|
|
@ -1,3 +1,7 @@
|
|||
#index:
|
||||
# path: /
|
||||
# controller: App\Controller\DefaultController::index
|
||||
app.swagger_ui:
|
||||
path: /ogdhcp/api/doc
|
||||
methods: GET
|
||||
defaults: { _controller: nelmio_api_doc.controller.swagger_ui }
|
|
@ -4,7 +4,7 @@
|
|||
# Put parameters here that don't need to change on each machine where the app is deployed
|
||||
# https://symfony.com/doc/current/best_practices.html#use-parameters-for-application-configuration
|
||||
parameters:
|
||||
|
||||
backup_dir: '%kernel.project_dir%/etc/kea/backup'
|
||||
services:
|
||||
# default configuration for services in *this* file
|
||||
_defaults:
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
<VirtualHost *:80>
|
||||
ServerName localhost
|
||||
ServerAlias api-test
|
||||
DocumentRoot /opt/ogdhcp/public
|
||||
|
||||
<Directory /opt/ogdhcp/public>
|
||||
|
@ -21,7 +22,7 @@
|
|||
</IfModule>
|
||||
|
||||
<FilesMatch \.php$>
|
||||
SetHandler "proxy:unix:/run/php/php8.1-fpm.sock|fcgi://localhost/"
|
||||
SetHandler "proxy:unix:/run/php/php8.3-fpm.sock|fcgi://localhost/"
|
||||
</FilesMatch>
|
||||
|
||||
ErrorLog ${APACHE_LOG_DIR}/ogdhcp_error.log
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
server {
|
||||
listen 8081;
|
||||
server_name __SERVERIP__ localhost; # IP del servidor
|
||||
|
||||
# Raíz del documento para el proyecto Symfony
|
||||
root __PUBLICDIR__;
|
||||
|
||||
# Bloque para manejar las solicitudes a /ogdhcp
|
||||
location /ogdhcp {
|
||||
try_files $uri $uri/ /index.php?$query_string;
|
||||
# Aumentar el tiempo de espera por el install ogdhcp (si es necesario)
|
||||
proxy_read_timeout 600;
|
||||
proxy_connect_timeout 600;
|
||||
proxy_send_timeout 600;
|
||||
send_timeout 600;
|
||||
}
|
||||
|
||||
# Bloque para manejar las solicitudes a index.php
|
||||
location ~ ^/index.php(/|$) {
|
||||
include fastcgi_params;
|
||||
fastcgi_pass unix:/run/php/php__PHPVERSION__-fpm-ogdhcp.sock;
|
||||
fastcgi_split_path_info ^(.+\.php)(/.*)$;
|
||||
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
|
||||
fastcgi_param PATH_INFO $fastcgi_path_info;
|
||||
fastcgi_param DOCUMENT_ROOT $document_root;
|
||||
internal;
|
||||
}
|
||||
|
||||
# Bloque para devolver 404 en cualquier solicitud a archivos PHP que no sean index.php
|
||||
location ~ \.php$ {
|
||||
return 404;
|
||||
}
|
||||
|
||||
# Logs de error y acceso para el proyecto Symfony
|
||||
error_log /var/log/nginx/ogdhcp_error.log;
|
||||
access_log /var/log/nginx/ogdhcp_access.log;
|
||||
|
||||
# Manejo de la ruta para la documentación de la API (Swagger)
|
||||
location /ogdhcp/api/doc {
|
||||
try_files $uri /index.php?$query_string;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"interfaces": ["eth0", "eth1"],
|
||||
"ogbootIP": "172.17.8.37",
|
||||
"ogDhcpIP": "172.17.8.37",
|
||||
"ogDhcp_Dir": "/opt/opengnsys/ogdhcp"
|
||||
|
||||
}
|
|
@ -10,7 +10,13 @@ function globalSetup() {
|
|||
current_dir=$(dirname "$0")
|
||||
PROGRAMDIR=$(readlink -e "$current_dir")
|
||||
PROGRAMNAME=$(basename "$0")
|
||||
OPENGNSYS_CLIENT_USER="ogdhcp"
|
||||
OPENGNSYS_CLIENT_USER="opengnsys"
|
||||
current_dir=$(dirname "$0")
|
||||
PROGRAMDIR=$(readlink -e "$current_dir")
|
||||
|
||||
# Ruta del archivo config_ogdhcp.json proporcionado por el usuario
|
||||
CONFIG_FILE="$PROGRAMDIR/config_ogdhcp.json"
|
||||
|
||||
|
||||
# Comprobar si se ha descargado el paquete comprimido (REMOTE=0) o sólo el instalador (REMOTE=1).
|
||||
if [ -d "$PROGRAMDIR/../installer" ]; then
|
||||
|
@ -27,7 +33,7 @@ function globalSetup() {
|
|||
|
||||
# Directorios de instalación y destino de OpenGnsys.
|
||||
WORKDIR=/tmp/ogdhcp_installer
|
||||
INSTALL_TARGET=/opt/ogdhcp
|
||||
INSTALL_TARGET=$(jq -r '.ogDhcp_Dir' "$CONFIG_FILE")
|
||||
PATH=$PATH:$INSTALL_TARGET/bin
|
||||
|
||||
if command -v service &>/dev/null; then
|
||||
|
@ -41,18 +47,14 @@ function globalSetup() {
|
|||
ENABLESERVICE="eval update-rc.d \$service defaults"
|
||||
DISABLESERVICE="eval update-rc.d \$service disable"
|
||||
|
||||
APACHESERV=apache2
|
||||
APACHECFGDIR=/etc/apache2
|
||||
APACHESITESDIR=sites-available
|
||||
APACHEOGSITE=ogdhcp
|
||||
APACHEUSER="www-data"
|
||||
APACHEGROUP="www-data"
|
||||
APACHEENABLEMODS="a2enmod headers ssl rewrite proxy_fcgi fastcgi actions alias"
|
||||
APACHEENABLESSL="a2ensite default-ssl"
|
||||
APACHEENABLEOG="a2ensite $APACHEENABLEOG"
|
||||
APACHEMAKECERT="make-ssl-cert generate-default-snakeoil --force-overwrite"
|
||||
|
||||
PHPFPMSERV=php7.2-fpm
|
||||
# Variables globales
|
||||
DEFAULTDEV=""
|
||||
NGINX_TEMPLATE="$INSTALL_TARGET/etc/nginxServer.conf.tmpl"
|
||||
NGINX_OUTPUT="/etc/nginx/sites-available/ogdhcp.conf"
|
||||
NGINX_CONF_PATH="/etc/nginx/nginx.conf"
|
||||
PHP_FPM_CONF_PATH="/etc/php/__PHPVERSION__/fpm/pool.d/www.conf"
|
||||
NEW_FPM_CONF_PATH="/etc/php/__PHPVERSION__/fpm/pool.d/ogdhcp.conf"
|
||||
SOCKET_PATH="/run/php/php__PHPVERSION__-fpm-ogdhcp.sock"
|
||||
|
||||
# Registro de incidencias.
|
||||
OGLOGFILE="$INSTALL_TARGET/var/log/${PROGRAMNAME%.sh}.log"
|
||||
|
@ -80,47 +82,32 @@ function checkDependencies() {
|
|||
php-bcmath
|
||||
composer
|
||||
unzip
|
||||
apache2
|
||||
libapache2-mod-php
|
||||
kea-dhcp4-server
|
||||
kea-common
|
||||
kea-ctrl-agent
|
||||
jq
|
||||
net-tools
|
||||
nginx
|
||||
|
||||
)
|
||||
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
apt-get update -y
|
||||
# Comprobar cada dependencia
|
||||
for dep in "${DEPENDENCIES[@]}"; do
|
||||
if ! dpkg -s "$dep" >/dev/null 2>&1; then
|
||||
echoAndLog "$dep is not installed. Installing..."
|
||||
sudo apt-get install -y "$dep"
|
||||
apt-get install -y --no-install-recommends "$dep"
|
||||
else
|
||||
echoAndLog "$dep is already installed."
|
||||
fi
|
||||
done
|
||||
|
||||
sed -i '/ConditionFileNotEmpty=\/etc\/kea\/kea-api-password/d' /usr/lib/systemd/system/kea-ctrl-agent.service
|
||||
chown -R _kea:_kea /etc/kea
|
||||
systemctl daemon-reload
|
||||
systemctl restart kea-ctrl-agent.service
|
||||
echoAndLog "Dependencies checked."
|
||||
}
|
||||
|
||||
# Función para instalar los paquetes necesarios para KEA-DHCP
|
||||
install_kea() {
|
||||
sudo apt-get install -y isc-kea-common isc-kea-ctrl-agent isc-kea-dhcp4-server isc-kea-dhcp6-server isc-kea-admin
|
||||
}
|
||||
|
||||
# Función para instalar Composer
|
||||
install_composer() {
|
||||
curl -sS https://getcomposer.org/installer | php
|
||||
sudo mv composer.phar /usr/local/bin/composer
|
||||
}
|
||||
|
||||
# Función para instalar Swagger UI
|
||||
install_swagger() {
|
||||
sudo apt-get install -y unzip
|
||||
wget https://github.com/swagger-api/swagger-ui/archive/master.zip
|
||||
unzip master.zip -d /var/www/html/
|
||||
sudo mv /var/www/html/swagger-ui-master /var/www/html/swagger-ui
|
||||
}
|
||||
|
||||
# Obtiene el código fuente del proyecto desde el repositorio de GitHub.
|
||||
function downloadCode() {
|
||||
|
@ -189,22 +176,32 @@ function createDirs() {
|
|||
# Cambiar permisos de usuario
|
||||
echoAndLog "Changing user permission"
|
||||
chown -R "$OPENGNSYS_CLIENT_USER:$OPENGNSYS_CLIENT_USER" "$INSTALL_TARGET"
|
||||
|
||||
# Copiar .env
|
||||
cp -a "$WORKDIR/ogdhcp/.env" "${path_opengnsys_base}/.env"
|
||||
}
|
||||
|
||||
|
||||
function create_ogdhcp_project {
|
||||
# Cambia al usuario ogdhcp y crea el proyecto Symfony
|
||||
# Crea el usuario ogdhcp si no existe
|
||||
local path_opengnsys_base="$1"
|
||||
composer create-project symfony/website-skeleton "$path_opengnsys_base"
|
||||
pushd "$path_opengnsys_base" || return
|
||||
# Elimina el archivo composer.lock
|
||||
rm composer.lock
|
||||
popd || return
|
||||
echoAndLog "Esqueleto de la aplicación creado y archivo composer.lock eliminado."
|
||||
}
|
||||
if ! id -u opengnsys &>/dev/null; then
|
||||
echoAndLog "${FUNCNAME}(): creating opengnsys user"
|
||||
useradd opengnsys 2>/dev/null
|
||||
if [ $? -ne 0 ]; then
|
||||
errorAndLog "${FUNCNAME}(): error creating opengnsys user"
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# Crea el directorio path_opengnsys_base con el usuario opengnsys
|
||||
echoAndLog "${FUNCNAME}(): creating directory $path_opengnsys_base with opengnsys user"
|
||||
sudo mkdir -p "$path_opengnsys_base"
|
||||
sudo chown opengnsys:opengnsys $path_opengnsys_base
|
||||
if [ $? -ne 0 ]; then
|
||||
errorAndLog "${FUNCNAME}(): error while creating directory $path_opengnsys_base"
|
||||
return 1
|
||||
fi
|
||||
|
||||
echoAndLog "Directory $path_opengnsys_base created with opengnsys user"
|
||||
}
|
||||
|
||||
function copyServerFiles() {
|
||||
if [ $# -ne 1 ]; then
|
||||
|
@ -220,9 +217,6 @@ function copyServerFiles() {
|
|||
#public
|
||||
src
|
||||
etc
|
||||
templates
|
||||
tests
|
||||
vendor
|
||||
.env
|
||||
composer.json
|
||||
composer.lock
|
||||
|
@ -234,9 +228,6 @@ function copyServerFiles() {
|
|||
#public
|
||||
src
|
||||
etc
|
||||
templates
|
||||
tests
|
||||
vendor
|
||||
.env
|
||||
composer.json
|
||||
composer.lock
|
||||
|
@ -271,53 +262,14 @@ function copyServerFiles() {
|
|||
popd || return
|
||||
}
|
||||
|
||||
function downloadComposer() {
|
||||
echoAndLog "Downloading composer.phar..."
|
||||
|
||||
# Crear el directorio de trabajo si no existe
|
||||
mkdir -p "$WORKDIR/ogdhcp/bin" || return
|
||||
|
||||
# Cambiar al directorio de trabajo
|
||||
pushd "$WORKDIR/ogdhcp/bin" || return
|
||||
|
||||
# Descargar composer.phar
|
||||
curl -sS https://getcomposer.org/installer | php
|
||||
|
||||
# Comprobar si la descarga fue exitosa
|
||||
if [ ! -f composer.phar ]; then
|
||||
errorAndLog "Failed to download composer.phar"
|
||||
popd
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Crear el directorio de destino si no existe
|
||||
mkdir -p "/opt/ogdhcp/bin" || return
|
||||
|
||||
# Mover composer.phar a /opt/ogdhcp/bin
|
||||
mv composer.phar "/opt/ogdhcp/bin/"
|
||||
|
||||
# Comprobar si el movimiento fue exitoso
|
||||
if [ ! -f "/opt/ogdhcp/bin/composer.phar" ]; then
|
||||
errorAndLog "Failed to move composer.phar to /opt/ogdhcp/bin"
|
||||
popd
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Volver al directorio original
|
||||
popd || return
|
||||
|
||||
echoAndLog "composer.phar downloaded and moved to /opt/ogdhcp/bin"
|
||||
return 0
|
||||
}
|
||||
|
||||
function runComposer() {
|
||||
echoAndLog "Running composer.phar to install dependencies..."
|
||||
|
||||
# Cambiar al directorio donde está composer.phar
|
||||
pushd /opt/ogdhcp/bin || return
|
||||
|
||||
local path_opengnsys_base="$1"
|
||||
pushd $path_opengnsys_base
|
||||
pwd
|
||||
# Ejecutar composer.phar
|
||||
sudo -u "$OPENGNSYS_CLIENT_USER" php composer.phar install
|
||||
sudo -u "$OPENGNSYS_CLIENT_USER" composer --no-interaction install
|
||||
|
||||
# Comprobar si la ejecución fue exitosa
|
||||
if [ $? -ne 0 ]; then
|
||||
|
@ -326,92 +278,270 @@ function runComposer() {
|
|||
return 1
|
||||
fi
|
||||
|
||||
# Volver al directorio original
|
||||
popd || return
|
||||
|
||||
echoAndLog "composer.phar ran successfully and dependencies were installed"
|
||||
return 0
|
||||
}
|
||||
|
||||
function install_swagger_ui {
|
||||
# Define la URL del archivo de Swagger UI que quieres descargar
|
||||
swagger_ui_url="https://github.com/swagger-api/swagger-ui/archive/refs/heads/master.zip"
|
||||
|
||||
# Define la ruta donde quieres descomprimir Swagger UI
|
||||
swagger_ui_path="/tmp/swagger-ui"
|
||||
get_first_network_interface_with_traffic() {
|
||||
while read -r line; do
|
||||
if [[ "$line" == *:* ]]; then
|
||||
interface=$(echo "$line" | cut -d ':' -f 1 | xargs)
|
||||
if [[ "$interface" != "lo" ]]; then
|
||||
received_bytes=$(echo "$line" | awk '{print $2}')
|
||||
transmitted_bytes=$(echo "$line" | awk '{print $10}')
|
||||
if (( received_bytes > 0 || transmitted_bytes > 0 )); then
|
||||
DEFAULTDEV="$interface"
|
||||
break
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
done < /proc/net/dev
|
||||
}
|
||||
comment_auth_kea() {
|
||||
KEA_CTRL_AGENT_CONF="/etc/kea/kea-ctrl-agent.conf"
|
||||
|
||||
# Verificar si el bloque de "authentication" ya está comentado
|
||||
if grep -q '^[^#]*"authentication": {' "$KEA_CTRL_AGENT_CONF"; then
|
||||
echo "Comentando el bloque de autenticación en $KEA_CTRL_AGENT_CONF..."
|
||||
|
||||
# Define la ruta de destino para los archivos de Swagger UI
|
||||
destination_path="/opt/ogdhcp/public"
|
||||
# Comentar solo el bloque de authentication desde la apertura hasta la línea con '},'
|
||||
sed -i '/"authentication": {/,/^[[:space:]]*},/ {
|
||||
s/^\([[:space:]]*\)\([^#]\)/\1#\2/
|
||||
}' "$KEA_CTRL_AGENT_CONF"
|
||||
|
||||
# Crea los directorios si no existen
|
||||
mkdir -p "$swagger_ui_path"
|
||||
mkdir -p "$destination_path"
|
||||
echo "Bloque de autenticación comentado correctamente."
|
||||
else
|
||||
echo "El bloque de autenticación ya está comentado."
|
||||
fi
|
||||
|
||||
# Descarga el archivo de Swagger UI
|
||||
wget "$swagger_ui_url" -O /tmp/swagger-ui.zip
|
||||
# Verificar si el bloque fue comentado correctamente
|
||||
if grep -q '^#\s*"authentication": {' "$KEA_CTRL_AGENT_CONF"; then
|
||||
echo "Confirmación: Bloque de autenticación comentado correctamente."
|
||||
|
||||
# Descomprime el archivo de Swagger UI en la ruta especificada
|
||||
unzip /tmp/swagger-ui.zip -d "$swagger_ui_path"
|
||||
# Reiniciar el servicio de Kea Control Agent para aplicar los cambios
|
||||
echo "Reiniciando el agente de Kea Control Agent..."
|
||||
sudo systemctl restart kea-ctrl-agent.service
|
||||
|
||||
# Copia los archivos de Swagger UI al directorio de destino
|
||||
cp -r "$swagger_ui_path"/swagger-ui-master/dist/* "$destination_path"
|
||||
|
||||
# Elimina el archivo descargado y el directorio temporal
|
||||
rm /tmp/swagger-ui.zip
|
||||
rm -r "$swagger_ui_path"
|
||||
/opt/ogdhcp/vendor/bin/openapi /opt/ogdhcp/src/DhcpBundle/Controller/ -o "$destination_path/swagger.json"
|
||||
echo "Swagger UI instalado en $destination_path."
|
||||
if systemctl is-active --quiet kea-ctrl-agent.service; then
|
||||
echo "El agente de Kea Control Agent se ha reiniciado correctamente."
|
||||
else
|
||||
echo "Error: No se pudo reiniciar el agente de Kea Control Agent."
|
||||
fi
|
||||
else
|
||||
echo "Error: No se pudo comentar correctamente el bloque de autenticación."
|
||||
fi
|
||||
}
|
||||
# Función para obtener la dirección IP de una interfaz
|
||||
get_ip_address() {
|
||||
local interface="$1"
|
||||
ip -4 addr show "$interface" | grep -oP "(?<=inet\s)\d+(\.\d+){3}"
|
||||
}
|
||||
|
||||
function installWebConsoleApacheConf() {
|
||||
if [ $# -ne 2 ]; then
|
||||
errorAndLog "${FUNCNAME}(): invalid number of parameters"
|
||||
# Función para obtener la versión de PHP instalada
|
||||
get_php_fpm_version() {
|
||||
php -v | grep -oP "PHP \K\d+\.\d+"
|
||||
}
|
||||
add_write_permission_apparmor() {
|
||||
APPARMOR_PROFILE="/etc/apparmor.d/usr.sbin.kea-dhcp4"
|
||||
|
||||
# Comprobar si las líneas existen
|
||||
if grep -q "/etc/kea/ r," "$APPARMOR_PROFILE" && grep -q "/etc/kea/** r," "$APPARMOR_PROFILE"; then
|
||||
echo "Modificando permisos en $APPARMOR_PROFILE..."
|
||||
|
||||
# Modificar las líneas /etc/kea/ r, y /etc/kea/** r, añadiendo w
|
||||
sed -i 's#/etc/kea/ r,#/etc/kea/ rw,#g' "$APPARMOR_PROFILE"
|
||||
sed -i 's#/etc/kea/\*\* r,#/etc/kea/** rw,#g' "$APPARMOR_PROFILE"
|
||||
|
||||
echo "Permisos de escritura añadidos correctamente a $APPARMOR_PROFILE."
|
||||
else
|
||||
echo "Las líneas no fueron encontradas o ya están modificadas."
|
||||
fi
|
||||
|
||||
# Recargar el perfil de AppArmor para aplicar los cambios
|
||||
echo "Recargando el perfil de AppArmor para kea-dhcp4..."
|
||||
sudo apparmor_parser -r "$APPARMOR_PROFILE"
|
||||
|
||||
if [ $? -eq 0 ]; then
|
||||
echo "El perfil de AppArmor se recargó correctamente."
|
||||
else
|
||||
echo "Error al recargar el perfil de AppArmor."
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
# Función para configurar Nginx
|
||||
setup_nginx() {
|
||||
local path_opengnsys_base="$1"
|
||||
local public_dir="$path_opengnsys_base/public"
|
||||
#ip_address_server=$(get_ip_address "$DEFAULTDEV")
|
||||
if [[ ! -f "$CONFIG_FILE" ]]; then
|
||||
echo "Error: El archivo de configuración no se encontró."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
local path_opengnsys_base="$1"
|
||||
local path_apache2_confd="$2"
|
||||
local OGHDPCDIR="${path_opengnsys_base}/public"
|
||||
local sockfile
|
||||
ip_address_server=$(jq -r '.ogDhcpIP' "$CONFIG_FILE")
|
||||
|
||||
if [ ! -d "$path_apache2_confd" ]; then
|
||||
errorAndLog "${FUNCNAME}(): path to apache2 conf.d can not found, verify your server installation"
|
||||
return 1
|
||||
if [[ -z "$ip_address_server" ]]; then
|
||||
echo "Error: No se pudo obtener la dirección IP del servidor desde el archivo de configuración."
|
||||
exit 1
|
||||
fi
|
||||
php_version=$(get_php_fpm_version)
|
||||
|
||||
if [[ -z "$php_version" ]]; then
|
||||
echo "Error: No se pudo obtener la versión de PHP."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
mkdir -p "$path_apache2_confd/{sites-available,sites-enabled}"
|
||||
|
||||
echoAndLog "${FUNCNAME}(): creating apache2 config file.."
|
||||
|
||||
# Activar PHP-FPM.
|
||||
echoAndLog "${FUNCNAME}(): configuring PHP-FPM"
|
||||
service="$PHPFPMSERV"
|
||||
$ENABLESERVICE; $STARTSERVICE
|
||||
sockfile=$(find /run/php -name "php*.sock" -type s -print 2>/dev/null | tail -1)
|
||||
|
||||
# Activar módulos de Apache.
|
||||
$APACHEENABLEMODS
|
||||
|
||||
# Generar configuración de consola web a partir del archivo de plantilla.
|
||||
if [ -n "$sockfile" ]; then
|
||||
sed -e "s,OGHDPCDIR,$OGHDPCDIR,g" \
|
||||
-e "s,proxy:fcgi:.*,proxy:unix:${sockfile%% *}|fcgi://localhost\",g" \
|
||||
"$WORKDIR/ogdhcp/etc/apache.conf.tmpl" > "$path_apache2_confd/$APACHESITESDIR/${APACHEOGSITE}.conf"
|
||||
else
|
||||
sed -e "s,OGHDPCDIR,$OGHDPCDIR,g" \
|
||||
"$WORKDIR/ogdhcp/server/etc/apache.conf.tmpl" > "$path_apache2_confd/$APACHESITESDIR/${APACHEOGSITE}.conf"
|
||||
# Leer y modificar la plantilla de configuración de nginx
|
||||
if [[ ! -f "$NGINX_TEMPLATE" ]]; then
|
||||
echo "Error: La plantilla de Nginx no se encontró."
|
||||
exit 1
|
||||
fi
|
||||
$APACHEENABLEOG
|
||||
if [ $? -ne 0 ]; then
|
||||
errorAndLog "${FUNCNAME}(): config file can't be linked to apache conf, verify your server installation"
|
||||
return 1
|
||||
fi
|
||||
echoAndLog "${FUNCNAME}(): config file created and linked, restarting apache daemon"
|
||||
service="$APACHESERV"
|
||||
$ENABLESERVICE; $STARTSERVICE
|
||||
return 0
|
||||
|
||||
nginx_content=$(<"$NGINX_TEMPLATE")
|
||||
nginx_content="${nginx_content//__SERVERIP__/$ip_address_server}"
|
||||
nginx_content="${nginx_content//__PHPVERSION__/$php_version}"
|
||||
nginx_content="${nginx_content//__PUBLICDIR__/$public_dir}"
|
||||
|
||||
# Crear el archivo de configuración de Nginx
|
||||
echo "$nginx_content" > "$NGINX_OUTPUT"
|
||||
echo "Archivo de configuración de Nginx creado en $NGINX_OUTPUT."
|
||||
|
||||
# Crear el enlace simbólico
|
||||
ln -sf "$NGINX_OUTPUT" /etc/nginx/sites-enabled/ogdhcp.conf
|
||||
echo "Enlace simbólico creado en /etc/nginx/sites-enabled/ogdhcp.conf."
|
||||
|
||||
# Modificar nginx.conf para ejecutar como opengnsys
|
||||
sed -i 's/user www-data;/user opengnsys;/g' "$NGINX_CONF_PATH"
|
||||
echo "Nginx configurado para ejecutarse como opengnsys."
|
||||
|
||||
# Reiniciar Nginx
|
||||
systemctl restart nginx.service
|
||||
echo "Servicio Nginx reiniciado."
|
||||
}
|
||||
|
||||
# Función para modificar el archivo de configuración PHP-FPM
|
||||
modify_php_fpm_config() {
|
||||
php_version=$(get_php_fpm_version)
|
||||
|
||||
if [[ -z "$php_version" ]]; then
|
||||
echo "Error: No se pudo obtener la versión de PHP."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
php_fpm_conf_path="/etc/php/$php_version/fpm/pool.d/www.conf"
|
||||
new_fpm_conf_path="/etc/php/$php_version/fpm/pool.d/ogdhcp.conf"
|
||||
socket_path="/run/php/php$php_version-fpm-ogdhcp.sock"
|
||||
|
||||
# Verificar si el archivo new_fpm_conf_path ya existe
|
||||
if [[ -f "$new_fpm_conf_path" ]]; then
|
||||
echo "El archivo $new_fpm_conf_path ya existe. No se realizarán modificaciones."
|
||||
return
|
||||
fi
|
||||
|
||||
# Copiar el archivo www.conf a opengnsys.conf
|
||||
cp "$php_fpm_conf_path" "$new_fpm_conf_path"
|
||||
|
||||
# Modificar el archivo ogdhcp.conf
|
||||
sed -i 's/\[www\]/[ogdhcp]/g' "$new_fpm_conf_path"
|
||||
sed -i 's/user = www-data/user = opengnsys/g' "$new_fpm_conf_path"
|
||||
sed -i 's/group = www-data/group = opengnsys/g' "$new_fpm_conf_path"
|
||||
sed -i "s|listen =.*|listen = $socket_path|g" "$new_fpm_conf_path"
|
||||
sed -i 's/listen.owner = www-data/listen.owner = opengnsys/g' "$new_fpm_conf_path"
|
||||
sed -i 's/listen.group = www-data/listen.group = opengnsys/g' "$new_fpm_conf_path"
|
||||
|
||||
# Reiniciar PHP-FPM
|
||||
systemctl restart php"$php_version"-fpm.service
|
||||
echo "PHP-FPM reiniciado."
|
||||
|
||||
# Verificar la creación del socket
|
||||
if [[ -S "$socket_path" ]]; then
|
||||
echo "Socket PHP-FPM $socket_path creado correctamente."
|
||||
else
|
||||
echo "Error: El socket PHP-FPM $socket_path no se ha creado."
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
configure_kea() {
|
||||
|
||||
# Verificar si jq está instalado
|
||||
if ! command -v jq &> /dev/null; then
|
||||
echo "jq no está instalado. Por favor, instala jq para continuar."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Verificar si el archivo de configuración existe
|
||||
if [ ! -f "$CONFIG_FILE" ]; then
|
||||
echo "El archivo $CONFIG_FILE no se encuentra. Asegúrate de que esté disponible antes de la instalación."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Leer los parámetros del archivo JSON usando jq
|
||||
INTERFACES=$(jq -r '.interfaces[]' "$CONFIG_FILE")
|
||||
OGBOOT_IP=$(jq -r '.ogbootIP' "$CONFIG_FILE")
|
||||
|
||||
# Crear la configuración mínima de Kea DHCP
|
||||
KEA_CONFIG="/etc/kea/kea-dhcp4.conf"
|
||||
|
||||
# Hacer una copia de seguridad del archivo kea-dhcp4.conf si ya existe
|
||||
if [ -f "$KEA_CONFIG" ]; then
|
||||
cp "$KEA_CONFIG" "$KEA_CONFIG.backup"
|
||||
echo "Se ha creado una copia de seguridad del archivo de configuración actual en $KEA_CONFIG.backup"
|
||||
fi
|
||||
|
||||
# Generar la configuración mínima para Kea DHCP
|
||||
cat > "$KEA_CONFIG" << EOL
|
||||
{
|
||||
"Dhcp4": {
|
||||
"interfaces-config": {
|
||||
"interfaces": [ $(
|
||||
for interface in $INTERFACES; do
|
||||
echo "\"$interface\""
|
||||
done | paste -sd "," -
|
||||
) ]
|
||||
},
|
||||
"client-classes": [
|
||||
{
|
||||
"name": "UEFI-64",
|
||||
"test": "not substring(option[60].hex,0,20) == 'PXEClient:Arch:00000'",
|
||||
"boot-file-name": "ipxe.efi",
|
||||
"next-server": "$OGBOOT_IP"
|
||||
},
|
||||
{
|
||||
"name": "Legacy",
|
||||
"test": "substring(option[60].hex,0,20) == 'PXEClient:Arch:00000'",
|
||||
"boot-file-name": "undionly.kpxe",
|
||||
"next-server": "$OGBOOT_IP"
|
||||
}
|
||||
],
|
||||
"control-socket": {
|
||||
"socket-name": "/run/kea/kea4-ctrl-socket",
|
||||
"socket-type": "unix"
|
||||
}
|
||||
}
|
||||
}
|
||||
EOL
|
||||
|
||||
echo "Se ha generado la configuración mínima de Kea DHCP en $KEA_CONFIG"
|
||||
# Reiniciar el servicio de Kea DHCP y verificar si se reinicia correctamente
|
||||
echo "Reiniciando el servicio Kea DHCP..."
|
||||
sudo systemctl restart kea-dhcp4-server.service
|
||||
|
||||
# Comprobar el estado del servicio Kea DHCP
|
||||
if systemctl is-active --quiet kea-dhcp4-server.service; then
|
||||
echo "Kea DHCP reiniciado correctamente."
|
||||
else
|
||||
echo "Error al reiniciar Kea DHCP."
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
|
||||
#####################################################################
|
||||
####### Algunas funciones útiles de propósito general:
|
||||
#####################################################################
|
||||
|
@ -459,7 +589,6 @@ mkdir -p $WORKDIR
|
|||
pushd $WORKDIR
|
||||
|
||||
checkDependencies
|
||||
install_kea
|
||||
# Si es necesario, descarga el repositorio de código en directorio temporal
|
||||
if [ $REMOTE -eq 1 ]; then
|
||||
downloadCode $GIT_REPO
|
||||
|
@ -492,18 +621,39 @@ if [ $? -ne 0 ]; then
|
|||
exit 1
|
||||
fi
|
||||
|
||||
downloadComposer
|
||||
|
||||
runComposer
|
||||
install_swagger_ui
|
||||
# Creando configuración de Apache.
|
||||
installWebConsoleApacheConf $INSTALL_TARGET $APACHECFGDIR
|
||||
comment_auth_kea
|
||||
if [ $? -ne 0 ]; then
|
||||
errorAndLog "Error configuring Apache for OpenGnsys Admin"
|
||||
errorAndLog "Error while commenting auth block!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
sudo apt-get update
|
||||
|
||||
runComposer ${INSTALL_TARGET}
|
||||
setup_nginx $INSTALL_TARGET
|
||||
if [ $? -ne 0 ]; then
|
||||
errorAndLog "Error configuring Nginx for OpenGnsys Admin"
|
||||
exit 1
|
||||
fi
|
||||
modify_php_fpm_config
|
||||
if [ $? -ne 0 ]; then
|
||||
errorAndLog "Error configuring PHP-FPM for OpenGnsys Admin"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
add_write_permission_apparmor
|
||||
if [ $? -ne 0 ]; then
|
||||
errorAndLog "Error adding write permission to AppArmor profile"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
configure_kea
|
||||
if [ $? -ne 0 ]; then
|
||||
errorAndLog "Error configuring Kea DHCP initial configuration"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
# install_kea
|
||||
# install_php
|
||||
# install_composer
|
||||
|
@ -512,4 +662,4 @@ sudo apt-get update
|
|||
# Ahora puedes clonar e instalar el componente ogDhcp
|
||||
# git clone <URL del repositorio de ogDhcp>
|
||||
# cd <directorio de ogDhcp>
|
||||
# composer install
|
||||
# composer install
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
#!/bin/bash
|
||||
set -x
|
||||
URL_REPO="https://ognproject.evlt.uma.es/gitea/opengnsys/ogdhcp.git"
|
||||
BRANCH=${OGDHCP_BRANCH:-"main"}
|
||||
DOWNLOADDIR=${OGDHCP_DOWNLOADDIR:-"/tmp/ogdhcp"}
|
||||
apt install -y git vim
|
||||
git config --global http.sslVerify false
|
||||
git clone -b $BRANCH $URL_REPO $DOWNLOADDIR
|
||||
cd $DOWNLOADDIR/installer
|
||||
|
||||
ogBoot_ServerIP=${1:-"172.17.8.82"}
|
||||
ogDhcp_ServerIP=${2:-"172.17.8.37"}
|
||||
ogDhcp_Dir=${3:-"/opt/opengnsys/ogdhcp"}
|
||||
|
||||
|
||||
cat > config_ogdhcp.json <<EOF
|
||||
{
|
||||
"interfaces": ["eth0", "eth1"],
|
||||
"ogbootIP": "$ogBoot_ServerIP",
|
||||
"ogDhcpIP": "$ogDhcp_ServerIP",
|
||||
"ogDhcp_Dir": "$ogDhcp_Dir"
|
||||
}
|
||||
EOF
|
||||
chmod 755 ogdhcp_installer.sh
|
||||
./ogdhcp_installer.sh
|
File diff suppressed because it is too large
Load Diff
|
@ -28,7 +28,8 @@ class CurlKeaService
|
|||
} else {
|
||||
return "Error: Comando no válido";
|
||||
}
|
||||
if (($command == 'config-set' || $command == 'config-write') && $create_backup) {
|
||||
//f (($command == 'config-set' || $command == 'config-write') && $create_backup) {
|
||||
if ($command == 'config-set' && $create_backup) {
|
||||
$this->backupConfig();
|
||||
}
|
||||
$jsonData = json_encode($requestData);
|
||||
|
|
|
@ -0,0 +1,118 @@
|
|||
pipeline {
|
||||
agent {
|
||||
node {
|
||||
label 'jenkins-slave'
|
||||
}
|
||||
}
|
||||
options {
|
||||
// Deshabilita ejecuciones concurrentes
|
||||
disableConcurrentBuilds()
|
||||
}
|
||||
environment {
|
||||
ESXI_PASS = credentials('VI_PASSWORD')
|
||||
QINDEL_PASS = credentials('jenkins-user-slave-password')
|
||||
PATH = "/home/qindel/bin/ovftool:${env.PATH}"
|
||||
}
|
||||
stages {
|
||||
stage('Prepare environment') {
|
||||
steps {
|
||||
dir ('tests/API-dhcp') {
|
||||
echo "Install vagrant plugin"
|
||||
sh '''
|
||||
if ! vagrant plugin list | grep -q vagrant-vmware-esxi; then
|
||||
echo "Vagrant plugin vagrant-vmware-esxi not found. Installing..."
|
||||
vagrant plugin install vagrant-vmware-esxi
|
||||
else
|
||||
echo "Vagrant plugin vagrant-vmware-esxi is already installed."
|
||||
fi
|
||||
'''
|
||||
echo "Deploy API server for DHCP with Vagrant"
|
||||
sh 'vagrant up --provider=vmware_esxi --provision'
|
||||
echo 'Create Python venv to work with robotframework'
|
||||
sh '''
|
||||
python3 -m venv robotframework
|
||||
. robotframework/bin/activate
|
||||
pip install -r requirements.txt
|
||||
'''
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
stage('Check Installation') {
|
||||
steps {
|
||||
dir ('tests/API-dhcp') {
|
||||
echo "Get IP of API server for DHCP with Vagrant"
|
||||
sh '''
|
||||
set -e
|
||||
new_ip=$(vagrant ssh -c "hostname -I" | tr -d '\r\n' | sed 's/^[^0-9]*//' | sed 's/[[:space:]]*$//')
|
||||
echo $new_ip > ip.txt
|
||||
echo "$QINDEL_PASS" | sudo -S bash -c "echo '$new_ip api-test' >> /etc/hosts"
|
||||
echo "IP: $new_ip"
|
||||
curl -X 'GET' "http://$new_ip/ogdhcp/v1/subnets" -H 'accept: /'
|
||||
'''
|
||||
script {
|
||||
def new_ip = readFile('ip.txt').trim()
|
||||
env.NEW_IP = new_ip
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
stage('Run API tests') {
|
||||
steps {
|
||||
dir ('tests/API-dhcp') {
|
||||
|
||||
echo 'Running API tests'
|
||||
|
||||
sh '''
|
||||
. robotframework/bin/activate
|
||||
robot --variable BASE_URL:http://${NEW_IP}/ogdhcp/v1 -d results/ robot/
|
||||
'''
|
||||
}
|
||||
// Aquí incluirías los comandos para ejecutar tus pruebas
|
||||
}
|
||||
}
|
||||
}
|
||||
post {
|
||||
success {
|
||||
// Si el trabajo ha sido exitoso, destruir la máquina de Vagrant
|
||||
echo "El trabajo ha finalizado con éxito. Destruyendo máquina Vagrant..."
|
||||
dir ('tests/API-dhcp') {
|
||||
sh 'vagrant destroy -f'
|
||||
}
|
||||
}
|
||||
always {
|
||||
// Recoger los resultados de los tests
|
||||
dir ('tests/API-dhcp') {
|
||||
robot outputPath: 'results',
|
||||
outputFileName: 'output.xml',
|
||||
logFileName: 'log.html',
|
||||
reportFileName: 'report.html',
|
||||
passThreshold: 100.0,
|
||||
unstableThreshold: 75.0
|
||||
}
|
||||
// Siempre se ejecutará, independientemente del resultado
|
||||
script {
|
||||
// Elimina la entrada del /etc/hosts
|
||||
sh "echo '$QINDEL_PASS' | sudo -S sed -i '/api-test/d' /etc/hosts"
|
||||
def recipientEmail = env.BUILD_USER_EMAIL ?: getCommitterEmail()
|
||||
|
||||
mail to: recipientEmail,
|
||||
subject: "Jenkins Job Completed: ${env.JOB_NAME} #${env.BUILD_NUMBER}",
|
||||
body: """
|
||||
El job '${env.JOB_NAME}' con número de build ${env.BUILD_NUMBER} ha finalizado.
|
||||
|
||||
Estado: ${currentBuild.currentResult}
|
||||
|
||||
Revisa los detalles del build en: ${env.BUILD_URL}
|
||||
"""
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def getCommitterEmail() {
|
||||
return sh(
|
||||
script: 'git log -1 --pretty=format:"%ae"',
|
||||
returnStdout: true
|
||||
).trim()
|
||||
}
|
|
@ -0,0 +1,163 @@
|
|||
#
|
||||
# Fully documented Vagrantfile available
|
||||
# in the wiki: https://github.com/josenk/vagrant-vmware-esxi/wiki
|
||||
|
||||
$script = <<SCRIPT
|
||||
SERVER_NAME=localhost
|
||||
echo "Provisioning with shell script..."
|
||||
cd /vagrant/installer
|
||||
chmod +x ogdhcp_installer.sh && ./ogdhcp_installer.sh
|
||||
SCRIPT
|
||||
|
||||
Vagrant.configure('2') do |config|
|
||||
config.vm.box = 'dummy'
|
||||
VM_TEMPLATE = 'template-ubuntu24'
|
||||
# Use rsync and NFS synced folders. (or use the option to disable them)
|
||||
# https://www.vagrantup.com/docs/synced-folders/
|
||||
#config.vm.synced_folder('.', '/vagrant', type: 'rsync')
|
||||
config.vm.synced_folder('../../', '/vagrant', type: 'rsync')
|
||||
|
||||
# Vagrant can configure additional network interfaces using a static IP or
|
||||
# DHCP. Use public_network or private_network to manually set a static IP and
|
||||
# optionally netmask. ESXi doesn't use the concept of public or private
|
||||
# networks so both are valid here. The primary network interface is considered the
|
||||
# "vagrant management" interface and cannot be changed and this plugin
|
||||
# supports 10 NICS, so you can specify 9 entries here!
|
||||
#
|
||||
# https://www.vagrantup.com/docs/networking/public_network.html
|
||||
# https://www.vagrantup.com/docs/networking/private_network.html
|
||||
#
|
||||
# *** Invalid settings could cause 'vagrant up' to fail ***
|
||||
#config.vm.network 'private_network', ip: '192.168.10.170', netmask: '255.255.255.0'
|
||||
#config.vm.network 'private_network', ip: '192.168.11.170'
|
||||
#config.vm.network 'public_network', ip: '192.168.12.170'
|
||||
|
||||
#
|
||||
# Provider (esxi) settings
|
||||
#
|
||||
config.vm.provision 'shell', inline: $script
|
||||
config.vm.provider :vmware_esxi do |esxi|
|
||||
|
||||
# REQUIRED! ESXi hostname/IP
|
||||
esxi.esxi_hostname = 'esxi-jenkins.evlt.uma.es'
|
||||
|
||||
# ESXi username
|
||||
esxi.esxi_username = 'root'
|
||||
|
||||
# IMPORTANT! Set ESXi password.
|
||||
# 1) 'prompt:'
|
||||
# 2) 'file:' or 'file:my_secret_file'
|
||||
# 3) 'env:' or 'env:my_secret_env_var'
|
||||
# 4) 'key:' or key:~/.ssh/some_ssh_private_key'
|
||||
# 5) or esxi.esxi_password = 'my_esxi_password'
|
||||
#
|
||||
esxi.esxi_password = 'env:ESXI_PASS'
|
||||
|
||||
# SSH port.
|
||||
#esxi.esxi_hostport = 22
|
||||
|
||||
# HIGHLY RECOMMENDED! ESXi Virtual Network
|
||||
# You should specify an ESXi Virtual Network! If it's not specified, the
|
||||
# default is to use the first found. You can specify up to 10 virtual
|
||||
# networks using an array format.
|
||||
esxi.esxi_virtual_network = ['vLan_742']
|
||||
|
||||
# OPTIONAL. Specify a Disk Store
|
||||
#esxi.esxi_disk_store = 'DS_001'
|
||||
|
||||
# OPTIONAL. Resource Pool
|
||||
# Vagrant will NOT create a Resource pool it for you.
|
||||
esxi.esxi_resource_pool = '/'
|
||||
|
||||
# Optional. Specify a VM to clone instead of uploading a box.
|
||||
# Vagrant can use any stopped VM as the source 'box'. The VM must be
|
||||
# registered, stopped and must have the vagrant insecure ssh key installed.
|
||||
# If the VM is stored in a resource pool, it must be specified.
|
||||
# See wiki: https://github.com/josenk/vagrant-vmware-esxi/wiki/How-to-clone_from_vm
|
||||
esxi.clone_from_vm = VM_TEMPLATE
|
||||
|
||||
# OPTIONAL. Guest VM name to use.
|
||||
# The Default will be automatically generated.
|
||||
#esxi.guest_name = 'Custom-Guest-VM_Name'
|
||||
|
||||
# OPTIONAL. When automatically naming VMs, use this prefix.
|
||||
#esxi.guest_name_prefix = 'V-'
|
||||
|
||||
# OPTIONAL. Set the guest username login. The default is 'vagrant'.
|
||||
#esxi.guest_username = 'vagrant'
|
||||
|
||||
# OPTIONAL. Memory size override
|
||||
#esxi.guest_memsize = '2048'
|
||||
|
||||
# OPTIONAL. Virtual CPUs override
|
||||
#esxi.guest_numvcpus = '2'
|
||||
|
||||
# OPTIONAL & RISKY. Specify up to 10 MAC addresses
|
||||
# The default is ovftool to automatically generate a MAC address.
|
||||
# You can specify an array of MAC addresses using upper or lower case,
|
||||
# separated by colons ':'.
|
||||
#esxi.guest_mac_address = ['00:50:56:aa:bb:cc', '00:50:56:01:01:01','00:50:56:02:02:02','00:50:56:BE:AF:01' ]
|
||||
|
||||
# OPTIONAL & RISKY. Specify a guest_nic_type
|
||||
# The validated list of guest_nic_types are 'e1000', 'e1000e', 'vmxnet',
|
||||
# 'vmxnet2', 'vmxnet3', 'Vlance', and 'Flexible'.
|
||||
#esxi.guest_nic_type = 'e1000'
|
||||
|
||||
# OPTIONAL. Specify a disk type.
|
||||
# If unspecified, it will be set to 'thin'. Otherwise, you can set to
|
||||
# 'thin', 'thick', or 'eagerzeroedthick'
|
||||
#esxi.guest_disk_type = 'thick'
|
||||
|
||||
# OPTIONAL. Boot disk size.
|
||||
# If unspecified, the boot disk size will be the same as the original
|
||||
# box. You can specify a larger boot disk size in GB. The extra disk space
|
||||
# will NOT automatically be available to your OS. You will need to
|
||||
# create or modify partitions, LVM and/or filesystems.
|
||||
#esxi.guest_boot_disk_size = 50
|
||||
|
||||
# OPTIONAL. Create additional storage for guests.
|
||||
# You can specify an array of up to 13 virtual disk sizes (in GB) that you
|
||||
# would like the provider to create once the guest has been created. You
|
||||
# can optionally specify the size and datastore using a hash.
|
||||
#esxi.guest_storage = [ 10, 20, { size: 30, datastore: 'datastore1' } ]
|
||||
|
||||
# OPTIONAL. specify snapshot options.
|
||||
#esxi.guest_snapshot_includememory = 'true'
|
||||
#esxi.guest_snapshot_quiesced = 'true'
|
||||
|
||||
# RISKY. guest_guestos
|
||||
# https://github.com/josenk/vagrant-vmware-esxi/wiki/VMware-ESXi-6.5-guestOS-types
|
||||
#esxi.guest_guestos = 'centos-64'
|
||||
|
||||
# OPTIONAL. guest_virtualhw_version
|
||||
# ESXi 6.7 supports these versions. 4,7,8,9,10,11,12,13 & 14.
|
||||
#esxi.guest_virtualhw_version = '9'
|
||||
|
||||
# OPTIONAL. Guest Autostart
|
||||
# Guest VM will autostart when esxi host is booted. 'true' or 'false'(default)
|
||||
#esxi.guest_autostart = 'false'
|
||||
|
||||
# RISKY. guest_custom_vmx_settings
|
||||
#esxi.guest_custom_vmx_settings = [['vhv.enable','TRUE'], ['floppy0.present','TRUE']]
|
||||
|
||||
# OPTIONAL. local_lax
|
||||
#esxi.local_lax = 'true'
|
||||
|
||||
# OPTIONAL. Guest IP Caching
|
||||
#esxi.local_use_ip_cache = 'True'
|
||||
|
||||
# DANGEROUS! Allow Overwrite
|
||||
# If unspecified, the default is to produce an error if overwriting
|
||||
# VMs and packages.
|
||||
#esxi.local_allow_overwrite = 'True'
|
||||
|
||||
# Advanced Users.
|
||||
# If set to 'True', all WARNINGS will produce a FAILURE and Vagrant will stop.
|
||||
#esxi.local_failonwarning = 'True'
|
||||
|
||||
# Plugin debug output.
|
||||
# Please send any bug reports with this debug output...
|
||||
#esxi.debug = 'true'
|
||||
|
||||
end
|
||||
end
|
|
@ -0,0 +1,374 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
from flask import Flask, jsonify, request
|
||||
import ipaddress
|
||||
import json
|
||||
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
|
||||
def convert_to_cidr(address, mask):
|
||||
"""
|
||||
Convert an IP address and subnet mask to CIDR notation.
|
||||
|
||||
Args:
|
||||
address (str): The IP address in dotted decimal format (e.g., '192.168.1.1').
|
||||
mask (str): The subnet mask in dotted decimal format (e.g., '255.255.255.0').
|
||||
|
||||
Returns:
|
||||
str: The CIDR notation of the network (e.g., '192.168.1.1/24').
|
||||
None: If there is an error in conversion, returns None and prints an error message.
|
||||
|
||||
Raises:
|
||||
ValueError: If the provided address or mask is invalid.
|
||||
"""
|
||||
# Convertir dirección y máscara a formato CIDR
|
||||
try:
|
||||
# Convertir la máscara de red de formato largo a formato corto
|
||||
# Cada octeto se convierte a su representación binaria y se cuenta el número de bits '1'
|
||||
cidr_mask = ipaddress.IPv4Network(f"0.0.0.0/{mask}").prefixlen
|
||||
red_objeto = f"{address}/{cidr_mask}"
|
||||
return red_objeto
|
||||
except ValueError as e:
|
||||
print(f"Error al convertir a CIDR: {e}")
|
||||
return None
|
||||
|
||||
|
||||
|
||||
subnets_collection = [{"id": 1,"subnet": "192.168.1.0/24", "next-server": "192.168.1.1", "boot-file-name": "pxelinux.0", "reservations": [] }]
|
||||
|
||||
|
||||
|
||||
# Endpoint GET /ogdhcp/v1/status
|
||||
"""
|
||||
Endpoint to get the status of the DHCP service.
|
||||
|
||||
This endpoint returns a JSON response with the current status of the DHCP service,
|
||||
including disk usage, subnets configuration, and the status of various services.
|
||||
|
||||
Returns:
|
||||
Response: A JSON response with the following structure:
|
||||
"total": str, # Total disk space
|
||||
"used": str, # Used disk space
|
||||
"available": str, # Available disk space
|
||||
"percentage": str # Percentage of disk space used
|
||||
"id": int, # Subnet ID
|
||||
"subnet": str, # Subnet address
|
||||
"pools": [
|
||||
"pool": str # IP address pool range
|
||||
"reservations": [
|
||||
"ip-address": str, # Reserved IP address
|
||||
"hw-address": str # Hardware address associated with the reservation
|
||||
]
|
||||
...
|
||||
"kea-ctrl-agent": str, # Status of kea-ctrl-agent service
|
||||
"kea-dhcp4": str, # Status of kea-dhcp4 service
|
||||
"nginx": str # Status of nginx service
|
||||
HTTP Status Code:
|
||||
200: If the request was successful.
|
||||
"""
|
||||
@app.route('/ogdhcp/v1/status', methods=['GET'])
|
||||
def get_status():
|
||||
# Simular respuesta de éxito
|
||||
return jsonify({
|
||||
"success": "Mensaje éxito",
|
||||
"message": {
|
||||
"disk_usage": {
|
||||
"total": "20G",
|
||||
"used": "15G",
|
||||
"available": "5G",
|
||||
"percentage": "75%"
|
||||
},
|
||||
"subnets": [
|
||||
{
|
||||
"id": 1,
|
||||
"subnet": "192.168.1.0/24",
|
||||
"pools": [{"pool": "192.168.1.10-192.168.1.100"}],
|
||||
"reservations": [{"ip-address": "192.168.1.20", "hw-address": "00:0c:29:6b:5e:71"}]
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"subnet": "10.0.0.0/24",
|
||||
"pools": [{"pool": "10.0.0.10-10.0.0.100"}],
|
||||
"reservations": []
|
||||
}
|
||||
],
|
||||
"services_status": {
|
||||
"kea-ctrl-agent": "active",
|
||||
"kea-dhcp4": "active",
|
||||
"nginx": "active"
|
||||
}
|
||||
}
|
||||
}), 200
|
||||
|
||||
# Endpoint GET /ogdhcp/v1/subnets
|
||||
|
||||
@app.route('/ogdhcp/v1/subnets', methods=['GET'])
|
||||
def get_subnets():
|
||||
# Simular respuesta de éxito
|
||||
return jsonify({
|
||||
"success": "Subredes obtenidas correctamente",
|
||||
"message": subnets_collection
|
||||
}), 200
|
||||
|
||||
# Endpoint POST /ogdhcp/v1/subnets
|
||||
"""
|
||||
Create a new subnet.
|
||||
Endpoint: /ogdhcp/v1/subnets
|
||||
Method: POST
|
||||
Request Body (JSON):
|
||||
{
|
||||
"id": <str>, # Unique identifier for the subnet
|
||||
"address": <str>, # IP address of the subnet
|
||||
"mask": <str>, # Subnet mask
|
||||
"nextServer": <str>, # (Optional) Next server IP address
|
||||
"bootFileName": <str> # (Optional) Boot file name
|
||||
}
|
||||
Responses:
|
||||
200 OK:
|
||||
{
|
||||
"message": <new_subnet>
|
||||
}
|
||||
400 Bad Request:
|
||||
- "Invalid JSON"
|
||||
- "Missing 'id', 'address' or 'mask' key"
|
||||
- {
|
||||
"error": "Error: La subred con el id '<id>' ya existe."
|
||||
}
|
||||
- {
|
||||
"error": "Error: La subred con la dirección '<subnet>' ya existe."
|
||||
}
|
||||
- "Invalid data format"
|
||||
Description:
|
||||
This endpoint allows the creation of a new subnet. It expects a JSON payload with the subnet details.
|
||||
The function checks if the provided JSON is valid and contains the required keys ('id', 'address', 'mask').
|
||||
It also ensures that the subnet ID and subnet address do not already exist in the collection.
|
||||
If the validation passes, the new subnet is added to the collection and a success response is returned.
|
||||
"""
|
||||
@app.route('/ogdhcp/v1/subnets', methods=['POST'])
|
||||
def create_subnet():
|
||||
try:
|
||||
new_subnet = json.loads(request.data)
|
||||
new_subnet["next-server"] = new_subnet.get("nextServer")
|
||||
new_subnet["boot-file-name"] = new_subnet.get("bootFileName")
|
||||
except json.JSONDecodeError:
|
||||
return "Invalid JSON", 400
|
||||
|
||||
|
||||
|
||||
if isinstance(new_subnet, dict):
|
||||
if "id" in new_subnet and "address" in new_subnet and "mask" in new_subnet:
|
||||
new_subnet_cidr = convert_to_cidr(new_subnet["address"], new_subnet["mask"])
|
||||
# Comprobar si el id ya existe en la colección
|
||||
for subnet in subnets_collection:
|
||||
if subnet.get("id") == new_subnet["id"]:
|
||||
return jsonify({
|
||||
"error": f"Error: La subred con el id '{new_subnet['id']}' ya existe."
|
||||
}), 400
|
||||
if subnet.get("subnet") == new_subnet_cidr:
|
||||
return jsonify({
|
||||
"error": f"Error: La subred con la dirección '{new_subnet_cidr}' ya existe."
|
||||
}), 400
|
||||
|
||||
# Si el id no existe, continuar con la creación de la subred
|
||||
new_subnet["subnet"] = convert_to_cidr(new_subnet["address"], new_subnet["mask"])
|
||||
subnets_collection.append(new_subnet)
|
||||
return jsonify({
|
||||
"success": "Subred agregada correctamente",
|
||||
"message": new_subnet
|
||||
}), 200
|
||||
|
||||
else:
|
||||
return "Missing 'id', 'address' or 'mask' key", 400
|
||||
else:
|
||||
return "Invalid data format", 400
|
||||
|
||||
|
||||
# Endpoint DELETE /ogdhcp/v1/subnets/<subnetId>
|
||||
"""
|
||||
Deletes a subnet from the subnets_collection based on the provided subnetId.
|
||||
|
||||
Args:
|
||||
subnetId (int): The ID of the subnet to be deleted.
|
||||
|
||||
Returns:
|
||||
Response: A JSON response indicating the success or failure of the deletion.
|
||||
- If the subnet is successfully deleted, returns a JSON response with a success message and HTTP status 200.
|
||||
- If the subnet with the given ID does not exist, returns a JSON response with an error message and HTTP status 404.
|
||||
"""
|
||||
@app.route('/ogdhcp/v1/subnets/<int:subnetId>', methods=['DELETE'])
|
||||
def delete_subnet(subnetId):
|
||||
subnet_to_delete = None
|
||||
for subnet in subnets_collection:
|
||||
if int(subnet["id"]) == subnetId:
|
||||
subnet_to_delete = subnet
|
||||
break
|
||||
if subnet_to_delete:
|
||||
print (f"Subnet Collection {subnets_collection}")
|
||||
print (f"Subnet to delete {subnet_to_delete}")
|
||||
subnets_collection.remove(subnet_to_delete)
|
||||
print (f"Subnet Collection {subnets_collection}")
|
||||
return jsonify({
|
||||
"success": "Subred eliminada correctamente"
|
||||
}), 200
|
||||
else:
|
||||
return jsonify({
|
||||
"error": f"Error: La subred con el id '{subnetId}' no existe"
|
||||
}), 404
|
||||
|
||||
# Endpoint PUT /ogdhcp/v1/subnets/<subnetId>
|
||||
"""
|
||||
Updates a subnet with the given subnetId based on the provided JSON data in the request.
|
||||
Args:
|
||||
subnetId (str): The ID of the subnet to be updated.
|
||||
Returns:
|
||||
Response: A JSON response indicating the success or failure of the update operation.
|
||||
- On success: Returns a JSON response with a success message and the updated subnet data, with a status code of 200.
|
||||
- On failure: Returns a JSON response with an error message and a status code of 400.
|
||||
Raises:
|
||||
json.JSONDecodeError: If the request data is not valid JSON.
|
||||
The function performs the following steps:
|
||||
1. Parses the JSON data from the request.
|
||||
2. Validates the presence of required fields ('address' and 'mask') in the JSON data.
|
||||
3. Converts the 'address' and 'mask' fields to a 'subnet' field in CIDR notation.
|
||||
4. Searches for the subnet with the given subnetId in the subnets_collection.
|
||||
5. Updates the subnet fields ('subnet', 'nextServer', 'bootFileName') if they are present in the JSON data.
|
||||
6. Returns a success response if the subnet is found and updated.
|
||||
7. Returns an error response if the subnet is not found.
|
||||
"""
|
||||
@app.route('/ogdhcp/v1/subnets/<int:subnetId>', methods=['PUT'])
|
||||
def update_subnet(subnetId):
|
||||
|
||||
|
||||
if subnetId == 0:
|
||||
return jsonify({
|
||||
"error": "Error al guardar la configuración en Kea DHCP: Unable to save configuration"
|
||||
}), 400
|
||||
try:
|
||||
modify_data = json.loads(request.data)
|
||||
except json.JSONDecodeError:
|
||||
return "Invalid JSON", 400
|
||||
|
||||
print ("Modify data", modify_data)
|
||||
print ("Modify data type", type(modify_data))
|
||||
if modify_data.get("address") != None and modify_data.get("mask") == None:
|
||||
print ("Address", modify_data.get("address"))
|
||||
return jsonify({
|
||||
"error": f"Error: La máscara de red es requerida con el parametro 'address'"
|
||||
}), 400
|
||||
if modify_data.get("mask") != None and modify_data.get("address") == None:
|
||||
return jsonify({
|
||||
"error": f"Error: La dirección de red es requerida con el parametro 'mask'"
|
||||
}), 400
|
||||
|
||||
subnet_to_update = None
|
||||
|
||||
for subnet in subnets_collection:
|
||||
# Casting subnet["id"] to int to avoid type mismatch
|
||||
if str(subnet["id"]) == str(subnetId):
|
||||
# subnet_to_update = subnet
|
||||
if modify_data.get("subnet"):
|
||||
subnet["subnet"] = modify_data["subnet"]
|
||||
|
||||
if modify_data.get("nextServer"):
|
||||
subnet["next-server"] = modify_data["nextServer"]
|
||||
|
||||
if modify_data.get("bootFileName"):
|
||||
subnet["boot-file-name"] = modify_data["bootFileName"]
|
||||
subnet_to_update = subnet
|
||||
break
|
||||
|
||||
if subnet_to_update:
|
||||
# subnet_to_update.update(modify_data)
|
||||
print ("Subnet to update", subnet_to_update)
|
||||
return jsonify({
|
||||
"success": "Subred modificada correctamente",
|
||||
"message": subnet_to_update
|
||||
}), 200
|
||||
|
||||
else:
|
||||
# Si no se encuentra la subred, devolver un error
|
||||
print (f"Subnet Collection {subnets_collection}")
|
||||
response = jsonify({
|
||||
"error": f"Error: La subred con el id '{subnetId}' no existe"
|
||||
})
|
||||
response.status_code = 404
|
||||
response.headers["Content-Type"] = "application/json"
|
||||
return response
|
||||
|
||||
|
||||
# Endpoint GET /ogdhcp/v1/subnets/<subnetId>/hosts
|
||||
@app.route('/ogdhcp/v1/subnets/<int:subnetId>/hosts', methods=['GET'])
|
||||
def get_hosts(subnetId):
|
||||
# Simular respuesta de éxito
|
||||
return jsonify({
|
||||
"success": "Hosts retrieved successfully",
|
||||
"message": [
|
||||
{"ip-address": "192.168.1.10", "hw-address": "00:0c:29:6b:5e:71", "hostname": "host1"},
|
||||
{"ip-address": "192.168.1.20", "hw-address": "00:0c:29:6b:5e:72", "hostname": "host2"}
|
||||
]
|
||||
}), 200
|
||||
|
||||
# Endpoint POST /ogdhcp/v1/subnets/<subnetId>/hosts
|
||||
@app.route('/ogdhcp/v1/subnets/<int:subnetId>/hosts', methods=['POST'])
|
||||
def create_host(subnetId):
|
||||
# Simular respuesta de éxito
|
||||
return jsonify({
|
||||
"success": "Host agregado correctamente",
|
||||
"message": {
|
||||
"id": 1,
|
||||
"subnet": "192.168.1.0/24",
|
||||
"next-server": "192.168.1.1",
|
||||
"boot-file-name": "pxelinux.0",
|
||||
"reservations": [
|
||||
{"hostname": "pc11", "hw-address": "56:6f:c7:4f:00:4f", "ip-address": "172.30.4.11"}
|
||||
]
|
||||
}
|
||||
}), 200
|
||||
|
||||
# Endpoint DELETE /ogdhcp/v1/subnets/<subnetId>/hosts
|
||||
@app.route('/ogdhcp/v1/subnets/<int:subnetId>/hosts', methods=['DELETE'])
|
||||
def delete_host(subnetId):
|
||||
# Simular respuesta de éxito
|
||||
return jsonify({
|
||||
"success": "Host eliminado correctamente",
|
||||
"message": {
|
||||
"id": 1,
|
||||
"subnet": "192.168.1.0/24",
|
||||
"next-server": "192.168.1.1",
|
||||
"boot-file-name": "pxelinux.0",
|
||||
"reservations": [
|
||||
{"hostname": "host2", "hw-address": "00:0c:29:6b:5e:72", "ip-address": "172.30.4.12"}
|
||||
]
|
||||
}
|
||||
}), 200
|
||||
|
||||
# Endpoint PUT /ogdhcp/v1/subnets/<subnetId>/hosts
|
||||
@app.route('/ogdhcp/v1/subnets/<int:subnetId>/hosts', methods=['PUT'])
|
||||
def update_host(subnetId):
|
||||
# Simular respuesta de éxito
|
||||
return jsonify({
|
||||
"success": "Host actualizado correctamente",
|
||||
"message": {
|
||||
"id": 1,
|
||||
"subnet": "192.168.1.0/24",
|
||||
"next-server": "192.168.1.1",
|
||||
"boot-file-name": "pxelinux.0",
|
||||
"reservations": [
|
||||
{"hostname": "pc11", "hw-address": "56:6f:c7:4f:01:01", "ip-address": "192.168.1.11"},
|
||||
{"hostname": "host2", "hw-address": "00:0c:29:6b:5e:72", "ip-address": "192.168.1.12"}
|
||||
]
|
||||
}
|
||||
}), 200
|
||||
|
||||
# Endpoint POST /ogdhcp/v1/backup
|
||||
@app.route('/ogdhcp/v1/backup', methods=['POST'])
|
||||
def backup_config():
|
||||
# Simular respuesta de éxito
|
||||
return jsonify({
|
||||
"success": "Configuración cargada correctamente"
|
||||
}), 200
|
||||
|
||||
if __name__ == '__main__':
|
||||
app.run(debug=True, port=8006)
|
|
@ -0,0 +1,2 @@
|
|||
robotframework
|
||||
robotframework-requests
|
|
@ -0,0 +1,215 @@
|
|||
*** Settings ***
|
||||
Documentation This is a basic skeleton for a Robot Framework test suite.
|
||||
Library Collections
|
||||
Library RequestsLibrary
|
||||
|
||||
|
||||
|
||||
*** Variables ***
|
||||
${BASE_URL} http://localhost:8006/ogdhcp/v1
|
||||
${headers} Create Dictionary Content-Type application/json
|
||||
${modified_subnet} Create Dictionary mask=255.255.192.0 address=192.168.1.0 nextServer=192.168.1.1 bootFileName=pxelinux.0
|
||||
${wrong_subnet_data_netmask} Create Dictionary mask=333.333.333.333 address=192.168.1.0 nextServer=192.168.1.1 bootFileName=pxelinux.0
|
||||
${wrong_subnet_data_address} Create Dictionary mask=255.255.255.0 address=444.168.1.0 nextServer=192.168.1.1 bootFileName=pxelinux.0
|
||||
${wrong_subnet_data_server} Create Dictionary mask=255.255.255.0 address=192.168.1.0 nextServer=555.168.1.1 bootFileName=pxelinux.0
|
||||
${invalid_net_id} 999
|
||||
${valid_net_id} 2
|
||||
${subnet_error} 0
|
||||
|
||||
*** Test Cases ***
|
||||
Get Status of the DHCP server
|
||||
[Documentation] Get status of the dhcp server and check services status
|
||||
[Tags] status
|
||||
${response}= GET ${BASE_URL}/status
|
||||
Status Should Be 200 ${response}
|
||||
Log ${response.json()}
|
||||
# Convertir la respuesta a JSON usando ${response.json()}
|
||||
${json}= Convert to Dictionary ${response.json()}
|
||||
Dictionary Should Contain Key ${json} success
|
||||
Dictionary Should Contain Key ${json} message
|
||||
Should Contain ${response.json()['message']} disk_usage
|
||||
Should Contain ${response.json()['message']} subnets
|
||||
Should Contain ${response.json()['message']['disk_usage']} total
|
||||
|
||||
|
||||
Get All Subnets
|
||||
[Documentation] Este test verifica que la API retorna las subredes correctamente con el código 200.
|
||||
[Tags] subnets
|
||||
${response}= GET ${BASE_URL}/subnets
|
||||
# Verificar código de estado HTTP
|
||||
Should Be Equal As Numbers ${response.status_code} 200
|
||||
${json}= Convert To Dictionary ${response.json()}
|
||||
# Verificar que la respuesta contiene las claves 'success' y 'message'
|
||||
Dictionary Should Contain Key ${json} success
|
||||
Dictionary Should Contain Key ${json} message
|
||||
# Validar el mensaje de éxito
|
||||
Should Be Equal ${json['success']} Subredes obtenidas correctamente
|
||||
# Verificar que 'message' es una lista
|
||||
# Should Be True ${json['message']} is list
|
||||
# Verificar que cada subred en 'message' tiene los campos esperados
|
||||
FOR ${subred} IN @{json['message']}
|
||||
Dictionary Should Contain Key ${subred} id
|
||||
Dictionary Should Contain Key ${subred} subnet
|
||||
END
|
||||
|
||||
Post a new subnet
|
||||
[Documentation] Post a new subnet
|
||||
[Tags] subnets
|
||||
${new_subnet} Create Dictionary
|
||||
... subnetId=${valid_net_id}
|
||||
... mask=255.255.255.0
|
||||
... address=192.168.2.0
|
||||
... nextServer=192.168.2.1
|
||||
... bootFileName=pxelinux.0
|
||||
${headers}= Create Dictionary Content-Type=application/json
|
||||
${response}= POST ${BASE_URL}/subnets json=${new_subnet} headers=${headers}
|
||||
Status Should Be 200 ${response}
|
||||
${json}= Convert to Dictionary ${response.json()}
|
||||
Dictionary Should Contain Key ${json} success
|
||||
Dictionary Should Contain Key ${json} message
|
||||
Should Contain ${json["success"]} Subred agregada correctamente
|
||||
Should Be Equal As Numbers ${json["message"]["id"]} ${valid_net_id}
|
||||
|
||||
|
||||
Post a new subnet with existing id
|
||||
[Documentation] Post a new subnet with invalid data
|
||||
[Tags] subnets
|
||||
${new_subnet} Create Dictionary
|
||||
... subnetId=2
|
||||
... mask=255.255.255.0
|
||||
... address=192.168.3.0
|
||||
... nextServer=192.168.3.1
|
||||
... bootFileName=pxelinux.0
|
||||
${headers}= Create Dictionary Content-Type=application/json
|
||||
${response}= POST ${BASE_URL}/subnets json=${new_subnet} headers=${headers} expected_status=400
|
||||
Status Should Be 400 ${response}
|
||||
${json}= Convert to Dictionary ${response.json()}
|
||||
Dictionary Should Contain Key ${json} error
|
||||
Should Contain ${response.json()["error"]} La subred con el id '${valid_net_id}' ya existe.
|
||||
|
||||
Post a new subnet with existing address
|
||||
[Documentation] Post a new subnet with invalid data
|
||||
[Tags] subnets
|
||||
${headers}= Create Dictionary Content-Type=application/json
|
||||
${new_subnet_invalid} Create Dictionary
|
||||
... subnetId=3
|
||||
... mask=255.255.255.0
|
||||
... address=192.168.1.0
|
||||
... nextServer=192.168.1.1
|
||||
... bootFileName=pxelinux.0
|
||||
|
||||
${response}= POST ${BASE_URL}/subnets json=${new_subnet_invalid} headers=${headers} expected_status=400
|
||||
Status Should Be 400 ${response}
|
||||
${json}= Convert to Dictionary ${response.json()}
|
||||
Dictionary Should Contain Key ${json} error
|
||||
Should Contain ${response.json()['error']} La subred con la dirección '192.168.1.0/24' ya existe
|
||||
|
||||
|
||||
Modify an existing subnet by id
|
||||
[Documentation] Modify a subnet by id
|
||||
[Tags] subnets
|
||||
${headers}= Create Dictionary Content-Type=application/json
|
||||
${modified_subnet}= Create Dictionary
|
||||
... mask=255.255.192.0
|
||||
... address=192.168.1.0
|
||||
... nextServer=192.168.1.1
|
||||
... bootFileName=pxelinux.0
|
||||
# Modificar la subred con id=2
|
||||
${response}= PUT ${BASE_URL}/subnets/2 json=${modified_subnet} headers=${headers} expected_status=200
|
||||
Status Should Be 200 ${response}
|
||||
${json}= Convert to Dictionary ${response.json()}
|
||||
# Verificar que la respuesta contiene clave 'success'
|
||||
Dictionary Should Contain Key ${json} success
|
||||
|
||||
# Validar el contenido del mensaje de éxito
|
||||
Should Be Equal ${json['success']} Subred modificada correctamente
|
||||
Should Be Equal ${json['message']['id']} 2
|
||||
|
||||
|
||||
Modify a subnet with invalid id
|
||||
[Documentation] Este test verifica que la modificación de una subred falla cuando el ID no existe.
|
||||
[Tags] subnets
|
||||
${headers}= Create Dictionary Content-Type=application/json
|
||||
${modificar_subred}= Create Dictionary mask=255.255.192.0 address=192.168.1.0 nextServer=192.168.1.1 bootFileName=pxelinux.0
|
||||
${response}= PUT ${BASE_URL}/ogdhcp/v1/subnets/${invalid_net_id} json=${modificar_subred} headers=${headers} expected_status=404
|
||||
|
||||
# Verificar código de estado HTTP
|
||||
Should Be Equal As Numbers ${response.status_code} 404
|
||||
|
||||
|
||||
|
||||
Modify subnet with error to save configuration
|
||||
[Documentation] Este test verifica que la modificación falla cuando hay un error al guardar la configuración en Kea DHCP.
|
||||
[Tags] subnets
|
||||
${headers}= Create Dictionary Content-Type=application/json
|
||||
${modificar_subred}= Create Dictionary subnet="192.168.1.0" mask="255.255.255.0" nextServer="192.168.1.1" bootFileName="pxelinux.0"
|
||||
${response}= PUT ${BASE_URL}/subnets/${subnet_error} json=${modificar_subred} headers=${headers} expected_status=400
|
||||
|
||||
# Verificar código de estado HTTP
|
||||
Should Be Equal As Numbers ${response.status_code} 400
|
||||
|
||||
${json}= Convert To Dictionary ${response.json()}
|
||||
|
||||
# Verificar que la respuesta contiene el error esperado
|
||||
Should Be Equal ${json['error']} Error al guardar la configuración en Kea DHCP: Unable to save configuration
|
||||
|
||||
Modify subnet with invalid configuration address without netmask
|
||||
[Documentation] Este test verifica que la modificación falla cuando hay un error en la configuración de Kea DHCP.
|
||||
[Tags] subnets
|
||||
${headers}= Create Dictionary Content-Type=application/json
|
||||
${modificar_subred}= Create Dictionary address="192.168.1.0" nextServer="192.168.1.1" bootFileName="pxelinux.0"
|
||||
|
||||
${response}= PUT ${BASE_URL}/subnets/2 json=${modificar_subred} headers=${headers} expected_status=400
|
||||
|
||||
# Verificar código de estado HTTP
|
||||
Should Be Equal As Numbers ${response.status_code} 400
|
||||
|
||||
${json}= Convert To Dictionary ${response.json()}
|
||||
|
||||
# Verificar que la respuesta contiene el error esperado
|
||||
Should Be Equal ${json['error']} Falta un parámetro requerido: mask
|
||||
|
||||
Modify subnet with invalid configuration netmask without address
|
||||
[Documentation] Este test verifica que la modificación falla cuando hay un error en la configuración de Kea DHCP.
|
||||
[Tags] subnets
|
||||
${headers}= Create Dictionary Content-Type=application/json
|
||||
${modificar_subred}= Create Dictionary mask="255.255.255.0" nextServer="192.168.1.1" bootFileName="pxelinux.0"
|
||||
|
||||
${response}= PUT ${BASE_URL}/subnets/2 json=${modificar_subred} headers=${headers} expected_status=400
|
||||
|
||||
# Verificar código de estado HTTP
|
||||
Should Be Equal As Numbers ${response.status_code} 400
|
||||
|
||||
${json}= Convert To Dictionary ${response.json()}
|
||||
|
||||
# Verificar que la respuesta contiene el error esperado
|
||||
Should Be Equal ${json['error']} Falta un parámetro requerido: address
|
||||
|
||||
Delete subnet by id
|
||||
[Documentation] Este test verifica que la subred se elimina correctamente con el código 200.
|
||||
[Tags] subnets
|
||||
${response}= DELETE ${BASE_URL}/subnets/${valid_net_id}
|
||||
# Verificar código de estado HTTP
|
||||
Should Be Equal As Numbers ${response.status_code} 200
|
||||
${json}= Convert To Dictionary ${response.json()}
|
||||
# Verificar que la respuesta contiene la clave 'success'
|
||||
Dictionary Should Contain Key ${json} success
|
||||
# Validar el mensaje de éxito
|
||||
Should Be Equal ${json['success']} Subred eliminada correctamente
|
||||
|
||||
Delete subnet - Error: wrong subnet Id
|
||||
[Documentation] Este test verifica que la eliminación falla si la subred con el ID no existe.
|
||||
[Tags] subnets
|
||||
${response}= DELETE ${BASE_URL}/subnets/${invalid_net_id} expected_status=404
|
||||
# Verificar código de estado HTTP
|
||||
Should Be Equal As Numbers ${response.status_code} 404
|
||||
${json}= Convert To Dictionary ${response.json()}
|
||||
# Verificar que la respuesta contiene la clave 'error'
|
||||
Dictionary Should Contain Key ${json} error
|
||||
# Validar el mensaje de error
|
||||
Should Be Equal ${json['error']} La subred con el id '999' no existe
|
||||
|
||||
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue