From 2946fc1d19c8d9dfbe2c7f4a381f0e1eeab2f9a0 Mon Sep 17 00:00:00 2001 From: lgromero Date: Fri, 18 Oct 2024 12:49:42 +0200 Subject: [PATCH] refs #981 #984 adds a minimal kea configuration to the installer, adds a json with the interfaces and the ogbootIp, adds gateway configuration when a subnet is create o modified in the controller --- installer/config_ogdhcp.json | 4 + installer/ogdhcp_installer.sh | 74 ++++++ src/DhcpBundle/Controller/DhcpController.php | 241 ++++++++++--------- 3 files changed, 211 insertions(+), 108 deletions(-) create mode 100644 installer/config_ogdhcp.json diff --git a/installer/config_ogdhcp.json b/installer/config_ogdhcp.json new file mode 100644 index 0000000..3e9feca --- /dev/null +++ b/installer/config_ogdhcp.json @@ -0,0 +1,4 @@ +{ + "interfaces": ["eth0", "eth1"], + "ogbootIP": "172.17.8.37" +} \ No newline at end of file diff --git a/installer/ogdhcp_installer.sh b/installer/ogdhcp_installer.sh index d193370..e739f30 100755 --- a/installer/ogdhcp_installer.sh +++ b/installer/ogdhcp_installer.sh @@ -450,6 +450,73 @@ modify_php_fpm_config() { } +configure_kea() { + # Ruta del archivo config_ogdhcp.json proporcionado por el usuario + CONFIG_FILE="config_ogdhcp.json" + + # 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" +} + + + ##################################################################### ####### Algunas funciones útiles de propósito general: ##################################################################### @@ -555,6 +622,13 @@ if [ $? -ne 0 ]; then 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 diff --git a/src/DhcpBundle/Controller/DhcpController.php b/src/DhcpBundle/Controller/DhcpController.php index d227498..959ece7 100644 --- a/src/DhcpBundle/Controller/DhcpController.php +++ b/src/DhcpBundle/Controller/DhcpController.php @@ -356,103 +356,115 @@ public function getSubnets(): JsonResponse */ -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(); - if (strpos($e->getMessage(), 'Undefined property') !== false) { - preg_match('/Undefined property: stdClass::\$(\w+)/', $e->getMessage(), $matches); - $paramFaltante = $matches[1] ?? 'desconocido'; - return new JsonResponse(['error' => "Falta un parámetro requerido: $paramFaltante"], 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'] = []; - } - - $subnets = $response[0]['arguments']['Dhcp4']['subnet4']; - - // Verificar si el nombre de la subred o el ID ya existe - $subnetNameExists = array_reduce($subnets, function ($exists, $subnetElement) use ($subnetName) { - return $exists || ($subnetElement['subnet'] === $subnetName); - }, false); - - $subnetIdExists = array_reduce($subnets, function ($exists, $subnetElement) use ($subnetId) { - return $exists || ($subnetElement['id'] === $subnetId); - }, false); - - if ($subnetNameExists) { - return new JsonResponse(['error' => "La subred con la ip '$subnetName' ya existe."], 400); - } elseif ($subnetIdExists) { - return new JsonResponse(['error' => "La subred con el ID '$subnetId' ya existe."], 400); - } else { - $response[0]['arguments']['Dhcp4']['subnet4'][] = $newSubnet; - - // Eliminar el campo 'hash' si existe - if (isset($response[0]['arguments']['hash'])) { - unset($response[0]['arguments']['hash']); - } - - $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) { - return new JsonResponse(['error' => "Error al guardar la configuración en Kea DHCP: " . $responseSet[0]["text"]], 400); - } else { - $responseWrite = $this->curlKeaService->executeCurlCommand('config-write', $configuration); - if ($responseWrite == false || $responseWrite[0]["result"] != 0) { - return new JsonResponse(['error' => "Error al guardar la configuración en Kea DHCP: " . $responseWrite[0]["text"]], 400); - } else { - // Realizar una nueva consulta a Kea para obtener la subred recién creada - $configGetResponse = $this->curlKeaService->executeCurlCommand('config-get'); - - // Buscar la subred creada - $createdSubnet = null; - foreach ($configGetResponse[0]['arguments']['Dhcp4']['subnet4'] as $subnet) { - if ($subnet['id'] == $subnetId) { - $createdSubnet = $subnet; - break; - } - } - - if ($createdSubnet === null) { - return new JsonResponse(['error' => "No se pudo encontrar la subred creada"], 400); - } - - return new JsonResponse(['success' => "Subred agregada correctamente", 'message' => $createdSubnet], 200); - } - } - } else { - return new JsonResponse(['error' => "Error en la configuración de Kea: " . $responseTest[0]["text"]], 400); - } - } - } catch (Exception $e) { - return new JsonResponse(['error' => "Error al obtener la configuración de Kea DHCP: " . $e->getMessage()], 500); - } -} + 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(); + if (strpos($e->getMessage(), 'Undefined property') !== false) { + preg_match('/Undefined property: stdClass::\$(\w+)/', $e->getMessage(), $matches); + $paramFaltante = $matches[1] ?? 'desconocido'; + return new JsonResponse(['error' => "Falta un parámetro requerido: $paramFaltante"], 400); + } + } + + try { + $response = $this->curlKeaService->executeCurlCommand('config-get'); + $subnetName = $address . '/' . $this->curlKeaService->convertMaskToCIDR($mask); + + // Crear el campo option-data para la puerta de enlace (gateway) + $gatewayIP = substr($address, 0, strrpos($address, '.')) . '.1'; + + $newSubnet = [ + "id" => $subnetId, + "subnet" => $subnetName, + "next-server" => $nextServer, + "boot-file-name" => $bootFileName, + "reservations" => [], + "option-data" => [ + [ + "name" => "routers", + "code" => 3, + "data" => $gatewayIP + ] + ] + ]; + + if (!isset($response[0]['arguments']['Dhcp4']['subnet4'])) { + $response[0]['arguments']['Dhcp4']['subnet4'] = []; + } + + $subnets = $response[0]['arguments']['Dhcp4']['subnet4']; + + // Verificar si el nombre de la subred o el ID ya existe + $subnetNameExists = array_reduce($subnets, function ($exists, $subnetElement) use ($subnetName) { + return $exists || ($subnetElement['subnet'] === $subnetName); + }, false); + + $subnetIdExists = array_reduce($subnets, function ($exists, $subnetElement) use ($subnetId) { + return $exists || ($subnetElement['id'] === $subnetId); + }, false); + + if ($subnetNameExists) { + return new JsonResponse(['error' => "La subred con la ip '$subnetName' ya existe."], 400); + } elseif ($subnetIdExists) { + return new JsonResponse(['error' => "La subred con el ID '$subnetId' ya existe."], 400); + } else { + $response[0]['arguments']['Dhcp4']['subnet4'][] = $newSubnet; + + // Eliminar el campo 'hash' si existe + if (isset($response[0]['arguments']['hash'])) { + unset($response[0]['arguments']['hash']); + } + + $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) { + return new JsonResponse(['error' => "Error al guardar la configuración en Kea DHCP: " . $responseSet[0]["text"]], 400); + } else { + $responseWrite = $this->curlKeaService->executeCurlCommand('config-write', $configuration); + if ($responseWrite == false || $responseWrite[0]["result"] != 0) { + return new JsonResponse(['error' => "Error al guardar la configuración en Kea DHCP: " . $responseWrite[0]["text"]], 400); + } else { + // Realizar una nueva consulta a Kea para obtener la subred recién creada + $configGetResponse = $this->curlKeaService->executeCurlCommand('config-get'); + + // Buscar la subred creada + $createdSubnet = null; + foreach ($configGetResponse[0]['arguments']['Dhcp4']['subnet4'] as $subnet) { + if ($subnet['id'] == $subnetId) { + $createdSubnet = $subnet; + break; + } + } + + if ($createdSubnet === null) { + return new JsonResponse(['error' => "No se pudo encontrar la subred creada"], 400); + } + + return new JsonResponse(['success' => "Subred agregada correctamente", 'message' => $createdSubnet], 200); + } + } + } else { + return new JsonResponse(['error' => "Error en la configuración de Kea: " . $responseTest[0]["text"]], 400); + } + } + } catch (Exception $e) { + return new JsonResponse(['error' => "Error al obtener la configuración de Kea DHCP: " . $e->getMessage()], 500); + } + } + /** * @OA\Delete( @@ -693,7 +705,7 @@ public function addDhcpSubnet(Request $request): JsonResponse public function modifyDhcpSubnet(Request $request): JsonResponse { $subnetId = (int) $request->get('subnetId'); - + try { $input = json_decode($request->getContent()); $mask = htmlspecialchars($input->mask); @@ -708,39 +720,52 @@ public function addDhcpSubnet(Request $request): JsonResponse return new JsonResponse(['error' => "Falta un parámetro requerido: $paramFaltante"], 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 = "La subred con el id '$subnetId' no existe"; return new JsonResponse(['error' => $responseError], 400); } else { + // Calcular el gateway añadiendo .1 al final de la subred + $gateway = preg_replace('/\d+$/', '1', $address); + + // Modificar la subred existente $response[0]['arguments']['Dhcp4']['subnet4'][$subnetIndex] = [ "id" => $subnetId, "subnet" => $subnetName, "next-server" => $nextServer, "boot-file-name" => $bootFileName, - "reservations" => [] + "reservations" => [], + "option-data" => [ + [ + "name" => "routers", + "code" => 3, + "data" => $gateway + ] + ] ]; + // Eliminar el campo 'hash' si existe if (isset($response[0]['arguments']['hash'])) { unset($response[0]['arguments']['hash']); } + $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) { @@ -757,7 +782,7 @@ public function addDhcpSubnet(Request $request): JsonResponse $updatedSubnet = array_filter($updatedResponse[0]['arguments']['Dhcp4']['subnet4'], function ($subnet) use ($subnetId) { return $subnet['id'] == $subnetId; }); - + $responseSuccess = "Subred modificada correctamente"; return new JsonResponse(['success' => $responseSuccess,'message' => reset($updatedSubnet)], 200); } @@ -772,7 +797,7 @@ public function addDhcpSubnet(Request $request): JsonResponse return new JsonResponse(['error' => $responseError], 500); } } - + /** * @OA\Get( * path="/ogdhcp/v1/subnets/{subnetId}/hosts", @@ -1035,7 +1060,7 @@ public function addDhcpHost(Request $request, $subnetId): JsonResponse } } if ($createdHost) { - return new JsonResponse(['success' => "Host agregado correctamente", 'newHost' => $createdHost], 200); + return new JsonResponse(['success' => "Host agregado correctamente", 'message' => $createdHost], 200); } else { return new JsonResponse(['error' => "No se pudo encontrar el host recién creado"], 400); }